001/*
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements.  See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License.  You may obtain a copy of the License at
008 *
009 *      http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017package org.apache.commons.lang3;
018
019import java.io.UnsupportedEncodingException;
020import java.nio.charset.Charset;
021import java.text.Normalizer;
022import java.util.ArrayList;
023import java.util.Arrays;
024import java.util.HashSet;
025import java.util.Iterator;
026import java.util.List;
027import java.util.Locale;
028import java.util.Objects;
029import java.util.Set;
030import java.util.function.Supplier;
031import java.util.regex.Pattern;
032
033import org.apache.commons.lang3.function.Suppliers;
034import org.apache.commons.lang3.function.ToBooleanBiFunction;
035import org.apache.commons.lang3.stream.LangCollectors;
036import org.apache.commons.lang3.stream.Streams;
037
038/**
039 * Operations on {@link String} that are
040 * {@code null} safe.
041 *
042 * <ul>
043 *  <li><b>IsEmpty/IsBlank</b>
044 *      - checks if a String contains text</li>
045 *  <li><b>Trim/Strip</b>
046 *      - removes leading and trailing whitespace</li>
047 *  <li><b>Equals/Compare</b>
048 *      - compares two strings in a null-safe manner</li>
049 *  <li><b>startsWith</b>
050 *      - check if a String starts with a prefix in a null-safe manner</li>
051 *  <li><b>endsWith</b>
052 *      - check if a String ends with a suffix in a null-safe manner</li>
053 *  <li><b>IndexOf/LastIndexOf/Contains</b>
054 *      - null-safe index-of checks
055 *  <li><b>IndexOfAny/LastIndexOfAny/IndexOfAnyBut/LastIndexOfAnyBut</b>
056 *      - index-of any of a set of Strings</li>
057 *  <li><b>ContainsOnly/ContainsNone/ContainsAny</b>
058 *      - checks if String contains only/none/any of these characters</li>
059 *  <li><b>Substring/Left/Right/Mid</b>
060 *      - null-safe substring extractions</li>
061 *  <li><b>SubstringBefore/SubstringAfter/SubstringBetween</b>
062 *      - substring extraction relative to other strings</li>
063 *  <li><b>Split/Join</b>
064 *      - splits a String into an array of substrings and vice versa</li>
065 *  <li><b>Remove/Delete</b>
066 *      - removes part of a String</li>
067 *  <li><b>Replace/Overlay</b>
068 *      - Searches a String and replaces one String with another</li>
069 *  <li><b>Chomp/Chop</b>
070 *      - removes the last part of a String</li>
071 *  <li><b>AppendIfMissing</b>
072 *      - appends a suffix to the end of the String if not present</li>
073 *  <li><b>PrependIfMissing</b>
074 *      - prepends a prefix to the start of the String if not present</li>
075 *  <li><b>LeftPad/RightPad/Center/Repeat</b>
076 *      - pads a String</li>
077 *  <li><b>UpperCase/LowerCase/SwapCase/Capitalize/Uncapitalize</b>
078 *      - changes the case of a String</li>
079 *  <li><b>CountMatches</b>
080 *      - counts the number of occurrences of one String in another</li>
081 *  <li><b>IsAlpha/IsNumeric/IsWhitespace/IsAsciiPrintable</b>
082 *      - checks the characters in a String</li>
083 *  <li><b>DefaultString</b>
084 *      - protects against a null input String</li>
085 *  <li><b>Rotate</b>
086 *      - rotate (circular shift) a String</li>
087 *  <li><b>Reverse/ReverseDelimited</b>
088 *      - reverses a String</li>
089 *  <li><b>Abbreviate</b>
090 *      - abbreviates a string using ellipses or another given String</li>
091 *  <li><b>Difference</b>
092 *      - compares Strings and reports on their differences</li>
093 *  <li><b>LevenshteinDistance</b>
094 *      - the number of changes needed to change one String into another</li>
095 * </ul>
096 *
097 * <p>The {@link StringUtils} class defines certain words related to
098 * String handling.</p>
099 *
100 * <ul>
101 *  <li>null - {@code null}</li>
102 *  <li>empty - a zero-length string ({@code ""})</li>
103 *  <li>space - the space character ({@code ' '}, char 32)</li>
104 *  <li>whitespace - the characters defined by {@link Character#isWhitespace(char)}</li>
105 *  <li>trim - the characters &lt;= 32 as in {@link String#trim()}</li>
106 * </ul>
107 *
108 * <p>{@link StringUtils} handles {@code null} input Strings quietly.
109 * That is to say that a {@code null} input will return {@code null}.
110 * Where a {@code boolean} or {@code int} is being returned
111 * details vary by method.</p>
112 *
113 * <p>A side effect of the {@code null} handling is that a
114 * {@link NullPointerException} should be considered a bug in
115 * {@link StringUtils}.</p>
116 *
117 * <p>Methods in this class include sample code in their Javadoc comments to explain their operation.
118 * The symbol {@code *} is used to indicate any input including {@code null}.</p>
119 *
120 * <p>#ThreadSafe#</p>
121 * @see String
122 * @since 1.0
123 */
124//@Immutable
125public class StringUtils {
126
127    // Performance testing notes (JDK 1.4, Jul03, scolebourne)
128    // Whitespace:
129    // Character.isWhitespace() is faster than WHITESPACE.indexOf()
130    // where WHITESPACE is a string of all whitespace characters
131    //
132    // Character access:
133    // String.charAt(n) versus toCharArray(), then array[n]
134    // String.charAt(n) is about 15% worse for a 10K string
135    // They are about equal for a length 50 string
136    // String.charAt(n) is about 4 times better for a length 3 string
137    // String.charAt(n) is best bet overall
138    //
139    // Append:
140    // String.concat about twice as fast as StringBuffer.append
141    // (not sure who tested this)
142
143    /**
144     * A String for a space character.
145     *
146     * @since 3.2
147     */
148    public static final String SPACE = " ";
149
150    /**
151     * The empty String {@code ""}.
152     * @since 2.0
153     */
154    public static final String EMPTY = "";
155
156    /**
157     * A String for linefeed LF ("\n").
158     *
159     * @see <a href="https://docs.oracle.com/javase/specs/jls/se8/html/jls-3.html#jls-3.10.6">JLF: Escape Sequences
160     *      for Character and String Literals</a>
161     * @since 3.2
162     */
163    public static final String LF = "\n";
164
165    /**
166     * A String for carriage return CR ("\r").
167     *
168     * @see <a href="https://docs.oracle.com/javase/specs/jls/se8/html/jls-3.html#jls-3.10.6">JLF: Escape Sequences
169     *      for Character and String Literals</a>
170     * @since 3.2
171     */
172    public static final String CR = "\r";
173
174    /**
175     * Represents a failed index search.
176     * @since 2.1
177     */
178    public static final int INDEX_NOT_FOUND = -1;
179
180    /**
181     * The maximum size to which the padding constant(s) can expand.
182     */
183    private static final int PAD_LIMIT = 8192;
184
185    /**
186     * Pattern used in {@link #stripAccents(String)}.
187     */
188    private static final Pattern STRIP_ACCENTS_PATTERN = Pattern.compile("\\p{InCombiningDiacriticalMarks}+"); //$NON-NLS-1$
189
190    /**
191     * Abbreviates a String using ellipses. This will turn
192     * "Now is the time for all good men" into "Now is the time for..."
193     *
194     * <p>Specifically:</p>
195     * <ul>
196     *   <li>If the number of characters in {@code str} is less than or equal to
197     *       {@code maxWidth}, return {@code str}.</li>
198     *   <li>Else abbreviate it to {@code (substring(str, 0, max-3) + "...")}.</li>
199     *   <li>If {@code maxWidth} is less than {@code 4}, throw an
200     *       {@link IllegalArgumentException}.</li>
201     *   <li>In no case will it return a String of length greater than
202     *       {@code maxWidth}.</li>
203     * </ul>
204     *
205     * <pre>
206     * StringUtils.abbreviate(null, *)      = null
207     * StringUtils.abbreviate("", 4)        = ""
208     * StringUtils.abbreviate("abcdefg", 6) = "abc..."
209     * StringUtils.abbreviate("abcdefg", 7) = "abcdefg"
210     * StringUtils.abbreviate("abcdefg", 8) = "abcdefg"
211     * StringUtils.abbreviate("abcdefg", 4) = "a..."
212     * StringUtils.abbreviate("abcdefg", 3) = IllegalArgumentException
213     * </pre>
214     *
215     * @param str  the String to check, may be null
216     * @param maxWidth  maximum length of result String, must be at least 4
217     * @return abbreviated String, {@code null} if null String input
218     * @throws IllegalArgumentException if the width is too small
219     * @since 2.0
220     */
221    public static String abbreviate(final String str, final int maxWidth) {
222        return abbreviate(str, "...", 0, maxWidth);
223    }
224
225    /**
226     * Abbreviates a String using ellipses. This will turn
227     * "Now is the time for all good men" into "...is the time for..."
228     *
229     * <p>Works like {@code abbreviate(String, int)}, but allows you to specify
230     * a "left edge" offset.  Note that this left edge is not necessarily going to
231     * be the leftmost character in the result, or the first character following the
232     * ellipses, but it will appear somewhere in the result.
233     *
234     * <p>In no case will it return a String of length greater than
235     * {@code maxWidth}.</p>
236     *
237     * <pre>
238     * StringUtils.abbreviate(null, *, *)                = null
239     * StringUtils.abbreviate("", 0, 4)                  = ""
240     * StringUtils.abbreviate("abcdefghijklmno", -1, 10) = "abcdefg..."
241     * StringUtils.abbreviate("abcdefghijklmno", 0, 10)  = "abcdefg..."
242     * StringUtils.abbreviate("abcdefghijklmno", 1, 10)  = "abcdefg..."
243     * StringUtils.abbreviate("abcdefghijklmno", 4, 10)  = "abcdefg..."
244     * StringUtils.abbreviate("abcdefghijklmno", 5, 10)  = "...fghi..."
245     * StringUtils.abbreviate("abcdefghijklmno", 6, 10)  = "...ghij..."
246     * StringUtils.abbreviate("abcdefghijklmno", 8, 10)  = "...ijklmno"
247     * StringUtils.abbreviate("abcdefghijklmno", 10, 10) = "...ijklmno"
248     * StringUtils.abbreviate("abcdefghijklmno", 12, 10) = "...ijklmno"
249     * StringUtils.abbreviate("abcdefghij", 0, 3)        = IllegalArgumentException
250     * StringUtils.abbreviate("abcdefghij", 5, 6)        = IllegalArgumentException
251     * </pre>
252     *
253     * @param str  the String to check, may be null
254     * @param offset  left edge of source String
255     * @param maxWidth  maximum length of result String, must be at least 4
256     * @return abbreviated String, {@code null} if null String input
257     * @throws IllegalArgumentException if the width is too small
258     * @since 2.0
259     */
260    public static String abbreviate(final String str, final int offset, final int maxWidth) {
261        return abbreviate(str, "...", offset, maxWidth);
262    }
263
264    /**
265     * Abbreviates a String using another given String as replacement marker. This will turn
266     * "Now is the time for all good men" into "Now is the time for..." if "..." was defined
267     * as the replacement marker.
268     *
269     * <p>Specifically:</p>
270     * <ul>
271     *   <li>If the number of characters in {@code str} is less than or equal to
272     *       {@code maxWidth}, return {@code str}.</li>
273     *   <li>Else abbreviate it to {@code (substring(str, 0, max-abbrevMarker.length) + abbrevMarker)}.</li>
274     *   <li>If {@code maxWidth} is less than {@code abbrevMarker.length + 1}, throw an
275     *       {@link IllegalArgumentException}.</li>
276     *   <li>In no case will it return a String of length greater than
277     *       {@code maxWidth}.</li>
278     * </ul>
279     *
280     * <pre>
281     * StringUtils.abbreviate(null, "...", *)      = null
282     * StringUtils.abbreviate("abcdefg", null, *)  = "abcdefg"
283     * StringUtils.abbreviate("", "...", 4)        = ""
284     * StringUtils.abbreviate("abcdefg", ".", 5)   = "abcd."
285     * StringUtils.abbreviate("abcdefg", ".", 7)   = "abcdefg"
286     * StringUtils.abbreviate("abcdefg", ".", 8)   = "abcdefg"
287     * StringUtils.abbreviate("abcdefg", "..", 4)  = "ab.."
288     * StringUtils.abbreviate("abcdefg", "..", 3)  = "a.."
289     * StringUtils.abbreviate("abcdefg", "..", 2)  = IllegalArgumentException
290     * StringUtils.abbreviate("abcdefg", "...", 3) = IllegalArgumentException
291     * </pre>
292     *
293     * @param str  the String to check, may be null
294     * @param abbrevMarker  the String used as replacement marker
295     * @param maxWidth  maximum length of result String, must be at least {@code abbrevMarker.length + 1}
296     * @return abbreviated String, {@code null} if null String input
297     * @throws IllegalArgumentException if the width is too small
298     * @since 3.6
299     */
300    public static String abbreviate(final String str, final String abbrevMarker, final int maxWidth) {
301        return abbreviate(str, abbrevMarker, 0, maxWidth);
302    }
303    /**
304     * Abbreviates a String using a given replacement marker. This will turn
305     * "Now is the time for all good men" into "...is the time for..." if "..." was defined
306     * as the replacement marker.
307     *
308     * <p>Works like {@code abbreviate(String, String, int)}, but allows you to specify
309     * a "left edge" offset.  Note that this left edge is not necessarily going to
310     * be the leftmost character in the result, or the first character following the
311     * replacement marker, but it will appear somewhere in the result.
312     *
313     * <p>In no case will it return a String of length greater than {@code maxWidth}.</p>
314     *
315     * <pre>
316     * StringUtils.abbreviate(null, null, *, *)                 = null
317     * StringUtils.abbreviate("abcdefghijklmno", null, *, *)    = "abcdefghijklmno"
318     * StringUtils.abbreviate("", "...", 0, 4)                  = ""
319     * StringUtils.abbreviate("abcdefghijklmno", "---", -1, 10) = "abcdefg---"
320     * StringUtils.abbreviate("abcdefghijklmno", ",", 0, 10)    = "abcdefghi,"
321     * StringUtils.abbreviate("abcdefghijklmno", ",", 1, 10)    = "abcdefghi,"
322     * StringUtils.abbreviate("abcdefghijklmno", ",", 2, 10)    = "abcdefghi,"
323     * StringUtils.abbreviate("abcdefghijklmno", "::", 4, 10)   = "::efghij::"
324     * StringUtils.abbreviate("abcdefghijklmno", "...", 6, 10)  = "...ghij..."
325     * StringUtils.abbreviate("abcdefghijklmno", "*", 9, 10)    = "*ghijklmno"
326     * StringUtils.abbreviate("abcdefghijklmno", "'", 10, 10)   = "'ghijklmno"
327     * StringUtils.abbreviate("abcdefghijklmno", "!", 12, 10)   = "!ghijklmno"
328     * StringUtils.abbreviate("abcdefghij", "abra", 0, 4)       = IllegalArgumentException
329     * StringUtils.abbreviate("abcdefghij", "...", 5, 6)        = IllegalArgumentException
330     * </pre>
331     *
332     * @param str  the String to check, may be null
333     * @param abbrevMarker  the String used as replacement marker
334     * @param offset  left edge of source String
335     * @param maxWidth  maximum length of result String, must be at least 4
336     * @return abbreviated String, {@code null} if null String input
337     * @throws IllegalArgumentException if the width is too small
338     * @since 3.6
339     */
340    public static String abbreviate(final String str, final String abbrevMarker, int offset, final int maxWidth) {
341        if (isNotEmpty(str) && EMPTY.equals(abbrevMarker) && maxWidth > 0) {
342            return substring(str, 0, maxWidth);
343        }
344        if (isAnyEmpty(str, abbrevMarker)) {
345            return str;
346        }
347        final int abbrevMarkerLength = abbrevMarker.length();
348        final int minAbbrevWidth = abbrevMarkerLength + 1;
349        final int minAbbrevWidthOffset = abbrevMarkerLength + abbrevMarkerLength + 1;
350
351        if (maxWidth < minAbbrevWidth) {
352            throw new IllegalArgumentException(String.format("Minimum abbreviation width is %d", minAbbrevWidth));
353        }
354        final int strLen = str.length();
355        if (strLen <= maxWidth) {
356            return str;
357        }
358        if (offset > strLen) {
359            offset = strLen;
360        }
361        if (strLen - offset < maxWidth - abbrevMarkerLength) {
362            offset = strLen - (maxWidth - abbrevMarkerLength);
363        }
364        if (offset <= abbrevMarkerLength + 1) {
365            return str.substring(0, maxWidth - abbrevMarkerLength) + abbrevMarker;
366        }
367        if (maxWidth < minAbbrevWidthOffset) {
368            throw new IllegalArgumentException(String.format("Minimum abbreviation width with offset is %d", minAbbrevWidthOffset));
369        }
370        if (offset + maxWidth - abbrevMarkerLength < strLen) {
371            return abbrevMarker + abbreviate(str.substring(offset), abbrevMarker, maxWidth - abbrevMarkerLength);
372        }
373        return abbrevMarker + str.substring(strLen - (maxWidth - abbrevMarkerLength));
374    }
375
376    /**
377     * Abbreviates a String to the length passed, replacing the middle characters with the supplied
378     * replacement String.
379     *
380     * <p>This abbreviation only occurs if the following criteria is met:</p>
381     * <ul>
382     * <li>Neither the String for abbreviation nor the replacement String are null or empty </li>
383     * <li>The length to truncate to is less than the length of the supplied String</li>
384     * <li>The length to truncate to is greater than 0</li>
385     * <li>The abbreviated String will have enough room for the length supplied replacement String
386     * and the first and last characters of the supplied String for abbreviation</li>
387     * </ul>
388     * <p>Otherwise, the returned String will be the same as the supplied String for abbreviation.
389     * </p>
390     *
391     * <pre>
392     * StringUtils.abbreviateMiddle(null, null, 0)    = null
393     * StringUtils.abbreviateMiddle("abc", null, 0)   = "abc"
394     * StringUtils.abbreviateMiddle("abc", ".", 0)    = "abc"
395     * StringUtils.abbreviateMiddle("abc", ".", 3)    = "abc"
396     * StringUtils.abbreviateMiddle("abcdef", ".", 4) = "ab.f"
397     * </pre>
398     *
399     * @param str  the String to abbreviate, may be null
400     * @param middle the String to replace the middle characters with, may be null
401     * @param length the length to abbreviate {@code str} to.
402     * @return the abbreviated String if the above criteria is met, or the original String supplied for abbreviation.
403     * @since 2.5
404     */
405    public static String abbreviateMiddle(final String str, final String middle, final int length) {
406        if (isAnyEmpty(str, middle) || length >= str.length() || length < middle.length() + 2) {
407            return str;
408        }
409        final int targetSting = length - middle.length();
410        final int startOffset = targetSting / 2 + targetSting % 2;
411        final int endOffset = str.length() - targetSting / 2;
412        return str.substring(0, startOffset) + middle + str.substring(endOffset);
413    }
414
415    /**
416     * Appends the suffix to the end of the string if the string does not
417     * already end with the suffix.
418     *
419     * @param str The string.
420     * @param suffix The suffix to append to the end of the string.
421     * @param ignoreCase Indicates whether the compare should ignore case.
422     * @param suffixes Additional suffixes that are valid terminators (optional).
423     *
424     * @return A new String if suffix was appended, the same string otherwise.
425     */
426    private static String appendIfMissing(final String str, final CharSequence suffix, final boolean ignoreCase, final CharSequence... suffixes) {
427        if (str == null || isEmpty(suffix) || endsWith(str, suffix, ignoreCase)) {
428            return str;
429        }
430        if (ArrayUtils.isNotEmpty(suffixes)) {
431            for (final CharSequence s : suffixes) {
432                if (endsWith(str, s, ignoreCase)) {
433                    return str;
434                }
435            }
436        }
437        return str + suffix;
438    }
439
440    /**
441     * Appends the suffix to the end of the string if the string does not
442     * already end with any of the suffixes.
443     *
444     * <pre>
445     * StringUtils.appendIfMissing(null, null)      = null
446     * StringUtils.appendIfMissing("abc", null)     = "abc"
447     * StringUtils.appendIfMissing("", "xyz"        = "xyz"
448     * StringUtils.appendIfMissing("abc", "xyz")    = "abcxyz"
449     * StringUtils.appendIfMissing("abcxyz", "xyz") = "abcxyz"
450     * StringUtils.appendIfMissing("abcXYZ", "xyz") = "abcXYZxyz"
451     * </pre>
452     * <p>With additional suffixes,</p>
453     * <pre>
454     * StringUtils.appendIfMissing(null, null, null)       = null
455     * StringUtils.appendIfMissing("abc", null, null)      = "abc"
456     * StringUtils.appendIfMissing("", "xyz", null)        = "xyz"
457     * StringUtils.appendIfMissing("abc", "xyz", new CharSequence[]{null}) = "abcxyz"
458     * StringUtils.appendIfMissing("abc", "xyz", "")       = "abc"
459     * StringUtils.appendIfMissing("abc", "xyz", "mno")    = "abcxyz"
460     * StringUtils.appendIfMissing("abcxyz", "xyz", "mno") = "abcxyz"
461     * StringUtils.appendIfMissing("abcmno", "xyz", "mno") = "abcmno"
462     * StringUtils.appendIfMissing("abcXYZ", "xyz", "mno") = "abcXYZxyz"
463     * StringUtils.appendIfMissing("abcMNO", "xyz", "mno") = "abcMNOxyz"
464     * </pre>
465     *
466     * @param str The string.
467     * @param suffix The suffix to append to the end of the string.
468     * @param suffixes Additional suffixes that are valid terminators.
469     *
470     * @return A new String if suffix was appended, the same string otherwise.
471     *
472     * @since 3.2
473     */
474    public static String appendIfMissing(final String str, final CharSequence suffix, final CharSequence... suffixes) {
475        return appendIfMissing(str, suffix, false, suffixes);
476    }
477
478    /**
479     * Appends the suffix to the end of the string if the string does not
480     * already end, case-insensitive, with any of the suffixes.
481     *
482     * <pre>
483     * StringUtils.appendIfMissingIgnoreCase(null, null)      = null
484     * StringUtils.appendIfMissingIgnoreCase("abc", null)     = "abc"
485     * StringUtils.appendIfMissingIgnoreCase("", "xyz")       = "xyz"
486     * StringUtils.appendIfMissingIgnoreCase("abc", "xyz")    = "abcxyz"
487     * StringUtils.appendIfMissingIgnoreCase("abcxyz", "xyz") = "abcxyz"
488     * StringUtils.appendIfMissingIgnoreCase("abcXYZ", "xyz") = "abcXYZ"
489     * </pre>
490     * <p>With additional suffixes,</p>
491     * <pre>
492     * StringUtils.appendIfMissingIgnoreCase(null, null, null)       = null
493     * StringUtils.appendIfMissingIgnoreCase("abc", null, null)      = "abc"
494     * StringUtils.appendIfMissingIgnoreCase("", "xyz", null)        = "xyz"
495     * StringUtils.appendIfMissingIgnoreCase("abc", "xyz", new CharSequence[]{null}) = "abcxyz"
496     * StringUtils.appendIfMissingIgnoreCase("abc", "xyz", "")       = "abc"
497     * StringUtils.appendIfMissingIgnoreCase("abc", "xyz", "mno")    = "abcxyz"
498     * StringUtils.appendIfMissingIgnoreCase("abcxyz", "xyz", "mno") = "abcxyz"
499     * StringUtils.appendIfMissingIgnoreCase("abcmno", "xyz", "mno") = "abcmno"
500     * StringUtils.appendIfMissingIgnoreCase("abcXYZ", "xyz", "mno") = "abcXYZ"
501     * StringUtils.appendIfMissingIgnoreCase("abcMNO", "xyz", "mno") = "abcMNO"
502     * </pre>
503     *
504     * @param str The string.
505     * @param suffix The suffix to append to the end of the string.
506     * @param suffixes Additional suffixes that are valid terminators.
507     *
508     * @return A new String if suffix was appended, the same string otherwise.
509     *
510     * @since 3.2
511     */
512    public static String appendIfMissingIgnoreCase(final String str, final CharSequence suffix, final CharSequence... suffixes) {
513        return appendIfMissing(str, suffix, true, suffixes);
514    }
515
516    /**
517     * Capitalizes a String changing the first character to title case as
518     * per {@link Character#toTitleCase(int)}. No other characters are changed.
519     *
520     * <p>For a word based algorithm, see {@link org.apache.commons.text.WordUtils#capitalize(String)}.
521     * A {@code null} input String returns {@code null}.</p>
522     *
523     * <pre>
524     * StringUtils.capitalize(null)    = null
525     * StringUtils.capitalize("")      = ""
526     * StringUtils.capitalize("cat")   = "Cat"
527     * StringUtils.capitalize("cAt")   = "CAt"
528     * StringUtils.capitalize("'cat'") = "'cat'"
529     * </pre>
530     *
531     * @param str the String to capitalize, may be null
532     * @return the capitalized String, {@code null} if null String input
533     * @see org.apache.commons.text.WordUtils#capitalize(String)
534     * @see #uncapitalize(String)
535     * @since 2.0
536     */
537    public static String capitalize(final String str) {
538        final int strLen = length(str);
539        if (strLen == 0) {
540            return str;
541        }
542
543        final int firstCodepoint = str.codePointAt(0);
544        final int newCodePoint = Character.toTitleCase(firstCodepoint);
545        if (firstCodepoint == newCodePoint) {
546            // already capitalized
547            return str;
548        }
549
550        final int[] newCodePoints = new int[strLen]; // cannot be longer than the char array
551        int outOffset = 0;
552        newCodePoints[outOffset++] = newCodePoint; // copy the first code point
553        for (int inOffset = Character.charCount(firstCodepoint); inOffset < strLen; ) {
554            final int codePoint = str.codePointAt(inOffset);
555            newCodePoints[outOffset++] = codePoint; // copy the remaining ones
556            inOffset += Character.charCount(codePoint);
557         }
558        return new String(newCodePoints, 0, outOffset);
559    }
560
561    /**
562     * Centers a String in a larger String of size {@code size}
563     * using the space character (' ').
564     *
565     * <p>If the size is less than the String length, the original String is returned.
566     * A {@code null} String returns {@code null}.
567     * A negative size is treated as zero.</p>
568     *
569     * <p>Equivalent to {@code center(str, size, " ")}.</p>
570     *
571     * <pre>
572     * StringUtils.center(null, *)   = null
573     * StringUtils.center("", 4)     = "    "
574     * StringUtils.center("ab", -1)  = "ab"
575     * StringUtils.center("ab", 4)   = " ab "
576     * StringUtils.center("abcd", 2) = "abcd"
577     * StringUtils.center("a", 4)    = " a  "
578     * </pre>
579     *
580     * @param str  the String to center, may be null
581     * @param size  the int size of new String, negative treated as zero
582     * @return centered String, {@code null} if null String input
583     */
584    public static String center(final String str, final int size) {
585        return center(str, size, ' ');
586    }
587
588    /**
589     * Centers a String in a larger String of size {@code size}.
590     * Uses a supplied character as the value to pad the String with.
591     *
592     * <p>If the size is less than the String length, the String is returned.
593     * A {@code null} String returns {@code null}.
594     * A negative size is treated as zero.</p>
595     *
596     * <pre>
597     * StringUtils.center(null, *, *)     = null
598     * StringUtils.center("", 4, ' ')     = "    "
599     * StringUtils.center("ab", -1, ' ')  = "ab"
600     * StringUtils.center("ab", 4, ' ')   = " ab "
601     * StringUtils.center("abcd", 2, ' ') = "abcd"
602     * StringUtils.center("a", 4, ' ')    = " a  "
603     * StringUtils.center("a", 4, 'y')    = "yayy"
604     * </pre>
605     *
606     * @param str  the String to center, may be null
607     * @param size  the int size of new String, negative treated as zero
608     * @param padChar  the character to pad the new String with
609     * @return centered String, {@code null} if null String input
610     * @since 2.0
611     */
612    public static String center(String str, final int size, final char padChar) {
613        if (str == null || size <= 0) {
614            return str;
615        }
616        final int strLen = str.length();
617        final int pads = size - strLen;
618        if (pads <= 0) {
619            return str;
620        }
621        str = leftPad(str, strLen + pads / 2, padChar);
622        return rightPad(str, size, padChar);
623    }
624
625    /**
626     * Centers a String in a larger String of size {@code size}.
627     * Uses a supplied String as the value to pad the String with.
628     *
629     * <p>If the size is less than the String length, the String is returned.
630     * A {@code null} String returns {@code null}.
631     * A negative size is treated as zero.</p>
632     *
633     * <pre>
634     * StringUtils.center(null, *, *)     = null
635     * StringUtils.center("", 4, " ")     = "    "
636     * StringUtils.center("ab", -1, " ")  = "ab"
637     * StringUtils.center("ab", 4, " ")   = " ab "
638     * StringUtils.center("abcd", 2, " ") = "abcd"
639     * StringUtils.center("a", 4, " ")    = " a  "
640     * StringUtils.center("a", 4, "yz")   = "yayz"
641     * StringUtils.center("abc", 7, null) = "  abc  "
642     * StringUtils.center("abc", 7, "")   = "  abc  "
643     * </pre>
644     *
645     * @param str  the String to center, may be null
646     * @param size  the int size of new String, negative treated as zero
647     * @param padStr  the String to pad the new String with, must not be null or empty
648     * @return centered String, {@code null} if null String input
649     * @throws IllegalArgumentException if padStr is {@code null} or empty
650     */
651    public static String center(String str, final int size, String padStr) {
652        if (str == null || size <= 0) {
653            return str;
654        }
655        if (isEmpty(padStr)) {
656            padStr = SPACE;
657        }
658        final int strLen = str.length();
659        final int pads = size - strLen;
660        if (pads <= 0) {
661            return str;
662        }
663        str = leftPad(str, strLen + pads / 2, padStr);
664        return rightPad(str, size, padStr);
665    }
666
667    /**
668     * Removes one newline from end of a String if it's there,
669     * otherwise leave it alone.  A newline is &quot;{@code \n}&quot;,
670     * &quot;{@code \r}&quot;, or &quot;{@code \r\n}&quot;.
671     *
672     * <p>NOTE: This method changed in 2.0.
673     * It now more closely matches Perl chomp.</p>
674     *
675     * <pre>
676     * StringUtils.chomp(null)          = null
677     * StringUtils.chomp("")            = ""
678     * StringUtils.chomp("abc \r")      = "abc "
679     * StringUtils.chomp("abc\n")       = "abc"
680     * StringUtils.chomp("abc\r\n")     = "abc"
681     * StringUtils.chomp("abc\r\n\r\n") = "abc\r\n"
682     * StringUtils.chomp("abc\n\r")     = "abc\n"
683     * StringUtils.chomp("abc\n\rabc")  = "abc\n\rabc"
684     * StringUtils.chomp("\r")          = ""
685     * StringUtils.chomp("\n")          = ""
686     * StringUtils.chomp("\r\n")        = ""
687     * </pre>
688     *
689     * @param str  the String to chomp a newline from, may be null
690     * @return String without newline, {@code null} if null String input
691     */
692    public static String chomp(final String str) {
693        if (isEmpty(str)) {
694            return str;
695        }
696
697        if (str.length() == 1) {
698            final char ch = str.charAt(0);
699            if (ch == CharUtils.CR || ch == CharUtils.LF) {
700                return EMPTY;
701            }
702            return str;
703        }
704
705        int lastIdx = str.length() - 1;
706        final char last = str.charAt(lastIdx);
707
708        if (last == CharUtils.LF) {
709            if (str.charAt(lastIdx - 1) == CharUtils.CR) {
710                lastIdx--;
711            }
712        } else if (last != CharUtils.CR) {
713            lastIdx++;
714        }
715        return str.substring(0, lastIdx);
716    }
717
718    /**
719     * Removes {@code separator} from the end of
720     * {@code str} if it's there, otherwise leave it alone.
721     *
722     * <p>NOTE: This method changed in version 2.0.
723     * It now more closely matches Perl chomp.
724     * For the previous behavior, use {@link #substringBeforeLast(String, String)}.
725     * This method uses {@link String#endsWith(String)}.</p>
726     *
727     * <pre>
728     * StringUtils.chomp(null, *)         = null
729     * StringUtils.chomp("", *)           = ""
730     * StringUtils.chomp("foobar", "bar") = "foo"
731     * StringUtils.chomp("foobar", "baz") = "foobar"
732     * StringUtils.chomp("foo", "foo")    = ""
733     * StringUtils.chomp("foo ", "foo")   = "foo "
734     * StringUtils.chomp(" foo", "foo")   = " "
735     * StringUtils.chomp("foo", "foooo")  = "foo"
736     * StringUtils.chomp("foo", "")       = "foo"
737     * StringUtils.chomp("foo", null)     = "foo"
738     * </pre>
739     *
740     * @param str  the String to chomp from, may be null
741     * @param separator  separator String, may be null
742     * @return String without trailing separator, {@code null} if null String input
743     * @deprecated This feature will be removed in Lang 4, use {@link StringUtils#removeEnd(String, String)} instead
744     */
745    @Deprecated
746    public static String chomp(final String str, final String separator) {
747        return removeEnd(str, separator);
748    }
749
750    /**
751     * Remove the last character from a String.
752     *
753     * <p>If the String ends in {@code \r\n}, then remove both
754     * of them.</p>
755     *
756     * <pre>
757     * StringUtils.chop(null)          = null
758     * StringUtils.chop("")            = ""
759     * StringUtils.chop("abc \r")      = "abc "
760     * StringUtils.chop("abc\n")       = "abc"
761     * StringUtils.chop("abc\r\n")     = "abc"
762     * StringUtils.chop("abc")         = "ab"
763     * StringUtils.chop("abc\nabc")    = "abc\nab"
764     * StringUtils.chop("a")           = ""
765     * StringUtils.chop("\r")          = ""
766     * StringUtils.chop("\n")          = ""
767     * StringUtils.chop("\r\n")        = ""
768     * </pre>
769     *
770     * @param str  the String to chop last character from, may be null
771     * @return String without last character, {@code null} if null String input
772     */
773    public static String chop(final String str) {
774        if (str == null) {
775            return null;
776        }
777        final int strLen = str.length();
778        if (strLen < 2) {
779            return EMPTY;
780        }
781        final int lastIdx = strLen - 1;
782        final String ret = str.substring(0, lastIdx);
783        final char last = str.charAt(lastIdx);
784        if (last == CharUtils.LF && ret.charAt(lastIdx - 1) == CharUtils.CR) {
785            return ret.substring(0, lastIdx - 1);
786        }
787        return ret;
788    }
789
790    /**
791     * Compare two Strings lexicographically, as per {@link String#compareTo(String)}, returning :
792     * <ul>
793     *  <li>{@code int = 0}, if {@code str1} is equal to {@code str2} (or both {@code null})</li>
794     *  <li>{@code int < 0}, if {@code str1} is less than {@code str2}</li>
795     *  <li>{@code int > 0}, if {@code str1} is greater than {@code str2}</li>
796     * </ul>
797     *
798     * <p>This is a {@code null} safe version of :</p>
799     * <blockquote><pre>str1.compareTo(str2)</pre></blockquote>
800     *
801     * <p>{@code null} value is considered less than non-{@code null} value.
802     * Two {@code null} references are considered equal.</p>
803     *
804     * <pre>{@code
805     * StringUtils.compare(null, null)   = 0
806     * StringUtils.compare(null , "a")   < 0
807     * StringUtils.compare("a", null)   > 0
808     * StringUtils.compare("abc", "abc") = 0
809     * StringUtils.compare("a", "b")     < 0
810     * StringUtils.compare("b", "a")     > 0
811     * StringUtils.compare("a", "B")     > 0
812     * StringUtils.compare("ab", "abc")  < 0
813     * }</pre>
814     *
815     * @see #compare(String, String, boolean)
816     * @see String#compareTo(String)
817     * @param str1  the String to compare from
818     * @param str2  the String to compare to
819     * @return &lt; 0, 0, &gt; 0, if {@code str1} is respectively less, equal or greater than {@code str2}
820     * @since 3.5
821     */
822    public static int compare(final String str1, final String str2) {
823        return compare(str1, str2, true);
824    }
825
826    /**
827     * Compare two Strings lexicographically, as per {@link String#compareTo(String)}, returning :
828     * <ul>
829     *  <li>{@code int = 0}, if {@code str1} is equal to {@code str2} (or both {@code null})</li>
830     *  <li>{@code int < 0}, if {@code str1} is less than {@code str2}</li>
831     *  <li>{@code int > 0}, if {@code str1} is greater than {@code str2}</li>
832     * </ul>
833     *
834     * <p>This is a {@code null} safe version of :</p>
835     * <blockquote><pre>str1.compareTo(str2)</pre></blockquote>
836     *
837     * <p>{@code null} inputs are handled according to the {@code nullIsLess} parameter.
838     * Two {@code null} references are considered equal.</p>
839     *
840     * <pre>{@code
841     * StringUtils.compare(null, null, *)     = 0
842     * StringUtils.compare(null , "a", true)  < 0
843     * StringUtils.compare(null , "a", false) > 0
844     * StringUtils.compare("a", null, true)   > 0
845     * StringUtils.compare("a", null, false)  < 0
846     * StringUtils.compare("abc", "abc", *)   = 0
847     * StringUtils.compare("a", "b", *)       < 0
848     * StringUtils.compare("b", "a", *)       > 0
849     * StringUtils.compare("a", "B", *)       > 0
850     * StringUtils.compare("ab", "abc", *)    < 0
851     * }</pre>
852     *
853     * @see String#compareTo(String)
854     * @param str1  the String to compare from
855     * @param str2  the String to compare to
856     * @param nullIsLess  whether consider {@code null} value less than non-{@code null} value
857     * @return &lt; 0, 0, &gt; 0, if {@code str1} is respectively less, equal ou greater than {@code str2}
858     * @since 3.5
859     */
860    public static int compare(final String str1, final String str2, final boolean nullIsLess) {
861        if (str1 == str2) { // NOSONARLINT this intentionally uses == to allow for both null
862            return 0;
863        }
864        if (str1 == null) {
865            return nullIsLess ? -1 : 1;
866        }
867        if (str2 == null) {
868            return nullIsLess ? 1 : - 1;
869        }
870        return str1.compareTo(str2);
871    }
872
873    /**
874     * Compare two Strings lexicographically, ignoring case differences,
875     * as per {@link String#compareToIgnoreCase(String)}, returning :
876     * <ul>
877     *  <li>{@code int = 0}, if {@code str1} is equal to {@code str2} (or both {@code null})</li>
878     *  <li>{@code int < 0}, if {@code str1} is less than {@code str2}</li>
879     *  <li>{@code int > 0}, if {@code str1} is greater than {@code str2}</li>
880     * </ul>
881     *
882     * <p>This is a {@code null} safe version of :</p>
883     * <blockquote><pre>str1.compareToIgnoreCase(str2)</pre></blockquote>
884     *
885     * <p>{@code null} value is considered less than non-{@code null} value.
886     * Two {@code null} references are considered equal.
887     * Comparison is case insensitive.</p>
888     *
889     * <pre>{@code
890     * StringUtils.compareIgnoreCase(null, null)   = 0
891     * StringUtils.compareIgnoreCase(null , "a")   < 0
892     * StringUtils.compareIgnoreCase("a", null)    > 0
893     * StringUtils.compareIgnoreCase("abc", "abc") = 0
894     * StringUtils.compareIgnoreCase("abc", "ABC") = 0
895     * StringUtils.compareIgnoreCase("a", "b")     < 0
896     * StringUtils.compareIgnoreCase("b", "a")     > 0
897     * StringUtils.compareIgnoreCase("a", "B")     < 0
898     * StringUtils.compareIgnoreCase("A", "b")     < 0
899     * StringUtils.compareIgnoreCase("ab", "ABC")  < 0
900     * }</pre>
901     *
902     * @see #compareIgnoreCase(String, String, boolean)
903     * @see String#compareToIgnoreCase(String)
904     * @param str1  the String to compare from
905     * @param str2  the String to compare to
906     * @return &lt; 0, 0, &gt; 0, if {@code str1} is respectively less, equal ou greater than {@code str2},
907     *          ignoring case differences.
908     * @since 3.5
909     */
910    public static int compareIgnoreCase(final String str1, final String str2) {
911        return compareIgnoreCase(str1, str2, true);
912    }
913
914    /**
915     * Compare two Strings lexicographically, ignoring case differences,
916     * as per {@link String#compareToIgnoreCase(String)}, returning :
917     * <ul>
918     *  <li>{@code int = 0}, if {@code str1} is equal to {@code str2} (or both {@code null})</li>
919     *  <li>{@code int < 0}, if {@code str1} is less than {@code str2}</li>
920     *  <li>{@code int > 0}, if {@code str1} is greater than {@code str2}</li>
921     * </ul>
922     *
923     * <p>This is a {@code null} safe version of :</p>
924     * <blockquote><pre>str1.compareToIgnoreCase(str2)</pre></blockquote>
925     *
926     * <p>{@code null} inputs are handled according to the {@code nullIsLess} parameter.
927     * Two {@code null} references are considered equal.
928     * Comparison is case insensitive.</p>
929     *
930     * <pre>{@code
931     * StringUtils.compareIgnoreCase(null, null, *)     = 0
932     * StringUtils.compareIgnoreCase(null , "a", true)  < 0
933     * StringUtils.compareIgnoreCase(null , "a", false) > 0
934     * StringUtils.compareIgnoreCase("a", null, true)   > 0
935     * StringUtils.compareIgnoreCase("a", null, false)  < 0
936     * StringUtils.compareIgnoreCase("abc", "abc", *)   = 0
937     * StringUtils.compareIgnoreCase("abc", "ABC", *)   = 0
938     * StringUtils.compareIgnoreCase("a", "b", *)       < 0
939     * StringUtils.compareIgnoreCase("b", "a", *)       > 0
940     * StringUtils.compareIgnoreCase("a", "B", *)       < 0
941     * StringUtils.compareIgnoreCase("A", "b", *)       < 0
942     * StringUtils.compareIgnoreCase("ab", "abc", *)    < 0
943     * }</pre>
944     *
945     * @see String#compareToIgnoreCase(String)
946     * @param str1  the String to compare from
947     * @param str2  the String to compare to
948     * @param nullIsLess  whether consider {@code null} value less than non-{@code null} value
949     * @return &lt; 0, 0, &gt; 0, if {@code str1} is respectively less, equal ou greater than {@code str2},
950     *          ignoring case differences.
951     * @since 3.5
952     */
953    public static int compareIgnoreCase(final String str1, final String str2, final boolean nullIsLess) {
954        if (str1 == str2) { // NOSONARLINT this intentionally uses == to allow for both null
955            return 0;
956        }
957        if (str1 == null) {
958            return nullIsLess ? -1 : 1;
959        }
960        if (str2 == null) {
961            return nullIsLess ? 1 : - 1;
962        }
963        return str1.compareToIgnoreCase(str2);
964    }
965
966    /**
967     * Checks if CharSequence contains a search CharSequence, handling {@code null}.
968     * This method uses {@link String#indexOf(String)} if possible.
969     *
970     * <p>A {@code null} CharSequence will return {@code false}.</p>
971     *
972     * <pre>
973     * StringUtils.contains(null, *)     = false
974     * StringUtils.contains(*, null)     = false
975     * StringUtils.contains("", "")      = true
976     * StringUtils.contains("abc", "")   = true
977     * StringUtils.contains("abc", "a")  = true
978     * StringUtils.contains("abc", "z")  = false
979     * </pre>
980     *
981     * @param seq  the CharSequence to check, may be null
982     * @param searchSeq  the CharSequence to find, may be null
983     * @return true if the CharSequence contains the search CharSequence,
984     *  false if not or {@code null} string input
985     * @since 2.0
986     * @since 3.0 Changed signature from contains(String, String) to contains(CharSequence, CharSequence)
987     */
988    public static boolean contains(final CharSequence seq, final CharSequence searchSeq) {
989        if (seq == null || searchSeq == null) {
990            return false;
991        }
992        return CharSequenceUtils.indexOf(seq, searchSeq, 0) >= 0;
993    }
994
995    /**
996     * Checks if CharSequence contains a search character, handling {@code null}.
997     * This method uses {@link String#indexOf(int)} if possible.
998     *
999     * <p>A {@code null} or empty ("") CharSequence will return {@code false}.</p>
1000     *
1001     * <pre>
1002     * StringUtils.contains(null, *)    = false
1003     * StringUtils.contains("", *)      = false
1004     * StringUtils.contains("abc", 'a') = true
1005     * StringUtils.contains("abc", 'z') = false
1006     * </pre>
1007     *
1008     * @param seq  the CharSequence to check, may be null
1009     * @param searchChar  the character to find
1010     * @return true if the CharSequence contains the search character,
1011     *  false if not or {@code null} string input
1012     * @since 2.0
1013     * @since 3.0 Changed signature from contains(String, int) to contains(CharSequence, int)
1014     */
1015    public static boolean contains(final CharSequence seq, final int searchChar) {
1016        if (isEmpty(seq)) {
1017            return false;
1018        }
1019        return CharSequenceUtils.indexOf(seq, searchChar, 0) >= 0;
1020    }
1021
1022    /**
1023     * Checks if the CharSequence contains any character in the given
1024     * set of characters.
1025     *
1026     * <p>A {@code null} CharSequence will return {@code false}.
1027     * A {@code null} or zero length search array will return {@code false}.</p>
1028     *
1029     * <pre>
1030     * StringUtils.containsAny(null, *)                  = false
1031     * StringUtils.containsAny("", *)                    = false
1032     * StringUtils.containsAny(*, null)                  = false
1033     * StringUtils.containsAny(*, [])                    = false
1034     * StringUtils.containsAny("zzabyycdxx", ['z', 'a']) = true
1035     * StringUtils.containsAny("zzabyycdxx", ['b', 'y']) = true
1036     * StringUtils.containsAny("zzabyycdxx", ['z', 'y']) = true
1037     * StringUtils.containsAny("aba", ['z'])             = false
1038     * </pre>
1039     *
1040     * @param cs  the CharSequence to check, may be null
1041     * @param searchChars  the chars to search for, may be null
1042     * @return the {@code true} if any of the chars are found,
1043     * {@code false} if no match or null input
1044     * @since 2.4
1045     * @since 3.0 Changed signature from containsAny(String, char[]) to containsAny(CharSequence, char...)
1046     */
1047    public static boolean containsAny(final CharSequence cs, final char... searchChars) {
1048        if (isEmpty(cs) || ArrayUtils.isEmpty(searchChars)) {
1049            return false;
1050        }
1051        final int csLength = cs.length();
1052        final int searchLength = searchChars.length;
1053        final int csLast = csLength - 1;
1054        final int searchLast = searchLength - 1;
1055        for (int i = 0; i < csLength; i++) {
1056            final char ch = cs.charAt(i);
1057            for (int j = 0; j < searchLength; j++) {
1058                if (searchChars[j] == ch) {
1059                    if (!Character.isHighSurrogate(ch)) {
1060                        // ch is in the Basic Multilingual Plane
1061                        return true;
1062                    }
1063                    if (j == searchLast) {
1064                        // missing low surrogate, fine, like String.indexOf(String)
1065                        return true;
1066                    }
1067                    if (i < csLast && searchChars[j + 1] == cs.charAt(i + 1)) {
1068                        return true;
1069                    }
1070                }
1071            }
1072        }
1073        return false;
1074    }
1075
1076    /**
1077     * Checks if the CharSequence contains any character in the given set of characters.
1078     *
1079     * <p>
1080     * A {@code null} CharSequence will return {@code false}. A {@code null} search CharSequence will return
1081     * {@code false}.
1082     * </p>
1083     *
1084     * <pre>
1085     * StringUtils.containsAny(null, *)               = false
1086     * StringUtils.containsAny("", *)                 = false
1087     * StringUtils.containsAny(*, null)               = false
1088     * StringUtils.containsAny(*, "")                 = false
1089     * StringUtils.containsAny("zzabyycdxx", "za")    = true
1090     * StringUtils.containsAny("zzabyycdxx", "by")    = true
1091     * StringUtils.containsAny("zzabyycdxx", "zy")    = true
1092     * StringUtils.containsAny("zzabyycdxx", "\tx")   = true
1093     * StringUtils.containsAny("zzabyycdxx", "$.#yF") = true
1094     * StringUtils.containsAny("aba", "z")            = false
1095     * </pre>
1096     *
1097     * @param cs
1098     *            the CharSequence to check, may be null
1099     * @param searchChars
1100     *            the chars to search for, may be null
1101     * @return the {@code true} if any of the chars are found, {@code false} if no match or null input
1102     * @since 2.4
1103     * @since 3.0 Changed signature from containsAny(String, String) to containsAny(CharSequence, CharSequence)
1104     */
1105    public static boolean containsAny(final CharSequence cs, final CharSequence searchChars) {
1106        if (searchChars == null) {
1107            return false;
1108        }
1109        return containsAny(cs, CharSequenceUtils.toCharArray(searchChars));
1110    }
1111
1112    /**
1113     * Checks if the CharSequence contains any of the CharSequences in the given array.
1114     *
1115     * <p>
1116     * A {@code null} {@code cs} CharSequence will return {@code false}. A {@code null} or zero length search array will
1117     * return {@code false}.
1118     * </p>
1119     *
1120     * <pre>
1121     * StringUtils.containsAny(null, *)            = false
1122     * StringUtils.containsAny("", *)              = false
1123     * StringUtils.containsAny(*, null)            = false
1124     * StringUtils.containsAny(*, [])              = false
1125     * StringUtils.containsAny("abcd", "ab", null) = true
1126     * StringUtils.containsAny("abcd", "ab", "cd") = true
1127     * StringUtils.containsAny("abc", "d", "abc")  = true
1128     * </pre>
1129     *
1130     * @param cs The CharSequence to check, may be null
1131     * @param searchCharSequences The array of CharSequences to search for, may be null. Individual CharSequences may be
1132     *        null as well.
1133     * @return {@code true} if any of the search CharSequences are found, {@code false} otherwise
1134     * @since 3.4
1135     */
1136    public static boolean containsAny(final CharSequence cs, final CharSequence... searchCharSequences) {
1137        return containsAny(StringUtils::contains, cs, searchCharSequences);
1138    }
1139
1140    /**
1141     * Checks if the CharSequence contains any of the CharSequences in the given array.
1142     *
1143     * <p>
1144     * A {@code null} {@code cs} CharSequence will return {@code false}. A {@code null} or zero length search array will
1145     * return {@code false}.
1146     * </p>
1147     *
1148     * @param cs The CharSequence to check, may be null
1149     * @param searchCharSequences The array of CharSequences to search for, may be null. Individual CharSequences may be
1150     *        null as well.
1151     * @return {@code true} if any of the search CharSequences are found, {@code false} otherwise
1152     * @since 3.12.0
1153     */
1154    private static boolean containsAny(final ToBooleanBiFunction<CharSequence, CharSequence> test,
1155        final CharSequence cs, final CharSequence... searchCharSequences) {
1156        if (isEmpty(cs) || ArrayUtils.isEmpty(searchCharSequences)) {
1157            return false;
1158        }
1159        for (final CharSequence searchCharSequence : searchCharSequences) {
1160            if (test.applyAsBoolean(cs, searchCharSequence)) {
1161                return true;
1162            }
1163        }
1164        return false;
1165    }
1166
1167    /**
1168     * Checks if the CharSequence contains any of the CharSequences in the given array, ignoring case.
1169     *
1170     * <p>
1171     * A {@code null} {@code cs} CharSequence will return {@code false}. A {@code null} or zero length search array will
1172     * return {@code false}.
1173     * </p>
1174     *
1175     * <pre>
1176     * StringUtils.containsAny(null, *)            = false
1177     * StringUtils.containsAny("", *)              = false
1178     * StringUtils.containsAny(*, null)            = false
1179     * StringUtils.containsAny(*, [])              = false
1180     * StringUtils.containsAny("abcd", "ab", null) = true
1181     * StringUtils.containsAny("abcd", "ab", "cd") = true
1182     * StringUtils.containsAny("abc", "d", "abc")  = true
1183     * StringUtils.containsAny("abc", "D", "ABC")  = true
1184     * StringUtils.containsAny("ABC", "d", "abc")  = true
1185     * </pre>
1186     *
1187     * @param cs The CharSequence to check, may be null
1188     * @param searchCharSequences The array of CharSequences to search for, may be null. Individual CharSequences may be
1189     *        null as well.
1190     * @return {@code true} if any of the search CharSequences are found, {@code false} otherwise
1191     * @since 3.12.0
1192     */
1193    public static boolean containsAnyIgnoreCase(final CharSequence cs, final CharSequence... searchCharSequences) {
1194        return containsAny(StringUtils::containsIgnoreCase, cs, searchCharSequences);
1195    }
1196
1197    /**
1198     * Checks if CharSequence contains a search CharSequence irrespective of case,
1199     * handling {@code null}. Case-insensitivity is defined as by
1200     * {@link String#equalsIgnoreCase(String)}.
1201     *
1202     * <p>A {@code null} CharSequence will return {@code false}.
1203     *
1204     * <pre>
1205     * StringUtils.containsIgnoreCase(null, *)    = false
1206     * StringUtils.containsIgnoreCase(*, null)    = false
1207     * StringUtils.containsIgnoreCase("", "")     = true
1208     * StringUtils.containsIgnoreCase("abc", "")  = true
1209     * StringUtils.containsIgnoreCase("abc", "a") = true
1210     * StringUtils.containsIgnoreCase("abc", "z") = false
1211     * StringUtils.containsIgnoreCase("abc", "A") = true
1212     * StringUtils.containsIgnoreCase("abc", "Z") = false
1213     * </pre>
1214     *
1215     * @param str  the CharSequence to check, may be null
1216     * @param searchStr  the CharSequence to find, may be null
1217     * @return true if the CharSequence contains the search CharSequence irrespective of
1218     * case or false if not or {@code null} string input
1219     * @since 3.0 Changed signature from containsIgnoreCase(String, String) to containsIgnoreCase(CharSequence, CharSequence)
1220     */
1221    public static boolean containsIgnoreCase(final CharSequence str, final CharSequence searchStr) {
1222        if (str == null || searchStr == null) {
1223            return false;
1224        }
1225        final int len = searchStr.length();
1226        final int max = str.length() - len;
1227        for (int i = 0; i <= max; i++) {
1228            if (CharSequenceUtils.regionMatches(str, true, i, searchStr, 0, len)) {
1229                return true;
1230            }
1231        }
1232        return false;
1233    }
1234
1235    /**
1236     * Checks that the CharSequence does not contain certain characters.
1237     *
1238     * <p>A {@code null} CharSequence will return {@code true}.
1239     * A {@code null} invalid character array will return {@code true}.
1240     * An empty CharSequence (length()=0) always returns true.</p>
1241     *
1242     * <pre>
1243     * StringUtils.containsNone(null, *)       = true
1244     * StringUtils.containsNone(*, null)       = true
1245     * StringUtils.containsNone("", *)         = true
1246     * StringUtils.containsNone("ab", '')      = true
1247     * StringUtils.containsNone("abab", 'xyz') = true
1248     * StringUtils.containsNone("ab1", 'xyz')  = true
1249     * StringUtils.containsNone("abz", 'xyz')  = false
1250     * </pre>
1251     *
1252     * @param cs  the CharSequence to check, may be null
1253     * @param searchChars  an array of invalid chars, may be null
1254     * @return true if it contains none of the invalid chars, or is null
1255     * @since 2.0
1256     * @since 3.0 Changed signature from containsNone(String, char[]) to containsNone(CharSequence, char...)
1257     */
1258    public static boolean containsNone(final CharSequence cs, final char... searchChars) {
1259        if (cs == null || searchChars == null) {
1260            return true;
1261        }
1262        final int csLen = cs.length();
1263        final int csLast = csLen - 1;
1264        final int searchLen = searchChars.length;
1265        final int searchLast = searchLen - 1;
1266        for (int i = 0; i < csLen; i++) {
1267            final char ch = cs.charAt(i);
1268            for (int j = 0; j < searchLen; j++) {
1269                if (searchChars[j] == ch) {
1270                    if (!Character.isHighSurrogate(ch)) {
1271                        // ch is in the Basic Multilingual Plane
1272                        return false;
1273                    }
1274                    if (j == searchLast) {
1275                        // missing low surrogate, fine, like String.indexOf(String)
1276                        return false;
1277                    }
1278                    if (i < csLast && searchChars[j + 1] == cs.charAt(i + 1)) {
1279                        return false;
1280                    }
1281                }
1282            }
1283        }
1284        return true;
1285    }
1286
1287    /**
1288     * Checks that the CharSequence does not contain certain characters.
1289     *
1290     * <p>A {@code null} CharSequence will return {@code true}.
1291     * A {@code null} invalid character array will return {@code true}.
1292     * An empty String ("") always returns true.</p>
1293     *
1294     * <pre>
1295     * StringUtils.containsNone(null, *)       = true
1296     * StringUtils.containsNone(*, null)       = true
1297     * StringUtils.containsNone("", *)         = true
1298     * StringUtils.containsNone("ab", "")      = true
1299     * StringUtils.containsNone("abab", "xyz") = true
1300     * StringUtils.containsNone("ab1", "xyz")  = true
1301     * StringUtils.containsNone("abz", "xyz")  = false
1302     * </pre>
1303     *
1304     * @param cs  the CharSequence to check, may be null
1305     * @param invalidChars  a String of invalid chars, may be null
1306     * @return true if it contains none of the invalid chars, or is null
1307     * @since 2.0
1308     * @since 3.0 Changed signature from containsNone(String, String) to containsNone(CharSequence, String)
1309     */
1310    public static boolean containsNone(final CharSequence cs, final String invalidChars) {
1311        if (invalidChars == null) {
1312            return true;
1313        }
1314        return containsNone(cs, invalidChars.toCharArray());
1315    }
1316
1317    /**
1318     * Checks if the CharSequence contains only certain characters.
1319     *
1320     * <p>A {@code null} CharSequence will return {@code false}.
1321     * A {@code null} valid character array will return {@code false}.
1322     * An empty CharSequence (length()=0) always returns {@code true}.</p>
1323     *
1324     * <pre>
1325     * StringUtils.containsOnly(null, *)       = false
1326     * StringUtils.containsOnly(*, null)       = false
1327     * StringUtils.containsOnly("", *)         = true
1328     * StringUtils.containsOnly("ab", '')      = false
1329     * StringUtils.containsOnly("abab", 'abc') = true
1330     * StringUtils.containsOnly("ab1", 'abc')  = false
1331     * StringUtils.containsOnly("abz", 'abc')  = false
1332     * </pre>
1333     *
1334     * @param cs  the String to check, may be null
1335     * @param valid  an array of valid chars, may be null
1336     * @return true if it only contains valid chars and is non-null
1337     * @since 3.0 Changed signature from containsOnly(String, char[]) to containsOnly(CharSequence, char...)
1338     */
1339    public static boolean containsOnly(final CharSequence cs, final char... valid) {
1340        // All these pre-checks are to maintain API with an older version
1341        if (valid == null || cs == null) {
1342            return false;
1343        }
1344        if (cs.length() == 0) {
1345            return true;
1346        }
1347        if (valid.length == 0) {
1348            return false;
1349        }
1350        return indexOfAnyBut(cs, valid) == INDEX_NOT_FOUND;
1351    }
1352
1353    /**
1354     * Checks if the CharSequence contains only certain characters.
1355     *
1356     * <p>A {@code null} CharSequence will return {@code false}.
1357     * A {@code null} valid character String will return {@code false}.
1358     * An empty String (length()=0) always returns {@code true}.</p>
1359     *
1360     * <pre>
1361     * StringUtils.containsOnly(null, *)       = false
1362     * StringUtils.containsOnly(*, null)       = false
1363     * StringUtils.containsOnly("", *)         = true
1364     * StringUtils.containsOnly("ab", "")      = false
1365     * StringUtils.containsOnly("abab", "abc") = true
1366     * StringUtils.containsOnly("ab1", "abc")  = false
1367     * StringUtils.containsOnly("abz", "abc")  = false
1368     * </pre>
1369     *
1370     * @param cs  the CharSequence to check, may be null
1371     * @param validChars  a String of valid chars, may be null
1372     * @return true if it only contains valid chars and is non-null
1373     * @since 2.0
1374     * @since 3.0 Changed signature from containsOnly(String, String) to containsOnly(CharSequence, String)
1375     */
1376    public static boolean containsOnly(final CharSequence cs, final String validChars) {
1377        if (cs == null || validChars == null) {
1378            return false;
1379        }
1380        return containsOnly(cs, validChars.toCharArray());
1381    }
1382
1383    /**
1384     * Check whether the given CharSequence contains any whitespace characters.
1385     *
1386     * <p>Whitespace is defined by {@link Character#isWhitespace(char)}.</p>
1387     *
1388     * @param seq the CharSequence to check (may be {@code null})
1389     * @return {@code true} if the CharSequence is not empty and
1390     * contains at least 1 (breaking) whitespace character
1391     * @since 3.0
1392     */
1393    // From org.springframework.util.StringUtils, under Apache License 2.0
1394    public static boolean containsWhitespace(final CharSequence seq) {
1395        if (isEmpty(seq)) {
1396            return false;
1397        }
1398        final int strLen = seq.length();
1399        for (int i = 0; i < strLen; i++) {
1400            if (Character.isWhitespace(seq.charAt(i))) {
1401                return true;
1402            }
1403        }
1404        return false;
1405    }
1406
1407    private static void convertRemainingAccentCharacters(final StringBuilder decomposed) {
1408        for (int i = 0; i < decomposed.length(); i++) {
1409            final char charAt = decomposed.charAt(i);
1410            switch (charAt) {
1411            case '\u0141':
1412                decomposed.setCharAt(i, 'L');
1413                break;
1414            case '\u0142':
1415                decomposed.setCharAt(i, 'l');
1416                break;
1417            // D with stroke
1418            case '\u0110':
1419                // LATIN CAPITAL LETTER D WITH STROKE
1420                decomposed.setCharAt(i, 'D');
1421                break;
1422            case '\u0111':
1423                // LATIN SMALL LETTER D WITH STROKE
1424                decomposed.setCharAt(i, 'd');
1425                break;
1426            // I with bar
1427            case '\u0197':
1428                decomposed.setCharAt(i, 'I');
1429                break;
1430            case '\u0268':
1431                decomposed.setCharAt(i, 'i');
1432                break;
1433            case '\u1D7B':
1434                decomposed.setCharAt(i, 'I');
1435                break;
1436            case '\u1DA4':
1437                decomposed.setCharAt(i, 'i');
1438                break;
1439            case '\u1DA7':
1440                decomposed.setCharAt(i, 'I');
1441                break;
1442            // U with bar
1443            case '\u0244':
1444                // LATIN CAPITAL LETTER U BAR
1445                decomposed.setCharAt(i, 'U');
1446                break;
1447            case '\u0289':
1448                // LATIN SMALL LETTER U BAR
1449                decomposed.setCharAt(i, 'u');
1450                break;
1451            case '\u1D7E':
1452                // LATIN SMALL CAPITAL LETTER U WITH STROKE
1453                decomposed.setCharAt(i, 'U');
1454                break;
1455            case '\u1DB6':
1456                // MODIFIER LETTER SMALL U BAR
1457                decomposed.setCharAt(i, 'u');
1458                break;
1459            // T with stroke
1460            case '\u0166':
1461                // LATIN CAPITAL LETTER T WITH STROKE
1462                decomposed.setCharAt(i, 'T');
1463                break;
1464            case '\u0167':
1465                // LATIN SMALL LETTER T WITH STROKE
1466                decomposed.setCharAt(i, 't');
1467                break;
1468            default:
1469                break;
1470            }
1471        }
1472    }
1473
1474    /**
1475     * Counts how many times the char appears in the given string.
1476     *
1477     * <p>A {@code null} or empty ("") String input returns {@code 0}.</p>
1478     *
1479     * <pre>
1480     * StringUtils.countMatches(null, *)     = 0
1481     * StringUtils.countMatches("", *)       = 0
1482     * StringUtils.countMatches("abba", 0)   = 0
1483     * StringUtils.countMatches("abba", 'a') = 2
1484     * StringUtils.countMatches("abba", 'b') = 2
1485     * StringUtils.countMatches("abba", 'x') = 0
1486     * </pre>
1487     *
1488     * @param str  the CharSequence to check, may be null
1489     * @param ch  the char to count
1490     * @return the number of occurrences, 0 if the CharSequence is {@code null}
1491     * @since 3.4
1492     */
1493    public static int countMatches(final CharSequence str, final char ch) {
1494        if (isEmpty(str)) {
1495            return 0;
1496        }
1497        int count = 0;
1498        // We could also call str.toCharArray() for faster lookups but that would generate more garbage.
1499        for (int i = 0; i < str.length(); i++) {
1500            if (ch == str.charAt(i)) {
1501                count++;
1502            }
1503        }
1504        return count;
1505    }
1506
1507    /**
1508     * Counts how many times the substring appears in the larger string.
1509     * Note that the code only counts non-overlapping matches.
1510     *
1511     * <p>A {@code null} or empty ("") String input returns {@code 0}.</p>
1512     *
1513     * <pre>
1514     * StringUtils.countMatches(null, *)        = 0
1515     * StringUtils.countMatches("", *)          = 0
1516     * StringUtils.countMatches("abba", null)   = 0
1517     * StringUtils.countMatches("abba", "")     = 0
1518     * StringUtils.countMatches("abba", "a")    = 2
1519     * StringUtils.countMatches("abba", "ab")   = 1
1520     * StringUtils.countMatches("abba", "xxx")  = 0
1521     * StringUtils.countMatches("ababa", "aba") = 1
1522     * </pre>
1523     *
1524     * @param str  the CharSequence to check, may be null
1525     * @param sub  the substring to count, may be null
1526     * @return the number of occurrences, 0 if either CharSequence is {@code null}
1527     * @since 3.0 Changed signature from countMatches(String, String) to countMatches(CharSequence, CharSequence)
1528     */
1529    public static int countMatches(final CharSequence str, final CharSequence sub) {
1530        if (isEmpty(str) || isEmpty(sub)) {
1531            return 0;
1532        }
1533        int count = 0;
1534        int idx = 0;
1535        while ((idx = CharSequenceUtils.indexOf(str, sub, idx)) != INDEX_NOT_FOUND) {
1536            count++;
1537            idx += sub.length();
1538        }
1539        return count;
1540    }
1541
1542    /**
1543     * Returns either the passed in CharSequence, or if the CharSequence is
1544     * whitespace, empty ("") or {@code null}, the value of {@code defaultStr}.
1545     *
1546     * <p>Whitespace is defined by {@link Character#isWhitespace(char)}.</p>
1547     *
1548     * <pre>
1549     * StringUtils.defaultIfBlank(null, "NULL")  = "NULL"
1550     * StringUtils.defaultIfBlank("", "NULL")    = "NULL"
1551     * StringUtils.defaultIfBlank(" ", "NULL")   = "NULL"
1552     * StringUtils.defaultIfBlank("bat", "NULL") = "bat"
1553     * StringUtils.defaultIfBlank("", null)      = null
1554     * </pre>
1555     * @param <T> the specific kind of CharSequence
1556     * @param str the CharSequence to check, may be null
1557     * @param defaultStr  the default CharSequence to return
1558     *  if the input is whitespace, empty ("") or {@code null}, may be null
1559     * @return the passed in CharSequence, or the default
1560     * @see StringUtils#defaultString(String, String)
1561     */
1562    public static <T extends CharSequence> T defaultIfBlank(final T str, final T defaultStr) {
1563        return isBlank(str) ? defaultStr : str;
1564    }
1565
1566    /**
1567     * Returns either the passed in CharSequence, or if the CharSequence is
1568     * empty or {@code null}, the value of {@code defaultStr}.
1569     *
1570     * <pre>
1571     * StringUtils.defaultIfEmpty(null, "NULL")  = "NULL"
1572     * StringUtils.defaultIfEmpty("", "NULL")    = "NULL"
1573     * StringUtils.defaultIfEmpty(" ", "NULL")   = " "
1574     * StringUtils.defaultIfEmpty("bat", "NULL") = "bat"
1575     * StringUtils.defaultIfEmpty("", null)      = null
1576     * </pre>
1577     * @param <T> the specific kind of CharSequence
1578     * @param str  the CharSequence to check, may be null
1579     * @param defaultStr  the default CharSequence to return
1580     *  if the input is empty ("") or {@code null}, may be null
1581     * @return the passed in CharSequence, or the default
1582     * @see StringUtils#defaultString(String, String)
1583     */
1584    public static <T extends CharSequence> T defaultIfEmpty(final T str, final T defaultStr) {
1585        return isEmpty(str) ? defaultStr : str;
1586    }
1587
1588    /**
1589     * Returns either the passed in String,
1590     * or if the String is {@code null}, an empty String ("").
1591     *
1592     * <pre>
1593     * StringUtils.defaultString(null)  = ""
1594     * StringUtils.defaultString("")    = ""
1595     * StringUtils.defaultString("bat") = "bat"
1596     * </pre>
1597     *
1598     * @see Objects#toString(Object, String)
1599     * @see String#valueOf(Object)
1600     * @param str  the String to check, may be null
1601     * @return the passed in String, or the empty String if it
1602     *  was {@code null}
1603     */
1604    public static String defaultString(final String str) {
1605        return Objects.toString(str, EMPTY);
1606    }
1607
1608    /**
1609     * Returns either the given String, or if the String is
1610     * {@code null}, {@code nullDefault}.
1611     *
1612     * <pre>
1613     * StringUtils.defaultString(null, "NULL")  = "NULL"
1614     * StringUtils.defaultString("", "NULL")    = ""
1615     * StringUtils.defaultString("bat", "NULL") = "bat"
1616     * </pre>
1617     * <p>
1618     * Since this is now provided by Java, instead call {@link Objects#toString(Object, String)}:
1619     * </p>
1620     * <pre>
1621     * Objects.toString(null, "NULL")  = "NULL"
1622     * Objects.toString("", "NULL")    = ""
1623     * Objects.toString("bat", "NULL") = "bat"
1624     * </pre>
1625     *
1626     * @see Objects#toString(Object, String)
1627     * @see String#valueOf(Object)
1628     * @param str  the String to check, may be null
1629     * @param nullDefault  the default String to return
1630     *  if the input is {@code null}, may be null
1631     * @return the passed in String, or the default if it was {@code null}
1632     * @deprecated Use {@link Objects#toString(Object, String)}
1633     */
1634    @Deprecated
1635    public static String defaultString(final String str, final String nullDefault) {
1636        return Objects.toString(str, nullDefault);
1637    }
1638
1639    /**
1640     * Deletes all whitespaces from a String as defined by
1641     * {@link Character#isWhitespace(char)}.
1642     *
1643     * <pre>
1644     * StringUtils.deleteWhitespace(null)         = null
1645     * StringUtils.deleteWhitespace("")           = ""
1646     * StringUtils.deleteWhitespace("abc")        = "abc"
1647     * StringUtils.deleteWhitespace("   ab  c  ") = "abc"
1648     * </pre>
1649     *
1650     * @param str  the String to delete whitespace from, may be null
1651     * @return the String without whitespaces, {@code null} if null String input
1652     */
1653    public static String deleteWhitespace(final String str) {
1654        if (isEmpty(str)) {
1655            return str;
1656        }
1657        final int sz = str.length();
1658        final char[] chs = new char[sz];
1659        int count = 0;
1660        for (int i = 0; i < sz; i++) {
1661            if (!Character.isWhitespace(str.charAt(i))) {
1662                chs[count++] = str.charAt(i);
1663            }
1664        }
1665        if (count == sz) {
1666            return str;
1667        }
1668        if (count == 0) {
1669            return EMPTY;
1670        }
1671        return new String(chs, 0, count);
1672    }
1673
1674    /**
1675     * Compares two Strings, and returns the portion where they differ.
1676     * More precisely, return the remainder of the second String,
1677     * starting from where it's different from the first. This means that
1678     * the difference between "abc" and "ab" is the empty String and not "c".
1679     *
1680     * <p>For example,
1681     * {@code difference("i am a machine", "i am a robot") -> "robot"}.</p>
1682     *
1683     * <pre>
1684     * StringUtils.difference(null, null)       = null
1685     * StringUtils.difference("", "")           = ""
1686     * StringUtils.difference("", "abc")        = "abc"
1687     * StringUtils.difference("abc", "")        = ""
1688     * StringUtils.difference("abc", "abc")     = ""
1689     * StringUtils.difference("abc", "ab")      = ""
1690     * StringUtils.difference("ab", "abxyz")    = "xyz"
1691     * StringUtils.difference("abcde", "abxyz") = "xyz"
1692     * StringUtils.difference("abcde", "xyz")   = "xyz"
1693     * </pre>
1694     *
1695     * @param str1  the first String, may be null
1696     * @param str2  the second String, may be null
1697     * @return the portion of str2 where it differs from str1; returns the
1698     * empty String if they are equal
1699     * @see #indexOfDifference(CharSequence,CharSequence)
1700     * @since 2.0
1701     */
1702    public static String difference(final String str1, final String str2) {
1703        if (str1 == null) {
1704            return str2;
1705        }
1706        if (str2 == null) {
1707            return str1;
1708        }
1709        final int at = indexOfDifference(str1, str2);
1710        if (at == INDEX_NOT_FOUND) {
1711            return EMPTY;
1712        }
1713        return str2.substring(at);
1714    }
1715
1716    /**
1717     * Check if a CharSequence ends with a specified suffix.
1718     *
1719     * <p>{@code null}s are handled without exceptions. Two {@code null}
1720     * references are considered to be equal. The comparison is case-sensitive.</p>
1721     *
1722     * <pre>
1723     * StringUtils.endsWith(null, null)      = true
1724     * StringUtils.endsWith(null, "def")     = false
1725     * StringUtils.endsWith("abcdef", null)  = false
1726     * StringUtils.endsWith("abcdef", "def") = true
1727     * StringUtils.endsWith("ABCDEF", "def") = false
1728     * StringUtils.endsWith("ABCDEF", "cde") = false
1729     * StringUtils.endsWith("ABCDEF", "")    = true
1730     * </pre>
1731     *
1732     * @see String#endsWith(String)
1733     * @param str  the CharSequence to check, may be null
1734     * @param suffix the suffix to find, may be null
1735     * @return {@code true} if the CharSequence ends with the suffix, case-sensitive, or
1736     *  both {@code null}
1737     * @since 2.4
1738     * @since 3.0 Changed signature from endsWith(String, String) to endsWith(CharSequence, CharSequence)
1739     */
1740    public static boolean endsWith(final CharSequence str, final CharSequence suffix) {
1741        return endsWith(str, suffix, false);
1742    }
1743
1744    /**
1745     * Check if a CharSequence ends with a specified suffix (optionally case-insensitive).
1746     *
1747     * @see String#endsWith(String)
1748     * @param str  the CharSequence to check, may be null
1749     * @param suffix the suffix to find, may be null
1750     * @param ignoreCase indicates whether the compare should ignore case
1751     *  (case-insensitive) or not.
1752     * @return {@code true} if the CharSequence starts with the prefix or
1753     *  both {@code null}
1754     */
1755    private static boolean endsWith(final CharSequence str, final CharSequence suffix, final boolean ignoreCase) {
1756        if (str == null || suffix == null) {
1757            return str == suffix;
1758        }
1759        if (suffix.length() > str.length()) {
1760            return false;
1761        }
1762        final int strOffset = str.length() - suffix.length();
1763        return CharSequenceUtils.regionMatches(str, ignoreCase, strOffset, suffix, 0, suffix.length());
1764    }
1765
1766    /**
1767     * Check if a CharSequence ends with any of the provided case-sensitive suffixes.
1768     *
1769     * <pre>
1770     * StringUtils.endsWithAny(null, null)                  = false
1771     * StringUtils.endsWithAny(null, new String[] {"abc"})  = false
1772     * StringUtils.endsWithAny("abcxyz", null)              = false
1773     * StringUtils.endsWithAny("abcxyz", new String[] {""}) = true
1774     * StringUtils.endsWithAny("abcxyz", new String[] {"xyz"}) = true
1775     * StringUtils.endsWithAny("abcxyz", new String[] {null, "xyz", "abc"}) = true
1776     * StringUtils.endsWithAny("abcXYZ", "def", "XYZ")      = true
1777     * StringUtils.endsWithAny("abcXYZ", "def", "xyz")      = false
1778     * </pre>
1779     *
1780     * @param sequence  the CharSequence to check, may be null
1781     * @param searchStrings the case-sensitive CharSequences to find, may be empty or contain {@code null}
1782     * @see StringUtils#endsWith(CharSequence, CharSequence)
1783     * @return {@code true} if the input {@code sequence} is {@code null} AND no {@code searchStrings} are provided, or
1784     *   the input {@code sequence} ends in any of the provided case-sensitive {@code searchStrings}.
1785     * @since 3.0
1786     */
1787    public static boolean endsWithAny(final CharSequence sequence, final CharSequence... searchStrings) {
1788        if (isEmpty(sequence) || ArrayUtils.isEmpty(searchStrings)) {
1789            return false;
1790        }
1791        for (final CharSequence searchString : searchStrings) {
1792            if (endsWith(sequence, searchString)) {
1793                return true;
1794            }
1795        }
1796        return false;
1797    }
1798
1799    /**
1800     * Case-insensitive check if a CharSequence ends with a specified suffix.
1801     *
1802     * <p>{@code null}s are handled without exceptions. Two {@code null}
1803     * references are considered to be equal. The comparison is case insensitive.</p>
1804     *
1805     * <pre>
1806     * StringUtils.endsWithIgnoreCase(null, null)      = true
1807     * StringUtils.endsWithIgnoreCase(null, "def")     = false
1808     * StringUtils.endsWithIgnoreCase("abcdef", null)  = false
1809     * StringUtils.endsWithIgnoreCase("abcdef", "def") = true
1810     * StringUtils.endsWithIgnoreCase("ABCDEF", "def") = true
1811     * StringUtils.endsWithIgnoreCase("ABCDEF", "cde") = false
1812     * </pre>
1813     *
1814     * @see String#endsWith(String)
1815     * @param str  the CharSequence to check, may be null
1816     * @param suffix the suffix to find, may be null
1817     * @return {@code true} if the CharSequence ends with the suffix, case-insensitive, or
1818     *  both {@code null}
1819     * @since 2.4
1820     * @since 3.0 Changed signature from endsWithIgnoreCase(String, String) to endsWithIgnoreCase(CharSequence, CharSequence)
1821     */
1822    public static boolean endsWithIgnoreCase(final CharSequence str, final CharSequence suffix) {
1823        return endsWith(str, suffix, true);
1824    }
1825
1826    /**
1827     * Compares two CharSequences, returning {@code true} if they represent
1828     * equal sequences of characters.
1829     *
1830     * <p>{@code null}s are handled without exceptions. Two {@code null}
1831     * references are considered to be equal. The comparison is <strong>case-sensitive</strong>.</p>
1832     *
1833     * <pre>
1834     * StringUtils.equals(null, null)   = true
1835     * StringUtils.equals(null, "abc")  = false
1836     * StringUtils.equals("abc", null)  = false
1837     * StringUtils.equals("abc", "abc") = true
1838     * StringUtils.equals("abc", "ABC") = false
1839     * </pre>
1840     *
1841     * @param cs1  the first CharSequence, may be {@code null}
1842     * @param cs2  the second CharSequence, may be {@code null}
1843     * @return {@code true} if the CharSequences are equal (case-sensitive), or both {@code null}
1844     * @since 3.0 Changed signature from equals(String, String) to equals(CharSequence, CharSequence)
1845     * @see Object#equals(Object)
1846     * @see #equalsIgnoreCase(CharSequence, CharSequence)
1847     */
1848    public static boolean equals(final CharSequence cs1, final CharSequence cs2) {
1849        if (cs1 == cs2) {
1850            return true;
1851        }
1852        if (cs1 == null || cs2 == null) {
1853            return false;
1854        }
1855        if (cs1.length() != cs2.length()) {
1856            return false;
1857        }
1858        if (cs1 instanceof String && cs2 instanceof String) {
1859            return cs1.equals(cs2);
1860        }
1861        // Step-wise comparison
1862        final int length = cs1.length();
1863        for (int i = 0; i < length; i++) {
1864            if (cs1.charAt(i) != cs2.charAt(i)) {
1865                return false;
1866            }
1867        }
1868        return true;
1869    }
1870
1871    /**
1872     * Compares given {@code string} to a CharSequences vararg of {@code searchStrings},
1873     * returning {@code true} if the {@code string} is equal to any of the {@code searchStrings}.
1874     *
1875     * <pre>
1876     * StringUtils.equalsAny(null, (CharSequence[]) null) = false
1877     * StringUtils.equalsAny(null, null, null)    = true
1878     * StringUtils.equalsAny(null, "abc", "def")  = false
1879     * StringUtils.equalsAny("abc", null, "def")  = false
1880     * StringUtils.equalsAny("abc", "abc", "def") = true
1881     * StringUtils.equalsAny("abc", "ABC", "DEF") = false
1882     * </pre>
1883     *
1884     * @param string to compare, may be {@code null}.
1885     * @param searchStrings a vararg of strings, may be {@code null}.
1886     * @return {@code true} if the string is equal (case-sensitive) to any other element of {@code searchStrings};
1887     * {@code false} if {@code searchStrings} is null or contains no matches.
1888     * @since 3.5
1889     */
1890    public static boolean equalsAny(final CharSequence string, final CharSequence... searchStrings) {
1891        if (ArrayUtils.isNotEmpty(searchStrings)) {
1892            for (final CharSequence next : searchStrings) {
1893                if (equals(string, next)) {
1894                    return true;
1895                }
1896            }
1897        }
1898        return false;
1899    }
1900
1901    /**
1902     * Compares given {@code string} to a CharSequences vararg of {@code searchStrings},
1903     * returning {@code true} if the {@code string} is equal to any of the {@code searchStrings}, ignoring case.
1904     *
1905     * <pre>
1906     * StringUtils.equalsAnyIgnoreCase(null, (CharSequence[]) null) = false
1907     * StringUtils.equalsAnyIgnoreCase(null, null, null)    = true
1908     * StringUtils.equalsAnyIgnoreCase(null, "abc", "def")  = false
1909     * StringUtils.equalsAnyIgnoreCase("abc", null, "def")  = false
1910     * StringUtils.equalsAnyIgnoreCase("abc", "abc", "def") = true
1911     * StringUtils.equalsAnyIgnoreCase("abc", "ABC", "DEF") = true
1912     * </pre>
1913     *
1914     * @param string to compare, may be {@code null}.
1915     * @param searchStrings a vararg of strings, may be {@code null}.
1916     * @return {@code true} if the string is equal (case-insensitive) to any other element of {@code searchStrings};
1917     * {@code false} if {@code searchStrings} is null or contains no matches.
1918     * @since 3.5
1919     */
1920    public static boolean equalsAnyIgnoreCase(final CharSequence string, final CharSequence... searchStrings) {
1921        if (ArrayUtils.isNotEmpty(searchStrings)) {
1922            for (final CharSequence next : searchStrings) {
1923                if (equalsIgnoreCase(string, next)) {
1924                    return true;
1925                }
1926            }
1927        }
1928        return false;
1929    }
1930
1931    /**
1932     * Compares two CharSequences, returning {@code true} if they represent
1933     * equal sequences of characters, ignoring case.
1934     *
1935     * <p>{@code null}s are handled without exceptions. Two {@code null}
1936     * references are considered equal. The comparison is <strong>case insensitive</strong>.</p>
1937     *
1938     * <pre>
1939     * StringUtils.equalsIgnoreCase(null, null)   = true
1940     * StringUtils.equalsIgnoreCase(null, "abc")  = false
1941     * StringUtils.equalsIgnoreCase("abc", null)  = false
1942     * StringUtils.equalsIgnoreCase("abc", "abc") = true
1943     * StringUtils.equalsIgnoreCase("abc", "ABC") = true
1944     * </pre>
1945     *
1946     * @param cs1  the first CharSequence, may be {@code null}
1947     * @param cs2  the second CharSequence, may be {@code null}
1948     * @return {@code true} if the CharSequences are equal (case-insensitive), or both {@code null}
1949     * @since 3.0 Changed signature from equalsIgnoreCase(String, String) to equalsIgnoreCase(CharSequence, CharSequence)
1950     * @see #equals(CharSequence, CharSequence)
1951     */
1952    public static boolean equalsIgnoreCase(final CharSequence cs1, final CharSequence cs2) {
1953        if (cs1 == cs2) {
1954            return true;
1955        }
1956        if (cs1 == null || cs2 == null) {
1957            return false;
1958        }
1959        if (cs1.length() != cs2.length()) {
1960            return false;
1961        }
1962        return CharSequenceUtils.regionMatches(cs1, true, 0, cs2, 0, cs1.length());
1963    }
1964
1965    /**
1966     * Returns the first value in the array which is not empty (""),
1967     * {@code null} or whitespace only.
1968     *
1969     * <p>Whitespace is defined by {@link Character#isWhitespace(char)}.</p>
1970     *
1971     * <p>If all values are blank or the array is {@code null}
1972     * or empty then {@code null} is returned.</p>
1973     *
1974     * <pre>
1975     * StringUtils.firstNonBlank(null, null, null)     = null
1976     * StringUtils.firstNonBlank(null, "", " ")        = null
1977     * StringUtils.firstNonBlank("abc")                = "abc"
1978     * StringUtils.firstNonBlank(null, "xyz")          = "xyz"
1979     * StringUtils.firstNonBlank(null, "", " ", "xyz") = "xyz"
1980     * StringUtils.firstNonBlank(null, "xyz", "abc")   = "xyz"
1981     * StringUtils.firstNonBlank()                     = null
1982     * </pre>
1983     *
1984     * @param <T> the specific kind of CharSequence
1985     * @param values  the values to test, may be {@code null} or empty
1986     * @return the first value from {@code values} which is not blank,
1987     *  or {@code null} if there are no non-blank values
1988     * @since 3.8
1989     */
1990    @SafeVarargs
1991    public static <T extends CharSequence> T firstNonBlank(final T... values) {
1992        if (values != null) {
1993            for (final T val : values) {
1994                if (isNotBlank(val)) {
1995                    return val;
1996                }
1997            }
1998        }
1999        return null;
2000    }
2001
2002    /**
2003     * Returns the first value in the array which is not empty.
2004     *
2005     * <p>If all values are empty or the array is {@code null}
2006     * or empty then {@code null} is returned.</p>
2007     *
2008     * <pre>
2009     * StringUtils.firstNonEmpty(null, null, null)   = null
2010     * StringUtils.firstNonEmpty(null, null, "")     = null
2011     * StringUtils.firstNonEmpty(null, "", " ")      = " "
2012     * StringUtils.firstNonEmpty("abc")              = "abc"
2013     * StringUtils.firstNonEmpty(null, "xyz")        = "xyz"
2014     * StringUtils.firstNonEmpty("", "xyz")          = "xyz"
2015     * StringUtils.firstNonEmpty(null, "xyz", "abc") = "xyz"
2016     * StringUtils.firstNonEmpty()                   = null
2017     * </pre>
2018     *
2019     * @param <T> the specific kind of CharSequence
2020     * @param values  the values to test, may be {@code null} or empty
2021     * @return the first value from {@code values} which is not empty,
2022     *  or {@code null} if there are no non-empty values
2023     * @since 3.8
2024     */
2025    @SafeVarargs
2026    public static <T extends CharSequence> T firstNonEmpty(final T... values) {
2027        if (values != null) {
2028            for (final T val : values) {
2029                if (isNotEmpty(val)) {
2030                    return val;
2031                }
2032            }
2033        }
2034        return null;
2035    }
2036
2037    /**
2038     * Calls {@link String#getBytes(Charset)} in a null-safe manner.
2039     *
2040     * @param string input string
2041     * @param charset The {@link Charset} to encode the {@link String}. If null, then use the default Charset.
2042     * @return The empty byte[] if {@code string} is null, the result of {@link String#getBytes(Charset)} otherwise.
2043     * @see String#getBytes(Charset)
2044     * @since 3.10
2045     */
2046    public static byte[] getBytes(final String string, final Charset charset) {
2047        return string == null ? ArrayUtils.EMPTY_BYTE_ARRAY : string.getBytes(Charsets.toCharset(charset));
2048    }
2049
2050    /**
2051     * Calls {@link String#getBytes(String)} in a null-safe manner.
2052     *
2053     * @param string input string
2054     * @param charset The {@link Charset} name to encode the {@link String}. If null, then use the default Charset.
2055     * @return The empty byte[] if {@code string} is null, the result of {@link String#getBytes(String)} otherwise.
2056     * @throws UnsupportedEncodingException Thrown when the named charset is not supported.
2057     * @see String#getBytes(String)
2058     * @since 3.10
2059     */
2060    public static byte[] getBytes(final String string, final String charset) throws UnsupportedEncodingException {
2061        return string == null ? ArrayUtils.EMPTY_BYTE_ARRAY : string.getBytes(Charsets.toCharsetName(charset));
2062    }
2063
2064    /**
2065     * Compares all Strings in an array and returns the initial sequence of
2066     * characters that is common to all of them.
2067     *
2068     * <p>For example,
2069     * {@code getCommonPrefix(new String[] {"i am a machine", "i am a robot"}) -&gt; "i am a "}</p>
2070     *
2071     * <pre>
2072     * StringUtils.getCommonPrefix(null)                             = ""
2073     * StringUtils.getCommonPrefix(new String[] {})                  = ""
2074     * StringUtils.getCommonPrefix(new String[] {"abc"})             = "abc"
2075     * StringUtils.getCommonPrefix(new String[] {null, null})        = ""
2076     * StringUtils.getCommonPrefix(new String[] {"", ""})            = ""
2077     * StringUtils.getCommonPrefix(new String[] {"", null})          = ""
2078     * StringUtils.getCommonPrefix(new String[] {"abc", null, null}) = ""
2079     * StringUtils.getCommonPrefix(new String[] {null, null, "abc"}) = ""
2080     * StringUtils.getCommonPrefix(new String[] {"", "abc"})         = ""
2081     * StringUtils.getCommonPrefix(new String[] {"abc", ""})         = ""
2082     * StringUtils.getCommonPrefix(new String[] {"abc", "abc"})      = "abc"
2083     * StringUtils.getCommonPrefix(new String[] {"abc", "a"})        = "a"
2084     * StringUtils.getCommonPrefix(new String[] {"ab", "abxyz"})     = "ab"
2085     * StringUtils.getCommonPrefix(new String[] {"abcde", "abxyz"})  = "ab"
2086     * StringUtils.getCommonPrefix(new String[] {"abcde", "xyz"})    = ""
2087     * StringUtils.getCommonPrefix(new String[] {"xyz", "abcde"})    = ""
2088     * StringUtils.getCommonPrefix(new String[] {"i am a machine", "i am a robot"}) = "i am a "
2089     * </pre>
2090     *
2091     * @param strs  array of String objects, entries may be null
2092     * @return the initial sequence of characters that are common to all Strings
2093     * in the array; empty String if the array is null, the elements are all null
2094     * or if there is no common prefix.
2095     * @since 2.4
2096     */
2097    public static String getCommonPrefix(final String... strs) {
2098        if (ArrayUtils.isEmpty(strs)) {
2099            return EMPTY;
2100        }
2101        final int smallestIndexOfDiff = indexOfDifference(strs);
2102        if (smallestIndexOfDiff == INDEX_NOT_FOUND) {
2103            // all strings were identical
2104            if (strs[0] == null) {
2105                return EMPTY;
2106            }
2107            return strs[0];
2108        }
2109        if (smallestIndexOfDiff == 0) {
2110            // there were no common initial characters
2111            return EMPTY;
2112        }
2113        // we found a common initial character sequence
2114        return strs[0].substring(0, smallestIndexOfDiff);
2115    }
2116
2117    /**
2118     * Checks if a String {@code str} contains Unicode digits,
2119     * if yes then concatenate all the digits in {@code str} and return it as a String.
2120     *
2121     * <p>An empty ("") String will be returned if no digits found in {@code str}.</p>
2122     *
2123     * <pre>
2124     * StringUtils.getDigits(null)                 = null
2125     * StringUtils.getDigits("")                   = ""
2126     * StringUtils.getDigits("abc")                = ""
2127     * StringUtils.getDigits("1000$")              = "1000"
2128     * StringUtils.getDigits("1123~45")            = "112345"
2129     * StringUtils.getDigits("(541) 754-3010")     = "5417543010"
2130     * StringUtils.getDigits("\u0967\u0968\u0969") = "\u0967\u0968\u0969"
2131     * </pre>
2132     *
2133     * @param str the String to extract digits from, may be null
2134     * @return String with only digits,
2135     *           or an empty ("") String if no digits found,
2136     *           or {@code null} String if {@code str} is null
2137     * @since 3.6
2138     */
2139    public static String getDigits(final String str) {
2140        if (isEmpty(str)) {
2141            return str;
2142        }
2143        final int sz = str.length();
2144        final StringBuilder strDigits = new StringBuilder(sz);
2145        for (int i = 0; i < sz; i++) {
2146            final char tempChar = str.charAt(i);
2147            if (Character.isDigit(tempChar)) {
2148                strDigits.append(tempChar);
2149            }
2150        }
2151        return strDigits.toString();
2152    }
2153
2154    /**
2155     * Find the Fuzzy Distance which indicates the similarity score between two Strings.
2156     *
2157     * <p>This string matching algorithm is similar to the algorithms of editors such as Sublime Text,
2158     * TextMate, Atom and others. One point is given for every matched character. Subsequent
2159     * matches yield two bonus points. A higher score indicates a higher similarity.</p>
2160     *
2161     * <pre>
2162     * StringUtils.getFuzzyDistance(null, null, null)                                    = IllegalArgumentException
2163     * StringUtils.getFuzzyDistance("", "", Locale.ENGLISH)                              = 0
2164     * StringUtils.getFuzzyDistance("Workshop", "b", Locale.ENGLISH)                     = 0
2165     * StringUtils.getFuzzyDistance("Room", "o", Locale.ENGLISH)                         = 1
2166     * StringUtils.getFuzzyDistance("Workshop", "w", Locale.ENGLISH)                     = 1
2167     * StringUtils.getFuzzyDistance("Workshop", "ws", Locale.ENGLISH)                    = 2
2168     * StringUtils.getFuzzyDistance("Workshop", "wo", Locale.ENGLISH)                    = 4
2169     * StringUtils.getFuzzyDistance("Apache Software Foundation", "asf", Locale.ENGLISH) = 3
2170     * </pre>
2171     *
2172     * @param term a full term that should be matched against, must not be null
2173     * @param query the query that will be matched against a term, must not be null
2174     * @param locale This string matching logic is case-insensitive. A locale is necessary to normalize
2175     *  both Strings to lower case.
2176     * @return result score
2177     * @throws IllegalArgumentException if either String input {@code null} or Locale input {@code null}
2178     * @since 3.4
2179     * @deprecated As of 3.6, use Apache Commons Text
2180     * <a href="https://commons.apache.org/proper/commons-text/javadocs/api-release/org/apache/commons/text/similarity/FuzzyScore.html">
2181     * FuzzyScore</a> instead
2182     */
2183    @Deprecated
2184    public static int getFuzzyDistance(final CharSequence term, final CharSequence query, final Locale locale) {
2185        if (term == null || query == null) {
2186            throw new IllegalArgumentException("Strings must not be null");
2187        }
2188        if (locale == null) {
2189            throw new IllegalArgumentException("Locale must not be null");
2190        }
2191
2192        // fuzzy logic is case-insensitive. We normalize the Strings to lower
2193        // case right from the start. Turning characters to lower case
2194        // via Character.toLowerCase(char) is unfortunately insufficient
2195        // as it does not accept a locale.
2196        final String termLowerCase = term.toString().toLowerCase(locale);
2197        final String queryLowerCase = query.toString().toLowerCase(locale);
2198
2199        // the resulting score
2200        int score = 0;
2201
2202        // the position in the term which will be scanned next for potential
2203        // query character matches
2204        int termIndex = 0;
2205
2206        // index of the previously matched character in the term
2207        int previousMatchingCharacterIndex = Integer.MIN_VALUE;
2208
2209        for (int queryIndex = 0; queryIndex < queryLowerCase.length(); queryIndex++) {
2210            final char queryChar = queryLowerCase.charAt(queryIndex);
2211
2212            boolean termCharacterMatchFound = false;
2213            for (; termIndex < termLowerCase.length() && !termCharacterMatchFound; termIndex++) {
2214                final char termChar = termLowerCase.charAt(termIndex);
2215
2216                if (queryChar == termChar) {
2217                    // simple character matches result in one point
2218                    score++;
2219
2220                    // subsequent character matches further improve
2221                    // the score.
2222                    if (previousMatchingCharacterIndex + 1 == termIndex) {
2223                        score += 2;
2224                    }
2225
2226                    previousMatchingCharacterIndex = termIndex;
2227
2228                    // we can leave the nested loop. Every character in the
2229                    // query can match at most one character in the term.
2230                    termCharacterMatchFound = true;
2231                }
2232            }
2233        }
2234
2235        return score;
2236    }
2237
2238    /**
2239     * Returns either the passed in CharSequence, or if the CharSequence is
2240     * whitespace, empty ("") or {@code null}, the value supplied by {@code defaultStrSupplier}.
2241     *
2242     * <p>Whitespace is defined by {@link Character#isWhitespace(char)}.</p>
2243     *
2244     * <p>Caller responsible for thread-safety and exception handling of default value supplier</p>
2245     *
2246     * <pre>
2247     * {@code
2248     * StringUtils.getIfBlank(null, () -> "NULL")   = "NULL"
2249     * StringUtils.getIfBlank("", () -> "NULL")     = "NULL"
2250     * StringUtils.getIfBlank(" ", () -> "NULL")    = "NULL"
2251     * StringUtils.getIfBlank("bat", () -> "NULL")  = "bat"
2252     * StringUtils.getIfBlank("", () -> null)       = null
2253     * StringUtils.getIfBlank("", null)             = null
2254     * }</pre>
2255     * @param <T> the specific kind of CharSequence
2256     * @param str the CharSequence to check, may be null
2257     * @param defaultSupplier the supplier of default CharSequence to return
2258     *  if the input is whitespace, empty ("") or {@code null}, may be null
2259     * @return the passed in CharSequence, or the default
2260     * @see StringUtils#defaultString(String, String)
2261     * @since 3.10
2262     */
2263    public static <T extends CharSequence> T getIfBlank(final T str, final Supplier<T> defaultSupplier) {
2264        return isBlank(str) ? Suppliers.get(defaultSupplier) : str;
2265    }
2266
2267    /**
2268     * Returns either the passed in CharSequence, or if the CharSequence is
2269     * empty or {@code null}, the value supplied by {@code defaultStrSupplier}.
2270     *
2271     * <p>Caller responsible for thread-safety and exception handling of default value supplier</p>
2272     *
2273     * <pre>
2274     * {@code
2275     * StringUtils.getIfEmpty(null, () -> "NULL")    = "NULL"
2276     * StringUtils.getIfEmpty("", () -> "NULL")      = "NULL"
2277     * StringUtils.getIfEmpty(" ", () -> "NULL")     = " "
2278     * StringUtils.getIfEmpty("bat", () -> "NULL")   = "bat"
2279     * StringUtils.getIfEmpty("", () -> null)        = null
2280     * StringUtils.getIfEmpty("", null)              = null
2281     * }
2282     * </pre>
2283     * @param <T> the specific kind of CharSequence
2284     * @param str  the CharSequence to check, may be null
2285     * @param defaultSupplier  the supplier of default CharSequence to return
2286     *  if the input is empty ("") or {@code null}, may be null
2287     * @return the passed in CharSequence, or the default
2288     * @see StringUtils#defaultString(String, String)
2289     * @since 3.10
2290     */
2291    public static <T extends CharSequence> T getIfEmpty(final T str, final Supplier<T> defaultSupplier) {
2292        return isEmpty(str) ? Suppliers.get(defaultSupplier) : str;
2293    }
2294
2295    /**
2296     * Find the Jaro Winkler Distance which indicates the similarity score between two Strings.
2297     *
2298     * <p>The Jaro measure is the weighted sum of percentage of matched characters from each file and transposed characters.
2299     * Winkler increased this measure for matching initial characters.</p>
2300     *
2301     * <p>This implementation is based on the Jaro Winkler similarity algorithm
2302     * from <a href="https://en.wikipedia.org/wiki/Jaro%E2%80%93Winkler_distance">https://en.wikipedia.org/wiki/Jaro%E2%80%93Winkler_distance</a>.</p>
2303     *
2304     * <pre>
2305     * StringUtils.getJaroWinklerDistance(null, null)          = IllegalArgumentException
2306     * StringUtils.getJaroWinklerDistance("", "")              = 0.0
2307     * StringUtils.getJaroWinklerDistance("", "a")             = 0.0
2308     * StringUtils.getJaroWinklerDistance("aaapppp", "")       = 0.0
2309     * StringUtils.getJaroWinklerDistance("frog", "fog")       = 0.93
2310     * StringUtils.getJaroWinklerDistance("fly", "ant")        = 0.0
2311     * StringUtils.getJaroWinklerDistance("elephant", "hippo") = 0.44
2312     * StringUtils.getJaroWinklerDistance("hippo", "elephant") = 0.44
2313     * StringUtils.getJaroWinklerDistance("hippo", "zzzzzzzz") = 0.0
2314     * StringUtils.getJaroWinklerDistance("hello", "hallo")    = 0.88
2315     * StringUtils.getJaroWinklerDistance("ABC Corporation", "ABC Corp") = 0.93
2316     * StringUtils.getJaroWinklerDistance("D N H Enterprises Inc", "D &amp; H Enterprises, Inc.") = 0.95
2317     * StringUtils.getJaroWinklerDistance("My Gym Children's Fitness Center", "My Gym. Childrens Fitness") = 0.92
2318     * StringUtils.getJaroWinklerDistance("PENNSYLVANIA", "PENNCISYLVNIA") = 0.88
2319     * </pre>
2320     *
2321     * @param first the first String, must not be null
2322     * @param second the second String, must not be null
2323     * @return result distance
2324     * @throws IllegalArgumentException if either String input {@code null}
2325     * @since 3.3
2326     * @deprecated As of 3.6, use Apache Commons Text
2327     * <a href="https://commons.apache.org/proper/commons-text/javadocs/api-release/org/apache/commons/text/similarity/JaroWinklerDistance.html">
2328     * JaroWinklerDistance</a> instead
2329     */
2330    @Deprecated
2331    public static double getJaroWinklerDistance(final CharSequence first, final CharSequence second) {
2332        final double DEFAULT_SCALING_FACTOR = 0.1;
2333
2334        if (first == null || second == null) {
2335            throw new IllegalArgumentException("Strings must not be null");
2336        }
2337
2338        final int[] mtp = matches(first, second);
2339        final double m = mtp[0];
2340        if (m == 0) {
2341            return 0D;
2342        }
2343        final double j = (m / first.length() + m / second.length() + (m - mtp[1]) / m) / 3;
2344        final double jw = j < 0.7D ? j : j + Math.min(DEFAULT_SCALING_FACTOR, 1D / mtp[3]) * mtp[2] * (1D - j);
2345        return Math.round(jw * 100.0D) / 100.0D;
2346    }
2347
2348    /**
2349     * Find the Levenshtein distance between two Strings.
2350     *
2351     * <p>This is the number of changes needed to change one String into
2352     * another, where each change is a single character modification (deletion,
2353     * insertion or substitution).</p>
2354     *
2355     * <p>The implementation uses a single-dimensional array of length s.length() + 1. See
2356     * <a href="https://blog.softwx.net/2014/12/optimizing-levenshtein-algorithm-in-c.html">
2357     * https://blog.softwx.net/2014/12/optimizing-levenshtein-algorithm-in-c.html</a> for details.</p>
2358     *
2359     * <pre>
2360     * StringUtils.getLevenshteinDistance(null, *)             = IllegalArgumentException
2361     * StringUtils.getLevenshteinDistance(*, null)             = IllegalArgumentException
2362     * StringUtils.getLevenshteinDistance("", "")              = 0
2363     * StringUtils.getLevenshteinDistance("", "a")             = 1
2364     * StringUtils.getLevenshteinDistance("aaapppp", "")       = 7
2365     * StringUtils.getLevenshteinDistance("frog", "fog")       = 1
2366     * StringUtils.getLevenshteinDistance("fly", "ant")        = 3
2367     * StringUtils.getLevenshteinDistance("elephant", "hippo") = 7
2368     * StringUtils.getLevenshteinDistance("hippo", "elephant") = 7
2369     * StringUtils.getLevenshteinDistance("hippo", "zzzzzzzz") = 8
2370     * StringUtils.getLevenshteinDistance("hello", "hallo")    = 1
2371     * </pre>
2372     *
2373     * @param s  the first String, must not be null
2374     * @param t  the second String, must not be null
2375     * @return result distance
2376     * @throws IllegalArgumentException if either String input {@code null}
2377     * @since 3.0 Changed signature from getLevenshteinDistance(String, String) to
2378     * getLevenshteinDistance(CharSequence, CharSequence)
2379     * @deprecated As of 3.6, use Apache Commons Text
2380     * <a href="https://commons.apache.org/proper/commons-text/javadocs/api-release/org/apache/commons/text/similarity/LevenshteinDistance.html">
2381     * LevenshteinDistance</a> instead
2382     */
2383    @Deprecated
2384    public static int getLevenshteinDistance(CharSequence s, CharSequence t) {
2385        if (s == null || t == null) {
2386            throw new IllegalArgumentException("Strings must not be null");
2387        }
2388
2389        int n = s.length();
2390        int m = t.length();
2391
2392        if (n == 0) {
2393            return m;
2394        }
2395        if (m == 0) {
2396            return n;
2397        }
2398
2399        if (n > m) {
2400            // swap the input strings to consume less memory
2401            final CharSequence tmp = s;
2402            s = t;
2403            t = tmp;
2404            n = m;
2405            m = t.length();
2406        }
2407
2408        final int[] p = new int[n + 1];
2409        // indexes into strings s and t
2410        int i; // iterates through s
2411        int j; // iterates through t
2412        int upperleft;
2413        int upper;
2414
2415        char jOfT; // jth character of t
2416        int cost;
2417
2418        for (i = 0; i <= n; i++) {
2419            p[i] = i;
2420        }
2421
2422        for (j = 1; j <= m; j++) {
2423            upperleft = p[0];
2424            jOfT = t.charAt(j - 1);
2425            p[0] = j;
2426
2427            for (i = 1; i <= n; i++) {
2428                upper = p[i];
2429                cost = s.charAt(i - 1) == jOfT ? 0 : 1;
2430                // minimum of cell to the left+1, to the top+1, diagonally left and up +cost
2431                p[i] = Math.min(Math.min(p[i - 1] + 1, p[i] + 1), upperleft + cost);
2432                upperleft = upper;
2433            }
2434        }
2435
2436        return p[n];
2437    }
2438
2439    /**
2440     * Find the Levenshtein distance between two Strings if it's less than or equal to a given
2441     * threshold.
2442     *
2443     * <p>This is the number of changes needed to change one String into
2444     * another, where each change is a single character modification (deletion,
2445     * insertion or substitution).</p>
2446     *
2447     * <p>This implementation follows from Algorithms on Strings, Trees and Sequences by Dan Gusfield
2448     * and Chas Emerick's implementation of the Levenshtein distance algorithm from
2449     * <a href="https://web.archive.org/web/20120212021906/http%3A//www.merriampark.com/ld.htm">http://www.merriampark.com/ld.htm</a></p>
2450     *
2451     * <pre>
2452     * StringUtils.getLevenshteinDistance(null, *, *)             = IllegalArgumentException
2453     * StringUtils.getLevenshteinDistance(*, null, *)             = IllegalArgumentException
2454     * StringUtils.getLevenshteinDistance(*, *, -1)               = IllegalArgumentException
2455     * StringUtils.getLevenshteinDistance("", "", 0)              = 0
2456     * StringUtils.getLevenshteinDistance("aaapppp", "", 8)       = 7
2457     * StringUtils.getLevenshteinDistance("aaapppp", "", 7)       = 7
2458     * StringUtils.getLevenshteinDistance("aaapppp", "", 6))      = -1
2459     * StringUtils.getLevenshteinDistance("elephant", "hippo", 7) = 7
2460     * StringUtils.getLevenshteinDistance("elephant", "hippo", 6) = -1
2461     * StringUtils.getLevenshteinDistance("hippo", "elephant", 7) = 7
2462     * StringUtils.getLevenshteinDistance("hippo", "elephant", 6) = -1
2463     * </pre>
2464     *
2465     * @param s  the first String, must not be null
2466     * @param t  the second String, must not be null
2467     * @param threshold the target threshold, must not be negative
2468     * @return result distance, or {@code -1} if the distance would be greater than the threshold
2469     * @throws IllegalArgumentException if either String input {@code null} or negative threshold
2470     * @deprecated As of 3.6, use Apache Commons Text
2471     * <a href="https://commons.apache.org/proper/commons-text/javadocs/api-release/org/apache/commons/text/similarity/LevenshteinDistance.html">
2472     * LevenshteinDistance</a> instead
2473     */
2474    @Deprecated
2475    public static int getLevenshteinDistance(CharSequence s, CharSequence t, final int threshold) {
2476        if (s == null || t == null) {
2477            throw new IllegalArgumentException("Strings must not be null");
2478        }
2479        if (threshold < 0) {
2480            throw new IllegalArgumentException("Threshold must not be negative");
2481        }
2482
2483        /*
2484        This implementation only computes the distance if it's less than or equal to the
2485        threshold value, returning -1 if it's greater.  The advantage is performance: unbounded
2486        distance is O(nm), but a bound of k allows us to reduce it to O(km) time by only
2487        computing a diagonal stripe of width 2k + 1 of the cost table.
2488        It is also possible to use this to compute the unbounded Levenshtein distance by starting
2489        the threshold at 1 and doubling each time until the distance is found; this is O(dm), where
2490        d is the distance.
2491
2492        One subtlety comes from needing to ignore entries on the border of our stripe
2493        eg.
2494        p[] = |#|#|#|*
2495        d[] =  *|#|#|#|
2496        We must ignore the entry to the left of the leftmost member
2497        We must ignore the entry above the rightmost member
2498
2499        Another subtlety comes from our stripe running off the matrix if the strings aren't
2500        of the same size.  Since string s is always swapped to be the shorter of the two,
2501        the stripe will always run off to the upper right instead of the lower left of the matrix.
2502
2503        As a concrete example, suppose s is of length 5, t is of length 7, and our threshold is 1.
2504        In this case we're going to walk a stripe of length 3.  The matrix would look like so:
2505
2506           1 2 3 4 5
2507        1 |#|#| | | |
2508        2 |#|#|#| | |
2509        3 | |#|#|#| |
2510        4 | | |#|#|#|
2511        5 | | | |#|#|
2512        6 | | | | |#|
2513        7 | | | | | |
2514
2515        Note how the stripe leads off the table as there is no possible way to turn a string of length 5
2516        into one of length 7 in edit distance of 1.
2517
2518        Additionally, this implementation decreases memory usage by using two
2519        single-dimensional arrays and swapping them back and forth instead of allocating
2520        an entire n by m matrix.  This requires a few minor changes, such as immediately returning
2521        when it's detected that the stripe has run off the matrix and initially filling the arrays with
2522        large values so that entries we don't compute are ignored.
2523
2524        See Algorithms on Strings, Trees and Sequences by Dan Gusfield for some discussion.
2525         */
2526
2527        int n = s.length(); // length of s
2528        int m = t.length(); // length of t
2529
2530        // if one string is empty, the edit distance is necessarily the length of the other
2531        if (n == 0) {
2532            return m <= threshold ? m : -1;
2533        }
2534        if (m == 0) {
2535            return n <= threshold ? n : -1;
2536        }
2537        if (Math.abs(n - m) > threshold) {
2538            // no need to calculate the distance if the length difference is greater than the threshold
2539            return -1;
2540        }
2541
2542        if (n > m) {
2543            // swap the two strings to consume less memory
2544            final CharSequence tmp = s;
2545            s = t;
2546            t = tmp;
2547            n = m;
2548            m = t.length();
2549        }
2550
2551        int[] p = new int[n + 1]; // 'previous' cost array, horizontally
2552        int[] d = new int[n + 1]; // cost array, horizontally
2553        int[] tmp; // placeholder to assist in swapping p and d
2554
2555        // fill in starting table values
2556        final int boundary = Math.min(n, threshold) + 1;
2557        for (int i = 0; i < boundary; i++) {
2558            p[i] = i;
2559        }
2560        // these fills ensure that the value above the rightmost entry of our
2561        // stripe will be ignored in following loop iterations
2562        Arrays.fill(p, boundary, p.length, Integer.MAX_VALUE);
2563        Arrays.fill(d, Integer.MAX_VALUE);
2564
2565        // iterates through t
2566        for (int j = 1; j <= m; j++) {
2567            final char jOfT = t.charAt(j - 1); // jth character of t
2568            d[0] = j;
2569
2570            // compute stripe indices, constrain to array size
2571            final int min = Math.max(1, j - threshold);
2572            final int max = j > Integer.MAX_VALUE - threshold ? n : Math.min(n, j + threshold);
2573
2574            // the stripe may lead off of the table if s and t are of different sizes
2575            if (min > max) {
2576                return -1;
2577            }
2578
2579            // ignore entry left of leftmost
2580            if (min > 1) {
2581                d[min - 1] = Integer.MAX_VALUE;
2582            }
2583
2584            // iterates through [min, max] in s
2585            for (int i = min; i <= max; i++) {
2586                if (s.charAt(i - 1) == jOfT) {
2587                    // diagonally left and up
2588                    d[i] = p[i - 1];
2589                } else {
2590                    // 1 + minimum of cell to the left, to the top, diagonally left and up
2591                    d[i] = 1 + Math.min(Math.min(d[i - 1], p[i]), p[i - 1]);
2592                }
2593            }
2594
2595            // copy current distance counts to 'previous row' distance counts
2596            tmp = p;
2597            p = d;
2598            d = tmp;
2599        }
2600
2601        // if p[n] is greater than the threshold, there's no guarantee on it being the correct
2602        // distance
2603        if (p[n] <= threshold) {
2604            return p[n];
2605        }
2606        return -1;
2607    }
2608
2609    /**
2610     * Finds the first index within a CharSequence, handling {@code null}.
2611     * This method uses {@link String#indexOf(String, int)} if possible.
2612     *
2613     * <p>A {@code null} CharSequence will return {@code -1}.</p>
2614     *
2615     * <pre>
2616     * StringUtils.indexOf(null, *)          = -1
2617     * StringUtils.indexOf(*, null)          = -1
2618     * StringUtils.indexOf("", "")           = 0
2619     * StringUtils.indexOf("", *)            = -1 (except when * = "")
2620     * StringUtils.indexOf("aabaabaa", "a")  = 0
2621     * StringUtils.indexOf("aabaabaa", "b")  = 2
2622     * StringUtils.indexOf("aabaabaa", "ab") = 1
2623     * StringUtils.indexOf("aabaabaa", "")   = 0
2624     * </pre>
2625     *
2626     * @param seq  the CharSequence to check, may be null
2627     * @param searchSeq  the CharSequence to find, may be null
2628     * @return the first index of the search CharSequence,
2629     *  -1 if no match or {@code null} string input
2630     * @since 2.0
2631     * @since 3.0 Changed signature from indexOf(String, String) to indexOf(CharSequence, CharSequence)
2632     */
2633    public static int indexOf(final CharSequence seq, final CharSequence searchSeq) {
2634        if (seq == null || searchSeq == null) {
2635            return INDEX_NOT_FOUND;
2636        }
2637        return CharSequenceUtils.indexOf(seq, searchSeq, 0);
2638    }
2639
2640    /**
2641     * Finds the first index within a CharSequence, handling {@code null}.
2642     * This method uses {@link String#indexOf(String, int)} if possible.
2643     *
2644     * <p>A {@code null} CharSequence will return {@code -1}.
2645     * A negative start position is treated as zero.
2646     * An empty ("") search CharSequence always matches.
2647     * A start position greater than the string length only matches
2648     * an empty search CharSequence.</p>
2649     *
2650     * <pre>
2651     * StringUtils.indexOf(null, *, *)          = -1
2652     * StringUtils.indexOf(*, null, *)          = -1
2653     * StringUtils.indexOf("", "", 0)           = 0
2654     * StringUtils.indexOf("", *, 0)            = -1 (except when * = "")
2655     * StringUtils.indexOf("aabaabaa", "a", 0)  = 0
2656     * StringUtils.indexOf("aabaabaa", "b", 0)  = 2
2657     * StringUtils.indexOf("aabaabaa", "ab", 0) = 1
2658     * StringUtils.indexOf("aabaabaa", "b", 3)  = 5
2659     * StringUtils.indexOf("aabaabaa", "b", 9)  = -1
2660     * StringUtils.indexOf("aabaabaa", "b", -1) = 2
2661     * StringUtils.indexOf("aabaabaa", "", 2)   = 2
2662     * StringUtils.indexOf("abc", "", 9)        = 3
2663     * </pre>
2664     *
2665     * @param seq  the CharSequence to check, may be null
2666     * @param searchSeq  the CharSequence to find, may be null
2667     * @param startPos  the start position, negative treated as zero
2668     * @return the first index of the search CharSequence (always &ge; startPos),
2669     *  -1 if no match or {@code null} string input
2670     * @since 2.0
2671     * @since 3.0 Changed signature from indexOf(String, String, int) to indexOf(CharSequence, CharSequence, int)
2672     */
2673    public static int indexOf(final CharSequence seq, final CharSequence searchSeq, final int startPos) {
2674        if (seq == null || searchSeq == null) {
2675            return INDEX_NOT_FOUND;
2676        }
2677        return CharSequenceUtils.indexOf(seq, searchSeq, startPos);
2678    }
2679
2680    /**
2681     * Returns the index within {@code seq} of the first occurrence of
2682     * the specified character. If a character with value
2683     * {@code searchChar} occurs in the character sequence represented by
2684     * {@code seq} {@link CharSequence} object, then the index (in Unicode
2685     * code units) of the first such occurrence is returned. For
2686     * values of {@code searchChar} in the range from 0 to 0xFFFF
2687     * (inclusive), this is the smallest value <em>k</em> such that:
2688     * <blockquote><pre>
2689     * this.charAt(<em>k</em>) == searchChar
2690     * </pre></blockquote>
2691     * is true. For other values of {@code searchChar}, it is the
2692     * smallest value <em>k</em> such that:
2693     * <blockquote><pre>
2694     * this.codePointAt(<em>k</em>) == searchChar
2695     * </pre></blockquote>
2696     * is true. In either case, if no such character occurs in {@code seq},
2697     * then {@code INDEX_NOT_FOUND (-1)} is returned.
2698     *
2699     * <p>Furthermore, a {@code null} or empty ("") CharSequence will
2700     * return {@code INDEX_NOT_FOUND (-1)}.</p>
2701     *
2702     * <pre>
2703     * StringUtils.indexOf(null, *)         = -1
2704     * StringUtils.indexOf("", *)           = -1
2705     * StringUtils.indexOf("aabaabaa", 'a') = 0
2706     * StringUtils.indexOf("aabaabaa", 'b') = 2
2707     * </pre>
2708     *
2709     * @param seq  the CharSequence to check, may be null
2710     * @param searchChar  the character to find
2711     * @return the first index of the search character,
2712     *  -1 if no match or {@code null} string input
2713     * @since 2.0
2714     * @since 3.0 Changed signature from indexOf(String, int) to indexOf(CharSequence, int)
2715     * @since 3.6 Updated {@link CharSequenceUtils} call to behave more like {@link String}
2716     */
2717    public static int indexOf(final CharSequence seq, final int searchChar) {
2718        if (isEmpty(seq)) {
2719            return INDEX_NOT_FOUND;
2720        }
2721        return CharSequenceUtils.indexOf(seq, searchChar, 0);
2722    }
2723
2724    /**
2725     * Returns the index within {@code seq} of the first occurrence of the
2726     * specified character, starting the search at the specified index.
2727     * <p>
2728     * If a character with value {@code searchChar} occurs in the
2729     * character sequence represented by the {@code seq} {@link CharSequence}
2730     * object at an index no smaller than {@code startPos}, then
2731     * the index of the first such occurrence is returned. For values
2732     * of {@code searchChar} in the range from 0 to 0xFFFF (inclusive),
2733     * this is the smallest value <em>k</em> such that:
2734     * <blockquote><pre>
2735     * (this.charAt(<em>k</em>) == searchChar) &amp;&amp; (<em>k</em> &gt;= startPos)
2736     * </pre></blockquote>
2737     * is true. For other values of {@code searchChar}, it is the
2738     * smallest value <em>k</em> such that:
2739     * <blockquote><pre>
2740     * (this.codePointAt(<em>k</em>) == searchChar) &amp;&amp; (<em>k</em> &gt;= startPos)
2741     * </pre></blockquote>
2742     * is true. In either case, if no such character occurs in {@code seq}
2743     * at or after position {@code startPos}, then
2744     * {@code -1} is returned.
2745     *
2746     * <p>
2747     * There is no restriction on the value of {@code startPos}. If it
2748     * is negative, it has the same effect as if it were zero: this entire
2749     * string may be searched. If it is greater than the length of this
2750     * string, it has the same effect as if it were equal to the length of
2751     * this string: {@code (INDEX_NOT_FOUND) -1} is returned. Furthermore, a
2752     * {@code null} or empty ("") CharSequence will
2753     * return {@code (INDEX_NOT_FOUND) -1}.
2754     *
2755     * <p>All indices are specified in {@code char} values
2756     * (Unicode code units).
2757     *
2758     * <pre>
2759     * StringUtils.indexOf(null, *, *)          = -1
2760     * StringUtils.indexOf("", *, *)            = -1
2761     * StringUtils.indexOf("aabaabaa", 'b', 0)  = 2
2762     * StringUtils.indexOf("aabaabaa", 'b', 3)  = 5
2763     * StringUtils.indexOf("aabaabaa", 'b', 9)  = -1
2764     * StringUtils.indexOf("aabaabaa", 'b', -1) = 2
2765     * </pre>
2766     *
2767     * @param seq  the CharSequence to check, may be null
2768     * @param searchChar  the character to find
2769     * @param startPos  the start position, negative treated as zero
2770     * @return the first index of the search character (always &ge; startPos),
2771     *  -1 if no match or {@code null} string input
2772     * @since 2.0
2773     * @since 3.0 Changed signature from indexOf(String, int, int) to indexOf(CharSequence, int, int)
2774     * @since 3.6 Updated {@link CharSequenceUtils} call to behave more like {@link String}
2775     */
2776    public static int indexOf(final CharSequence seq, final int searchChar, final int startPos) {
2777        if (isEmpty(seq)) {
2778            return INDEX_NOT_FOUND;
2779        }
2780        return CharSequenceUtils.indexOf(seq, searchChar, startPos);
2781    }
2782
2783    /**
2784     * Search a CharSequence to find the first index of any
2785     * character in the given set of characters.
2786     *
2787     * <p>A {@code null} String will return {@code -1}.
2788     * A {@code null} or zero length search array will return {@code -1}.</p>
2789     *
2790     * <pre>
2791     * StringUtils.indexOfAny(null, *)                  = -1
2792     * StringUtils.indexOfAny("", *)                    = -1
2793     * StringUtils.indexOfAny(*, null)                  = -1
2794     * StringUtils.indexOfAny(*, [])                    = -1
2795     * StringUtils.indexOfAny("zzabyycdxx", ['z', 'a']) = 0
2796     * StringUtils.indexOfAny("zzabyycdxx", ['b', 'y']) = 3
2797     * StringUtils.indexOfAny("aba", ['z'])             = -1
2798     * </pre>
2799     *
2800     * @param cs  the CharSequence to check, may be null
2801     * @param searchChars  the chars to search for, may be null
2802     * @return the index of any of the chars, -1 if no match or null input
2803     * @since 2.0
2804     * @since 3.0 Changed signature from indexOfAny(String, char[]) to indexOfAny(CharSequence, char...)
2805     */
2806    public static int indexOfAny(final CharSequence cs, final char... searchChars) {
2807        if (isEmpty(cs) || ArrayUtils.isEmpty(searchChars)) {
2808            return INDEX_NOT_FOUND;
2809        }
2810        final int csLen = cs.length();
2811        final int csLast = csLen - 1;
2812        final int searchLen = searchChars.length;
2813        final int searchLast = searchLen - 1;
2814        for (int i = 0; i < csLen; i++) {
2815            final char ch = cs.charAt(i);
2816            for (int j = 0; j < searchLen; j++) {
2817                if (searchChars[j] == ch) {
2818                    if (i >= csLast || j >= searchLast || !Character.isHighSurrogate(ch)) {
2819                        return i;
2820                    }
2821                    // ch is a supplementary character
2822                    if (searchChars[j + 1] == cs.charAt(i + 1)) {
2823                        return i;
2824                    }
2825                }
2826            }
2827        }
2828        return INDEX_NOT_FOUND;
2829    }
2830
2831    /**
2832     * Find the first index of any of a set of potential substrings.
2833     *
2834     * <p>A {@code null} CharSequence will return {@code -1}.
2835     * A {@code null} or zero length search array will return {@code -1}.
2836     * A {@code null} search array entry will be ignored, but a search
2837     * array containing "" will return {@code 0} if {@code str} is not
2838     * null. This method uses {@link String#indexOf(String)} if possible.</p>
2839     *
2840     * <pre>
2841     * StringUtils.indexOfAny(null, *)                      = -1
2842     * StringUtils.indexOfAny(*, null)                      = -1
2843     * StringUtils.indexOfAny(*, [])                        = -1
2844     * StringUtils.indexOfAny("zzabyycdxx", ["ab", "cd"])   = 2
2845     * StringUtils.indexOfAny("zzabyycdxx", ["cd", "ab"])   = 2
2846     * StringUtils.indexOfAny("zzabyycdxx", ["mn", "op"])   = -1
2847     * StringUtils.indexOfAny("zzabyycdxx", ["zab", "aby"]) = 1
2848     * StringUtils.indexOfAny("zzabyycdxx", [""])           = 0
2849     * StringUtils.indexOfAny("", [""])                     = 0
2850     * StringUtils.indexOfAny("", ["a"])                    = -1
2851     * </pre>
2852     *
2853     * @param str  the CharSequence to check, may be null
2854     * @param searchStrs  the CharSequences to search for, may be null
2855     * @return the first index of any of the searchStrs in str, -1 if no match
2856     * @since 3.0 Changed signature from indexOfAny(String, String[]) to indexOfAny(CharSequence, CharSequence...)
2857     */
2858    public static int indexOfAny(final CharSequence str, final CharSequence... searchStrs) {
2859        if (str == null || searchStrs == null) {
2860            return INDEX_NOT_FOUND;
2861        }
2862
2863        // String's can't have a MAX_VALUEth index.
2864        int ret = Integer.MAX_VALUE;
2865
2866        int tmp;
2867        for (final CharSequence search : searchStrs) {
2868            if (search == null) {
2869                continue;
2870            }
2871            tmp = CharSequenceUtils.indexOf(str, search, 0);
2872            if (tmp == INDEX_NOT_FOUND) {
2873                continue;
2874            }
2875
2876            if (tmp < ret) {
2877                ret = tmp;
2878            }
2879        }
2880
2881        return ret == Integer.MAX_VALUE ? INDEX_NOT_FOUND : ret;
2882    }
2883
2884    /**
2885     * Search a CharSequence to find the first index of any
2886     * character in the given set of characters.
2887     *
2888     * <p>A {@code null} String will return {@code -1}.
2889     * A {@code null} search string will return {@code -1}.</p>
2890     *
2891     * <pre>
2892     * StringUtils.indexOfAny(null, *)            = -1
2893     * StringUtils.indexOfAny("", *)              = -1
2894     * StringUtils.indexOfAny(*, null)            = -1
2895     * StringUtils.indexOfAny(*, "")              = -1
2896     * StringUtils.indexOfAny("zzabyycdxx", "za") = 0
2897     * StringUtils.indexOfAny("zzabyycdxx", "by") = 3
2898     * StringUtils.indexOfAny("aba", "z")         = -1
2899     * </pre>
2900     *
2901     * @param cs  the CharSequence to check, may be null
2902     * @param searchChars  the chars to search for, may be null
2903     * @return the index of any of the chars, -1 if no match or null input
2904     * @since 2.0
2905     * @since 3.0 Changed signature from indexOfAny(String, String) to indexOfAny(CharSequence, String)
2906     */
2907    public static int indexOfAny(final CharSequence cs, final String searchChars) {
2908        if (isEmpty(cs) || isEmpty(searchChars)) {
2909            return INDEX_NOT_FOUND;
2910        }
2911        return indexOfAny(cs, searchChars.toCharArray());
2912    }
2913
2914    /**
2915     * Searches a CharSequence to find the first index of any
2916     * character not in the given set of characters.
2917     *
2918     * <p>A {@code null} CharSequence will return {@code -1}.
2919     * A {@code null} or zero length search array will return {@code -1}.</p>
2920     *
2921     * <pre>
2922     * StringUtils.indexOfAnyBut(null, *)                              = -1
2923     * StringUtils.indexOfAnyBut("", *)                                = -1
2924     * StringUtils.indexOfAnyBut(*, null)                              = -1
2925     * StringUtils.indexOfAnyBut(*, [])                                = -1
2926     * StringUtils.indexOfAnyBut("zzabyycdxx", new char[] {'z', 'a'} ) = 3
2927     * StringUtils.indexOfAnyBut("aba", new char[] {'z'} )             = 0
2928     * StringUtils.indexOfAnyBut("aba", new char[] {'a', 'b'} )        = -1
2929
2930     * </pre>
2931     *
2932     * @param cs  the CharSequence to check, may be null
2933     * @param searchChars  the chars to search for, may be null
2934     * @return the index of any of the chars, -1 if no match or null input
2935     * @since 2.0
2936     * @since 3.0 Changed signature from indexOfAnyBut(String, char[]) to indexOfAnyBut(CharSequence, char...)
2937     */
2938    public static int indexOfAnyBut(final CharSequence cs, final char... searchChars) {
2939        if (isEmpty(cs) || ArrayUtils.isEmpty(searchChars)) {
2940            return INDEX_NOT_FOUND;
2941        }
2942        final int csLen = cs.length();
2943        final int csLast = csLen - 1;
2944        final int searchLen = searchChars.length;
2945        final int searchLast = searchLen - 1;
2946        outer:
2947        for (int i = 0; i < csLen; i++) {
2948            final char ch = cs.charAt(i);
2949            for (int j = 0; j < searchLen; j++) {
2950                if (searchChars[j] == ch) {
2951                    if (i >= csLast || j >= searchLast || !Character.isHighSurrogate(ch)) {
2952                        continue outer;
2953                    }
2954                    if (searchChars[j + 1] == cs.charAt(i + 1)) {
2955                        continue outer;
2956                    }
2957                }
2958            }
2959            return i;
2960        }
2961        return INDEX_NOT_FOUND;
2962    }
2963
2964    /**
2965     * Search a CharSequence to find the first index of any
2966     * character not in the given set of characters.
2967     *
2968     * <p>A {@code null} CharSequence will return {@code -1}.
2969     * A {@code null} or empty search string will return {@code -1}.</p>
2970     *
2971     * <pre>
2972     * StringUtils.indexOfAnyBut(null, *)            = -1
2973     * StringUtils.indexOfAnyBut("", *)              = -1
2974     * StringUtils.indexOfAnyBut(*, null)            = -1
2975     * StringUtils.indexOfAnyBut(*, "")              = -1
2976     * StringUtils.indexOfAnyBut("zzabyycdxx", "za") = 3
2977     * StringUtils.indexOfAnyBut("zzabyycdxx", "")   = -1
2978     * StringUtils.indexOfAnyBut("aba", "ab")        = -1
2979     * </pre>
2980     *
2981     * @param seq  the CharSequence to check, may be null
2982     * @param searchChars  the chars to search for, may be null
2983     * @return the index of any of the chars, -1 if no match or null input
2984     * @since 2.0
2985     * @since 3.0 Changed signature from indexOfAnyBut(String, String) to indexOfAnyBut(CharSequence, CharSequence)
2986     */
2987    public static int indexOfAnyBut(final CharSequence seq, final CharSequence searchChars) {
2988        if (isEmpty(seq) || isEmpty(searchChars)) {
2989            return INDEX_NOT_FOUND;
2990        }
2991        final int strLen = seq.length();
2992        for (int i = 0; i < strLen; i++) {
2993            final char ch = seq.charAt(i);
2994            final boolean chFound = CharSequenceUtils.indexOf(searchChars, ch, 0) >= 0;
2995            if (i + 1 < strLen && Character.isHighSurrogate(ch)) {
2996                final char ch2 = seq.charAt(i + 1);
2997                if (chFound && CharSequenceUtils.indexOf(searchChars, ch2, 0) < 0) {
2998                    return i;
2999                }
3000            } else if (!chFound) {
3001                return i;
3002            }
3003        }
3004        return INDEX_NOT_FOUND;
3005    }
3006
3007    /**
3008     * Compares all CharSequences in an array and returns the index at which the
3009     * CharSequences begin to differ.
3010     *
3011     * <p>For example,
3012     * {@code indexOfDifference(new String[] {"i am a machine", "i am a robot"}) -> 7}</p>
3013     *
3014     * <pre>
3015     * StringUtils.indexOfDifference(null)                             = -1
3016     * StringUtils.indexOfDifference(new String[] {})                  = -1
3017     * StringUtils.indexOfDifference(new String[] {"abc"})             = -1
3018     * StringUtils.indexOfDifference(new String[] {null, null})        = -1
3019     * StringUtils.indexOfDifference(new String[] {"", ""})            = -1
3020     * StringUtils.indexOfDifference(new String[] {"", null})          = 0
3021     * StringUtils.indexOfDifference(new String[] {"abc", null, null}) = 0
3022     * StringUtils.indexOfDifference(new String[] {null, null, "abc"}) = 0
3023     * StringUtils.indexOfDifference(new String[] {"", "abc"})         = 0
3024     * StringUtils.indexOfDifference(new String[] {"abc", ""})         = 0
3025     * StringUtils.indexOfDifference(new String[] {"abc", "abc"})      = -1
3026     * StringUtils.indexOfDifference(new String[] {"abc", "a"})        = 1
3027     * StringUtils.indexOfDifference(new String[] {"ab", "abxyz"})     = 2
3028     * StringUtils.indexOfDifference(new String[] {"abcde", "abxyz"})  = 2
3029     * StringUtils.indexOfDifference(new String[] {"abcde", "xyz"})    = 0
3030     * StringUtils.indexOfDifference(new String[] {"xyz", "abcde"})    = 0
3031     * StringUtils.indexOfDifference(new String[] {"i am a machine", "i am a robot"}) = 7
3032     * </pre>
3033     *
3034     * @param css  array of CharSequences, entries may be null
3035     * @return the index where the strings begin to differ; -1 if they are all equal
3036     * @since 2.4
3037     * @since 3.0 Changed signature from indexOfDifference(String...) to indexOfDifference(CharSequence...)
3038     */
3039    public static int indexOfDifference(final CharSequence... css) {
3040        if (ArrayUtils.getLength(css) <= 1) {
3041            return INDEX_NOT_FOUND;
3042        }
3043        boolean anyStringNull = false;
3044        boolean allStringsNull = true;
3045        final int arrayLen = css.length;
3046        int shortestStrLen = Integer.MAX_VALUE;
3047        int longestStrLen = 0;
3048
3049        // find the min and max string lengths; this avoids checking to make
3050        // sure we are not exceeding the length of the string each time through
3051        // the bottom loop.
3052        for (final CharSequence cs : css) {
3053            if (cs == null) {
3054                anyStringNull = true;
3055                shortestStrLen = 0;
3056            } else {
3057                allStringsNull = false;
3058                shortestStrLen = Math.min(cs.length(), shortestStrLen);
3059                longestStrLen = Math.max(cs.length(), longestStrLen);
3060            }
3061        }
3062
3063        // handle lists containing all nulls or all empty strings
3064        if (allStringsNull || longestStrLen == 0 && !anyStringNull) {
3065            return INDEX_NOT_FOUND;
3066        }
3067
3068        // handle lists containing some nulls or some empty strings
3069        if (shortestStrLen == 0) {
3070            return 0;
3071        }
3072
3073        // find the position with the first difference across all strings
3074        int firstDiff = -1;
3075        for (int stringPos = 0; stringPos < shortestStrLen; stringPos++) {
3076            final char comparisonChar = css[0].charAt(stringPos);
3077            for (int arrayPos = 1; arrayPos < arrayLen; arrayPos++) {
3078                if (css[arrayPos].charAt(stringPos) != comparisonChar) {
3079                    firstDiff = stringPos;
3080                    break;
3081                }
3082            }
3083            if (firstDiff != -1) {
3084                break;
3085            }
3086        }
3087
3088        if (firstDiff == -1 && shortestStrLen != longestStrLen) {
3089            // we compared all of the characters up to the length of the
3090            // shortest string and didn't find a match, but the string lengths
3091            // vary, so return the length of the shortest string.
3092            return shortestStrLen;
3093        }
3094        return firstDiff;
3095    }
3096
3097    /**
3098     * Compares two CharSequences, and returns the index at which the
3099     * CharSequences begin to differ.
3100     *
3101     * <p>For example,
3102     * {@code indexOfDifference("i am a machine", "i am a robot") -> 7}</p>
3103     *
3104     * <pre>
3105     * StringUtils.indexOfDifference(null, null)       = -1
3106     * StringUtils.indexOfDifference("", "")           = -1
3107     * StringUtils.indexOfDifference("", "abc")        = 0
3108     * StringUtils.indexOfDifference("abc", "")        = 0
3109     * StringUtils.indexOfDifference("abc", "abc")     = -1
3110     * StringUtils.indexOfDifference("ab", "abxyz")    = 2
3111     * StringUtils.indexOfDifference("abcde", "abxyz") = 2
3112     * StringUtils.indexOfDifference("abcde", "xyz")   = 0
3113     * </pre>
3114     *
3115     * @param cs1  the first CharSequence, may be null
3116     * @param cs2  the second CharSequence, may be null
3117     * @return the index where cs1 and cs2 begin to differ; -1 if they are equal
3118     * @since 2.0
3119     * @since 3.0 Changed signature from indexOfDifference(String, String) to
3120     * indexOfDifference(CharSequence, CharSequence)
3121     */
3122    public static int indexOfDifference(final CharSequence cs1, final CharSequence cs2) {
3123        if (cs1 == cs2) {
3124            return INDEX_NOT_FOUND;
3125        }
3126        if (cs1 == null || cs2 == null) {
3127            return 0;
3128        }
3129        int i;
3130        for (i = 0; i < cs1.length() && i < cs2.length(); ++i) {
3131            if (cs1.charAt(i) != cs2.charAt(i)) {
3132                break;
3133            }
3134        }
3135        if (i < cs2.length() || i < cs1.length()) {
3136            return i;
3137        }
3138        return INDEX_NOT_FOUND;
3139    }
3140
3141    /**
3142     * Case in-sensitive find of the first index within a CharSequence.
3143     *
3144     * <p>A {@code null} CharSequence will return {@code -1}.
3145     * A negative start position is treated as zero.
3146     * An empty ("") search CharSequence always matches.
3147     * A start position greater than the string length only matches
3148     * an empty search CharSequence.</p>
3149     *
3150     * <pre>
3151     * StringUtils.indexOfIgnoreCase(null, *)          = -1
3152     * StringUtils.indexOfIgnoreCase(*, null)          = -1
3153     * StringUtils.indexOfIgnoreCase("", "")           = 0
3154     * StringUtils.indexOfIgnoreCase(" ", " ")         = 0
3155     * StringUtils.indexOfIgnoreCase("aabaabaa", "a")  = 0
3156     * StringUtils.indexOfIgnoreCase("aabaabaa", "b")  = 2
3157     * StringUtils.indexOfIgnoreCase("aabaabaa", "ab") = 1
3158     * </pre>
3159     *
3160     * @param str  the CharSequence to check, may be null
3161     * @param searchStr  the CharSequence to find, may be null
3162     * @return the first index of the search CharSequence,
3163     *  -1 if no match or {@code null} string input
3164     * @since 2.5
3165     * @since 3.0 Changed signature from indexOfIgnoreCase(String, String) to indexOfIgnoreCase(CharSequence, CharSequence)
3166     */
3167    public static int indexOfIgnoreCase(final CharSequence str, final CharSequence searchStr) {
3168        return indexOfIgnoreCase(str, searchStr, 0);
3169    }
3170
3171    /**
3172     * Case in-sensitive find of the first index within a CharSequence
3173     * from the specified position.
3174     *
3175     * <p>A {@code null} CharSequence will return {@code -1}.
3176     * A negative start position is treated as zero.
3177     * An empty ("") search CharSequence always matches.
3178     * A start position greater than the string length only matches
3179     * an empty search CharSequence.</p>
3180     *
3181     * <pre>
3182     * StringUtils.indexOfIgnoreCase(null, *, *)          = -1
3183     * StringUtils.indexOfIgnoreCase(*, null, *)          = -1
3184     * StringUtils.indexOfIgnoreCase("", "", 0)           = 0
3185     * StringUtils.indexOfIgnoreCase("aabaabaa", "A", 0)  = 0
3186     * StringUtils.indexOfIgnoreCase("aabaabaa", "B", 0)  = 2
3187     * StringUtils.indexOfIgnoreCase("aabaabaa", "AB", 0) = 1
3188     * StringUtils.indexOfIgnoreCase("aabaabaa", "B", 3)  = 5
3189     * StringUtils.indexOfIgnoreCase("aabaabaa", "B", 9)  = -1
3190     * StringUtils.indexOfIgnoreCase("aabaabaa", "B", -1) = 2
3191     * StringUtils.indexOfIgnoreCase("aabaabaa", "", 2)   = 2
3192     * StringUtils.indexOfIgnoreCase("abc", "", 9)        = -1
3193     * </pre>
3194     *
3195     * @param str  the CharSequence to check, may be null
3196     * @param searchStr  the CharSequence to find, may be null
3197     * @param startPos  the start position, negative treated as zero
3198     * @return the first index of the search CharSequence (always &ge; startPos),
3199     *  -1 if no match or {@code null} string input
3200     * @since 2.5
3201     * @since 3.0 Changed signature from indexOfIgnoreCase(String, String, int) to indexOfIgnoreCase(CharSequence, CharSequence, int)
3202     */
3203    public static int indexOfIgnoreCase(final CharSequence str, final CharSequence searchStr, int startPos) {
3204        if (str == null || searchStr == null) {
3205            return INDEX_NOT_FOUND;
3206        }
3207        if (startPos < 0) {
3208            startPos = 0;
3209        }
3210        final int endLimit = str.length() - searchStr.length() + 1;
3211        if (startPos > endLimit) {
3212            return INDEX_NOT_FOUND;
3213        }
3214        if (searchStr.length() == 0) {
3215            return startPos;
3216        }
3217        for (int i = startPos; i < endLimit; i++) {
3218            if (CharSequenceUtils.regionMatches(str, true, i, searchStr, 0, searchStr.length())) {
3219                return i;
3220            }
3221        }
3222        return INDEX_NOT_FOUND;
3223    }
3224
3225    /**
3226     * Checks if all of the CharSequences are empty (""), null or whitespace only.
3227     *
3228     * <p>Whitespace is defined by {@link Character#isWhitespace(char)}.</p>
3229     *
3230     * <pre>
3231     * StringUtils.isAllBlank(null)             = true
3232     * StringUtils.isAllBlank(null, "foo")      = false
3233     * StringUtils.isAllBlank(null, null)       = true
3234     * StringUtils.isAllBlank("", "bar")        = false
3235     * StringUtils.isAllBlank("bob", "")        = false
3236     * StringUtils.isAllBlank("  bob  ", null)  = false
3237     * StringUtils.isAllBlank(" ", "bar")       = false
3238     * StringUtils.isAllBlank("foo", "bar")     = false
3239     * StringUtils.isAllBlank(new String[] {})  = true
3240     * </pre>
3241     *
3242     * @param css  the CharSequences to check, may be null or empty
3243     * @return {@code true} if all of the CharSequences are empty or null or whitespace only
3244     * @since 3.6
3245     */
3246    public static boolean isAllBlank(final CharSequence... css) {
3247        if (ArrayUtils.isEmpty(css)) {
3248            return true;
3249        }
3250        for (final CharSequence cs : css) {
3251            if (isNotBlank(cs)) {
3252               return false;
3253            }
3254        }
3255        return true;
3256    }
3257
3258    /**
3259     * Checks if all of the CharSequences are empty ("") or null.
3260     *
3261     * <pre>
3262     * StringUtils.isAllEmpty(null)             = true
3263     * StringUtils.isAllEmpty(null, "")         = true
3264     * StringUtils.isAllEmpty(new String[] {})  = true
3265     * StringUtils.isAllEmpty(null, "foo")      = false
3266     * StringUtils.isAllEmpty("", "bar")        = false
3267     * StringUtils.isAllEmpty("bob", "")        = false
3268     * StringUtils.isAllEmpty("  bob  ", null)  = false
3269     * StringUtils.isAllEmpty(" ", "bar")       = false
3270     * StringUtils.isAllEmpty("foo", "bar")     = false
3271     * </pre>
3272     *
3273     * @param css  the CharSequences to check, may be null or empty
3274     * @return {@code true} if all of the CharSequences are empty or null
3275     * @since 3.6
3276     */
3277    public static boolean isAllEmpty(final CharSequence... css) {
3278        if (ArrayUtils.isEmpty(css)) {
3279            return true;
3280        }
3281        for (final CharSequence cs : css) {
3282            if (isNotEmpty(cs)) {
3283                return false;
3284            }
3285        }
3286        return true;
3287    }
3288
3289    /**
3290     * Checks if the CharSequence contains only lowercase characters.
3291     *
3292     * <p>{@code null} will return {@code false}.
3293     * An empty CharSequence (length()=0) will return {@code false}.</p>
3294     *
3295     * <pre>
3296     * StringUtils.isAllLowerCase(null)   = false
3297     * StringUtils.isAllLowerCase("")     = false
3298     * StringUtils.isAllLowerCase("  ")   = false
3299     * StringUtils.isAllLowerCase("abc")  = true
3300     * StringUtils.isAllLowerCase("abC")  = false
3301     * StringUtils.isAllLowerCase("ab c") = false
3302     * StringUtils.isAllLowerCase("ab1c") = false
3303     * StringUtils.isAllLowerCase("ab/c") = false
3304     * </pre>
3305     *
3306     * @param cs  the CharSequence to check, may be null
3307     * @return {@code true} if only contains lowercase characters, and is non-null
3308     * @since 2.5
3309     * @since 3.0 Changed signature from isAllLowerCase(String) to isAllLowerCase(CharSequence)
3310     */
3311    public static boolean isAllLowerCase(final CharSequence cs) {
3312        if (isEmpty(cs)) {
3313            return false;
3314        }
3315        final int sz = cs.length();
3316        for (int i = 0; i < sz; i++) {
3317            if (!Character.isLowerCase(cs.charAt(i))) {
3318                return false;
3319            }
3320        }
3321        return true;
3322    }
3323
3324    /**
3325     * Checks if the CharSequence contains only uppercase characters.
3326     *
3327     * <p>{@code null} will return {@code false}.
3328     * An empty String (length()=0) will return {@code false}.</p>
3329     *
3330     * <pre>
3331     * StringUtils.isAllUpperCase(null)   = false
3332     * StringUtils.isAllUpperCase("")     = false
3333     * StringUtils.isAllUpperCase("  ")   = false
3334     * StringUtils.isAllUpperCase("ABC")  = true
3335     * StringUtils.isAllUpperCase("aBC")  = false
3336     * StringUtils.isAllUpperCase("A C")  = false
3337     * StringUtils.isAllUpperCase("A1C")  = false
3338     * StringUtils.isAllUpperCase("A/C")  = false
3339     * </pre>
3340     *
3341     * @param cs the CharSequence to check, may be null
3342     * @return {@code true} if only contains uppercase characters, and is non-null
3343     * @since 2.5
3344     * @since 3.0 Changed signature from isAllUpperCase(String) to isAllUpperCase(CharSequence)
3345     */
3346    public static boolean isAllUpperCase(final CharSequence cs) {
3347        if (isEmpty(cs)) {
3348            return false;
3349        }
3350        final int sz = cs.length();
3351        for (int i = 0; i < sz; i++) {
3352            if (!Character.isUpperCase(cs.charAt(i))) {
3353                return false;
3354            }
3355        }
3356        return true;
3357    }
3358
3359    /**
3360     * Checks if the CharSequence contains only Unicode letters.
3361     *
3362     * <p>{@code null} will return {@code false}.
3363     * An empty CharSequence (length()=0) will return {@code false}.</p>
3364     *
3365     * <pre>
3366     * StringUtils.isAlpha(null)   = false
3367     * StringUtils.isAlpha("")     = false
3368     * StringUtils.isAlpha("  ")   = false
3369     * StringUtils.isAlpha("abc")  = true
3370     * StringUtils.isAlpha("ab2c") = false
3371     * StringUtils.isAlpha("ab-c") = false
3372     * </pre>
3373     *
3374     * @param cs  the CharSequence to check, may be null
3375     * @return {@code true} if only contains letters, and is non-null
3376     * @since 3.0 Changed signature from isAlpha(String) to isAlpha(CharSequence)
3377     * @since 3.0 Changed "" to return false and not true
3378     */
3379    public static boolean isAlpha(final CharSequence cs) {
3380        if (isEmpty(cs)) {
3381            return false;
3382        }
3383        final int sz = cs.length();
3384        for (int i = 0; i < sz; i++) {
3385            if (!Character.isLetter(cs.charAt(i))) {
3386                return false;
3387            }
3388        }
3389        return true;
3390    }
3391
3392    /**
3393     * Checks if the CharSequence contains only Unicode letters or digits.
3394     *
3395     * <p>{@code null} will return {@code false}.
3396     * An empty CharSequence (length()=0) will return {@code false}.</p>
3397     *
3398     * <pre>
3399     * StringUtils.isAlphanumeric(null)   = false
3400     * StringUtils.isAlphanumeric("")     = false
3401     * StringUtils.isAlphanumeric("  ")   = false
3402     * StringUtils.isAlphanumeric("abc")  = true
3403     * StringUtils.isAlphanumeric("ab c") = false
3404     * StringUtils.isAlphanumeric("ab2c") = true
3405     * StringUtils.isAlphanumeric("ab-c") = false
3406     * </pre>
3407     *
3408     * @param cs  the CharSequence to check, may be null
3409     * @return {@code true} if only contains letters or digits,
3410     *  and is non-null
3411     * @since 3.0 Changed signature from isAlphanumeric(String) to isAlphanumeric(CharSequence)
3412     * @since 3.0 Changed "" to return false and not true
3413     */
3414    public static boolean isAlphanumeric(final CharSequence cs) {
3415        if (isEmpty(cs)) {
3416            return false;
3417        }
3418        final int sz = cs.length();
3419        for (int i = 0; i < sz; i++) {
3420            if (!Character.isLetterOrDigit(cs.charAt(i))) {
3421                return false;
3422            }
3423        }
3424        return true;
3425    }
3426
3427    /**
3428     * Checks if the CharSequence contains only Unicode letters, digits
3429     * or space ({@code ' '}).
3430     *
3431     * <p>{@code null} will return {@code false}.
3432     * An empty CharSequence (length()=0) will return {@code true}.</p>
3433     *
3434     * <pre>
3435     * StringUtils.isAlphanumericSpace(null)   = false
3436     * StringUtils.isAlphanumericSpace("")     = true
3437     * StringUtils.isAlphanumericSpace("  ")   = true
3438     * StringUtils.isAlphanumericSpace("abc")  = true
3439     * StringUtils.isAlphanumericSpace("ab c") = true
3440     * StringUtils.isAlphanumericSpace("ab2c") = true
3441     * StringUtils.isAlphanumericSpace("ab-c") = false
3442     * </pre>
3443     *
3444     * @param cs  the CharSequence to check, may be null
3445     * @return {@code true} if only contains letters, digits or space,
3446     *  and is non-null
3447     * @since 3.0 Changed signature from isAlphanumericSpace(String) to isAlphanumericSpace(CharSequence)
3448     */
3449    public static boolean isAlphanumericSpace(final CharSequence cs) {
3450        if (cs == null) {
3451            return false;
3452        }
3453        final int sz = cs.length();
3454        for (int i = 0; i < sz; i++) {
3455            final char nowChar = cs.charAt(i);
3456            if (nowChar != ' ' && !Character.isLetterOrDigit(nowChar) ) {
3457                return false;
3458            }
3459        }
3460        return true;
3461    }
3462
3463    /**
3464     * Checks if the CharSequence contains only Unicode letters and
3465     * space (' ').
3466     *
3467     * <p>{@code null} will return {@code false}
3468     * An empty CharSequence (length()=0) will return {@code true}.</p>
3469     *
3470     * <pre>
3471     * StringUtils.isAlphaSpace(null)   = false
3472     * StringUtils.isAlphaSpace("")     = true
3473     * StringUtils.isAlphaSpace("  ")   = true
3474     * StringUtils.isAlphaSpace("abc")  = true
3475     * StringUtils.isAlphaSpace("ab c") = true
3476     * StringUtils.isAlphaSpace("ab2c") = false
3477     * StringUtils.isAlphaSpace("ab-c") = false
3478     * </pre>
3479     *
3480     * @param cs  the CharSequence to check, may be null
3481     * @return {@code true} if only contains letters and space,
3482     *  and is non-null
3483     * @since 3.0 Changed signature from isAlphaSpace(String) to isAlphaSpace(CharSequence)
3484     */
3485    public static boolean isAlphaSpace(final CharSequence cs) {
3486        if (cs == null) {
3487            return false;
3488        }
3489        final int sz = cs.length();
3490        for (int i = 0; i < sz; i++) {
3491            final char nowChar = cs.charAt(i);
3492            if (nowChar != ' ' && !Character.isLetter(nowChar)) {
3493                return false;
3494            }
3495        }
3496        return true;
3497    }
3498
3499    /**
3500     * Checks if any of the CharSequences are empty ("") or null or whitespace only.
3501     *
3502     * <p>Whitespace is defined by {@link Character#isWhitespace(char)}.</p>
3503     *
3504     * <pre>
3505     * StringUtils.isAnyBlank((String) null)    = true
3506     * StringUtils.isAnyBlank((String[]) null)  = false
3507     * StringUtils.isAnyBlank(null, "foo")      = true
3508     * StringUtils.isAnyBlank(null, null)       = true
3509     * StringUtils.isAnyBlank("", "bar")        = true
3510     * StringUtils.isAnyBlank("bob", "")        = true
3511     * StringUtils.isAnyBlank("  bob  ", null)  = true
3512     * StringUtils.isAnyBlank(" ", "bar")       = true
3513     * StringUtils.isAnyBlank(new String[] {})  = false
3514     * StringUtils.isAnyBlank(new String[]{""}) = true
3515     * StringUtils.isAnyBlank("foo", "bar")     = false
3516     * </pre>
3517     *
3518     * @param css  the CharSequences to check, may be null or empty
3519     * @return {@code true} if any of the CharSequences are empty or null or whitespace only
3520     * @since 3.2
3521     */
3522    public static boolean isAnyBlank(final CharSequence... css) {
3523        if (ArrayUtils.isEmpty(css)) {
3524            return false;
3525        }
3526        for (final CharSequence cs : css) {
3527            if (isBlank(cs)) {
3528                return true;
3529            }
3530        }
3531        return false;
3532    }
3533
3534    /**
3535     * Checks if any of the CharSequences are empty ("") or null.
3536     *
3537     * <pre>
3538     * StringUtils.isAnyEmpty((String) null)    = true
3539     * StringUtils.isAnyEmpty((String[]) null)  = false
3540     * StringUtils.isAnyEmpty(null, "foo")      = true
3541     * StringUtils.isAnyEmpty("", "bar")        = true
3542     * StringUtils.isAnyEmpty("bob", "")        = true
3543     * StringUtils.isAnyEmpty("  bob  ", null)  = true
3544     * StringUtils.isAnyEmpty(" ", "bar")       = false
3545     * StringUtils.isAnyEmpty("foo", "bar")     = false
3546     * StringUtils.isAnyEmpty(new String[]{})   = false
3547     * StringUtils.isAnyEmpty(new String[]{""}) = true
3548     * </pre>
3549     *
3550     * @param css  the CharSequences to check, may be null or empty
3551     * @return {@code true} if any of the CharSequences are empty or null
3552     * @since 3.2
3553     */
3554    public static boolean isAnyEmpty(final CharSequence... css) {
3555        if (ArrayUtils.isEmpty(css)) {
3556            return false;
3557        }
3558        for (final CharSequence cs : css) {
3559            if (isEmpty(cs)) {
3560                return true;
3561            }
3562        }
3563        return false;
3564    }
3565
3566    /**
3567     * Checks if the CharSequence contains only ASCII printable characters.
3568     *
3569     * <p>{@code null} will return {@code false}.
3570     * An empty CharSequence (length()=0) will return {@code true}.</p>
3571     *
3572     * <pre>
3573     * StringUtils.isAsciiPrintable(null)     = false
3574     * StringUtils.isAsciiPrintable("")       = true
3575     * StringUtils.isAsciiPrintable(" ")      = true
3576     * StringUtils.isAsciiPrintable("Ceki")   = true
3577     * StringUtils.isAsciiPrintable("ab2c")   = true
3578     * StringUtils.isAsciiPrintable("!ab-c~") = true
3579     * StringUtils.isAsciiPrintable("\u0020") = true
3580     * StringUtils.isAsciiPrintable("\u0021") = true
3581     * StringUtils.isAsciiPrintable("\u007e") = true
3582     * StringUtils.isAsciiPrintable("\u007f") = false
3583     * StringUtils.isAsciiPrintable("Ceki G\u00fclc\u00fc") = false
3584     * </pre>
3585     *
3586     * @param cs the CharSequence to check, may be null
3587     * @return {@code true} if every character is in the range
3588     *  32 through 126
3589     * @since 2.1
3590     * @since 3.0 Changed signature from isAsciiPrintable(String) to isAsciiPrintable(CharSequence)
3591     */
3592    public static boolean isAsciiPrintable(final CharSequence cs) {
3593        if (cs == null) {
3594            return false;
3595        }
3596        final int sz = cs.length();
3597        for (int i = 0; i < sz; i++) {
3598            if (!CharUtils.isAsciiPrintable(cs.charAt(i))) {
3599                return false;
3600            }
3601        }
3602        return true;
3603    }
3604
3605    /**
3606     * Checks if a CharSequence is empty (""), null or whitespace only.
3607     *
3608     * <p>Whitespace is defined by {@link Character#isWhitespace(char)}.</p>
3609     *
3610     * <pre>
3611     * StringUtils.isBlank(null)      = true
3612     * StringUtils.isBlank("")        = true
3613     * StringUtils.isBlank(" ")       = true
3614     * StringUtils.isBlank("bob")     = false
3615     * StringUtils.isBlank("  bob  ") = false
3616     * </pre>
3617     *
3618     * @param cs  the CharSequence to check, may be null
3619     * @return {@code true} if the CharSequence is null, empty or whitespace only
3620     * @since 2.0
3621     * @since 3.0 Changed signature from isBlank(String) to isBlank(CharSequence)
3622     */
3623    public static boolean isBlank(final CharSequence cs) {
3624        final int strLen = length(cs);
3625        if (strLen == 0) {
3626            return true;
3627        }
3628        for (int i = 0; i < strLen; i++) {
3629            if (!Character.isWhitespace(cs.charAt(i))) {
3630                return false;
3631            }
3632        }
3633        return true;
3634    }
3635
3636    /**
3637     * Checks if a CharSequence is empty ("") or null.
3638     *
3639     * <pre>
3640     * StringUtils.isEmpty(null)      = true
3641     * StringUtils.isEmpty("")        = true
3642     * StringUtils.isEmpty(" ")       = false
3643     * StringUtils.isEmpty("bob")     = false
3644     * StringUtils.isEmpty("  bob  ") = false
3645     * </pre>
3646     *
3647     * <p>NOTE: This method changed in Lang version 2.0.
3648     * It no longer trims the CharSequence.
3649     * That functionality is available in isBlank().</p>
3650     *
3651     * @param cs  the CharSequence to check, may be null
3652     * @return {@code true} if the CharSequence is empty or null
3653     * @since 3.0 Changed signature from isEmpty(String) to isEmpty(CharSequence)
3654     */
3655    public static boolean isEmpty(final CharSequence cs) {
3656        return cs == null || cs.length() == 0;
3657    }
3658
3659    /**
3660     * Checks if the CharSequence contains mixed casing of both uppercase and lowercase characters.
3661     *
3662     * <p>{@code null} will return {@code false}. An empty CharSequence ({@code length()=0}) will return
3663     * {@code false}.</p>
3664     *
3665     * <pre>
3666     * StringUtils.isMixedCase(null)    = false
3667     * StringUtils.isMixedCase("")      = false
3668     * StringUtils.isMixedCase(" ")     = false
3669     * StringUtils.isMixedCase("ABC")   = false
3670     * StringUtils.isMixedCase("abc")   = false
3671     * StringUtils.isMixedCase("aBc")   = true
3672     * StringUtils.isMixedCase("A c")   = true
3673     * StringUtils.isMixedCase("A1c")   = true
3674     * StringUtils.isMixedCase("a/C")   = true
3675     * StringUtils.isMixedCase("aC\t")  = true
3676     * </pre>
3677     *
3678     * @param cs the CharSequence to check, may be null
3679     * @return {@code true} if the CharSequence contains both uppercase and lowercase characters
3680     * @since 3.5
3681     */
3682    public static boolean isMixedCase(final CharSequence cs) {
3683        if (isEmpty(cs) || cs.length() == 1) {
3684            return false;
3685        }
3686        boolean containsUppercase = false;
3687        boolean containsLowercase = false;
3688        final int sz = cs.length();
3689        for (int i = 0; i < sz; i++) {
3690            final char nowChar = cs.charAt(i);
3691            if (Character.isUpperCase(nowChar)) {
3692                containsUppercase = true;
3693            } else if (Character.isLowerCase(nowChar)) {
3694                containsLowercase = true;
3695            }
3696            if (containsUppercase && containsLowercase) {
3697                return true;
3698            }
3699        }
3700        return false;
3701    }
3702
3703    /**
3704     * Checks if none of the CharSequences are empty (""), null or whitespace only.
3705     *
3706     * <p>Whitespace is defined by {@link Character#isWhitespace(char)}.</p>
3707     *
3708     * <pre>
3709     * StringUtils.isNoneBlank((String) null)    = false
3710     * StringUtils.isNoneBlank((String[]) null)  = true
3711     * StringUtils.isNoneBlank(null, "foo")      = false
3712     * StringUtils.isNoneBlank(null, null)       = false
3713     * StringUtils.isNoneBlank("", "bar")        = false
3714     * StringUtils.isNoneBlank("bob", "")        = false
3715     * StringUtils.isNoneBlank("  bob  ", null)  = false
3716     * StringUtils.isNoneBlank(" ", "bar")       = false
3717     * StringUtils.isNoneBlank(new String[] {})  = true
3718     * StringUtils.isNoneBlank(new String[]{""}) = false
3719     * StringUtils.isNoneBlank("foo", "bar")     = true
3720     * </pre>
3721     *
3722     * @param css  the CharSequences to check, may be null or empty
3723     * @return {@code true} if none of the CharSequences are empty or null or whitespace only
3724     * @since 3.2
3725     */
3726    public static boolean isNoneBlank(final CharSequence... css) {
3727      return !isAnyBlank(css);
3728    }
3729
3730    /**
3731     * Checks if none of the CharSequences are empty ("") or null.
3732     *
3733     * <pre>
3734     * StringUtils.isNoneEmpty((String) null)    = false
3735     * StringUtils.isNoneEmpty((String[]) null)  = true
3736     * StringUtils.isNoneEmpty(null, "foo")      = false
3737     * StringUtils.isNoneEmpty("", "bar")        = false
3738     * StringUtils.isNoneEmpty("bob", "")        = false
3739     * StringUtils.isNoneEmpty("  bob  ", null)  = false
3740     * StringUtils.isNoneEmpty(new String[] {})  = true
3741     * StringUtils.isNoneEmpty(new String[]{""}) = false
3742     * StringUtils.isNoneEmpty(" ", "bar")       = true
3743     * StringUtils.isNoneEmpty("foo", "bar")     = true
3744     * </pre>
3745     *
3746     * @param css  the CharSequences to check, may be null or empty
3747     * @return {@code true} if none of the CharSequences are empty or null
3748     * @since 3.2
3749     */
3750    public static boolean isNoneEmpty(final CharSequence... css) {
3751      return !isAnyEmpty(css);
3752    }
3753
3754    /**
3755     * Checks if a CharSequence is not empty (""), not null and not whitespace only.
3756     *
3757     * <p>Whitespace is defined by {@link Character#isWhitespace(char)}.</p>
3758     *
3759     * <pre>
3760     * StringUtils.isNotBlank(null)      = false
3761     * StringUtils.isNotBlank("")        = false
3762     * StringUtils.isNotBlank(" ")       = false
3763     * StringUtils.isNotBlank("bob")     = true
3764     * StringUtils.isNotBlank("  bob  ") = true
3765     * </pre>
3766     *
3767     * @param cs  the CharSequence to check, may be null
3768     * @return {@code true} if the CharSequence is
3769     *  not empty and not null and not whitespace only
3770     * @since 2.0
3771     * @since 3.0 Changed signature from isNotBlank(String) to isNotBlank(CharSequence)
3772     */
3773    public static boolean isNotBlank(final CharSequence cs) {
3774        return !isBlank(cs);
3775    }
3776
3777    /**
3778     * Checks if a CharSequence is not empty ("") and not null.
3779     *
3780     * <pre>
3781     * StringUtils.isNotEmpty(null)      = false
3782     * StringUtils.isNotEmpty("")        = false
3783     * StringUtils.isNotEmpty(" ")       = true
3784     * StringUtils.isNotEmpty("bob")     = true
3785     * StringUtils.isNotEmpty("  bob  ") = true
3786     * </pre>
3787     *
3788     * @param cs  the CharSequence to check, may be null
3789     * @return {@code true} if the CharSequence is not empty and not null
3790     * @since 3.0 Changed signature from isNotEmpty(String) to isNotEmpty(CharSequence)
3791     */
3792    public static boolean isNotEmpty(final CharSequence cs) {
3793        return !isEmpty(cs);
3794    }
3795
3796    /**
3797     * Checks if the CharSequence contains only Unicode digits.
3798     * A decimal point is not a Unicode digit and returns false.
3799     *
3800     * <p>{@code null} will return {@code false}.
3801     * An empty CharSequence (length()=0) will return {@code false}.</p>
3802     *
3803     * <p>Note that the method does not allow for a leading sign, either positive or negative.
3804     * Also, if a String passes the numeric test, it may still generate a NumberFormatException
3805     * when parsed by Integer.parseInt or Long.parseLong, e.g. if the value is outside the range
3806     * for int or long respectively.</p>
3807     *
3808     * <pre>
3809     * StringUtils.isNumeric(null)   = false
3810     * StringUtils.isNumeric("")     = false
3811     * StringUtils.isNumeric("  ")   = false
3812     * StringUtils.isNumeric("123")  = true
3813     * StringUtils.isNumeric("\u0967\u0968\u0969")  = true
3814     * StringUtils.isNumeric("12 3") = false
3815     * StringUtils.isNumeric("ab2c") = false
3816     * StringUtils.isNumeric("12-3") = false
3817     * StringUtils.isNumeric("12.3") = false
3818     * StringUtils.isNumeric("-123") = false
3819     * StringUtils.isNumeric("+123") = false
3820     * </pre>
3821     *
3822     * @param cs  the CharSequence to check, may be null
3823     * @return {@code true} if only contains digits, and is non-null
3824     * @since 3.0 Changed signature from isNumeric(String) to isNumeric(CharSequence)
3825     * @since 3.0 Changed "" to return false and not true
3826     */
3827    public static boolean isNumeric(final CharSequence cs) {
3828        if (isEmpty(cs)) {
3829            return false;
3830        }
3831        final int sz = cs.length();
3832        for (int i = 0; i < sz; i++) {
3833            if (!Character.isDigit(cs.charAt(i))) {
3834                return false;
3835            }
3836        }
3837        return true;
3838    }
3839
3840    /**
3841     * Checks if the CharSequence contains only Unicode digits or space
3842     * ({@code ' '}).
3843     * A decimal point is not a Unicode digit and returns false.
3844     *
3845     * <p>{@code null} will return {@code false}.
3846     * An empty CharSequence (length()=0) will return {@code true}.</p>
3847     *
3848     * <pre>
3849     * StringUtils.isNumericSpace(null)   = false
3850     * StringUtils.isNumericSpace("")     = true
3851     * StringUtils.isNumericSpace("  ")   = true
3852     * StringUtils.isNumericSpace("123")  = true
3853     * StringUtils.isNumericSpace("12 3") = true
3854     * StringUtils.isNumericSpace("\u0967\u0968\u0969")   = true
3855     * StringUtils.isNumericSpace("\u0967\u0968 \u0969")  = true
3856     * StringUtils.isNumericSpace("ab2c") = false
3857     * StringUtils.isNumericSpace("12-3") = false
3858     * StringUtils.isNumericSpace("12.3") = false
3859     * </pre>
3860     *
3861     * @param cs  the CharSequence to check, may be null
3862     * @return {@code true} if only contains digits or space,
3863     *  and is non-null
3864     * @since 3.0 Changed signature from isNumericSpace(String) to isNumericSpace(CharSequence)
3865     */
3866    public static boolean isNumericSpace(final CharSequence cs) {
3867        if (cs == null) {
3868            return false;
3869        }
3870        final int sz = cs.length();
3871        for (int i = 0; i < sz; i++) {
3872            final char nowChar = cs.charAt(i);
3873            if (nowChar != ' ' && !Character.isDigit(nowChar)) {
3874                return false;
3875            }
3876        }
3877        return true;
3878    }
3879
3880    /**
3881     * Checks if the CharSequence contains only whitespace.
3882     *
3883     * <p>Whitespace is defined by {@link Character#isWhitespace(char)}.</p>
3884     *
3885     * <p>{@code null} will return {@code false}.
3886     * An empty CharSequence (length()=0) will return {@code true}.</p>
3887     *
3888     * <pre>
3889     * StringUtils.isWhitespace(null)   = false
3890     * StringUtils.isWhitespace("")     = true
3891     * StringUtils.isWhitespace("  ")   = true
3892     * StringUtils.isWhitespace("abc")  = false
3893     * StringUtils.isWhitespace("ab2c") = false
3894     * StringUtils.isWhitespace("ab-c") = false
3895     * </pre>
3896     *
3897     * @param cs  the CharSequence to check, may be null
3898     * @return {@code true} if only contains whitespace, and is non-null
3899     * @since 2.0
3900     * @since 3.0 Changed signature from isWhitespace(String) to isWhitespace(CharSequence)
3901     */
3902    public static boolean isWhitespace(final CharSequence cs) {
3903        if (cs == null) {
3904            return false;
3905        }
3906        final int sz = cs.length();
3907        for (int i = 0; i < sz; i++) {
3908            if (!Character.isWhitespace(cs.charAt(i))) {
3909                return false;
3910            }
3911        }
3912        return true;
3913    }
3914
3915    /**
3916     * Joins the elements of the provided array into a single String containing the provided list of elements.
3917     *
3918     * <p>
3919     * No delimiter is added before or after the list. Null objects or empty strings within the array are represented
3920     * by empty strings.
3921     * </p>
3922     *
3923     * <pre>
3924     * StringUtils.join(null, *)             = null
3925     * StringUtils.join([], *)               = ""
3926     * StringUtils.join([null], *)           = ""
3927     * StringUtils.join([false, false], ';') = "false;false"
3928     * </pre>
3929     *
3930     * @param array
3931     *            the array of values to join together, may be null
3932     * @param delimiter
3933     *            the separator character to use
3934     * @return the joined String, {@code null} if null array input
3935     * @since 3.12.0
3936     */
3937    public static String join(final boolean[] array, final char delimiter) {
3938        if (array == null) {
3939            return null;
3940        }
3941        return join(array, delimiter, 0, array.length);
3942    }
3943
3944    /**
3945     * Joins the elements of the provided array into a single String containing the provided list of elements.
3946     *
3947     * <p>
3948     * No delimiter is added before or after the list. Null objects or empty strings within the array are represented
3949     * by empty strings.
3950     * </p>
3951     *
3952     * <pre>
3953     * StringUtils.join(null, *)                  = null
3954     * StringUtils.join([], *)                    = ""
3955     * StringUtils.join([null], *)                = ""
3956     * StringUtils.join([true, false, true], ';') = "true;false;true"
3957     * </pre>
3958     *
3959     * @param array
3960     *            the array of values to join together, may be null
3961     * @param delimiter
3962     *            the separator character to use
3963     * @param startIndex
3964     *            the first index to start joining from. It is an error to pass in a start index past the end of the
3965     *            array
3966     * @param endIndex
3967     *            the index to stop joining from (exclusive). It is an error to pass in an end index past the end of
3968     *            the array
3969     * @return the joined String, {@code null} if null array input
3970     * @since 3.12.0
3971     */
3972    public static String join(final boolean[] array, final char delimiter, final int startIndex, final int endIndex) {
3973        if (array == null) {
3974            return null;
3975        }
3976        if (endIndex - startIndex <= 0) {
3977            return EMPTY;
3978        }
3979        final StringBuilder stringBuilder = new StringBuilder(array.length * 5 + array.length - 1);
3980        for (int i = startIndex; i < endIndex; i++) {
3981            stringBuilder
3982                    .append(array[i])
3983                    .append(delimiter);
3984        }
3985        return stringBuilder.substring(0, stringBuilder.length() - 1);
3986    }
3987
3988    /**
3989     * Joins the elements of the provided array into a single String containing the provided list of elements.
3990     *
3991     * <p>
3992     * No delimiter is added before or after the list. Null objects or empty strings within the array are represented
3993     * by empty strings.
3994     * </p>
3995     *
3996     * <pre>
3997     * StringUtils.join(null, *)         = null
3998     * StringUtils.join([], *)           = ""
3999     * StringUtils.join([null], *)       = ""
4000     * StringUtils.join([1, 2, 3], ';')  = "1;2;3"
4001     * StringUtils.join([1, 2, 3], null) = "123"
4002     * </pre>
4003     *
4004     * @param array
4005     *            the array of values to join together, may be null
4006     * @param delimiter
4007     *            the separator character to use
4008     * @return the joined String, {@code null} if null array input
4009     * @since 3.2
4010     */
4011    public static String join(final byte[] array, final char delimiter) {
4012        if (array == null) {
4013            return null;
4014        }
4015        return join(array, delimiter, 0, array.length);
4016    }
4017
4018    /**
4019     * Joins the elements of the provided array into a single String containing the provided list of elements.
4020     *
4021     * <p>
4022     * No delimiter is added before or after the list. Null objects or empty strings within the array are represented
4023     * by empty strings.
4024     * </p>
4025     *
4026     * <pre>
4027     * StringUtils.join(null, *)         = null
4028     * StringUtils.join([], *)           = ""
4029     * StringUtils.join([null], *)       = ""
4030     * StringUtils.join([1, 2, 3], ';')  = "1;2;3"
4031     * StringUtils.join([1, 2, 3], null) = "123"
4032     * </pre>
4033     *
4034     * @param array
4035     *            the array of values to join together, may be null
4036     * @param delimiter
4037     *            the separator character to use
4038     * @param startIndex
4039     *            the first index to start joining from. It is an error to pass in a start index past the end of the
4040     *            array
4041     * @param endIndex
4042     *            the index to stop joining from (exclusive). It is an error to pass in an end index past the end of
4043     *            the array
4044     * @return the joined String, {@code null} if null array input
4045     * @since 3.2
4046     */
4047    public static String join(final byte[] array, final char delimiter, final int startIndex, final int endIndex) {
4048        if (array == null) {
4049            return null;
4050        }
4051        if (endIndex - startIndex <= 0) {
4052            return EMPTY;
4053        }
4054        final StringBuilder stringBuilder = new StringBuilder();
4055        for (int i = startIndex; i < endIndex; i++) {
4056            stringBuilder
4057                    .append(array[i])
4058                    .append(delimiter);
4059        }
4060        return stringBuilder.substring(0, stringBuilder.length() - 1);
4061    }
4062
4063    /**
4064     * Joins the elements of the provided array into a single String containing the provided list of elements.
4065     *
4066     * <p>
4067     * No delimiter is added before or after the list. Null objects or empty strings within the array are represented
4068     * by empty strings.
4069     * </p>
4070     *
4071     * <pre>
4072     * StringUtils.join(null, *)         = null
4073     * StringUtils.join([], *)           = ""
4074     * StringUtils.join([null], *)       = ""
4075     * StringUtils.join([1, 2, 3], ';')  = "1;2;3"
4076     * StringUtils.join([1, 2, 3], null) = "123"
4077     * </pre>
4078     *
4079     * @param array
4080     *            the array of values to join together, may be null
4081     * @param delimiter
4082     *            the separator character to use
4083     * @return the joined String, {@code null} if null array input
4084     * @since 3.2
4085     */
4086    public static String join(final char[] array, final char delimiter) {
4087        if (array == null) {
4088            return null;
4089        }
4090        return join(array, delimiter, 0, array.length);
4091    }
4092
4093    /**
4094     * Joins the elements of the provided array into a single String containing the provided list of elements.
4095     *
4096     * <p>
4097     * No delimiter is added before or after the list. Null objects or empty strings within the array are represented
4098     * by empty strings.
4099     * </p>
4100     *
4101     * <pre>
4102     * StringUtils.join(null, *)         = null
4103     * StringUtils.join([], *)           = ""
4104     * StringUtils.join([null], *)       = ""
4105     * StringUtils.join([1, 2, 3], ';')  = "1;2;3"
4106     * StringUtils.join([1, 2, 3], null) = "123"
4107     * </pre>
4108     *
4109     * @param array
4110     *            the array of values to join together, may be null
4111     * @param delimiter
4112     *            the separator character to use
4113     * @param startIndex
4114     *            the first index to start joining from. It is an error to pass in a start index past the end of the
4115     *            array
4116     * @param endIndex
4117     *            the index to stop joining from (exclusive). It is an error to pass in an end index past the end of
4118     *            the array
4119     * @return the joined String, {@code null} if null array input
4120     * @since 3.2
4121     */
4122    public static String join(final char[] array, final char delimiter, final int startIndex, final int endIndex) {
4123        if (array == null) {
4124            return null;
4125        }
4126        if (endIndex - startIndex <= 0) {
4127            return EMPTY;
4128        }
4129        final StringBuilder stringBuilder = new StringBuilder(array.length * 2 - 1);
4130        for (int i = startIndex; i < endIndex; i++) {
4131            stringBuilder
4132                    .append(array[i])
4133                    .append(delimiter);
4134        }
4135        return stringBuilder.substring(0, stringBuilder.length() - 1);
4136    }
4137
4138    /**
4139     * Joins the elements of the provided array into a single String containing the provided list of elements.
4140     *
4141     * <p>
4142     * No delimiter is added before or after the list. Null objects or empty strings within the array are represented
4143     * by empty strings.
4144     * </p>
4145     *
4146     * <pre>
4147     * StringUtils.join(null, *)               = null
4148     * StringUtils.join([], *)                 = ""
4149     * StringUtils.join([null], *)             = ""
4150     * StringUtils.join([1, 2, 3], ';')  = "1;2;3"
4151     * StringUtils.join([1, 2, 3], null) = "123"
4152     * </pre>
4153     *
4154     * @param array
4155     *            the array of values to join together, may be null
4156     * @param delimiter
4157     *            the separator character to use
4158     * @return the joined String, {@code null} if null array input
4159     * @since 3.2
4160     */
4161    public static String join(final double[] array, final char delimiter) {
4162        if (array == null) {
4163            return null;
4164        }
4165        return join(array, delimiter, 0, array.length);
4166    }
4167
4168    /**
4169     * Joins the elements of the provided array into a single String containing the provided list of elements.
4170     *
4171     * <p>
4172     * No delimiter is added before or after the list. Null objects or empty strings within the array are represented
4173     * by empty strings.
4174     * </p>
4175     *
4176     * <pre>
4177     * StringUtils.join(null, *)               = null
4178     * StringUtils.join([], *)                 = ""
4179     * StringUtils.join([null], *)             = ""
4180     * StringUtils.join([1, 2, 3], ';')  = "1;2;3"
4181     * StringUtils.join([1, 2, 3], null) = "123"
4182     * </pre>
4183     *
4184     * @param array
4185     *            the array of values to join together, may be null
4186     * @param delimiter
4187     *            the separator character to use
4188     * @param startIndex
4189     *            the first index to start joining from. It is an error to pass in a start index past the end of the
4190     *            array
4191     * @param endIndex
4192     *            the index to stop joining from (exclusive). It is an error to pass in an end index past the end of
4193     *            the array
4194     * @return the joined String, {@code null} if null array input
4195     * @since 3.2
4196     */
4197    public static String join(final double[] array, final char delimiter, final int startIndex, final int endIndex) {
4198        if (array == null) {
4199            return null;
4200        }
4201        if (endIndex - startIndex <= 0) {
4202            return EMPTY;
4203        }
4204        final StringBuilder stringBuilder = new StringBuilder();
4205        for (int i = startIndex; i < endIndex; i++) {
4206            stringBuilder
4207                    .append(array[i])
4208                    .append(delimiter);
4209        }
4210        return stringBuilder.substring(0, stringBuilder.length() - 1);
4211    }
4212
4213    /**
4214     * Joins the elements of the provided array into a single String containing the provided list of elements.
4215     *
4216     * <p>
4217     * No delimiter is added before or after the list. Null objects or empty strings within the array are represented
4218     * by empty strings.
4219     * </p>
4220     *
4221     * <pre>
4222     * StringUtils.join(null, *)               = null
4223     * StringUtils.join([], *)                 = ""
4224     * StringUtils.join([null], *)             = ""
4225     * StringUtils.join([1, 2, 3], ';')  = "1;2;3"
4226     * StringUtils.join([1, 2, 3], null) = "123"
4227     * </pre>
4228     *
4229     * @param array
4230     *            the array of values to join together, may be null
4231     * @param delimiter
4232     *            the separator character to use
4233     * @return the joined String, {@code null} if null array input
4234     * @since 3.2
4235     */
4236    public static String join(final float[] array, final char delimiter) {
4237        if (array == null) {
4238            return null;
4239        }
4240        return join(array, delimiter, 0, array.length);
4241    }
4242
4243    /**
4244     * Joins the elements of the provided array into a single String containing the provided list of elements.
4245     *
4246     * <p>
4247     * No delimiter is added before or after the list. Null objects or empty strings within the array are represented
4248     * by empty strings.
4249     * </p>
4250     *
4251     * <pre>
4252     * StringUtils.join(null, *)               = null
4253     * StringUtils.join([], *)                 = ""
4254     * StringUtils.join([null], *)             = ""
4255     * StringUtils.join([1, 2, 3], ';')  = "1;2;3"
4256     * StringUtils.join([1, 2, 3], null) = "123"
4257     * </pre>
4258     *
4259     * @param array
4260     *            the array of values to join together, may be null
4261     * @param delimiter
4262     *            the separator character to use
4263     * @param startIndex
4264     *            the first index to start joining from. It is an error to pass in a start index past the end of the
4265     *            array
4266     * @param endIndex
4267     *            the index to stop joining from (exclusive). It is an error to pass in an end index past the end of
4268     *            the array
4269     * @return the joined String, {@code null} if null array input
4270     * @since 3.2
4271     */
4272    public static String join(final float[] array, final char delimiter, final int startIndex, final int endIndex) {
4273        if (array == null) {
4274            return null;
4275        }
4276        if (endIndex - startIndex <= 0) {
4277            return EMPTY;
4278        }
4279        final StringBuilder stringBuilder = new StringBuilder();
4280        for (int i = startIndex; i < endIndex; i++) {
4281            stringBuilder
4282                    .append(array[i])
4283                    .append(delimiter);
4284        }
4285        return stringBuilder.substring(0, stringBuilder.length() - 1);
4286    }
4287
4288    /**
4289     * Joins the elements of the provided array into a single String containing the provided list of elements.
4290     *
4291     * <p>
4292     * No delimiter is added before or after the list. Null objects or empty strings within the array are represented
4293     * by empty strings.
4294     * </p>
4295     *
4296     * <pre>
4297     * StringUtils.join(null, *)               = null
4298     * StringUtils.join([], *)                 = ""
4299     * StringUtils.join([null], *)             = ""
4300     * StringUtils.join([1, 2, 3], ';')  = "1;2;3"
4301     * StringUtils.join([1, 2, 3], null) = "123"
4302     * </pre>
4303     *
4304     * @param array
4305     *            the array of values to join together, may be null
4306     * @param separator
4307     *            the separator character to use
4308     * @return the joined String, {@code null} if null array input
4309     * @since 3.2
4310     */
4311    public static String join(final int[] array, final char separator) {
4312        if (array == null) {
4313            return null;
4314        }
4315        return join(array, separator, 0, array.length);
4316    }
4317
4318    /**
4319     * Joins the elements of the provided array into a single String containing the provided list of elements.
4320     *
4321     * <p>
4322     * No delimiter is added before or after the list. Null objects or empty strings within the array are represented
4323     * by empty strings.
4324     * </p>
4325     *
4326     * <pre>
4327     * StringUtils.join(null, *)               = null
4328     * StringUtils.join([], *)                 = ""
4329     * StringUtils.join([null], *)             = ""
4330     * StringUtils.join([1, 2, 3], ';')  = "1;2;3"
4331     * StringUtils.join([1, 2, 3], null) = "123"
4332     * </pre>
4333     *
4334     * @param array
4335     *            the array of values to join together, may be null
4336     * @param delimiter
4337     *            the separator character to use
4338     * @param startIndex
4339     *            the first index to start joining from. It is an error to pass in a start index past the end of the
4340     *            array
4341     * @param endIndex
4342     *            the index to stop joining from (exclusive). It is an error to pass in an end index past the end of
4343     *            the array
4344     * @return the joined String, {@code null} if null array input
4345     * @since 3.2
4346     */
4347    public static String join(final int[] array, final char delimiter, final int startIndex, final int endIndex) {
4348        if (array == null) {
4349            return null;
4350        }
4351        if (endIndex - startIndex <= 0) {
4352            return EMPTY;
4353        }
4354        final StringBuilder stringBuilder = new StringBuilder();
4355        for (int i = startIndex; i < endIndex; i++) {
4356            stringBuilder
4357                    .append(array[i])
4358                    .append(delimiter);
4359        }
4360        return stringBuilder.substring(0, stringBuilder.length() - 1);
4361    }
4362
4363    /**
4364     * Joins the elements of the provided {@link Iterable} into
4365     * a single String containing the provided elements.
4366     *
4367     * <p>No delimiter is added before or after the list. Null objects or empty
4368     * strings within the iteration are represented by empty strings.</p>
4369     *
4370     * <p>See the examples here: {@link #join(Object[],char)}.</p>
4371     *
4372     * @param iterable  the {@link Iterable} providing the values to join together, may be null
4373     * @param separator  the separator character to use
4374     * @return the joined String, {@code null} if null iterator input
4375     * @since 2.3
4376     */
4377    public static String join(final Iterable<?> iterable, final char separator) {
4378        return iterable != null ? join(iterable.iterator(), separator) : null;
4379    }
4380
4381    /**
4382     * Joins the elements of the provided {@link Iterable} into
4383     * a single String containing the provided elements.
4384     *
4385     * <p>No delimiter is added before or after the list.
4386     * A {@code null} separator is the same as an empty String ("").</p>
4387     *
4388     * <p>See the examples here: {@link #join(Object[],String)}.</p>
4389     *
4390     * @param iterable  the {@link Iterable} providing the values to join together, may be null
4391     * @param separator  the separator character to use, null treated as ""
4392     * @return the joined String, {@code null} if null iterator input
4393     * @since 2.3
4394     */
4395    public static String join(final Iterable<?> iterable, final String separator) {
4396        return iterable != null ? join(iterable.iterator(), separator) : null;
4397    }
4398
4399    /**
4400     * Joins the elements of the provided {@link Iterator} into
4401     * a single String containing the provided elements.
4402     *
4403     * <p>No delimiter is added before or after the list. Null objects or empty
4404     * strings within the iteration are represented by empty strings.</p>
4405     *
4406     * <p>See the examples here: {@link #join(Object[],char)}.</p>
4407     *
4408     * @param iterator  the {@link Iterator} of values to join together, may be null
4409     * @param separator  the separator character to use
4410     * @return the joined String, {@code null} if null iterator input
4411     * @since 2.0
4412     */
4413    public static String join(final Iterator<?> iterator, final char separator) {
4414        // handle null, zero and one elements before building a buffer
4415        if (iterator == null) {
4416            return null;
4417        }
4418        if (!iterator.hasNext()) {
4419            return EMPTY;
4420        }
4421        return Streams.of(iterator).collect(LangCollectors.joining(toStringOrEmpty(String.valueOf(separator)), EMPTY, EMPTY, StringUtils::toStringOrEmpty));
4422    }
4423
4424    /**
4425     * Joins the elements of the provided {@link Iterator} into
4426     * a single String containing the provided elements.
4427     *
4428     * <p>No delimiter is added before or after the list.
4429     * A {@code null} separator is the same as an empty String ("").</p>
4430     *
4431     * <p>See the examples here: {@link #join(Object[],String)}.</p>
4432     *
4433     * @param iterator  the {@link Iterator} of values to join together, may be null
4434     * @param separator  the separator character to use, null treated as ""
4435     * @return the joined String, {@code null} if null iterator input
4436     */
4437    public static String join(final Iterator<?> iterator, final String separator) {
4438        // handle null, zero and one elements before building a buffer
4439        if (iterator == null) {
4440            return null;
4441        }
4442        if (!iterator.hasNext()) {
4443            return EMPTY;
4444        }
4445        return Streams.of(iterator).collect(LangCollectors.joining(toStringOrEmpty(separator), EMPTY, EMPTY, StringUtils::toStringOrEmpty));
4446    }
4447
4448    /**
4449     * Joins the elements of the provided {@link List} into a single String
4450     * containing the provided list of elements.
4451     *
4452     * <p>No delimiter is added before or after the list.
4453     * Null objects or empty strings within the array are represented by
4454     * empty strings.</p>
4455     *
4456     * <pre>
4457     * StringUtils.join(null, *)               = null
4458     * StringUtils.join([], *)                 = ""
4459     * StringUtils.join([null], *)             = ""
4460     * StringUtils.join(["a", "b", "c"], ';')  = "a;b;c"
4461     * StringUtils.join(["a", "b", "c"], null) = "abc"
4462     * StringUtils.join([null, "", "a"], ';')  = ";;a"
4463     * </pre>
4464     *
4465     * @param list  the {@link List} of values to join together, may be null
4466     * @param separator  the separator character to use
4467     * @param startIndex the first index to start joining from.  It is
4468     * an error to pass in a start index past the end of the list
4469     * @param endIndex the index to stop joining from (exclusive). It is
4470     * an error to pass in an end index past the end of the list
4471     * @return the joined String, {@code null} if null list input
4472     * @since 3.8
4473     */
4474    public static String join(final List<?> list, final char separator, final int startIndex, final int endIndex) {
4475        if (list == null) {
4476            return null;
4477        }
4478        final int noOfItems = endIndex - startIndex;
4479        if (noOfItems <= 0) {
4480            return EMPTY;
4481        }
4482        final List<?> subList = list.subList(startIndex, endIndex);
4483        return join(subList.iterator(), separator);
4484    }
4485
4486    /**
4487     * Joins the elements of the provided {@link List} into a single String
4488     * containing the provided list of elements.
4489     *
4490     * <p>No delimiter is added before or after the list.
4491     * Null objects or empty strings within the array are represented by
4492     * empty strings.</p>
4493     *
4494     * <pre>
4495     * StringUtils.join(null, *)               = null
4496     * StringUtils.join([], *)                 = ""
4497     * StringUtils.join([null], *)             = ""
4498     * StringUtils.join(["a", "b", "c"], ';')  = "a;b;c"
4499     * StringUtils.join(["a", "b", "c"], null) = "abc"
4500     * StringUtils.join([null, "", "a"], ';')  = ";;a"
4501     * </pre>
4502     *
4503     * @param list  the {@link List} of values to join together, may be null
4504     * @param separator  the separator character to use
4505     * @param startIndex the first index to start joining from.  It is
4506     * an error to pass in a start index past the end of the list
4507     * @param endIndex the index to stop joining from (exclusive). It is
4508     * an error to pass in an end index past the end of the list
4509     * @return the joined String, {@code null} if null list input
4510     * @since 3.8
4511     */
4512    public static String join(final List<?> list, final String separator, final int startIndex, final int endIndex) {
4513        if (list == null) {
4514            return null;
4515        }
4516        final int noOfItems = endIndex - startIndex;
4517        if (noOfItems <= 0) {
4518            return EMPTY;
4519        }
4520        final List<?> subList = list.subList(startIndex, endIndex);
4521        return join(subList.iterator(), separator);
4522    }
4523
4524    /**
4525     * Joins the elements of the provided array into a single String containing the provided list of elements.
4526     *
4527     * <p>
4528     * No delimiter is added before or after the list. Null objects or empty strings within the array are represented
4529     * by empty strings.
4530     * </p>
4531     *
4532     * <pre>
4533     * StringUtils.join(null, *)               = null
4534     * StringUtils.join([], *)                 = ""
4535     * StringUtils.join([null], *)             = ""
4536     * StringUtils.join([1, 2, 3], ';')  = "1;2;3"
4537     * StringUtils.join([1, 2, 3], null) = "123"
4538     * </pre>
4539     *
4540     * @param array
4541     *            the array of values to join together, may be null
4542     * @param separator
4543     *            the separator character to use
4544     * @return the joined String, {@code null} if null array input
4545     * @since 3.2
4546     */
4547    public static String join(final long[] array, final char separator) {
4548        if (array == null) {
4549            return null;
4550        }
4551        return join(array, separator, 0, array.length);
4552    }
4553
4554    /**
4555     * Joins the elements of the provided array into a single String containing the provided list of elements.
4556     *
4557     * <p>
4558     * No delimiter is added before or after the list. Null objects or empty strings within the array are represented
4559     * by empty strings.
4560     * </p>
4561     *
4562     * <pre>
4563     * StringUtils.join(null, *)               = null
4564     * StringUtils.join([], *)                 = ""
4565     * StringUtils.join([null], *)             = ""
4566     * StringUtils.join([1, 2, 3], ';')  = "1;2;3"
4567     * StringUtils.join([1, 2, 3], null) = "123"
4568     * </pre>
4569     *
4570     * @param array
4571     *            the array of values to join together, may be null
4572     * @param delimiter
4573     *            the separator character to use
4574     * @param startIndex
4575     *            the first index to start joining from. It is an error to pass in a start index past the end of the
4576     *            array
4577     * @param endIndex
4578     *            the index to stop joining from (exclusive). It is an error to pass in an end index past the end of
4579     *            the array
4580     * @return the joined String, {@code null} if null array input
4581     * @since 3.2
4582     */
4583    public static String join(final long[] array, final char delimiter, final int startIndex, final int endIndex) {
4584        if (array == null) {
4585            return null;
4586        }
4587        if (endIndex - startIndex <= 0) {
4588            return EMPTY;
4589        }
4590        final StringBuilder stringBuilder = new StringBuilder();
4591        for (int i = startIndex; i < endIndex; i++) {
4592            stringBuilder
4593                    .append(array[i])
4594                    .append(delimiter);
4595        }
4596        return stringBuilder.substring(0, stringBuilder.length() - 1);
4597    }
4598
4599    /**
4600     * Joins the elements of the provided array into a single String
4601     * containing the provided list of elements.
4602     *
4603     * <p>No delimiter is added before or after the list.
4604     * Null objects or empty strings within the array are represented by
4605     * empty strings.</p>
4606     *
4607     * <pre>
4608     * StringUtils.join(null, *)               = null
4609     * StringUtils.join([], *)                 = ""
4610     * StringUtils.join([null], *)             = ""
4611     * StringUtils.join(["a", "b", "c"], ';')  = "a;b;c"
4612     * StringUtils.join(["a", "b", "c"], null) = "abc"
4613     * StringUtils.join([null, "", "a"], ';')  = ";;a"
4614     * </pre>
4615     *
4616     * @param array  the array of values to join together, may be null
4617     * @param delimiter  the separator character to use
4618     * @return the joined String, {@code null} if null array input
4619     * @since 2.0
4620     */
4621    public static String join(final Object[] array, final char delimiter) {
4622        if (array == null) {
4623            return null;
4624        }
4625        return join(array, delimiter, 0, array.length);
4626    }
4627
4628    /**
4629     * Joins the elements of the provided array into a single String
4630     * containing the provided list of elements.
4631     *
4632     * <p>No delimiter is added before or after the list.
4633     * Null objects or empty strings within the array are represented by
4634     * empty strings.</p>
4635     *
4636     * <pre>
4637     * StringUtils.join(null, *)               = null
4638     * StringUtils.join([], *)                 = ""
4639     * StringUtils.join([null], *)             = ""
4640     * StringUtils.join(["a", "b", "c"], ';')  = "a;b;c"
4641     * StringUtils.join(["a", "b", "c"], null) = "abc"
4642     * StringUtils.join([null, "", "a"], ';')  = ";;a"
4643     * </pre>
4644     *
4645     * @param array  the array of values to join together, may be null
4646     * @param delimiter  the separator character to use
4647     * @param startIndex the first index to start joining from.  It is
4648     * an error to pass in a start index past the end of the array
4649     * @param endIndex the index to stop joining from (exclusive). It is
4650     * an error to pass in an end index past the end of the array
4651     * @return the joined String, {@code null} if null array input
4652     * @since 2.0
4653     */
4654    public static String join(final Object[] array, final char delimiter, final int startIndex, final int endIndex) {
4655        return join(array, String.valueOf(delimiter), startIndex, endIndex);
4656    }
4657
4658    /**
4659     * Joins the elements of the provided array into a single String
4660     * containing the provided list of elements.
4661     *
4662     * <p>No delimiter is added before or after the list.
4663     * A {@code null} separator is the same as an empty String ("").
4664     * Null objects or empty strings within the array are represented by
4665     * empty strings.</p>
4666     *
4667     * <pre>
4668     * StringUtils.join(null, *)                = null
4669     * StringUtils.join([], *)                  = ""
4670     * StringUtils.join([null], *)              = ""
4671     * StringUtils.join(["a", "b", "c"], "--")  = "a--b--c"
4672     * StringUtils.join(["a", "b", "c"], null)  = "abc"
4673     * StringUtils.join(["a", "b", "c"], "")    = "abc"
4674     * StringUtils.join([null, "", "a"], ',')   = ",,a"
4675     * </pre>
4676     *
4677     * @param array  the array of values to join together, may be null
4678     * @param delimiter  the separator character to use, null treated as ""
4679     * @return the joined String, {@code null} if null array input
4680     */
4681    public static String join(final Object[] array, final String delimiter) {
4682        return array != null ? join(array, toStringOrEmpty(delimiter), 0, array.length) : null;
4683    }
4684
4685    /**
4686     * Joins the elements of the provided array into a single String
4687     * containing the provided list of elements.
4688     *
4689     * <p>No delimiter is added before or after the list.
4690     * A {@code null} separator is the same as an empty String ("").
4691     * Null objects or empty strings within the array are represented by
4692     * empty strings.</p>
4693     *
4694     * <pre>
4695     * StringUtils.join(null, *, *, *)                = null
4696     * StringUtils.join([], *, *, *)                  = ""
4697     * StringUtils.join([null], *, *, *)              = ""
4698     * StringUtils.join(["a", "b", "c"], "--", 0, 3)  = "a--b--c"
4699     * StringUtils.join(["a", "b", "c"], "--", 1, 3)  = "b--c"
4700     * StringUtils.join(["a", "b", "c"], "--", 2, 3)  = "c"
4701     * StringUtils.join(["a", "b", "c"], "--", 2, 2)  = ""
4702     * StringUtils.join(["a", "b", "c"], null, 0, 3)  = "abc"
4703     * StringUtils.join(["a", "b", "c"], "", 0, 3)    = "abc"
4704     * StringUtils.join([null, "", "a"], ',', 0, 3)   = ",,a"
4705     * </pre>
4706     *
4707     * @param array  the array of values to join together, may be null
4708     * @param delimiter  the separator character to use, null treated as ""
4709     * @param startIndex the first index to start joining from.
4710     * @param endIndex the index to stop joining from (exclusive).
4711     * @return the joined String, {@code null} if null array input; or the empty string
4712     * if {@code endIndex - startIndex <= 0}. The number of joined entries is given by
4713     * {@code endIndex - startIndex}
4714     * @throws ArrayIndexOutOfBoundsException ife<br>
4715     * {@code startIndex < 0} or <br>
4716     * {@code startIndex >= array.length()} or <br>
4717     * {@code endIndex < 0} or <br>
4718     * {@code endIndex > array.length()}
4719     */
4720    public static String join(final Object[] array, final String delimiter, final int startIndex, final int endIndex) {
4721        return array != null ? Streams.of(array).skip(startIndex).limit(Math.max(0, endIndex - startIndex))
4722            .collect(LangCollectors.joining(delimiter, EMPTY, EMPTY, StringUtils::toStringOrEmpty)) : null;
4723    }
4724
4725    /**
4726     * Joins the elements of the provided array into a single String containing the provided list of elements.
4727     *
4728     * <p>
4729     * No delimiter is added before or after the list. Null objects or empty strings within the array are represented
4730     * by empty strings.
4731     * </p>
4732     *
4733     * <pre>
4734     * StringUtils.join(null, *)               = null
4735     * StringUtils.join([], *)                 = ""
4736     * StringUtils.join([null], *)             = ""
4737     * StringUtils.join([1, 2, 3], ';')  = "1;2;3"
4738     * StringUtils.join([1, 2, 3], null) = "123"
4739     * </pre>
4740     *
4741     * @param array
4742     *            the array of values to join together, may be null
4743     * @param delimiter
4744     *            the separator character to use
4745     * @return the joined String, {@code null} if null array input
4746     * @since 3.2
4747     */
4748    public static String join(final short[] array, final char delimiter) {
4749        if (array == null) {
4750            return null;
4751        }
4752        return join(array, delimiter, 0, array.length);
4753    }
4754
4755    /**
4756     * Joins the elements of the provided array into a single String containing the provided list of elements.
4757     *
4758     * <p>
4759     * No delimiter is added before or after the list. Null objects or empty strings within the array are represented
4760     * by empty strings.
4761     * </p>
4762     *
4763     * <pre>
4764     * StringUtils.join(null, *)               = null
4765     * StringUtils.join([], *)                 = ""
4766     * StringUtils.join([null], *)             = ""
4767     * StringUtils.join([1, 2, 3], ';')  = "1;2;3"
4768     * StringUtils.join([1, 2, 3], null) = "123"
4769     * </pre>
4770     *
4771     * @param array
4772     *            the array of values to join together, may be null
4773     * @param delimiter
4774     *            the separator character to use
4775     * @param startIndex
4776     *            the first index to start joining from. It is an error to pass in a start index past the end of the
4777     *            array
4778     * @param endIndex
4779     *            the index to stop joining from (exclusive). It is an error to pass in an end index past the end of
4780     *            the array
4781     * @return the joined String, {@code null} if null array input
4782     * @since 3.2
4783     */
4784    public static String join(final short[] array, final char delimiter, final int startIndex, final int endIndex) {
4785        if (array == null) {
4786            return null;
4787        }
4788        if (endIndex - startIndex <= 0) {
4789            return EMPTY;
4790        }
4791        final StringBuilder stringBuilder = new StringBuilder();
4792        for (int i = startIndex; i < endIndex; i++) {
4793            stringBuilder
4794                    .append(array[i])
4795                    .append(delimiter);
4796        }
4797        return stringBuilder.substring(0, stringBuilder.length() - 1);
4798    }
4799
4800    /**
4801     * Joins the elements of the provided array into a single String
4802     * containing the provided list of elements.
4803     *
4804     * <p>No separator is added to the joined String.
4805     * Null objects or empty strings within the array are represented by
4806     * empty strings.</p>
4807     *
4808     * <pre>
4809     * StringUtils.join(null)            = null
4810     * StringUtils.join([])              = ""
4811     * StringUtils.join([null])          = ""
4812     * StringUtils.join(["a", "b", "c"]) = "abc"
4813     * StringUtils.join([null, "", "a"]) = "a"
4814     * </pre>
4815     *
4816     * @param <T> the specific type of values to join together
4817     * @param elements  the values to join together, may be null
4818     * @return the joined String, {@code null} if null array input
4819     * @since 2.0
4820     * @since 3.0 Changed signature to use varargs
4821     */
4822    @SafeVarargs
4823    public static <T> String join(final T... elements) {
4824        return join(elements, null);
4825    }
4826
4827    /**
4828     * Joins the elements of the provided varargs into a
4829     * single String containing the provided elements.
4830     *
4831     * <p>No delimiter is added before or after the list.
4832     * {@code null} elements and separator are treated as empty Strings ("").</p>
4833     *
4834     * <pre>
4835     * StringUtils.joinWith(",", {"a", "b"})        = "a,b"
4836     * StringUtils.joinWith(",", {"a", "b",""})     = "a,b,"
4837     * StringUtils.joinWith(",", {"a", null, "b"})  = "a,,b"
4838     * StringUtils.joinWith(null, {"a", "b"})       = "ab"
4839     * </pre>
4840     *
4841     * @param delimiter the separator character to use, null treated as ""
4842     * @param array the varargs providing the values to join together. {@code null} elements are treated as ""
4843     * @return the joined String.
4844     * @throws IllegalArgumentException if a null varargs is provided
4845     * @since 3.5
4846     */
4847    public static String joinWith(final String delimiter, final Object... array) {
4848        if (array == null) {
4849            throw new IllegalArgumentException("Object varargs must not be null");
4850        }
4851        return join(array, delimiter);
4852    }
4853
4854    /**
4855     * Finds the last index within a CharSequence, handling {@code null}.
4856     * This method uses {@link String#lastIndexOf(String)} if possible.
4857     *
4858     * <p>A {@code null} CharSequence will return {@code -1}.</p>
4859     *
4860     * <pre>
4861     * StringUtils.lastIndexOf(null, *)          = -1
4862     * StringUtils.lastIndexOf(*, null)          = -1
4863     * StringUtils.lastIndexOf("", "")           = 0
4864     * StringUtils.lastIndexOf("aabaabaa", "a")  = 7
4865     * StringUtils.lastIndexOf("aabaabaa", "b")  = 5
4866     * StringUtils.lastIndexOf("aabaabaa", "ab") = 4
4867     * StringUtils.lastIndexOf("aabaabaa", "")   = 8
4868     * </pre>
4869     *
4870     * @param seq  the CharSequence to check, may be null
4871     * @param searchSeq  the CharSequence to find, may be null
4872     * @return the last index of the search String,
4873     *  -1 if no match or {@code null} string input
4874     * @since 2.0
4875     * @since 3.0 Changed signature from lastIndexOf(String, String) to lastIndexOf(CharSequence, CharSequence)
4876     */
4877    public static int lastIndexOf(final CharSequence seq, final CharSequence searchSeq) {
4878        if (seq == null) {
4879            return INDEX_NOT_FOUND;
4880        }
4881        return CharSequenceUtils.lastIndexOf(seq, searchSeq, seq.length());
4882    }
4883
4884    /**
4885     * Finds the last index within a CharSequence, handling {@code null}.
4886     * This method uses {@link String#lastIndexOf(String, int)} if possible.
4887     *
4888     * <p>A {@code null} CharSequence will return {@code -1}.
4889     * A negative start position returns {@code -1}.
4890     * An empty ("") search CharSequence always matches unless the start position is negative.
4891     * A start position greater than the string length searches the whole string.
4892     * The search starts at the startPos and works backwards; matches starting after the start
4893     * position are ignored.
4894     * </p>
4895     *
4896     * <pre>
4897     * StringUtils.lastIndexOf(null, *, *)          = -1
4898     * StringUtils.lastIndexOf(*, null, *)          = -1
4899     * StringUtils.lastIndexOf("aabaabaa", "a", 8)  = 7
4900     * StringUtils.lastIndexOf("aabaabaa", "b", 8)  = 5
4901     * StringUtils.lastIndexOf("aabaabaa", "ab", 8) = 4
4902     * StringUtils.lastIndexOf("aabaabaa", "b", 9)  = 5
4903     * StringUtils.lastIndexOf("aabaabaa", "b", -1) = -1
4904     * StringUtils.lastIndexOf("aabaabaa", "a", 0)  = 0
4905     * StringUtils.lastIndexOf("aabaabaa", "b", 0)  = -1
4906     * StringUtils.lastIndexOf("aabaabaa", "b", 1)  = -1
4907     * StringUtils.lastIndexOf("aabaabaa", "b", 2)  = 2
4908     * StringUtils.lastIndexOf("aabaabaa", "ba", 2)  = 2
4909     * </pre>
4910     *
4911     * @param seq  the CharSequence to check, may be null
4912     * @param searchSeq  the CharSequence to find, may be null
4913     * @param startPos  the start position, negative treated as zero
4914     * @return the last index of the search CharSequence (always &le; startPos),
4915     *  -1 if no match or {@code null} string input
4916     * @since 2.0
4917     * @since 3.0 Changed signature from lastIndexOf(String, String, int) to lastIndexOf(CharSequence, CharSequence, int)
4918     */
4919    public static int lastIndexOf(final CharSequence seq, final CharSequence searchSeq, final int startPos) {
4920        return CharSequenceUtils.lastIndexOf(seq, searchSeq, startPos);
4921    }
4922
4923    /**
4924     * Returns the index within {@code seq} of the last occurrence of
4925     * the specified character. For values of {@code searchChar} in the
4926     * range from 0 to 0xFFFF (inclusive), the index (in Unicode code
4927     * units) returned is the largest value <em>k</em> such that:
4928     * <blockquote><pre>
4929     * this.charAt(<em>k</em>) == searchChar
4930     * </pre></blockquote>
4931     * is true. For other values of {@code searchChar}, it is the
4932     * largest value <em>k</em> such that:
4933     * <blockquote><pre>
4934     * this.codePointAt(<em>k</em>) == searchChar
4935     * </pre></blockquote>
4936     * is true.  In either case, if no such character occurs in this
4937     * string, then {@code -1} is returned. Furthermore, a {@code null} or empty ("")
4938     * {@link CharSequence} will return {@code -1}. The
4939     * {@code seq} {@link CharSequence} object is searched backwards
4940     * starting at the last character.
4941     *
4942     * <pre>
4943     * StringUtils.lastIndexOf(null, *)         = -1
4944     * StringUtils.lastIndexOf("", *)           = -1
4945     * StringUtils.lastIndexOf("aabaabaa", 'a') = 7
4946     * StringUtils.lastIndexOf("aabaabaa", 'b') = 5
4947     * </pre>
4948     *
4949     * @param seq  the {@link CharSequence} to check, may be null
4950     * @param searchChar  the character to find
4951     * @return the last index of the search character,
4952     *  -1 if no match or {@code null} string input
4953     * @since 2.0
4954     * @since 3.0 Changed signature from lastIndexOf(String, int) to lastIndexOf(CharSequence, int)
4955     * @since 3.6 Updated {@link CharSequenceUtils} call to behave more like {@link String}
4956     */
4957    public static int lastIndexOf(final CharSequence seq, final int searchChar) {
4958        if (isEmpty(seq)) {
4959            return INDEX_NOT_FOUND;
4960        }
4961        return CharSequenceUtils.lastIndexOf(seq, searchChar, seq.length());
4962    }
4963
4964    /**
4965     * Returns the index within {@code seq} of the last occurrence of
4966     * the specified character, searching backward starting at the
4967     * specified index. For values of {@code searchChar} in the range
4968     * from 0 to 0xFFFF (inclusive), the index returned is the largest
4969     * value <em>k</em> such that:
4970     * <blockquote><pre>
4971     * (this.charAt(<em>k</em>) == searchChar) &amp;&amp; (<em>k</em> &lt;= startPos)
4972     * </pre></blockquote>
4973     * is true. For other values of {@code searchChar}, it is the
4974     * largest value <em>k</em> such that:
4975     * <blockquote><pre>
4976     * (this.codePointAt(<em>k</em>) == searchChar) &amp;&amp; (<em>k</em> &lt;= startPos)
4977     * </pre></blockquote>
4978     * is true. In either case, if no such character occurs in {@code seq}
4979     * at or before position {@code startPos}, then
4980     * {@code -1} is returned. Furthermore, a {@code null} or empty ("")
4981     * {@link CharSequence} will return {@code -1}. A start position greater
4982     * than the string length searches the whole string.
4983     * The search starts at the {@code startPos} and works backwards;
4984     * matches starting after the start position are ignored.
4985     *
4986     * <p>All indices are specified in {@code char} values
4987     * (Unicode code units).
4988     *
4989     * <pre>
4990     * StringUtils.lastIndexOf(null, *, *)          = -1
4991     * StringUtils.lastIndexOf("", *,  *)           = -1
4992     * StringUtils.lastIndexOf("aabaabaa", 'b', 8)  = 5
4993     * StringUtils.lastIndexOf("aabaabaa", 'b', 4)  = 2
4994     * StringUtils.lastIndexOf("aabaabaa", 'b', 0)  = -1
4995     * StringUtils.lastIndexOf("aabaabaa", 'b', 9)  = 5
4996     * StringUtils.lastIndexOf("aabaabaa", 'b', -1) = -1
4997     * StringUtils.lastIndexOf("aabaabaa", 'a', 0)  = 0
4998     * </pre>
4999     *
5000     * @param seq  the CharSequence to check, may be null
5001     * @param searchChar  the character to find
5002     * @param startPos  the start position
5003     * @return the last index of the search character (always &le; startPos),
5004     *  -1 if no match or {@code null} string input
5005     * @since 2.0
5006     * @since 3.0 Changed signature from lastIndexOf(String, int, int) to lastIndexOf(CharSequence, int, int)
5007     */
5008    public static int lastIndexOf(final CharSequence seq, final int searchChar, final int startPos) {
5009        if (isEmpty(seq)) {
5010            return INDEX_NOT_FOUND;
5011        }
5012        return CharSequenceUtils.lastIndexOf(seq, searchChar, startPos);
5013    }
5014
5015    /**
5016     * Find the latest index of any substring in a set of potential substrings.
5017     *
5018     * <p>A {@code null} CharSequence will return {@code -1}.
5019     * A {@code null} search array will return {@code -1}.
5020     * A {@code null} or zero length search array entry will be ignored,
5021     * but a search array containing "" will return the length of {@code str}
5022     * if {@code str} is not null. This method uses {@link String#indexOf(String)} if possible</p>
5023     *
5024     * <pre>
5025     * StringUtils.lastIndexOfAny(null, *)                    = -1
5026     * StringUtils.lastIndexOfAny(*, null)                    = -1
5027     * StringUtils.lastIndexOfAny(*, [])                      = -1
5028     * StringUtils.lastIndexOfAny(*, [null])                  = -1
5029     * StringUtils.lastIndexOfAny("zzabyycdxx", ["ab", "cd"]) = 6
5030     * StringUtils.lastIndexOfAny("zzabyycdxx", ["cd", "ab"]) = 6
5031     * StringUtils.lastIndexOfAny("zzabyycdxx", ["mn", "op"]) = -1
5032     * StringUtils.lastIndexOfAny("zzabyycdxx", ["mn", "op"]) = -1
5033     * StringUtils.lastIndexOfAny("zzabyycdxx", ["mn", ""])   = 10
5034     * </pre>
5035     *
5036     * @param str  the CharSequence to check, may be null
5037     * @param searchStrs  the CharSequences to search for, may be null
5038     * @return the last index of any of the CharSequences, -1 if no match
5039     * @since 3.0 Changed signature from lastIndexOfAny(String, String[]) to lastIndexOfAny(CharSequence, CharSequence)
5040     */
5041    public static int lastIndexOfAny(final CharSequence str, final CharSequence... searchStrs) {
5042        if (str == null || searchStrs == null) {
5043            return INDEX_NOT_FOUND;
5044        }
5045        int ret = INDEX_NOT_FOUND;
5046        int tmp;
5047        for (final CharSequence search : searchStrs) {
5048            if (search == null) {
5049                continue;
5050            }
5051            tmp = CharSequenceUtils.lastIndexOf(str, search, str.length());
5052            if (tmp > ret) {
5053                ret = tmp;
5054            }
5055        }
5056        return ret;
5057    }
5058
5059    /**
5060     * Case in-sensitive find of the last index within a CharSequence.
5061     *
5062     * <p>A {@code null} CharSequence will return {@code -1}.
5063     * A negative start position returns {@code -1}.
5064     * An empty ("") search CharSequence always matches unless the start position is negative.
5065     * A start position greater than the string length searches the whole string.</p>
5066     *
5067     * <pre>
5068     * StringUtils.lastIndexOfIgnoreCase(null, *)          = -1
5069     * StringUtils.lastIndexOfIgnoreCase(*, null)          = -1
5070     * StringUtils.lastIndexOfIgnoreCase("aabaabaa", "A")  = 7
5071     * StringUtils.lastIndexOfIgnoreCase("aabaabaa", "B")  = 5
5072     * StringUtils.lastIndexOfIgnoreCase("aabaabaa", "AB") = 4
5073     * </pre>
5074     *
5075     * @param str  the CharSequence to check, may be null
5076     * @param searchStr  the CharSequence to find, may be null
5077     * @return the first index of the search CharSequence,
5078     *  -1 if no match or {@code null} string input
5079     * @since 2.5
5080     * @since 3.0 Changed signature from lastIndexOfIgnoreCase(String, String) to lastIndexOfIgnoreCase(CharSequence, CharSequence)
5081     */
5082    public static int lastIndexOfIgnoreCase(final CharSequence str, final CharSequence searchStr) {
5083        if (str == null || searchStr == null) {
5084            return INDEX_NOT_FOUND;
5085        }
5086        return lastIndexOfIgnoreCase(str, searchStr, str.length());
5087    }
5088
5089    /**
5090     * Case in-sensitive find of the last index within a CharSequence
5091     * from the specified position.
5092     *
5093     * <p>A {@code null} CharSequence will return {@code -1}.
5094     * A negative start position returns {@code -1}.
5095     * An empty ("") search CharSequence always matches unless the start position is negative.
5096     * A start position greater than the string length searches the whole string.
5097     * The search starts at the startPos and works backwards; matches starting after the start
5098     * position are ignored.
5099     * </p>
5100     *
5101     * <pre>
5102     * StringUtils.lastIndexOfIgnoreCase(null, *, *)          = -1
5103     * StringUtils.lastIndexOfIgnoreCase(*, null, *)          = -1
5104     * StringUtils.lastIndexOfIgnoreCase("aabaabaa", "A", 8)  = 7
5105     * StringUtils.lastIndexOfIgnoreCase("aabaabaa", "B", 8)  = 5
5106     * StringUtils.lastIndexOfIgnoreCase("aabaabaa", "AB", 8) = 4
5107     * StringUtils.lastIndexOfIgnoreCase("aabaabaa", "B", 9)  = 5
5108     * StringUtils.lastIndexOfIgnoreCase("aabaabaa", "B", -1) = -1
5109     * StringUtils.lastIndexOfIgnoreCase("aabaabaa", "A", 0)  = 0
5110     * StringUtils.lastIndexOfIgnoreCase("aabaabaa", "B", 0)  = -1
5111     * </pre>
5112     *
5113     * @param str  the CharSequence to check, may be null
5114     * @param searchStr  the CharSequence to find, may be null
5115     * @param startPos  the start position
5116     * @return the last index of the search CharSequence (always &le; startPos),
5117     *  -1 if no match or {@code null} input
5118     * @since 2.5
5119     * @since 3.0 Changed signature from lastIndexOfIgnoreCase(String, String, int) to lastIndexOfIgnoreCase(CharSequence, CharSequence, int)
5120     */
5121    public static int lastIndexOfIgnoreCase(final CharSequence str, final CharSequence searchStr, int startPos) {
5122        if (str == null || searchStr == null) {
5123            return INDEX_NOT_FOUND;
5124        }
5125        final int searchStrLength = searchStr.length();
5126        final int strLength = str.length();
5127        if (startPos > strLength - searchStrLength) {
5128            startPos = strLength - searchStrLength;
5129        }
5130        if (startPos < 0) {
5131            return INDEX_NOT_FOUND;
5132        }
5133        if (searchStrLength == 0) {
5134            return startPos;
5135        }
5136
5137        for (int i = startPos; i >= 0; i--) {
5138            if (CharSequenceUtils.regionMatches(str, true, i, searchStr, 0, searchStrLength)) {
5139                return i;
5140            }
5141        }
5142        return INDEX_NOT_FOUND;
5143    }
5144
5145    /**
5146     * Finds the n-th last index within a String, handling {@code null}.
5147     * This method uses {@link String#lastIndexOf(String)}.
5148     *
5149     * <p>A {@code null} String will return {@code -1}.</p>
5150     *
5151     * <pre>
5152     * StringUtils.lastOrdinalIndexOf(null, *, *)          = -1
5153     * StringUtils.lastOrdinalIndexOf(*, null, *)          = -1
5154     * StringUtils.lastOrdinalIndexOf("", "", *)           = 0
5155     * StringUtils.lastOrdinalIndexOf("aabaabaa", "a", 1)  = 7
5156     * StringUtils.lastOrdinalIndexOf("aabaabaa", "a", 2)  = 6
5157     * StringUtils.lastOrdinalIndexOf("aabaabaa", "b", 1)  = 5
5158     * StringUtils.lastOrdinalIndexOf("aabaabaa", "b", 2)  = 2
5159     * StringUtils.lastOrdinalIndexOf("aabaabaa", "ab", 1) = 4
5160     * StringUtils.lastOrdinalIndexOf("aabaabaa", "ab", 2) = 1
5161     * StringUtils.lastOrdinalIndexOf("aabaabaa", "", 1)   = 8
5162     * StringUtils.lastOrdinalIndexOf("aabaabaa", "", 2)   = 8
5163     * </pre>
5164     *
5165     * <p>Note that 'tail(CharSequence str, int n)' may be implemented as: </p>
5166     *
5167     * <pre>
5168     *   str.substring(lastOrdinalIndexOf(str, "\n", n) + 1)
5169     * </pre>
5170     *
5171     * @param str  the CharSequence to check, may be null
5172     * @param searchStr  the CharSequence to find, may be null
5173     * @param ordinal  the n-th last {@code searchStr} to find
5174     * @return the n-th last index of the search CharSequence,
5175     *  {@code -1} ({@code INDEX_NOT_FOUND}) if no match or {@code null} string input
5176     * @since 2.5
5177     * @since 3.0 Changed signature from lastOrdinalIndexOf(String, String, int) to lastOrdinalIndexOf(CharSequence, CharSequence, int)
5178     */
5179    public static int lastOrdinalIndexOf(final CharSequence str, final CharSequence searchStr, final int ordinal) {
5180        return ordinalIndexOf(str, searchStr, ordinal, true);
5181    }
5182
5183    /**
5184     * Gets the leftmost {@code len} characters of a String.
5185     *
5186     * <p>If {@code len} characters are not available, or the
5187     * String is {@code null}, the String will be returned without
5188     * an exception. An empty String is returned if len is negative.</p>
5189     *
5190     * <pre>
5191     * StringUtils.left(null, *)    = null
5192     * StringUtils.left(*, -ve)     = ""
5193     * StringUtils.left("", *)      = ""
5194     * StringUtils.left("abc", 0)   = ""
5195     * StringUtils.left("abc", 2)   = "ab"
5196     * StringUtils.left("abc", 4)   = "abc"
5197     * </pre>
5198     *
5199     * @param str  the String to get the leftmost characters from, may be null
5200     * @param len  the length of the required String
5201     * @return the leftmost characters, {@code null} if null String input
5202     */
5203    public static String left(final String str, final int len) {
5204        if (str == null) {
5205            return null;
5206        }
5207        if (len < 0) {
5208            return EMPTY;
5209        }
5210        if (str.length() <= len) {
5211            return str;
5212        }
5213        return str.substring(0, len);
5214    }
5215
5216    /**
5217     * Left pad a String with spaces (' ').
5218     *
5219     * <p>The String is padded to the size of {@code size}.</p>
5220     *
5221     * <pre>
5222     * StringUtils.leftPad(null, *)   = null
5223     * StringUtils.leftPad("", 3)     = "   "
5224     * StringUtils.leftPad("bat", 3)  = "bat"
5225     * StringUtils.leftPad("bat", 5)  = "  bat"
5226     * StringUtils.leftPad("bat", 1)  = "bat"
5227     * StringUtils.leftPad("bat", -1) = "bat"
5228     * </pre>
5229     *
5230     * @param str  the String to pad out, may be null
5231     * @param size  the size to pad to
5232     * @return left padded String or original String if no padding is necessary,
5233     *  {@code null} if null String input
5234     */
5235    public static String leftPad(final String str, final int size) {
5236        return leftPad(str, size, ' ');
5237    }
5238
5239    /**
5240     * Left pad a String with a specified character.
5241     *
5242     * <p>Pad to a size of {@code size}.</p>
5243     *
5244     * <pre>
5245     * StringUtils.leftPad(null, *, *)     = null
5246     * StringUtils.leftPad("", 3, 'z')     = "zzz"
5247     * StringUtils.leftPad("bat", 3, 'z')  = "bat"
5248     * StringUtils.leftPad("bat", 5, 'z')  = "zzbat"
5249     * StringUtils.leftPad("bat", 1, 'z')  = "bat"
5250     * StringUtils.leftPad("bat", -1, 'z') = "bat"
5251     * </pre>
5252     *
5253     * @param str  the String to pad out, may be null
5254     * @param size  the size to pad to
5255     * @param padChar  the character to pad with
5256     * @return left padded String or original String if no padding is necessary,
5257     *  {@code null} if null String input
5258     * @since 2.0
5259     */
5260    public static String leftPad(final String str, final int size, final char padChar) {
5261        if (str == null) {
5262            return null;
5263        }
5264        final int pads = size - str.length();
5265        if (pads <= 0) {
5266            return str; // returns original String when possible
5267        }
5268        if (pads > PAD_LIMIT) {
5269            return leftPad(str, size, String.valueOf(padChar));
5270        }
5271        return repeat(padChar, pads).concat(str);
5272    }
5273
5274    /**
5275     * Left pad a String with a specified String.
5276     *
5277     * <p>Pad to a size of {@code size}.</p>
5278     *
5279     * <pre>
5280     * StringUtils.leftPad(null, *, *)      = null
5281     * StringUtils.leftPad("", 3, "z")      = "zzz"
5282     * StringUtils.leftPad("bat", 3, "yz")  = "bat"
5283     * StringUtils.leftPad("bat", 5, "yz")  = "yzbat"
5284     * StringUtils.leftPad("bat", 8, "yz")  = "yzyzybat"
5285     * StringUtils.leftPad("bat", 1, "yz")  = "bat"
5286     * StringUtils.leftPad("bat", -1, "yz") = "bat"
5287     * StringUtils.leftPad("bat", 5, null)  = "  bat"
5288     * StringUtils.leftPad("bat", 5, "")    = "  bat"
5289     * </pre>
5290     *
5291     * @param str  the String to pad out, may be null
5292     * @param size  the size to pad to
5293     * @param padStr  the String to pad with, null or empty treated as single space
5294     * @return left padded String or original String if no padding is necessary,
5295     *  {@code null} if null String input
5296     */
5297    public static String leftPad(final String str, final int size, String padStr) {
5298        if (str == null) {
5299            return null;
5300        }
5301        if (isEmpty(padStr)) {
5302            padStr = SPACE;
5303        }
5304        final int padLen = padStr.length();
5305        final int strLen = str.length();
5306        final int pads = size - strLen;
5307        if (pads <= 0) {
5308            return str; // returns original String when possible
5309        }
5310        if (padLen == 1 && pads <= PAD_LIMIT) {
5311            return leftPad(str, size, padStr.charAt(0));
5312        }
5313
5314        if (pads == padLen) {
5315            return padStr.concat(str);
5316        }
5317        if (pads < padLen) {
5318            return padStr.substring(0, pads).concat(str);
5319        }
5320        final char[] padding = new char[pads];
5321        final char[] padChars = padStr.toCharArray();
5322        for (int i = 0; i < pads; i++) {
5323            padding[i] = padChars[i % padLen];
5324        }
5325        return new String(padding).concat(str);
5326    }
5327
5328    /**
5329     * Gets a CharSequence length or {@code 0} if the CharSequence is
5330     * {@code null}.
5331     *
5332     * @param cs
5333     *            a CharSequence or {@code null}
5334     * @return CharSequence length or {@code 0} if the CharSequence is
5335     *         {@code null}.
5336     * @since 2.4
5337     * @since 3.0 Changed signature from length(String) to length(CharSequence)
5338     */
5339    public static int length(final CharSequence cs) {
5340        return cs == null ? 0 : cs.length();
5341    }
5342
5343    /**
5344     * Converts a String to lower case as per {@link String#toLowerCase()}.
5345     *
5346     * <p>A {@code null} input String returns {@code null}.</p>
5347     *
5348     * <pre>
5349     * StringUtils.lowerCase(null)  = null
5350     * StringUtils.lowerCase("")    = ""
5351     * StringUtils.lowerCase("aBc") = "abc"
5352     * </pre>
5353     *
5354     * <p><strong>Note:</strong> As described in the documentation for {@link String#toLowerCase()},
5355     * the result of this method is affected by the current locale.
5356     * For platform-independent case transformations, the method {@link #lowerCase(String, Locale)}
5357     * should be used with a specific locale (e.g. {@link Locale#ENGLISH}).</p>
5358     *
5359     * @param str  the String to lower case, may be null
5360     * @return the lower cased String, {@code null} if null String input
5361     */
5362    public static String lowerCase(final String str) {
5363        if (str == null) {
5364            return null;
5365        }
5366        return str.toLowerCase();
5367    }
5368
5369    /**
5370     * Converts a String to lower case as per {@link String#toLowerCase(Locale)}.
5371     *
5372     * <p>A {@code null} input String returns {@code null}.</p>
5373     *
5374     * <pre>
5375     * StringUtils.lowerCase(null, Locale.ENGLISH)  = null
5376     * StringUtils.lowerCase("", Locale.ENGLISH)    = ""
5377     * StringUtils.lowerCase("aBc", Locale.ENGLISH) = "abc"
5378     * </pre>
5379     *
5380     * @param str  the String to lower case, may be null
5381     * @param locale  the locale that defines the case transformation rules, must not be null
5382     * @return the lower cased String, {@code null} if null String input
5383     * @since 2.5
5384     */
5385    public static String lowerCase(final String str, final Locale locale) {
5386        if (str == null) {
5387            return null;
5388        }
5389        return str.toLowerCase(LocaleUtils.toLocale(locale));
5390    }
5391
5392    private static int[] matches(final CharSequence first, final CharSequence second) {
5393        final CharSequence max;
5394        final CharSequence min;
5395        if (first.length() > second.length()) {
5396            max = first;
5397            min = second;
5398        } else {
5399            max = second;
5400            min = first;
5401        }
5402        final int range = Math.max(max.length() / 2 - 1, 0);
5403        final int[] matchIndexes = ArrayFill.fill(new int[min.length()], -1);
5404        final boolean[] matchFlags = new boolean[max.length()];
5405        int matches = 0;
5406        for (int mi = 0; mi < min.length(); mi++) {
5407            final char c1 = min.charAt(mi);
5408            for (int xi = Math.max(mi - range, 0), xn = Math.min(mi + range + 1, max.length()); xi < xn; xi++) {
5409                if (!matchFlags[xi] && c1 == max.charAt(xi)) {
5410                    matchIndexes[mi] = xi;
5411                    matchFlags[xi] = true;
5412                    matches++;
5413                    break;
5414                }
5415            }
5416        }
5417        final char[] ms1 = new char[matches];
5418        final char[] ms2 = new char[matches];
5419        for (int i = 0, si = 0; i < min.length(); i++) {
5420            if (matchIndexes[i] != -1) {
5421                ms1[si] = min.charAt(i);
5422                si++;
5423            }
5424        }
5425        for (int i = 0, si = 0; i < max.length(); i++) {
5426            if (matchFlags[i]) {
5427                ms2[si] = max.charAt(i);
5428                si++;
5429            }
5430        }
5431        int transpositions = 0;
5432        for (int mi = 0; mi < ms1.length; mi++) {
5433            if (ms1[mi] != ms2[mi]) {
5434                transpositions++;
5435            }
5436        }
5437        int prefix = 0;
5438        for (int mi = 0; mi < min.length(); mi++) {
5439            if (first.charAt(mi) != second.charAt(mi)) {
5440                break;
5441            }
5442            prefix++;
5443        }
5444        return new int[] { matches, transpositions / 2, prefix, max.length() };
5445    }
5446
5447    /**
5448     * Gets {@code len} characters from the middle of a String.
5449     *
5450     * <p>If {@code len} characters are not available, the remainder
5451     * of the String will be returned without an exception. If the
5452     * String is {@code null}, {@code null} will be returned.
5453     * An empty String is returned if len is negative or exceeds the
5454     * length of {@code str}.</p>
5455     *
5456     * <pre>
5457     * StringUtils.mid(null, *, *)    = null
5458     * StringUtils.mid(*, *, -ve)     = ""
5459     * StringUtils.mid("", 0, *)      = ""
5460     * StringUtils.mid("abc", 0, 2)   = "ab"
5461     * StringUtils.mid("abc", 0, 4)   = "abc"
5462     * StringUtils.mid("abc", 2, 4)   = "c"
5463     * StringUtils.mid("abc", 4, 2)   = ""
5464     * StringUtils.mid("abc", -2, 2)  = "ab"
5465     * </pre>
5466     *
5467     * @param str  the String to get the characters from, may be null
5468     * @param pos  the position to start from, negative treated as zero
5469     * @param len  the length of the required String
5470     * @return the middle characters, {@code null} if null String input
5471     */
5472    public static String mid(final String str, int pos, final int len) {
5473        if (str == null) {
5474            return null;
5475        }
5476        if (len < 0 || pos > str.length()) {
5477            return EMPTY;
5478        }
5479        if (pos < 0) {
5480            pos = 0;
5481        }
5482        if (str.length() <= pos + len) {
5483            return str.substring(pos);
5484        }
5485        return str.substring(pos, pos + len);
5486    }
5487
5488    /**
5489     * Similar to <a
5490     * href="https://www.w3.org/TR/xpath/#function-normalize-space">https://www.w3.org/TR/xpath/#function-normalize
5491     * -space</a>
5492     *
5493     * <p>
5494     * The function returns the argument string with whitespace normalized by using
5495     * {@code {@link #trim(String)}} to remove leading and trailing whitespace
5496     * and then replacing sequences of whitespace characters by a single space.
5497     * </p>
5498     * In XML Whitespace characters are the same as those allowed by the <a
5499     * href="https://www.w3.org/TR/REC-xml/#NT-S">S</a> production, which is S ::= (#x20 | #x9 | #xD | #xA)+
5500     * <p>
5501     * Java's regexp pattern \s defines whitespace as [ \t\n\x0B\f\r]
5502     *
5503     * <p>For reference:</p>
5504     * <ul>
5505     * <li>\x0B = vertical tab</li>
5506     * <li>\f = #xC = form feed</li>
5507     * <li>#x20 = space</li>
5508     * <li>#x9 = \t</li>
5509     * <li>#xA = \n</li>
5510     * <li>#xD = \r</li>
5511     * </ul>
5512     *
5513     * <p>
5514     * The difference is that Java's whitespace includes vertical tab and form feed, which this functional will also
5515     * normalize. Additionally {@code {@link #trim(String)}} removes control characters (char &lt;= 32) from both
5516     * ends of this String.
5517     * </p>
5518     *
5519     * @see Pattern
5520     * @see #trim(String)
5521     * @see <a
5522     *      href="https://www.w3.org/TR/xpath/#function-normalize-space">https://www.w3.org/TR/xpath/#function-normalize-space</a>
5523     * @param str the source String to normalize whitespaces from, may be null
5524     * @return the modified string with whitespace normalized, {@code null} if null String input
5525     *
5526     * @since 3.0
5527     */
5528    public static String normalizeSpace(final String str) {
5529        // LANG-1020: Improved performance significantly by normalizing manually instead of using regex
5530        // See https://github.com/librucha/commons-lang-normalizespaces-benchmark for performance test
5531        if (isEmpty(str)) {
5532            return str;
5533        }
5534        final int size = str.length();
5535        final char[] newChars = new char[size];
5536        int count = 0;
5537        int whitespacesCount = 0;
5538        boolean startWhitespaces = true;
5539        for (int i = 0; i < size; i++) {
5540            final char actualChar = str.charAt(i);
5541            final boolean isWhitespace = Character.isWhitespace(actualChar);
5542            if (isWhitespace) {
5543                if (whitespacesCount == 0 && !startWhitespaces) {
5544                    newChars[count++] = SPACE.charAt(0);
5545                }
5546                whitespacesCount++;
5547            } else {
5548                startWhitespaces = false;
5549                newChars[count++] = actualChar == 160 ? 32 : actualChar;
5550                whitespacesCount = 0;
5551            }
5552        }
5553        if (startWhitespaces) {
5554            return EMPTY;
5555        }
5556        return new String(newChars, 0, count - (whitespacesCount > 0 ? 1 : 0)).trim();
5557    }
5558
5559    /**
5560     * Finds the n-th index within a CharSequence, handling {@code null}.
5561     * This method uses {@link String#indexOf(String)} if possible.
5562     * <p><b>Note:</b> The code starts looking for a match at the start of the target,
5563     * incrementing the starting index by one after each successful match
5564     * (unless {@code searchStr} is an empty string in which case the position
5565     * is never incremented and {@code 0} is returned immediately).
5566     * This means that matches may overlap.</p>
5567     * <p>A {@code null} CharSequence will return {@code -1}.</p>
5568     *
5569     * <pre>
5570     * StringUtils.ordinalIndexOf(null, *, *)          = -1
5571     * StringUtils.ordinalIndexOf(*, null, *)          = -1
5572     * StringUtils.ordinalIndexOf("", "", *)           = 0
5573     * StringUtils.ordinalIndexOf("aabaabaa", "a", 1)  = 0
5574     * StringUtils.ordinalIndexOf("aabaabaa", "a", 2)  = 1
5575     * StringUtils.ordinalIndexOf("aabaabaa", "b", 1)  = 2
5576     * StringUtils.ordinalIndexOf("aabaabaa", "b", 2)  = 5
5577     * StringUtils.ordinalIndexOf("aabaabaa", "ab", 1) = 1
5578     * StringUtils.ordinalIndexOf("aabaabaa", "ab", 2) = 4
5579     * StringUtils.ordinalIndexOf("aabaabaa", "", 1)   = 0
5580     * StringUtils.ordinalIndexOf("aabaabaa", "", 2)   = 0
5581     * </pre>
5582     *
5583     * <p>Matches may overlap:</p>
5584     * <pre>
5585     * StringUtils.ordinalIndexOf("ababab", "aba", 1)   = 0
5586     * StringUtils.ordinalIndexOf("ababab", "aba", 2)   = 2
5587     * StringUtils.ordinalIndexOf("ababab", "aba", 3)   = -1
5588     *
5589     * StringUtils.ordinalIndexOf("abababab", "abab", 1) = 0
5590     * StringUtils.ordinalIndexOf("abababab", "abab", 2) = 2
5591     * StringUtils.ordinalIndexOf("abababab", "abab", 3) = 4
5592     * StringUtils.ordinalIndexOf("abababab", "abab", 4) = -1
5593     * </pre>
5594     *
5595     * <p>Note that 'head(CharSequence str, int n)' may be implemented as: </p>
5596     *
5597     * <pre>
5598     *   str.substring(0, lastOrdinalIndexOf(str, "\n", n))
5599     * </pre>
5600     *
5601     * @param str  the CharSequence to check, may be null
5602     * @param searchStr  the CharSequence to find, may be null
5603     * @param ordinal  the n-th {@code searchStr} to find
5604     * @return the n-th index of the search CharSequence,
5605     *  {@code -1} ({@code INDEX_NOT_FOUND}) if no match or {@code null} string input
5606     * @since 2.1
5607     * @since 3.0 Changed signature from ordinalIndexOf(String, String, int) to ordinalIndexOf(CharSequence, CharSequence, int)
5608     */
5609    public static int ordinalIndexOf(final CharSequence str, final CharSequence searchStr, final int ordinal) {
5610        return ordinalIndexOf(str, searchStr, ordinal, false);
5611    }
5612
5613    /**
5614     * Finds the n-th index within a String, handling {@code null}.
5615     * This method uses {@link String#indexOf(String)} if possible.
5616     * <p>Note that matches may overlap<p>
5617     *
5618     * <p>A {@code null} CharSequence will return {@code -1}.</p>
5619     *
5620     * @param str  the CharSequence to check, may be null
5621     * @param searchStr  the CharSequence to find, may be null
5622     * @param ordinal  the n-th {@code searchStr} to find, overlapping matches are allowed.
5623     * @param lastIndex true if lastOrdinalIndexOf() otherwise false if ordinalIndexOf()
5624     * @return the n-th index of the search CharSequence,
5625     *  {@code -1} ({@code INDEX_NOT_FOUND}) if no match or {@code null} string input
5626     */
5627    // Shared code between ordinalIndexOf(String, String, int) and lastOrdinalIndexOf(String, String, int)
5628    private static int ordinalIndexOf(final CharSequence str, final CharSequence searchStr, final int ordinal, final boolean lastIndex) {
5629        if (str == null || searchStr == null || ordinal <= 0) {
5630            return INDEX_NOT_FOUND;
5631        }
5632        if (searchStr.length() == 0) {
5633            return lastIndex ? str.length() : 0;
5634        }
5635        int found = 0;
5636        // set the initial index beyond the end of the string
5637        // this is to allow for the initial index decrement/increment
5638        int index = lastIndex ? str.length() : INDEX_NOT_FOUND;
5639        do {
5640            if (lastIndex) {
5641                index = CharSequenceUtils.lastIndexOf(str, searchStr, index - 1); // step backwards through string
5642            } else {
5643                index = CharSequenceUtils.indexOf(str, searchStr, index + 1); // step forwards through string
5644            }
5645            if (index < 0) {
5646                return index;
5647            }
5648            found++;
5649        } while (found < ordinal);
5650        return index;
5651    }
5652
5653    /**
5654     * Overlays part of a String with another String.
5655     *
5656     * <p>A {@code null} string input returns {@code null}.
5657     * A negative index is treated as zero.
5658     * An index greater than the string length is treated as the string length.
5659     * The start index is always the smaller of the two indices.</p>
5660     *
5661     * <pre>
5662     * StringUtils.overlay(null, *, *, *)            = null
5663     * StringUtils.overlay("", "abc", 0, 0)          = "abc"
5664     * StringUtils.overlay("abcdef", null, 2, 4)     = "abef"
5665     * StringUtils.overlay("abcdef", "", 2, 4)       = "abef"
5666     * StringUtils.overlay("abcdef", "", 4, 2)       = "abef"
5667     * StringUtils.overlay("abcdef", "zzzz", 2, 4)   = "abzzzzef"
5668     * StringUtils.overlay("abcdef", "zzzz", 4, 2)   = "abzzzzef"
5669     * StringUtils.overlay("abcdef", "zzzz", -1, 4)  = "zzzzef"
5670     * StringUtils.overlay("abcdef", "zzzz", 2, 8)   = "abzzzz"
5671     * StringUtils.overlay("abcdef", "zzzz", -2, -3) = "zzzzabcdef"
5672     * StringUtils.overlay("abcdef", "zzzz", 8, 10)  = "abcdefzzzz"
5673     * </pre>
5674     *
5675     * @param str  the String to do overlaying in, may be null
5676     * @param overlay  the String to overlay, may be null
5677     * @param start  the position to start overlaying at
5678     * @param end  the position to stop overlaying before
5679     * @return overlayed String, {@code null} if null String input
5680     * @since 2.0
5681     */
5682    public static String overlay(final String str, String overlay, int start, int end) {
5683        if (str == null) {
5684            return null;
5685        }
5686        if (overlay == null) {
5687            overlay = EMPTY;
5688        }
5689        final int len = str.length();
5690        if (start < 0) {
5691            start = 0;
5692        }
5693        if (start > len) {
5694            start = len;
5695        }
5696        if (end < 0) {
5697            end = 0;
5698        }
5699        if (end > len) {
5700            end = len;
5701        }
5702        if (start > end) {
5703            final int temp = start;
5704            start = end;
5705            end = temp;
5706        }
5707        return str.substring(0, start) +
5708            overlay +
5709            str.substring(end);
5710    }
5711
5712    /**
5713     * Prepends the prefix to the start of the string if the string does not
5714     * already start with any of the prefixes.
5715     *
5716     * @param str The string.
5717     * @param prefix The prefix to prepend to the start of the string.
5718     * @param ignoreCase Indicates whether the compare should ignore case.
5719     * @param prefixes Additional prefixes that are valid (optional).
5720     *
5721     * @return A new String if prefix was prepended, the same string otherwise.
5722     */
5723    private static String prependIfMissing(final String str, final CharSequence prefix, final boolean ignoreCase, final CharSequence... prefixes) {
5724        if (str == null || isEmpty(prefix) || startsWith(str, prefix, ignoreCase)) {
5725            return str;
5726        }
5727        if (ArrayUtils.isNotEmpty(prefixes)) {
5728            for (final CharSequence p : prefixes) {
5729                if (startsWith(str, p, ignoreCase)) {
5730                    return str;
5731                }
5732            }
5733        }
5734        return prefix + str;
5735    }
5736
5737    /**
5738     * Prepends the prefix to the start of the string if the string does not
5739     * already start with any of the prefixes.
5740     *
5741     * <pre>
5742     * StringUtils.prependIfMissing(null, null) = null
5743     * StringUtils.prependIfMissing("abc", null) = "abc"
5744     * StringUtils.prependIfMissing("", "xyz") = "xyz"
5745     * StringUtils.prependIfMissing("abc", "xyz") = "xyzabc"
5746     * StringUtils.prependIfMissing("xyzabc", "xyz") = "xyzabc"
5747     * StringUtils.prependIfMissing("XYZabc", "xyz") = "xyzXYZabc"
5748     * </pre>
5749     * <p>With additional prefixes,</p>
5750     * <pre>
5751     * StringUtils.prependIfMissing(null, null, null) = null
5752     * StringUtils.prependIfMissing("abc", null, null) = "abc"
5753     * StringUtils.prependIfMissing("", "xyz", null) = "xyz"
5754     * StringUtils.prependIfMissing("abc", "xyz", new CharSequence[]{null}) = "xyzabc"
5755     * StringUtils.prependIfMissing("abc", "xyz", "") = "abc"
5756     * StringUtils.prependIfMissing("abc", "xyz", "mno") = "xyzabc"
5757     * StringUtils.prependIfMissing("xyzabc", "xyz", "mno") = "xyzabc"
5758     * StringUtils.prependIfMissing("mnoabc", "xyz", "mno") = "mnoabc"
5759     * StringUtils.prependIfMissing("XYZabc", "xyz", "mno") = "xyzXYZabc"
5760     * StringUtils.prependIfMissing("MNOabc", "xyz", "mno") = "xyzMNOabc"
5761     * </pre>
5762     *
5763     * @param str The string.
5764     * @param prefix The prefix to prepend to the start of the string.
5765     * @param prefixes Additional prefixes that are valid.
5766     *
5767     * @return A new String if prefix was prepended, the same string otherwise.
5768     *
5769     * @since 3.2
5770     */
5771    public static String prependIfMissing(final String str, final CharSequence prefix, final CharSequence... prefixes) {
5772        return prependIfMissing(str, prefix, false, prefixes);
5773    }
5774
5775    /**
5776     * Prepends the prefix to the start of the string if the string does not
5777     * already start, case-insensitive, with any of the prefixes.
5778     *
5779     * <pre>
5780     * StringUtils.prependIfMissingIgnoreCase(null, null) = null
5781     * StringUtils.prependIfMissingIgnoreCase("abc", null) = "abc"
5782     * StringUtils.prependIfMissingIgnoreCase("", "xyz") = "xyz"
5783     * StringUtils.prependIfMissingIgnoreCase("abc", "xyz") = "xyzabc"
5784     * StringUtils.prependIfMissingIgnoreCase("xyzabc", "xyz") = "xyzabc"
5785     * StringUtils.prependIfMissingIgnoreCase("XYZabc", "xyz") = "XYZabc"
5786     * </pre>
5787     * <p>With additional prefixes,</p>
5788     * <pre>
5789     * StringUtils.prependIfMissingIgnoreCase(null, null, null) = null
5790     * StringUtils.prependIfMissingIgnoreCase("abc", null, null) = "abc"
5791     * StringUtils.prependIfMissingIgnoreCase("", "xyz", null) = "xyz"
5792     * StringUtils.prependIfMissingIgnoreCase("abc", "xyz", new CharSequence[]{null}) = "xyzabc"
5793     * StringUtils.prependIfMissingIgnoreCase("abc", "xyz", "") = "abc"
5794     * StringUtils.prependIfMissingIgnoreCase("abc", "xyz", "mno") = "xyzabc"
5795     * StringUtils.prependIfMissingIgnoreCase("xyzabc", "xyz", "mno") = "xyzabc"
5796     * StringUtils.prependIfMissingIgnoreCase("mnoabc", "xyz", "mno") = "mnoabc"
5797     * StringUtils.prependIfMissingIgnoreCase("XYZabc", "xyz", "mno") = "XYZabc"
5798     * StringUtils.prependIfMissingIgnoreCase("MNOabc", "xyz", "mno") = "MNOabc"
5799     * </pre>
5800     *
5801     * @param str The string.
5802     * @param prefix The prefix to prepend to the start of the string.
5803     * @param prefixes Additional prefixes that are valid (optional).
5804     *
5805     * @return A new String if prefix was prepended, the same string otherwise.
5806     *
5807     * @since 3.2
5808     */
5809    public static String prependIfMissingIgnoreCase(final String str, final CharSequence prefix, final CharSequence... prefixes) {
5810        return prependIfMissing(str, prefix, true, prefixes);
5811    }
5812
5813    /**
5814     * Removes all occurrences of a character from within the source string.
5815     *
5816     * <p>A {@code null} source string will return {@code null}.
5817     * An empty ("") source string will return the empty string.</p>
5818     *
5819     * <pre>
5820     * StringUtils.remove(null, *)       = null
5821     * StringUtils.remove("", *)         = ""
5822     * StringUtils.remove("queued", 'u') = "qeed"
5823     * StringUtils.remove("queued", 'z') = "queued"
5824     * </pre>
5825     *
5826     * @param str  the source String to search, may be null
5827     * @param remove  the char to search for and remove, may be null
5828     * @return the substring with the char removed if found,
5829     *  {@code null} if null String input
5830     * @since 2.1
5831     */
5832    public static String remove(final String str, final char remove) {
5833        if (isEmpty(str) || str.indexOf(remove) == INDEX_NOT_FOUND) {
5834            return str;
5835        }
5836        final char[] chars = str.toCharArray();
5837        int pos = 0;
5838        for (int i = 0; i < chars.length; i++) {
5839            if (chars[i] != remove) {
5840                chars[pos++] = chars[i];
5841            }
5842        }
5843        return new String(chars, 0, pos);
5844    }
5845
5846    /**
5847     * Removes all occurrences of a substring from within the source string.
5848     *
5849     * <p>A {@code null} source string will return {@code null}.
5850     * An empty ("") source string will return the empty string.
5851     * A {@code null} remove string will return the source string.
5852     * An empty ("") remove string will return the source string.</p>
5853     *
5854     * <pre>
5855     * StringUtils.remove(null, *)        = null
5856     * StringUtils.remove("", *)          = ""
5857     * StringUtils.remove(*, null)        = *
5858     * StringUtils.remove(*, "")          = *
5859     * StringUtils.remove("queued", "ue") = "qd"
5860     * StringUtils.remove("queued", "zz") = "queued"
5861     * </pre>
5862     *
5863     * @param str  the source String to search, may be null
5864     * @param remove  the String to search for and remove, may be null
5865     * @return the substring with the string removed if found,
5866     *  {@code null} if null String input
5867     * @since 2.1
5868     */
5869    public static String remove(final String str, final String remove) {
5870        if (isEmpty(str) || isEmpty(remove)) {
5871            return str;
5872        }
5873        return replace(str, remove, EMPTY, -1);
5874    }
5875
5876    /**
5877     * Removes each substring of the text String that matches the given regular expression.
5878     *
5879     * This method is a {@code null} safe equivalent to:
5880     * <ul>
5881     *  <li>{@code text.replaceAll(regex, StringUtils.EMPTY)}</li>
5882     *  <li>{@code Pattern.compile(regex).matcher(text).replaceAll(StringUtils.EMPTY)}</li>
5883     * </ul>
5884     *
5885     * <p>A {@code null} reference passed to this method is a no-op.</p>
5886     *
5887     * <p>Unlike in the {@link #removePattern(String, String)} method, the {@link Pattern#DOTALL} option
5888     * is NOT automatically added.
5889     * To use the DOTALL option prepend {@code "(?s)"} to the regex.
5890     * DOTALL is also known as single-line mode in Perl.</p>
5891     *
5892     * <pre>{@code
5893     * StringUtils.removeAll(null, *)      = null
5894     * StringUtils.removeAll("any", (String) null)  = "any"
5895     * StringUtils.removeAll("any", "")    = "any"
5896     * StringUtils.removeAll("any", ".*")  = ""
5897     * StringUtils.removeAll("any", ".+")  = ""
5898     * StringUtils.removeAll("abc", ".?")  = ""
5899     * StringUtils.removeAll("A<__>\n<__>B", "<.*>")      = "A\nB"
5900     * StringUtils.removeAll("A<__>\n<__>B", "(?s)<.*>")  = "AB"
5901     * StringUtils.removeAll("ABCabc123abc", "[a-z]")     = "ABC123"
5902     * }</pre>
5903     *
5904     * @param text  text to remove from, may be null
5905     * @param regex  the regular expression to which this string is to be matched
5906     * @return  the text with any removes processed,
5907     *              {@code null} if null String input
5908     *
5909     * @throws  java.util.regex.PatternSyntaxException
5910     *              if the regular expression's syntax is invalid
5911     *
5912     * @see #replaceAll(String, String, String)
5913     * @see #removePattern(String, String)
5914     * @see String#replaceAll(String, String)
5915     * @see java.util.regex.Pattern
5916     * @see java.util.regex.Pattern#DOTALL
5917     * @since 3.5
5918     *
5919     * @deprecated Moved to RegExUtils.
5920     */
5921    @Deprecated
5922    public static String removeAll(final String text, final String regex) {
5923        return RegExUtils.removeAll(text, regex);
5924    }
5925
5926    /**
5927     * Removes a substring only if it is at the end of a source string,
5928     * otherwise returns the source string.
5929     *
5930     * <p>A {@code null} source string will return {@code null}.
5931     * An empty ("") source string will return the empty string.
5932     * A {@code null} search string will return the source string.</p>
5933     *
5934     * <pre>
5935     * StringUtils.removeEnd(null, *)      = null
5936     * StringUtils.removeEnd("", *)        = ""
5937     * StringUtils.removeEnd(*, null)      = *
5938     * StringUtils.removeEnd("www.domain.com", ".com.")  = "www.domain.com"
5939     * StringUtils.removeEnd("www.domain.com", ".com")   = "www.domain"
5940     * StringUtils.removeEnd("www.domain.com", "domain") = "www.domain.com"
5941     * StringUtils.removeEnd("abc", "")    = "abc"
5942     * </pre>
5943     *
5944     * @param str  the source String to search, may be null
5945     * @param remove  the String to search for and remove, may be null
5946     * @return the substring with the string removed if found,
5947     *  {@code null} if null String input
5948     * @since 2.1
5949     */
5950    public static String removeEnd(final String str, final String remove) {
5951        if (isEmpty(str) || isEmpty(remove)) {
5952            return str;
5953        }
5954        if (str.endsWith(remove)) {
5955            return str.substring(0, str.length() - remove.length());
5956        }
5957        return str;
5958    }
5959
5960    /**
5961     * Case-insensitive removal of a substring if it is at the end of a source string,
5962     * otherwise returns the source string.
5963     *
5964     * <p>A {@code null} source string will return {@code null}.
5965     * An empty ("") source string will return the empty string.
5966     * A {@code null} search string will return the source string.</p>
5967     *
5968     * <pre>
5969     * StringUtils.removeEndIgnoreCase(null, *)      = null
5970     * StringUtils.removeEndIgnoreCase("", *)        = ""
5971     * StringUtils.removeEndIgnoreCase(*, null)      = *
5972     * StringUtils.removeEndIgnoreCase("www.domain.com", ".com.")  = "www.domain.com"
5973     * StringUtils.removeEndIgnoreCase("www.domain.com", ".com")   = "www.domain"
5974     * StringUtils.removeEndIgnoreCase("www.domain.com", "domain") = "www.domain.com"
5975     * StringUtils.removeEndIgnoreCase("abc", "")    = "abc"
5976     * StringUtils.removeEndIgnoreCase("www.domain.com", ".COM") = "www.domain")
5977     * StringUtils.removeEndIgnoreCase("www.domain.COM", ".com") = "www.domain")
5978     * </pre>
5979     *
5980     * @param str  the source String to search, may be null
5981     * @param remove  the String to search for (case-insensitive) and remove, may be null
5982     * @return the substring with the string removed if found,
5983     *  {@code null} if null String input
5984     * @since 2.4
5985     */
5986    public static String removeEndIgnoreCase(final String str, final String remove) {
5987        if (isEmpty(str) || isEmpty(remove)) {
5988            return str;
5989        }
5990        if (endsWithIgnoreCase(str, remove)) {
5991            return str.substring(0, str.length() - remove.length());
5992        }
5993        return str;
5994    }
5995
5996    /**
5997     * Removes the first substring of the text string that matches the given regular expression.
5998     *
5999     * This method is a {@code null} safe equivalent to:
6000     * <ul>
6001     *  <li>{@code text.replaceFirst(regex, StringUtils.EMPTY)}</li>
6002     *  <li>{@code Pattern.compile(regex).matcher(text).replaceFirst(StringUtils.EMPTY)}</li>
6003     * </ul>
6004     *
6005     * <p>A {@code null} reference passed to this method is a no-op.</p>
6006     *
6007     * <p>The {@link Pattern#DOTALL} option is NOT automatically added.
6008     * To use the DOTALL option prepend {@code "(?s)"} to the regex.
6009     * DOTALL is also known as single-line mode in Perl.</p>
6010     *
6011     * <pre>{@code
6012     * StringUtils.removeFirst(null, *)      = null
6013     * StringUtils.removeFirst("any", (String) null)  = "any"
6014     * StringUtils.removeFirst("any", "")    = "any"
6015     * StringUtils.removeFirst("any", ".*")  = ""
6016     * StringUtils.removeFirst("any", ".+")  = ""
6017     * StringUtils.removeFirst("abc", ".?")  = "bc"
6018     * StringUtils.removeFirst("A<__>\n<__>B", "<.*>")      = "A\n<__>B"
6019     * StringUtils.removeFirst("A<__>\n<__>B", "(?s)<.*>")  = "AB"
6020     * StringUtils.removeFirst("ABCabc123", "[a-z]")          = "ABCbc123"
6021     * StringUtils.removeFirst("ABCabc123abc", "[a-z]+")      = "ABC123abc"
6022     * }</pre>
6023     *
6024     * @param text  text to remove from, may be null
6025     * @param regex  the regular expression to which this string is to be matched
6026     * @return  the text with the first replacement processed,
6027     *              {@code null} if null String input
6028     *
6029     * @throws  java.util.regex.PatternSyntaxException
6030     *              if the regular expression's syntax is invalid
6031     *
6032     * @see #replaceFirst(String, String, String)
6033     * @see String#replaceFirst(String, String)
6034     * @see java.util.regex.Pattern
6035     * @see java.util.regex.Pattern#DOTALL
6036     * @since 3.5
6037     *
6038     * @deprecated Moved to RegExUtils.
6039     */
6040    @Deprecated
6041    public static String removeFirst(final String text, final String regex) {
6042        return replaceFirst(text, regex, EMPTY);
6043    }
6044
6045    /**
6046     * Case-insensitive removal of all occurrences of a substring from within
6047     * the source string.
6048     *
6049     * <p>
6050     * A {@code null} source string will return {@code null}. An empty ("")
6051     * source string will return the empty string. A {@code null} remove string
6052     * will return the source string. An empty ("") remove string will return
6053     * the source string.
6054     * </p>
6055     *
6056     * <pre>
6057     * StringUtils.removeIgnoreCase(null, *)        = null
6058     * StringUtils.removeIgnoreCase("", *)          = ""
6059     * StringUtils.removeIgnoreCase(*, null)        = *
6060     * StringUtils.removeIgnoreCase(*, "")          = *
6061     * StringUtils.removeIgnoreCase("queued", "ue") = "qd"
6062     * StringUtils.removeIgnoreCase("queued", "zz") = "queued"
6063     * StringUtils.removeIgnoreCase("quEUed", "UE") = "qd"
6064     * StringUtils.removeIgnoreCase("queued", "zZ") = "queued"
6065     * </pre>
6066     *
6067     * @param str
6068     *            the source String to search, may be null
6069     * @param remove
6070     *            the String to search for (case-insensitive) and remove, may be
6071     *            null
6072     * @return the substring with the string removed if found, {@code null} if
6073     *         null String input
6074     * @since 3.5
6075     */
6076    public static String removeIgnoreCase(final String str, final String remove) {
6077        return replaceIgnoreCase(str, remove, EMPTY, -1);
6078    }
6079
6080    /**
6081     * Removes each substring of the source String that matches the given regular expression using the DOTALL option.
6082     *
6083     * This call is a {@code null} safe equivalent to:
6084     * <ul>
6085     * <li>{@code source.replaceAll(&quot;(?s)&quot; + regex, StringUtils.EMPTY)}</li>
6086     * <li>{@code Pattern.compile(regex, Pattern.DOTALL).matcher(source).replaceAll(StringUtils.EMPTY)}</li>
6087     * </ul>
6088     *
6089     * <p>A {@code null} reference passed to this method is a no-op.</p>
6090     *
6091     * <pre>{@code
6092     * StringUtils.removePattern(null, *)       = null
6093     * StringUtils.removePattern("any", (String) null)   = "any"
6094     * StringUtils.removePattern("A<__>\n<__>B", "<.*>")  = "AB"
6095     * StringUtils.removePattern("ABCabc123", "[a-z]")    = "ABC123"
6096     * }</pre>
6097     *
6098     * @param source
6099     *            the source string
6100     * @param regex
6101     *            the regular expression to which this string is to be matched
6102     * @return The resulting {@link String}
6103     * @see #replacePattern(String, String, String)
6104     * @see String#replaceAll(String, String)
6105     * @see Pattern#DOTALL
6106     * @since 3.2
6107     * @since 3.5 Changed {@code null} reference passed to this method is a no-op.
6108     *
6109     * @deprecated Moved to RegExUtils.
6110     */
6111    @Deprecated
6112    public static String removePattern(final String source, final String regex) {
6113        return RegExUtils.removePattern(source, regex);
6114    }
6115
6116    /**
6117     * Removes a char only if it is at the beginning of a source string,
6118     * otherwise returns the source string.
6119     *
6120     * <p>A {@code null} source string will return {@code null}.
6121     * An empty ("") source string will return the empty string.
6122     * A {@code null} search char will return the source string.</p>
6123     *
6124     * <pre>
6125     * StringUtils.removeStart(null, *)      = null
6126     * StringUtils.removeStart("", *)        = ""
6127     * StringUtils.removeStart(*, null)      = *
6128     * StringUtils.removeStart("/path", '/') = "path"
6129     * StringUtils.removeStart("path", '/')  = "path"
6130     * StringUtils.removeStart("path", 0)    = "path"
6131     * </pre>
6132     *
6133     * @param str  the source String to search, may be null.
6134     * @param remove  the char to search for and remove.
6135     * @return the substring with the char removed if found,
6136     *  {@code null} if null String input.
6137     * @since 3.13.0
6138     */
6139    public static String removeStart(final String str, final char remove) {
6140        if (isEmpty(str)) {
6141            return str;
6142        }
6143        return str.charAt(0) == remove ? str.substring(1) : str;
6144    }
6145
6146    /**
6147     * Removes a substring only if it is at the beginning of a source string,
6148     * otherwise returns the source string.
6149     *
6150     * <p>A {@code null} source string will return {@code null}.
6151     * An empty ("") source string will return the empty string.
6152     * A {@code null} search string will return the source string.</p>
6153     *
6154     * <pre>
6155     * StringUtils.removeStart(null, *)      = null
6156     * StringUtils.removeStart("", *)        = ""
6157     * StringUtils.removeStart(*, null)      = *
6158     * StringUtils.removeStart("www.domain.com", "www.")   = "domain.com"
6159     * StringUtils.removeStart("domain.com", "www.")       = "domain.com"
6160     * StringUtils.removeStart("www.domain.com", "domain") = "www.domain.com"
6161     * StringUtils.removeStart("abc", "")    = "abc"
6162     * </pre>
6163     *
6164     * @param str  the source String to search, may be null
6165     * @param remove  the String to search for and remove, may be null
6166     * @return the substring with the string removed if found,
6167     *  {@code null} if null String input
6168     * @since 2.1
6169     */
6170    public static String removeStart(final String str, final String remove) {
6171        if (isEmpty(str) || isEmpty(remove)) {
6172            return str;
6173        }
6174        if (str.startsWith(remove)) {
6175            return str.substring(remove.length());
6176        }
6177        return str;
6178    }
6179
6180    /**
6181     * Case-insensitive removal of a substring if it is at the beginning of a source string,
6182     * otherwise returns the source string.
6183     *
6184     * <p>A {@code null} source string will return {@code null}.
6185     * An empty ("") source string will return the empty string.
6186     * A {@code null} search string will return the source string.</p>
6187     *
6188     * <pre>
6189     * StringUtils.removeStartIgnoreCase(null, *)      = null
6190     * StringUtils.removeStartIgnoreCase("", *)        = ""
6191     * StringUtils.removeStartIgnoreCase(*, null)      = *
6192     * StringUtils.removeStartIgnoreCase("www.domain.com", "www.")   = "domain.com"
6193     * StringUtils.removeStartIgnoreCase("www.domain.com", "WWW.")   = "domain.com"
6194     * StringUtils.removeStartIgnoreCase("domain.com", "www.")       = "domain.com"
6195     * StringUtils.removeStartIgnoreCase("www.domain.com", "domain") = "www.domain.com"
6196     * StringUtils.removeStartIgnoreCase("abc", "")    = "abc"
6197     * </pre>
6198     *
6199     * @param str  the source String to search, may be null
6200     * @param remove  the String to search for (case-insensitive) and remove, may be null
6201     * @return the substring with the string removed if found,
6202     *  {@code null} if null String input
6203     * @since 2.4
6204     */
6205    public static String removeStartIgnoreCase(final String str, final String remove) {
6206        if (str != null && startsWithIgnoreCase(str, remove)) {
6207            return str.substring(length(remove));
6208        }
6209        return str;
6210    }
6211
6212    /**
6213     * Returns padding using the specified delimiter repeated
6214     * to a given length.
6215     *
6216     * <pre>
6217     * StringUtils.repeat('e', 0)  = ""
6218     * StringUtils.repeat('e', 3)  = "eee"
6219     * StringUtils.repeat('e', -2) = ""
6220     * </pre>
6221     *
6222     * <p>Note: this method does not support padding with
6223     * <a href="https://www.unicode.org/glossary/#supplementary_character">Unicode Supplementary Characters</a>
6224     * as they require a pair of {@code char}s to be represented.
6225     * If you are needing to support full I18N of your applications
6226     * consider using {@link #repeat(String, int)} instead.
6227     * </p>
6228     *
6229     * @param ch  character to repeat
6230     * @param repeat  number of times to repeat char, negative treated as zero
6231     * @return String with repeated character
6232     * @see #repeat(String, int)
6233     */
6234    public static String repeat(final char ch, final int repeat) {
6235        if (repeat <= 0) {
6236            return EMPTY;
6237        }
6238        return new String(ArrayFill.fill(new char[repeat], ch));
6239    }
6240
6241    /**
6242     * Repeat a String {@code repeat} times to form a
6243     * new String.
6244     *
6245     * <pre>
6246     * StringUtils.repeat(null, 2) = null
6247     * StringUtils.repeat("", 0)   = ""
6248     * StringUtils.repeat("", 2)   = ""
6249     * StringUtils.repeat("a", 3)  = "aaa"
6250     * StringUtils.repeat("ab", 2) = "abab"
6251     * StringUtils.repeat("a", -2) = ""
6252     * </pre>
6253     *
6254     * @param str  the String to repeat, may be null
6255     * @param repeat  number of times to repeat str, negative treated as zero
6256     * @return a new String consisting of the original String repeated,
6257     *  {@code null} if null String input
6258     */
6259    public static String repeat(final String str, final int repeat) {
6260        // Performance tuned for 2.0 (JDK1.4)
6261        if (str == null) {
6262            return null;
6263        }
6264        if (repeat <= 0) {
6265            return EMPTY;
6266        }
6267        final int inputLength = str.length();
6268        if (repeat == 1 || inputLength == 0) {
6269            return str;
6270        }
6271        if (inputLength == 1 && repeat <= PAD_LIMIT) {
6272            return repeat(str.charAt(0), repeat);
6273        }
6274
6275        final int outputLength = inputLength * repeat;
6276        switch (inputLength) {
6277            case 1 :
6278                return repeat(str.charAt(0), repeat);
6279            case 2 :
6280                final char ch0 = str.charAt(0);
6281                final char ch1 = str.charAt(1);
6282                final char[] output2 = new char[outputLength];
6283                for (int i = repeat * 2 - 2; i >= 0; i--, i--) {
6284                    output2[i] = ch0;
6285                    output2[i + 1] = ch1;
6286                }
6287                return new String(output2);
6288            default :
6289                final StringBuilder buf = new StringBuilder(outputLength);
6290                for (int i = 0; i < repeat; i++) {
6291                    buf.append(str);
6292                }
6293                return buf.toString();
6294        }
6295    }
6296
6297    /**
6298     * Repeat a String {@code repeat} times to form a
6299     * new String, with a String separator injected each time.
6300     *
6301     * <pre>
6302     * StringUtils.repeat(null, null, 2) = null
6303     * StringUtils.repeat(null, "x", 2)  = null
6304     * StringUtils.repeat("", null, 0)   = ""
6305     * StringUtils.repeat("", "", 2)     = ""
6306     * StringUtils.repeat("", "x", 3)    = "xx"
6307     * StringUtils.repeat("?", ", ", 3)  = "?, ?, ?"
6308     * </pre>
6309     *
6310     * @param str        the String to repeat, may be null
6311     * @param separator  the String to inject, may be null
6312     * @param repeat     number of times to repeat str, negative treated as zero
6313     * @return a new String consisting of the original String repeated,
6314     *  {@code null} if null String input
6315     * @since 2.5
6316     */
6317    public static String repeat(final String str, final String separator, final int repeat) {
6318        if (str == null || separator == null) {
6319            return repeat(str, repeat);
6320        }
6321        // given that repeat(String, int) is quite optimized, better to rely on it than try and splice this into it
6322        final String result = repeat(str + separator, repeat);
6323        return removeEnd(result, separator);
6324    }
6325
6326    /**
6327     * Replaces all occurrences of a String within another String.
6328     *
6329     * <p>A {@code null} reference passed to this method is a no-op.</p>
6330     *
6331     * <pre>
6332     * StringUtils.replace(null, *, *)        = null
6333     * StringUtils.replace("", *, *)          = ""
6334     * StringUtils.replace("any", null, *)    = "any"
6335     * StringUtils.replace("any", *, null)    = "any"
6336     * StringUtils.replace("any", "", *)      = "any"
6337     * StringUtils.replace("aba", "a", null)  = "aba"
6338     * StringUtils.replace("aba", "a", "")    = "b"
6339     * StringUtils.replace("aba", "a", "z")   = "zbz"
6340     * </pre>
6341     *
6342     * @see #replace(String text, String searchString, String replacement, int max)
6343     * @param text  text to search and replace in, may be null
6344     * @param searchString  the String to search for, may be null
6345     * @param replacement  the String to replace it with, may be null
6346     * @return the text with any replacements processed,
6347     *  {@code null} if null String input
6348     */
6349    public static String replace(final String text, final String searchString, final String replacement) {
6350        return replace(text, searchString, replacement, -1);
6351    }
6352
6353    /**
6354     * Replaces a String with another String inside a larger String,
6355     * for the first {@code max} values of the search String.
6356     *
6357     * <p>A {@code null} reference passed to this method is a no-op.</p>
6358     *
6359     * <pre>
6360     * StringUtils.replace(null, *, *, *)         = null
6361     * StringUtils.replace("", *, *, *)           = ""
6362     * StringUtils.replace("any", null, *, *)     = "any"
6363     * StringUtils.replace("any", *, null, *)     = "any"
6364     * StringUtils.replace("any", "", *, *)       = "any"
6365     * StringUtils.replace("any", *, *, 0)        = "any"
6366     * StringUtils.replace("abaa", "a", null, -1) = "abaa"
6367     * StringUtils.replace("abaa", "a", "", -1)   = "b"
6368     * StringUtils.replace("abaa", "a", "z", 0)   = "abaa"
6369     * StringUtils.replace("abaa", "a", "z", 1)   = "zbaa"
6370     * StringUtils.replace("abaa", "a", "z", 2)   = "zbza"
6371     * StringUtils.replace("abaa", "a", "z", -1)  = "zbzz"
6372     * </pre>
6373     *
6374     * @param text  text to search and replace in, may be null
6375     * @param searchString  the String to search for, may be null
6376     * @param replacement  the String to replace it with, may be null
6377     * @param max  maximum number of values to replace, or {@code -1} if no maximum
6378     * @return the text with any replacements processed,
6379     *  {@code null} if null String input
6380     */
6381    public static String replace(final String text, final String searchString, final String replacement, final int max) {
6382        return replace(text, searchString, replacement, max, false);
6383    }
6384
6385    /**
6386     * Replaces a String with another String inside a larger String,
6387     * for the first {@code max} values of the search String,
6388     * case-sensitively/insensitively based on {@code ignoreCase} value.
6389     *
6390     * <p>A {@code null} reference passed to this method is a no-op.</p>
6391     *
6392     * <pre>
6393     * StringUtils.replace(null, *, *, *, false)         = null
6394     * StringUtils.replace("", *, *, *, false)           = ""
6395     * StringUtils.replace("any", null, *, *, false)     = "any"
6396     * StringUtils.replace("any", *, null, *, false)     = "any"
6397     * StringUtils.replace("any", "", *, *, false)       = "any"
6398     * StringUtils.replace("any", *, *, 0, false)        = "any"
6399     * StringUtils.replace("abaa", "a", null, -1, false) = "abaa"
6400     * StringUtils.replace("abaa", "a", "", -1, false)   = "b"
6401     * StringUtils.replace("abaa", "a", "z", 0, false)   = "abaa"
6402     * StringUtils.replace("abaa", "A", "z", 1, false)   = "abaa"
6403     * StringUtils.replace("abaa", "A", "z", 1, true)   = "zbaa"
6404     * StringUtils.replace("abAa", "a", "z", 2, true)   = "zbza"
6405     * StringUtils.replace("abAa", "a", "z", -1, true)  = "zbzz"
6406     * </pre>
6407     *
6408     * @param text  text to search and replace in, may be null
6409     * @param searchString  the String to search for (case-insensitive), may be null
6410     * @param replacement  the String to replace it with, may be null
6411     * @param max  maximum number of values to replace, or {@code -1} if no maximum
6412     * @param ignoreCase if true replace is case-insensitive, otherwise case-sensitive
6413     * @return the text with any replacements processed,
6414     *  {@code null} if null String input
6415     */
6416     private static String replace(final String text, String searchString, final String replacement, int max, final boolean ignoreCase) {
6417         if (isEmpty(text) || isEmpty(searchString) || replacement == null || max == 0) {
6418             return text;
6419         }
6420         if (ignoreCase) {
6421             searchString = searchString.toLowerCase();
6422         }
6423         int start = 0;
6424         int end = ignoreCase ? indexOfIgnoreCase(text, searchString, start) : indexOf(text, searchString, start);
6425         if (end == INDEX_NOT_FOUND) {
6426             return text;
6427         }
6428         final int replLength = searchString.length();
6429         int increase = Math.max(replacement.length() - replLength, 0);
6430         increase *= max < 0 ? 16 : Math.min(max, 64);
6431         final StringBuilder buf = new StringBuilder(text.length() + increase);
6432         while (end != INDEX_NOT_FOUND) {
6433             buf.append(text, start, end).append(replacement);
6434             start = end + replLength;
6435             if (--max == 0) {
6436                 break;
6437             }
6438             end = ignoreCase ? indexOfIgnoreCase(text, searchString, start) : indexOf(text, searchString, start);
6439         }
6440         buf.append(text, start, text.length());
6441         return buf.toString();
6442     }
6443
6444    /**
6445     * Replaces each substring of the text String that matches the given regular expression
6446     * with the given replacement.
6447     *
6448     * This method is a {@code null} safe equivalent to:
6449     * <ul>
6450     *  <li>{@code text.replaceAll(regex, replacement)}</li>
6451     *  <li>{@code Pattern.compile(regex).matcher(text).replaceAll(replacement)}</li>
6452     * </ul>
6453     *
6454     * <p>A {@code null} reference passed to this method is a no-op.</p>
6455     *
6456     * <p>Unlike in the {@link #replacePattern(String, String, String)} method, the {@link Pattern#DOTALL} option
6457     * is NOT automatically added.
6458     * To use the DOTALL option prepend {@code "(?s)"} to the regex.
6459     * DOTALL is also known as single-line mode in Perl.</p>
6460     *
6461     * <pre>{@code
6462     * StringUtils.replaceAll(null, *, *)       = null
6463     * StringUtils.replaceAll("any", (String) null, *)   = "any"
6464     * StringUtils.replaceAll("any", *, null)   = "any"
6465     * StringUtils.replaceAll("", "", "zzz")    = "zzz"
6466     * StringUtils.replaceAll("", ".*", "zzz")  = "zzz"
6467     * StringUtils.replaceAll("", ".+", "zzz")  = ""
6468     * StringUtils.replaceAll("abc", "", "ZZ")  = "ZZaZZbZZcZZ"
6469     * StringUtils.replaceAll("<__>\n<__>", "<.*>", "z")      = "z\nz"
6470     * StringUtils.replaceAll("<__>\n<__>", "(?s)<.*>", "z")  = "z"
6471     * StringUtils.replaceAll("ABCabc123", "[a-z]", "_")       = "ABC___123"
6472     * StringUtils.replaceAll("ABCabc123", "[^A-Z0-9]+", "_")  = "ABC_123"
6473     * StringUtils.replaceAll("ABCabc123", "[^A-Z0-9]+", "")   = "ABC123"
6474     * StringUtils.replaceAll("Lorem ipsum  dolor   sit", "( +)([a-z]+)", "_$2")  = "Lorem_ipsum_dolor_sit"
6475     * }</pre>
6476     *
6477     * @param text  text to search and replace in, may be null
6478     * @param regex  the regular expression to which this string is to be matched
6479     * @param replacement  the string to be substituted for each match
6480     * @return  the text with any replacements processed,
6481     *              {@code null} if null String input
6482     *
6483     * @throws  java.util.regex.PatternSyntaxException
6484     *              if the regular expression's syntax is invalid
6485     *
6486     * @see #replacePattern(String, String, String)
6487     * @see String#replaceAll(String, String)
6488     * @see java.util.regex.Pattern
6489     * @see java.util.regex.Pattern#DOTALL
6490     * @since 3.5
6491     *
6492     * @deprecated Moved to RegExUtils.
6493     */
6494    @Deprecated
6495    public static String replaceAll(final String text, final String regex, final String replacement) {
6496        return RegExUtils.replaceAll(text, regex, replacement);
6497    }
6498
6499    /**
6500     * Replaces all occurrences of a character in a String with another.
6501     * This is a null-safe version of {@link String#replace(char, char)}.
6502     *
6503     * <p>A {@code null} string input returns {@code null}.
6504     * An empty ("") string input returns an empty string.</p>
6505     *
6506     * <pre>
6507     * StringUtils.replaceChars(null, *, *)        = null
6508     * StringUtils.replaceChars("", *, *)          = ""
6509     * StringUtils.replaceChars("abcba", 'b', 'y') = "aycya"
6510     * StringUtils.replaceChars("abcba", 'z', 'y') = "abcba"
6511     * </pre>
6512     *
6513     * @param str  String to replace characters in, may be null
6514     * @param searchChar  the character to search for, may be null
6515     * @param replaceChar  the character to replace, may be null
6516     * @return modified String, {@code null} if null string input
6517     * @since 2.0
6518     */
6519    public static String replaceChars(final String str, final char searchChar, final char replaceChar) {
6520        if (str == null) {
6521            return null;
6522        }
6523        return str.replace(searchChar, replaceChar);
6524    }
6525
6526    /**
6527     * Replaces multiple characters in a String in one go.
6528     * This method can also be used to delete characters.
6529     *
6530     * <p>For example:<br>
6531     * {@code replaceChars(&quot;hello&quot;, &quot;ho&quot;, &quot;jy&quot;) = jelly}.</p>
6532     *
6533     * <p>A {@code null} string input returns {@code null}.
6534     * An empty ("") string input returns an empty string.
6535     * A null or empty set of search characters returns the input string.</p>
6536     *
6537     * <p>The length of the search characters should normally equal the length
6538     * of the replace characters.
6539     * If the search characters is longer, then the extra search characters
6540     * are deleted.
6541     * If the search characters is shorter, then the extra replace characters
6542     * are ignored.</p>
6543     *
6544     * <pre>
6545     * StringUtils.replaceChars(null, *, *)           = null
6546     * StringUtils.replaceChars("", *, *)             = ""
6547     * StringUtils.replaceChars("abc", null, *)       = "abc"
6548     * StringUtils.replaceChars("abc", "", *)         = "abc"
6549     * StringUtils.replaceChars("abc", "b", null)     = "ac"
6550     * StringUtils.replaceChars("abc", "b", "")       = "ac"
6551     * StringUtils.replaceChars("abcba", "bc", "yz")  = "ayzya"
6552     * StringUtils.replaceChars("abcba", "bc", "y")   = "ayya"
6553     * StringUtils.replaceChars("abcba", "bc", "yzx") = "ayzya"
6554     * </pre>
6555     *
6556     * @param str  String to replace characters in, may be null
6557     * @param searchChars  a set of characters to search for, may be null
6558     * @param replaceChars  a set of characters to replace, may be null
6559     * @return modified String, {@code null} if null string input
6560     * @since 2.0
6561     */
6562    public static String replaceChars(final String str, final String searchChars, String replaceChars) {
6563        if (isEmpty(str) || isEmpty(searchChars)) {
6564            return str;
6565        }
6566        if (replaceChars == null) {
6567            replaceChars = EMPTY;
6568        }
6569        boolean modified = false;
6570        final int replaceCharsLength = replaceChars.length();
6571        final int strLength = str.length();
6572        final StringBuilder buf = new StringBuilder(strLength);
6573        for (int i = 0; i < strLength; i++) {
6574            final char ch = str.charAt(i);
6575            final int index = searchChars.indexOf(ch);
6576            if (index >= 0) {
6577                modified = true;
6578                if (index < replaceCharsLength) {
6579                    buf.append(replaceChars.charAt(index));
6580                }
6581            } else {
6582                buf.append(ch);
6583            }
6584        }
6585        if (modified) {
6586            return buf.toString();
6587        }
6588        return str;
6589    }
6590
6591    /**
6592     * Replaces all occurrences of Strings within another String.
6593     *
6594     * <p>
6595     * A {@code null} reference passed to this method is a no-op, or if
6596     * any "search string" or "string to replace" is null, that replace will be
6597     * ignored. This will not repeat. For repeating replaces, call the
6598     * overloaded method.
6599     * </p>
6600     *
6601     * <pre>
6602     *  StringUtils.replaceEach(null, *, *)        = null
6603     *  StringUtils.replaceEach("", *, *)          = ""
6604     *  StringUtils.replaceEach("aba", null, null) = "aba"
6605     *  StringUtils.replaceEach("aba", new String[0], null) = "aba"
6606     *  StringUtils.replaceEach("aba", null, new String[0]) = "aba"
6607     *  StringUtils.replaceEach("aba", new String[]{"a"}, null)  = "aba"
6608     *  StringUtils.replaceEach("aba", new String[]{"a"}, new String[]{""})  = "b"
6609     *  StringUtils.replaceEach("aba", new String[]{null}, new String[]{"a"})  = "aba"
6610     *  StringUtils.replaceEach("abcde", new String[]{"ab", "d"}, new String[]{"w", "t"})  = "wcte"
6611     *  (example of how it does not repeat)
6612     *  StringUtils.replaceEach("abcde", new String[]{"ab", "d"}, new String[]{"d", "t"})  = "dcte"
6613     * </pre>
6614     *
6615     * @param text
6616     *            text to search and replace in, no-op if null
6617     * @param searchList
6618     *            the Strings to search for, no-op if null
6619     * @param replacementList
6620     *            the Strings to replace them with, no-op if null
6621     * @return the text with any replacements processed, {@code null} if
6622     *         null String input
6623     * @throws IllegalArgumentException
6624     *             if the lengths of the arrays are not the same (null is ok,
6625     *             and/or size 0)
6626     * @since 2.4
6627     */
6628    public static String replaceEach(final String text, final String[] searchList, final String[] replacementList) {
6629        return replaceEach(text, searchList, replacementList, false, 0);
6630    }
6631
6632    /**
6633     * Replace all occurrences of Strings within another String.
6634     * This is a private recursive helper method for {@link #replaceEachRepeatedly(String, String[], String[])} and
6635     * {@link #replaceEach(String, String[], String[])}
6636     *
6637     * <p>
6638     * A {@code null} reference passed to this method is a no-op, or if
6639     * any "search string" or "string to replace" is null, that replace will be
6640     * ignored.
6641     * </p>
6642     *
6643     * <pre>
6644     *  StringUtils.replaceEach(null, *, *, *, *) = null
6645     *  StringUtils.replaceEach("", *, *, *, *) = ""
6646     *  StringUtils.replaceEach("aba", null, null, *, *) = "aba"
6647     *  StringUtils.replaceEach("aba", new String[0], null, *, *) = "aba"
6648     *  StringUtils.replaceEach("aba", null, new String[0], *, *) = "aba"
6649     *  StringUtils.replaceEach("aba", new String[]{"a"}, null, *, *) = "aba"
6650     *  StringUtils.replaceEach("aba", new String[]{"a"}, new String[]{""}, *, >=0) = "b"
6651     *  StringUtils.replaceEach("aba", new String[]{null}, new String[]{"a"}, *, >=0) = "aba"
6652     *  StringUtils.replaceEach("abcde", new String[]{"ab", "d"}, new String[]{"w", "t"}, *, >=0) = "wcte"
6653     *  (example of how it repeats)
6654     *  StringUtils.replaceEach("abcde", new String[]{"ab", "d"}, new String[]{"d", "t"}, false, >=0) = "dcte"
6655     *  StringUtils.replaceEach("abcde", new String[]{"ab", "d"}, new String[]{"d", "t"}, true, >=2) = "tcte"
6656     *  StringUtils.replaceEach("abcde", new String[]{"ab", "d"}, new String[]{"d", "ab"}, *, *) = IllegalStateException
6657     * </pre>
6658     *
6659     * @param text
6660     *            text to search and replace in, no-op if null
6661     * @param searchList
6662     *            the Strings to search for, no-op if null
6663     * @param replacementList
6664     *            the Strings to replace them with, no-op if null
6665     * @param repeat if true, then replace repeatedly
6666     *       until there are no more possible replacements or timeToLive < 0
6667     * @param timeToLive
6668     *            if less than 0 then there is a circular reference and endless
6669     *            loop
6670     * @return the text with any replacements processed, {@code null} if
6671     *         null String input
6672     * @throws IllegalStateException
6673     *             if the search is repeating and there is an endless loop due
6674     *             to outputs of one being inputs to another
6675     * @throws IllegalArgumentException
6676     *             if the lengths of the arrays are not the same (null is ok,
6677     *             and/or size 0)
6678     * @since 2.4
6679     */
6680    private static String replaceEach(
6681            final String text, final String[] searchList, final String[] replacementList, final boolean repeat, final int timeToLive) {
6682
6683        // mchyzer Performance note: This creates very few new objects (one major goal)
6684        // let me know if there are performance requests, we can create a harness to measure
6685
6686        // if recursing, this shouldn't be less than 0
6687        if (timeToLive < 0) {
6688            final Set<String> searchSet = new HashSet<>(Arrays.asList(searchList));
6689            final Set<String> replacementSet = new HashSet<>(Arrays.asList(replacementList));
6690            searchSet.retainAll(replacementSet);
6691            if (!searchSet.isEmpty()) {
6692                throw new IllegalStateException("Aborting to protect against StackOverflowError - " +
6693                        "output of one loop is the input of another");
6694            }
6695        }
6696
6697        if (isEmpty(text) || ArrayUtils.isEmpty(searchList) || ArrayUtils.isEmpty(replacementList) || ArrayUtils.isNotEmpty(searchList) && timeToLive == -1) {
6698            return text;
6699        }
6700
6701        final int searchLength = searchList.length;
6702        final int replacementLength = replacementList.length;
6703
6704        // make sure lengths are ok, these need to be equal
6705        if (searchLength != replacementLength) {
6706            throw new IllegalArgumentException("Search and Replace array lengths don't match: "
6707                + searchLength
6708                + " vs "
6709                + replacementLength);
6710        }
6711
6712        // keep track of which still have matches
6713        final boolean[] noMoreMatchesForReplIndex = new boolean[searchLength];
6714
6715        // index on index that the match was found
6716        int textIndex = -1;
6717        int replaceIndex = -1;
6718        int tempIndex;
6719
6720        // index of replace array that will replace the search string found
6721        // NOTE: logic duplicated below START
6722        for (int i = 0; i < searchLength; i++) {
6723            if (noMoreMatchesForReplIndex[i] || isEmpty(searchList[i]) || replacementList[i] == null) {
6724                continue;
6725            }
6726            tempIndex = text.indexOf(searchList[i]);
6727
6728            // see if we need to keep searching for this
6729            if (tempIndex == -1) {
6730                noMoreMatchesForReplIndex[i] = true;
6731            } else if (textIndex == -1 || tempIndex < textIndex) {
6732                textIndex = tempIndex;
6733                replaceIndex = i;
6734            }
6735        }
6736        // NOTE: logic mostly below END
6737
6738        // no search strings found, we are done
6739        if (textIndex == -1) {
6740            return text;
6741        }
6742
6743        int start = 0;
6744
6745        // get a good guess on the size of the result buffer so it doesn't have to double if it goes over a bit
6746        int increase = 0;
6747
6748        // count the replacement text elements that are larger than their corresponding text being replaced
6749        for (int i = 0; i < searchList.length; i++) {
6750            if (searchList[i] == null || replacementList[i] == null) {
6751                continue;
6752            }
6753            final int greater = replacementList[i].length() - searchList[i].length();
6754            if (greater > 0) {
6755                increase += 3 * greater; // assume 3 matches
6756            }
6757        }
6758        // have upper-bound at 20% increase, then let Java take over
6759        increase = Math.min(increase, text.length() / 5);
6760
6761        final StringBuilder buf = new StringBuilder(text.length() + increase);
6762
6763        while (textIndex != -1) {
6764
6765            for (int i = start; i < textIndex; i++) {
6766                buf.append(text.charAt(i));
6767            }
6768            buf.append(replacementList[replaceIndex]);
6769
6770            start = textIndex + searchList[replaceIndex].length();
6771
6772            textIndex = -1;
6773            replaceIndex = -1;
6774            // find the next earliest match
6775            // NOTE: logic mostly duplicated above START
6776            for (int i = 0; i < searchLength; i++) {
6777                if (noMoreMatchesForReplIndex[i] || isEmpty(searchList[i]) || replacementList[i] == null) {
6778                    continue;
6779                }
6780                tempIndex = text.indexOf(searchList[i], start);
6781
6782                // see if we need to keep searching for this
6783                if (tempIndex == -1) {
6784                    noMoreMatchesForReplIndex[i] = true;
6785                } else if (textIndex == -1 || tempIndex < textIndex) {
6786                    textIndex = tempIndex;
6787                    replaceIndex = i;
6788                }
6789            }
6790            // NOTE: logic duplicated above END
6791
6792        }
6793        final int textLength = text.length();
6794        for (int i = start; i < textLength; i++) {
6795            buf.append(text.charAt(i));
6796        }
6797        final String result = buf.toString();
6798        if (!repeat) {
6799            return result;
6800        }
6801
6802        return replaceEach(result, searchList, replacementList, repeat, timeToLive - 1);
6803    }
6804
6805    /**
6806     * Replaces all occurrences of Strings within another String.
6807     *
6808     * <p>
6809     * A {@code null} reference passed to this method is a no-op, or if
6810     * any "search string" or "string to replace" is null, that replace will be
6811     * ignored.
6812     * </p>
6813     *
6814     * <pre>
6815     *  StringUtils.replaceEachRepeatedly(null, *, *) = null
6816     *  StringUtils.replaceEachRepeatedly("", *, *) = ""
6817     *  StringUtils.replaceEachRepeatedly("aba", null, null) = "aba"
6818     *  StringUtils.replaceEachRepeatedly("aba", new String[0], null) = "aba"
6819     *  StringUtils.replaceEachRepeatedly("aba", null, new String[0]) = "aba"
6820     *  StringUtils.replaceEachRepeatedly("aba", new String[]{"a"}, null) = "aba"
6821     *  StringUtils.replaceEachRepeatedly("aba", new String[]{"a"}, new String[]{""}) = "b"
6822     *  StringUtils.replaceEachRepeatedly("aba", new String[]{null}, new String[]{"a"}) = "aba"
6823     *  StringUtils.replaceEachRepeatedly("abcde", new String[]{"ab", "d"}, new String[]{"w", "t"}) = "wcte"
6824     *  (example of how it repeats)
6825     *  StringUtils.replaceEachRepeatedly("abcde", new String[]{"ab", "d"}, new String[]{"d", "t"}) = "tcte"
6826     *  StringUtils.replaceEachRepeatedly("abcde", new String[]{"ab", "d"}, new String[]{"d", "ab"}) = IllegalStateException
6827     * </pre>
6828     *
6829     * @param text
6830     *            text to search and replace in, no-op if null
6831     * @param searchList
6832     *            the Strings to search for, no-op if null
6833     * @param replacementList
6834     *            the Strings to replace them with, no-op if null
6835     * @return the text with any replacements processed, {@code null} if
6836     *         null String input
6837     * @throws IllegalStateException
6838     *             if the search is repeating and there is an endless loop due
6839     *             to outputs of one being inputs to another
6840     * @throws IllegalArgumentException
6841     *             if the lengths of the arrays are not the same (null is ok,
6842     *             and/or size 0)
6843     * @since 2.4
6844     */
6845    public static String replaceEachRepeatedly(final String text, final String[] searchList, final String[] replacementList) {
6846        return replaceEach(text, searchList, replacementList, true, ArrayUtils.getLength(searchList));
6847    }
6848
6849    /**
6850     * Replaces the first substring of the text string that matches the given regular expression
6851     * with the given replacement.
6852     *
6853     * This method is a {@code null} safe equivalent to:
6854     * <ul>
6855     *  <li>{@code text.replaceFirst(regex, replacement)}</li>
6856     *  <li>{@code Pattern.compile(regex).matcher(text).replaceFirst(replacement)}</li>
6857     * </ul>
6858     *
6859     * <p>A {@code null} reference passed to this method is a no-op.</p>
6860     *
6861     * <p>The {@link Pattern#DOTALL} option is NOT automatically added.
6862     * To use the DOTALL option prepend {@code "(?s)"} to the regex.
6863     * DOTALL is also known as single-line mode in Perl.</p>
6864     *
6865     * <pre>{@code
6866     * StringUtils.replaceFirst(null, *, *)       = null
6867     * StringUtils.replaceFirst("any", (String) null, *)   = "any"
6868     * StringUtils.replaceFirst("any", *, null)   = "any"
6869     * StringUtils.replaceFirst("", "", "zzz")    = "zzz"
6870     * StringUtils.replaceFirst("", ".*", "zzz")  = "zzz"
6871     * StringUtils.replaceFirst("", ".+", "zzz")  = ""
6872     * StringUtils.replaceFirst("abc", "", "ZZ")  = "ZZabc"
6873     * StringUtils.replaceFirst("<__>\n<__>", "<.*>", "z")      = "z\n<__>"
6874     * StringUtils.replaceFirst("<__>\n<__>", "(?s)<.*>", "z")  = "z"
6875     * StringUtils.replaceFirst("ABCabc123", "[a-z]", "_")          = "ABC_bc123"
6876     * StringUtils.replaceFirst("ABCabc123abc", "[^A-Z0-9]+", "_")  = "ABC_123abc"
6877     * StringUtils.replaceFirst("ABCabc123abc", "[^A-Z0-9]+", "")   = "ABC123abc"
6878     * StringUtils.replaceFirst("Lorem ipsum  dolor   sit", "( +)([a-z]+)", "_$2")  = "Lorem_ipsum  dolor   sit"
6879     * }</pre>
6880     *
6881     * @param text  text to search and replace in, may be null
6882     * @param regex  the regular expression to which this string is to be matched
6883     * @param replacement  the string to be substituted for the first match
6884     * @return  the text with the first replacement processed,
6885     *              {@code null} if null String input
6886     *
6887     * @throws  java.util.regex.PatternSyntaxException
6888     *              if the regular expression's syntax is invalid
6889     *
6890     * @see String#replaceFirst(String, String)
6891     * @see java.util.regex.Pattern
6892     * @see java.util.regex.Pattern#DOTALL
6893     * @since 3.5
6894     *
6895     * @deprecated Moved to RegExUtils.
6896     */
6897    @Deprecated
6898    public static String replaceFirst(final String text, final String regex, final String replacement) {
6899        return RegExUtils.replaceFirst(text, regex, replacement);
6900    }
6901
6902    /**
6903     * Case insensitively replaces all occurrences of a String within another String.
6904     *
6905     * <p>A {@code null} reference passed to this method is a no-op.</p>
6906     *
6907     * <pre>
6908     * StringUtils.replaceIgnoreCase(null, *, *)        = null
6909     * StringUtils.replaceIgnoreCase("", *, *)          = ""
6910     * StringUtils.replaceIgnoreCase("any", null, *)    = "any"
6911     * StringUtils.replaceIgnoreCase("any", *, null)    = "any"
6912     * StringUtils.replaceIgnoreCase("any", "", *)      = "any"
6913     * StringUtils.replaceIgnoreCase("aba", "a", null)  = "aba"
6914     * StringUtils.replaceIgnoreCase("abA", "A", "")    = "b"
6915     * StringUtils.replaceIgnoreCase("aba", "A", "z")   = "zbz"
6916     * </pre>
6917     *
6918     * @see #replaceIgnoreCase(String text, String searchString, String replacement, int max)
6919     * @param text  text to search and replace in, may be null
6920     * @param searchString  the String to search for (case-insensitive), may be null
6921     * @param replacement  the String to replace it with, may be null
6922     * @return the text with any replacements processed,
6923     *  {@code null} if null String input
6924     * @since 3.5
6925     */
6926     public static String replaceIgnoreCase(final String text, final String searchString, final String replacement) {
6927         return replaceIgnoreCase(text, searchString, replacement, -1);
6928     }
6929
6930    /**
6931     * Case insensitively replaces a String with another String inside a larger String,
6932     * for the first {@code max} values of the search String.
6933     *
6934     * <p>A {@code null} reference passed to this method is a no-op.</p>
6935     *
6936     * <pre>
6937     * StringUtils.replaceIgnoreCase(null, *, *, *)         = null
6938     * StringUtils.replaceIgnoreCase("", *, *, *)           = ""
6939     * StringUtils.replaceIgnoreCase("any", null, *, *)     = "any"
6940     * StringUtils.replaceIgnoreCase("any", *, null, *)     = "any"
6941     * StringUtils.replaceIgnoreCase("any", "", *, *)       = "any"
6942     * StringUtils.replaceIgnoreCase("any", *, *, 0)        = "any"
6943     * StringUtils.replaceIgnoreCase("abaa", "a", null, -1) = "abaa"
6944     * StringUtils.replaceIgnoreCase("abaa", "a", "", -1)   = "b"
6945     * StringUtils.replaceIgnoreCase("abaa", "a", "z", 0)   = "abaa"
6946     * StringUtils.replaceIgnoreCase("abaa", "A", "z", 1)   = "zbaa"
6947     * StringUtils.replaceIgnoreCase("abAa", "a", "z", 2)   = "zbza"
6948     * StringUtils.replaceIgnoreCase("abAa", "a", "z", -1)  = "zbzz"
6949     * </pre>
6950     *
6951     * @param text  text to search and replace in, may be null
6952     * @param searchString  the String to search for (case-insensitive), may be null
6953     * @param replacement  the String to replace it with, may be null
6954     * @param max  maximum number of values to replace, or {@code -1} if no maximum
6955     * @return the text with any replacements processed,
6956     *  {@code null} if null String input
6957     * @since 3.5
6958     */
6959    public static String replaceIgnoreCase(final String text, final String searchString, final String replacement, final int max) {
6960        return replace(text, searchString, replacement, max, true);
6961    }
6962
6963    /**
6964     * Replaces a String with another String inside a larger String, once.
6965     *
6966     * <p>A {@code null} reference passed to this method is a no-op.</p>
6967     *
6968     * <pre>
6969     * StringUtils.replaceOnce(null, *, *)        = null
6970     * StringUtils.replaceOnce("", *, *)          = ""
6971     * StringUtils.replaceOnce("any", null, *)    = "any"
6972     * StringUtils.replaceOnce("any", *, null)    = "any"
6973     * StringUtils.replaceOnce("any", "", *)      = "any"
6974     * StringUtils.replaceOnce("aba", "a", null)  = "aba"
6975     * StringUtils.replaceOnce("aba", "a", "")    = "ba"
6976     * StringUtils.replaceOnce("aba", "a", "z")   = "zba"
6977     * </pre>
6978     *
6979     * @see #replace(String text, String searchString, String replacement, int max)
6980     * @param text  text to search and replace in, may be null
6981     * @param searchString  the String to search for, may be null
6982     * @param replacement  the String to replace with, may be null
6983     * @return the text with any replacements processed,
6984     *  {@code null} if null String input
6985     */
6986    public static String replaceOnce(final String text, final String searchString, final String replacement) {
6987        return replace(text, searchString, replacement, 1);
6988    }
6989
6990    /**
6991     * Case insensitively replaces a String with another String inside a larger String, once.
6992     *
6993     * <p>A {@code null} reference passed to this method is a no-op.</p>
6994     *
6995     * <pre>
6996     * StringUtils.replaceOnceIgnoreCase(null, *, *)        = null
6997     * StringUtils.replaceOnceIgnoreCase("", *, *)          = ""
6998     * StringUtils.replaceOnceIgnoreCase("any", null, *)    = "any"
6999     * StringUtils.replaceOnceIgnoreCase("any", *, null)    = "any"
7000     * StringUtils.replaceOnceIgnoreCase("any", "", *)      = "any"
7001     * StringUtils.replaceOnceIgnoreCase("aba", "a", null)  = "aba"
7002     * StringUtils.replaceOnceIgnoreCase("aba", "a", "")    = "ba"
7003     * StringUtils.replaceOnceIgnoreCase("aba", "a", "z")   = "zba"
7004     * StringUtils.replaceOnceIgnoreCase("FoOFoofoo", "foo", "") = "Foofoo"
7005     * </pre>
7006     *
7007     * @see #replaceIgnoreCase(String text, String searchString, String replacement, int max)
7008     * @param text  text to search and replace in, may be null
7009     * @param searchString  the String to search for (case-insensitive), may be null
7010     * @param replacement  the String to replace with, may be null
7011     * @return the text with any replacements processed,
7012     *  {@code null} if null String input
7013     * @since 3.5
7014     */
7015    public static String replaceOnceIgnoreCase(final String text, final String searchString, final String replacement) {
7016        return replaceIgnoreCase(text, searchString, replacement, 1);
7017    }
7018
7019    /**
7020     * Replaces each substring of the source String that matches the given regular expression with the given
7021     * replacement using the {@link Pattern#DOTALL} option. DOTALL is also known as single-line mode in Perl.
7022     *
7023     * This call is a {@code null} safe equivalent to:
7024     * <ul>
7025     * <li>{@code source.replaceAll(&quot;(?s)&quot; + regex, replacement)}</li>
7026     * <li>{@code Pattern.compile(regex, Pattern.DOTALL).matcher(source).replaceAll(replacement)}</li>
7027     * </ul>
7028     *
7029     * <p>A {@code null} reference passed to this method is a no-op.</p>
7030     *
7031     * <pre>{@code
7032     * StringUtils.replacePattern(null, *, *)       = null
7033     * StringUtils.replacePattern("any", (String) null, *)   = "any"
7034     * StringUtils.replacePattern("any", *, null)   = "any"
7035     * StringUtils.replacePattern("", "", "zzz")    = "zzz"
7036     * StringUtils.replacePattern("", ".*", "zzz")  = "zzz"
7037     * StringUtils.replacePattern("", ".+", "zzz")  = ""
7038     * StringUtils.replacePattern("<__>\n<__>", "<.*>", "z")       = "z"
7039     * StringUtils.replacePattern("ABCabc123", "[a-z]", "_")       = "ABC___123"
7040     * StringUtils.replacePattern("ABCabc123", "[^A-Z0-9]+", "_")  = "ABC_123"
7041     * StringUtils.replacePattern("ABCabc123", "[^A-Z0-9]+", "")   = "ABC123"
7042     * StringUtils.replacePattern("Lorem ipsum  dolor   sit", "( +)([a-z]+)", "_$2")  = "Lorem_ipsum_dolor_sit"
7043     * }</pre>
7044     *
7045     * @param source
7046     *            the source string
7047     * @param regex
7048     *            the regular expression to which this string is to be matched
7049     * @param replacement
7050     *            the string to be substituted for each match
7051     * @return The resulting {@link String}
7052     * @see #replaceAll(String, String, String)
7053     * @see String#replaceAll(String, String)
7054     * @see Pattern#DOTALL
7055     * @since 3.2
7056     * @since 3.5 Changed {@code null} reference passed to this method is a no-op.
7057     *
7058     * @deprecated Moved to RegExUtils.
7059     */
7060    @Deprecated
7061    public static String replacePattern(final String source, final String regex, final String replacement) {
7062        return RegExUtils.replacePattern(source, regex, replacement);
7063    }
7064
7065    /**
7066     * Reverses a String as per {@link StringBuilder#reverse()}.
7067     *
7068     * <p>A {@code null} String returns {@code null}.</p>
7069     *
7070     * <pre>
7071     * StringUtils.reverse(null)  = null
7072     * StringUtils.reverse("")    = ""
7073     * StringUtils.reverse("bat") = "tab"
7074     * </pre>
7075     *
7076     * @param str  the String to reverse, may be null
7077     * @return the reversed String, {@code null} if null String input
7078     */
7079    public static String reverse(final String str) {
7080        if (str == null) {
7081            return null;
7082        }
7083        return new StringBuilder(str).reverse().toString();
7084    }
7085
7086    /**
7087     * Reverses a String that is delimited by a specific character.
7088     *
7089     * <p>The Strings between the delimiters are not reversed.
7090     * Thus java.lang.String becomes String.lang.java (if the delimiter
7091     * is {@code '.'}).</p>
7092     *
7093     * <pre>
7094     * StringUtils.reverseDelimited(null, *)      = null
7095     * StringUtils.reverseDelimited("", *)        = ""
7096     * StringUtils.reverseDelimited("a.b.c", 'x') = "a.b.c"
7097     * StringUtils.reverseDelimited("a.b.c", ".") = "c.b.a"
7098     * </pre>
7099     *
7100     * @param str  the String to reverse, may be null
7101     * @param separatorChar  the separator character to use
7102     * @return the reversed String, {@code null} if null String input
7103     * @since 2.0
7104     */
7105    public static String reverseDelimited(final String str, final char separatorChar) {
7106        final String[] strs = split(str, separatorChar);
7107        ArrayUtils.reverse(strs);
7108        return join(strs, separatorChar);
7109    }
7110
7111    /**
7112     * Gets the rightmost {@code len} characters of a String.
7113     *
7114     * <p>If {@code len} characters are not available, or the String
7115     * is {@code null}, the String will be returned without an
7116     * an exception. An empty String is returned if len is negative.</p>
7117     *
7118     * <pre>
7119     * StringUtils.right(null, *)    = null
7120     * StringUtils.right(*, -ve)     = ""
7121     * StringUtils.right("", *)      = ""
7122     * StringUtils.right("abc", 0)   = ""
7123     * StringUtils.right("abc", 2)   = "bc"
7124     * StringUtils.right("abc", 4)   = "abc"
7125     * </pre>
7126     *
7127     * @param str  the String to get the rightmost characters from, may be null
7128     * @param len  the length of the required String
7129     * @return the rightmost characters, {@code null} if null String input
7130     */
7131    public static String right(final String str, final int len) {
7132        if (str == null) {
7133            return null;
7134        }
7135        if (len < 0) {
7136            return EMPTY;
7137        }
7138        if (str.length() <= len) {
7139            return str;
7140        }
7141        return str.substring(str.length() - len);
7142    }
7143
7144    /**
7145     * Right pad a String with spaces (' ').
7146     *
7147     * <p>The String is padded to the size of {@code size}.</p>
7148     *
7149     * <pre>
7150     * StringUtils.rightPad(null, *)   = null
7151     * StringUtils.rightPad("", 3)     = "   "
7152     * StringUtils.rightPad("bat", 3)  = "bat"
7153     * StringUtils.rightPad("bat", 5)  = "bat  "
7154     * StringUtils.rightPad("bat", 1)  = "bat"
7155     * StringUtils.rightPad("bat", -1) = "bat"
7156     * </pre>
7157     *
7158     * @param str  the String to pad out, may be null
7159     * @param size  the size to pad to
7160     * @return right padded String or original String if no padding is necessary,
7161     *  {@code null} if null String input
7162     */
7163    public static String rightPad(final String str, final int size) {
7164        return rightPad(str, size, ' ');
7165    }
7166
7167    /**
7168     * Right pad a String with a specified character.
7169     *
7170     * <p>The String is padded to the size of {@code size}.</p>
7171     *
7172     * <pre>
7173     * StringUtils.rightPad(null, *, *)     = null
7174     * StringUtils.rightPad("", 3, 'z')     = "zzz"
7175     * StringUtils.rightPad("bat", 3, 'z')  = "bat"
7176     * StringUtils.rightPad("bat", 5, 'z')  = "batzz"
7177     * StringUtils.rightPad("bat", 1, 'z')  = "bat"
7178     * StringUtils.rightPad("bat", -1, 'z') = "bat"
7179     * </pre>
7180     *
7181     * @param str  the String to pad out, may be null
7182     * @param size  the size to pad to
7183     * @param padChar  the character to pad with
7184     * @return right padded String or original String if no padding is necessary,
7185     *  {@code null} if null String input
7186     * @since 2.0
7187     */
7188    public static String rightPad(final String str, final int size, final char padChar) {
7189        if (str == null) {
7190            return null;
7191        }
7192        final int pads = size - str.length();
7193        if (pads <= 0) {
7194            return str; // returns original String when possible
7195        }
7196        if (pads > PAD_LIMIT) {
7197            return rightPad(str, size, String.valueOf(padChar));
7198        }
7199        return str.concat(repeat(padChar, pads));
7200    }
7201
7202    /**
7203     * Right pad a String with a specified String.
7204     *
7205     * <p>The String is padded to the size of {@code size}.</p>
7206     *
7207     * <pre>
7208     * StringUtils.rightPad(null, *, *)      = null
7209     * StringUtils.rightPad("", 3, "z")      = "zzz"
7210     * StringUtils.rightPad("bat", 3, "yz")  = "bat"
7211     * StringUtils.rightPad("bat", 5, "yz")  = "batyz"
7212     * StringUtils.rightPad("bat", 8, "yz")  = "batyzyzy"
7213     * StringUtils.rightPad("bat", 1, "yz")  = "bat"
7214     * StringUtils.rightPad("bat", -1, "yz") = "bat"
7215     * StringUtils.rightPad("bat", 5, null)  = "bat  "
7216     * StringUtils.rightPad("bat", 5, "")    = "bat  "
7217     * </pre>
7218     *
7219     * @param str  the String to pad out, may be null
7220     * @param size  the size to pad to
7221     * @param padStr  the String to pad with, null or empty treated as single space
7222     * @return right padded String or original String if no padding is necessary,
7223     *  {@code null} if null String input
7224     */
7225    public static String rightPad(final String str, final int size, String padStr) {
7226        if (str == null) {
7227            return null;
7228        }
7229        if (isEmpty(padStr)) {
7230            padStr = SPACE;
7231        }
7232        final int padLen = padStr.length();
7233        final int strLen = str.length();
7234        final int pads = size - strLen;
7235        if (pads <= 0) {
7236            return str; // returns original String when possible
7237        }
7238        if (padLen == 1 && pads <= PAD_LIMIT) {
7239            return rightPad(str, size, padStr.charAt(0));
7240        }
7241
7242        if (pads == padLen) {
7243            return str.concat(padStr);
7244        }
7245        if (pads < padLen) {
7246            return str.concat(padStr.substring(0, pads));
7247        }
7248        final char[] padding = new char[pads];
7249        final char[] padChars = padStr.toCharArray();
7250        for (int i = 0; i < pads; i++) {
7251            padding[i] = padChars[i % padLen];
7252        }
7253        return str.concat(new String(padding));
7254    }
7255
7256    /**
7257     * Rotate (circular shift) a String of {@code shift} characters.
7258     * <ul>
7259     *  <li>If {@code shift > 0}, right circular shift (ex : ABCDEF =&gt; FABCDE)</li>
7260     *  <li>If {@code shift < 0}, left circular shift (ex : ABCDEF =&gt; BCDEFA)</li>
7261     * </ul>
7262     *
7263     * <pre>
7264     * StringUtils.rotate(null, *)        = null
7265     * StringUtils.rotate("", *)          = ""
7266     * StringUtils.rotate("abcdefg", 0)   = "abcdefg"
7267     * StringUtils.rotate("abcdefg", 2)   = "fgabcde"
7268     * StringUtils.rotate("abcdefg", -2)  = "cdefgab"
7269     * StringUtils.rotate("abcdefg", 7)   = "abcdefg"
7270     * StringUtils.rotate("abcdefg", -7)  = "abcdefg"
7271     * StringUtils.rotate("abcdefg", 9)   = "fgabcde"
7272     * StringUtils.rotate("abcdefg", -9)  = "cdefgab"
7273     * </pre>
7274     *
7275     * @param str  the String to rotate, may be null
7276     * @param shift  number of time to shift (positive : right shift, negative : left shift)
7277     * @return the rotated String,
7278     *          or the original String if {@code shift == 0},
7279     *          or {@code null} if null String input
7280     * @since 3.5
7281     */
7282    public static String rotate(final String str, final int shift) {
7283        if (str == null) {
7284            return null;
7285        }
7286
7287        final int strLen = str.length();
7288        if (shift == 0 || strLen == 0 || shift % strLen == 0) {
7289            return str;
7290        }
7291
7292        final StringBuilder builder = new StringBuilder(strLen);
7293        final int offset = - (shift % strLen);
7294        builder.append(substring(str, offset));
7295        builder.append(substring(str, 0, offset));
7296        return builder.toString();
7297    }
7298
7299    /**
7300     * Splits the provided text into an array, using whitespace as the
7301     * separator.
7302     * Whitespace is defined by {@link Character#isWhitespace(char)}.
7303     *
7304     * <p>The separator is not included in the returned String array.
7305     * Adjacent separators are treated as one separator.
7306     * For more control over the split use the StrTokenizer class.</p>
7307     *
7308     * <p>A {@code null} input String returns {@code null}.</p>
7309     *
7310     * <pre>
7311     * StringUtils.split(null)       = null
7312     * StringUtils.split("")         = []
7313     * StringUtils.split("abc def")  = ["abc", "def"]
7314     * StringUtils.split("abc  def") = ["abc", "def"]
7315     * StringUtils.split(" abc ")    = ["abc"]
7316     * </pre>
7317     *
7318     * @param str  the String to parse, may be null
7319     * @return an array of parsed Strings, {@code null} if null String input
7320     */
7321    public static String[] split(final String str) {
7322        return split(str, null, -1);
7323    }
7324
7325    /**
7326     * Splits the provided text into an array, separator specified.
7327     * This is an alternative to using StringTokenizer.
7328     *
7329     * <p>The separator is not included in the returned String array.
7330     * Adjacent separators are treated as one separator.
7331     * For more control over the split use the StrTokenizer class.</p>
7332     *
7333     * <p>A {@code null} input String returns {@code null}.</p>
7334     *
7335     * <pre>
7336     * StringUtils.split(null, *)         = null
7337     * StringUtils.split("", *)           = []
7338     * StringUtils.split("a.b.c", '.')    = ["a", "b", "c"]
7339     * StringUtils.split("a..b.c", '.')   = ["a", "b", "c"]
7340     * StringUtils.split("a:b:c", '.')    = ["a:b:c"]
7341     * StringUtils.split("a b c", ' ')    = ["a", "b", "c"]
7342     * </pre>
7343     *
7344     * @param str  the String to parse, may be null
7345     * @param separatorChar  the character used as the delimiter
7346     * @return an array of parsed Strings, {@code null} if null String input
7347     * @since 2.0
7348     */
7349    public static String[] split(final String str, final char separatorChar) {
7350        return splitWorker(str, separatorChar, false);
7351    }
7352
7353    /**
7354     * Splits the provided text into an array, separators specified.
7355     * This is an alternative to using StringTokenizer.
7356     *
7357     * <p>The separator is not included in the returned String array.
7358     * Adjacent separators are treated as one separator.
7359     * For more control over the split use the StrTokenizer class.</p>
7360     *
7361     * <p>A {@code null} input String returns {@code null}.
7362     * A {@code null} separatorChars splits on whitespace.</p>
7363     *
7364     * <pre>
7365     * StringUtils.split(null, *)         = null
7366     * StringUtils.split("", *)           = []
7367     * StringUtils.split("abc def", null) = ["abc", "def"]
7368     * StringUtils.split("abc def", " ")  = ["abc", "def"]
7369     * StringUtils.split("abc  def", " ") = ["abc", "def"]
7370     * StringUtils.split("ab:cd:ef", ":") = ["ab", "cd", "ef"]
7371     * </pre>
7372     *
7373     * @param str  the String to parse, may be null
7374     * @param separatorChars  the characters used as the delimiters,
7375     *  {@code null} splits on whitespace
7376     * @return an array of parsed Strings, {@code null} if null String input
7377     */
7378    public static String[] split(final String str, final String separatorChars) {
7379        return splitWorker(str, separatorChars, -1, false);
7380    }
7381
7382    /**
7383     * Splits the provided text into an array with a maximum length,
7384     * separators specified.
7385     *
7386     * <p>The separator is not included in the returned String array.
7387     * Adjacent separators are treated as one separator.</p>
7388     *
7389     * <p>A {@code null} input String returns {@code null}.
7390     * A {@code null} separatorChars splits on whitespace.</p>
7391     *
7392     * <p>If more than {@code max} delimited substrings are found, the last
7393     * returned string includes all characters after the first {@code max - 1}
7394     * returned strings (including separator characters).</p>
7395     *
7396     * <pre>
7397     * StringUtils.split(null, *, *)            = null
7398     * StringUtils.split("", *, *)              = []
7399     * StringUtils.split("ab cd ef", null, 0)   = ["ab", "cd", "ef"]
7400     * StringUtils.split("ab   cd ef", null, 0) = ["ab", "cd", "ef"]
7401     * StringUtils.split("ab:cd:ef", ":", 0)    = ["ab", "cd", "ef"]
7402     * StringUtils.split("ab:cd:ef", ":", 2)    = ["ab", "cd:ef"]
7403     * </pre>
7404     *
7405     * @param str  the String to parse, may be null
7406     * @param separatorChars  the characters used as the delimiters,
7407     *  {@code null} splits on whitespace
7408     * @param max  the maximum number of elements to include in the
7409     *  array. A zero or negative value implies no limit
7410     * @return an array of parsed Strings, {@code null} if null String input
7411     */
7412    public static String[] split(final String str, final String separatorChars, final int max) {
7413        return splitWorker(str, separatorChars, max, false);
7414    }
7415
7416    /**
7417     * Splits a String by Character type as returned by
7418     * {@code java.lang.Character.getType(char)}. Groups of contiguous
7419     * characters of the same type are returned as complete tokens.
7420     * <pre>
7421     * StringUtils.splitByCharacterType(null)         = null
7422     * StringUtils.splitByCharacterType("")           = []
7423     * StringUtils.splitByCharacterType("ab de fg")   = ["ab", " ", "de", " ", "fg"]
7424     * StringUtils.splitByCharacterType("ab   de fg") = ["ab", "   ", "de", " ", "fg"]
7425     * StringUtils.splitByCharacterType("ab:cd:ef")   = ["ab", ":", "cd", ":", "ef"]
7426     * StringUtils.splitByCharacterType("number5")    = ["number", "5"]
7427     * StringUtils.splitByCharacterType("fooBar")     = ["foo", "B", "ar"]
7428     * StringUtils.splitByCharacterType("foo200Bar")  = ["foo", "200", "B", "ar"]
7429     * StringUtils.splitByCharacterType("ASFRules")   = ["ASFR", "ules"]
7430     * </pre>
7431     * @param str the String to split, may be {@code null}
7432     * @return an array of parsed Strings, {@code null} if null String input
7433     * @since 2.4
7434     */
7435    public static String[] splitByCharacterType(final String str) {
7436        return splitByCharacterType(str, false);
7437    }
7438
7439    /**
7440     * <p>Splits a String by Character type as returned by
7441     * {@code java.lang.Character.getType(char)}. Groups of contiguous
7442     * characters of the same type are returned as complete tokens, with the
7443     * following exception: if {@code camelCase} is {@code true},
7444     * the character of type {@code Character.UPPERCASE_LETTER}, if any,
7445     * immediately preceding a token of type {@code Character.LOWERCASE_LETTER}
7446     * will belong to the following token rather than to the preceding, if any,
7447     * {@code Character.UPPERCASE_LETTER} token.
7448     * @param str the String to split, may be {@code null}
7449     * @param camelCase whether to use so-called "camel-case" for letter types
7450     * @return an array of parsed Strings, {@code null} if null String input
7451     * @since 2.4
7452     */
7453    private static String[] splitByCharacterType(final String str, final boolean camelCase) {
7454        if (str == null) {
7455            return null;
7456        }
7457        if (str.isEmpty()) {
7458            return ArrayUtils.EMPTY_STRING_ARRAY;
7459        }
7460        final char[] c = str.toCharArray();
7461        final List<String> list = new ArrayList<>();
7462        int tokenStart = 0;
7463        int currentType = Character.getType(c[tokenStart]);
7464        for (int pos = tokenStart + 1; pos < c.length; pos++) {
7465            final int type = Character.getType(c[pos]);
7466            if (type == currentType) {
7467                continue;
7468            }
7469            if (camelCase && type == Character.LOWERCASE_LETTER && currentType == Character.UPPERCASE_LETTER) {
7470                final int newTokenStart = pos - 1;
7471                if (newTokenStart != tokenStart) {
7472                    list.add(new String(c, tokenStart, newTokenStart - tokenStart));
7473                    tokenStart = newTokenStart;
7474                }
7475            } else {
7476                list.add(new String(c, tokenStart, pos - tokenStart));
7477                tokenStart = pos;
7478            }
7479            currentType = type;
7480        }
7481        list.add(new String(c, tokenStart, c.length - tokenStart));
7482        return list.toArray(ArrayUtils.EMPTY_STRING_ARRAY);
7483    }
7484
7485    /**
7486     * <p>Splits a String by Character type as returned by
7487     * {@code java.lang.Character.getType(char)}. Groups of contiguous
7488     * characters of the same type are returned as complete tokens, with the
7489     * following exception: the character of type
7490     * {@code Character.UPPERCASE_LETTER}, if any, immediately
7491     * preceding a token of type {@code Character.LOWERCASE_LETTER}
7492     * will belong to the following token rather than to the preceding, if any,
7493     * {@code Character.UPPERCASE_LETTER} token.
7494     * <pre>
7495     * StringUtils.splitByCharacterTypeCamelCase(null)         = null
7496     * StringUtils.splitByCharacterTypeCamelCase("")           = []
7497     * StringUtils.splitByCharacterTypeCamelCase("ab de fg")   = ["ab", " ", "de", " ", "fg"]
7498     * StringUtils.splitByCharacterTypeCamelCase("ab   de fg") = ["ab", "   ", "de", " ", "fg"]
7499     * StringUtils.splitByCharacterTypeCamelCase("ab:cd:ef")   = ["ab", ":", "cd", ":", "ef"]
7500     * StringUtils.splitByCharacterTypeCamelCase("number5")    = ["number", "5"]
7501     * StringUtils.splitByCharacterTypeCamelCase("fooBar")     = ["foo", "Bar"]
7502     * StringUtils.splitByCharacterTypeCamelCase("foo200Bar")  = ["foo", "200", "Bar"]
7503     * StringUtils.splitByCharacterTypeCamelCase("ASFRules")   = ["ASF", "Rules"]
7504     * </pre>
7505     * @param str the String to split, may be {@code null}
7506     * @return an array of parsed Strings, {@code null} if null String input
7507     * @since 2.4
7508     */
7509    public static String[] splitByCharacterTypeCamelCase(final String str) {
7510        return splitByCharacterType(str, true);
7511    }
7512
7513    /**
7514     * <p>Splits the provided text into an array, separator string specified.
7515     *
7516     * <p>The separator(s) will not be included in the returned String array.
7517     * Adjacent separators are treated as one separator.</p>
7518     *
7519     * <p>A {@code null} input String returns {@code null}.
7520     * A {@code null} separator splits on whitespace.</p>
7521     *
7522     * <pre>
7523     * StringUtils.splitByWholeSeparator(null, *)               = null
7524     * StringUtils.splitByWholeSeparator("", *)                 = []
7525     * StringUtils.splitByWholeSeparator("ab de fg", null)      = ["ab", "de", "fg"]
7526     * StringUtils.splitByWholeSeparator("ab   de fg", null)    = ["ab", "de", "fg"]
7527     * StringUtils.splitByWholeSeparator("ab:cd:ef", ":")       = ["ab", "cd", "ef"]
7528     * StringUtils.splitByWholeSeparator("ab-!-cd-!-ef", "-!-") = ["ab", "cd", "ef"]
7529     * </pre>
7530     *
7531     * @param str  the String to parse, may be null
7532     * @param separator  String containing the String to be used as a delimiter,
7533     *  {@code null} splits on whitespace
7534     * @return an array of parsed Strings, {@code null} if null String was input
7535     */
7536    public static String[] splitByWholeSeparator(final String str, final String separator) {
7537        return splitByWholeSeparatorWorker(str, separator, -1, false);
7538    }
7539
7540    /**
7541     * Splits the provided text into an array, separator string specified.
7542     * Returns a maximum of {@code max} substrings.
7543     *
7544     * <p>The separator(s) will not be included in the returned String array.
7545     * Adjacent separators are treated as one separator.</p>
7546     *
7547     * <p>A {@code null} input String returns {@code null}.
7548     * A {@code null} separator splits on whitespace.</p>
7549     *
7550     * <pre>
7551     * StringUtils.splitByWholeSeparator(null, *, *)               = null
7552     * StringUtils.splitByWholeSeparator("", *, *)                 = []
7553     * StringUtils.splitByWholeSeparator("ab de fg", null, 0)      = ["ab", "de", "fg"]
7554     * StringUtils.splitByWholeSeparator("ab   de fg", null, 0)    = ["ab", "de", "fg"]
7555     * StringUtils.splitByWholeSeparator("ab:cd:ef", ":", 2)       = ["ab", "cd:ef"]
7556     * StringUtils.splitByWholeSeparator("ab-!-cd-!-ef", "-!-", 5) = ["ab", "cd", "ef"]
7557     * StringUtils.splitByWholeSeparator("ab-!-cd-!-ef", "-!-", 2) = ["ab", "cd-!-ef"]
7558     * </pre>
7559     *
7560     * @param str  the String to parse, may be null
7561     * @param separator  String containing the String to be used as a delimiter,
7562     *  {@code null} splits on whitespace
7563     * @param max  the maximum number of elements to include in the returned
7564     *  array. A zero or negative value implies no limit.
7565     * @return an array of parsed Strings, {@code null} if null String was input
7566     */
7567    public static String[] splitByWholeSeparator( final String str, final String separator, final int max) {
7568        return splitByWholeSeparatorWorker(str, separator, max, false);
7569    }
7570
7571    /**
7572     * Splits the provided text into an array, separator string specified.
7573     *
7574     * <p>The separator is not included in the returned String array.
7575     * Adjacent separators are treated as separators for empty tokens.
7576     * For more control over the split use the StrTokenizer class.</p>
7577     *
7578     * <p>A {@code null} input String returns {@code null}.
7579     * A {@code null} separator splits on whitespace.</p>
7580     *
7581     * <pre>
7582     * StringUtils.splitByWholeSeparatorPreserveAllTokens(null, *)               = null
7583     * StringUtils.splitByWholeSeparatorPreserveAllTokens("", *)                 = []
7584     * StringUtils.splitByWholeSeparatorPreserveAllTokens("ab de fg", null)      = ["ab", "de", "fg"]
7585     * StringUtils.splitByWholeSeparatorPreserveAllTokens("ab   de fg", null)    = ["ab", "", "", "de", "fg"]
7586     * StringUtils.splitByWholeSeparatorPreserveAllTokens("ab:cd:ef", ":")       = ["ab", "cd", "ef"]
7587     * StringUtils.splitByWholeSeparatorPreserveAllTokens("ab-!-cd-!-ef", "-!-") = ["ab", "cd", "ef"]
7588     * </pre>
7589     *
7590     * @param str  the String to parse, may be null
7591     * @param separator  String containing the String to be used as a delimiter,
7592     *  {@code null} splits on whitespace
7593     * @return an array of parsed Strings, {@code null} if null String was input
7594     * @since 2.4
7595     */
7596    public static String[] splitByWholeSeparatorPreserveAllTokens(final String str, final String separator) {
7597        return splitByWholeSeparatorWorker(str, separator, -1, true);
7598    }
7599
7600    /**
7601     * Splits the provided text into an array, separator string specified.
7602     * Returns a maximum of {@code max} substrings.
7603     *
7604     * <p>The separator is not included in the returned String array.
7605     * Adjacent separators are treated as separators for empty tokens.
7606     * For more control over the split use the StrTokenizer class.</p>
7607     *
7608     * <p>A {@code null} input String returns {@code null}.
7609     * A {@code null} separator splits on whitespace.</p>
7610     *
7611     * <pre>
7612     * StringUtils.splitByWholeSeparatorPreserveAllTokens(null, *, *)               = null
7613     * StringUtils.splitByWholeSeparatorPreserveAllTokens("", *, *)                 = []
7614     * StringUtils.splitByWholeSeparatorPreserveAllTokens("ab de fg", null, 0)      = ["ab", "de", "fg"]
7615     * StringUtils.splitByWholeSeparatorPreserveAllTokens("ab   de fg", null, 0)    = ["ab", "", "", "de", "fg"]
7616     * StringUtils.splitByWholeSeparatorPreserveAllTokens("ab:cd:ef", ":", 2)       = ["ab", "cd:ef"]
7617     * StringUtils.splitByWholeSeparatorPreserveAllTokens("ab-!-cd-!-ef", "-!-", 5) = ["ab", "cd", "ef"]
7618     * StringUtils.splitByWholeSeparatorPreserveAllTokens("ab-!-cd-!-ef", "-!-", 2) = ["ab", "cd-!-ef"]
7619     * </pre>
7620     *
7621     * @param str  the String to parse, may be null
7622     * @param separator  String containing the String to be used as a delimiter,
7623     *  {@code null} splits on whitespace
7624     * @param max  the maximum number of elements to include in the returned
7625     *  array. A zero or negative value implies no limit.
7626     * @return an array of parsed Strings, {@code null} if null String was input
7627     * @since 2.4
7628     */
7629    public static String[] splitByWholeSeparatorPreserveAllTokens(final String str, final String separator, final int max) {
7630        return splitByWholeSeparatorWorker(str, separator, max, true);
7631    }
7632
7633    /**
7634     * Performs the logic for the {@code splitByWholeSeparatorPreserveAllTokens} methods.
7635     *
7636     * @param str  the String to parse, may be {@code null}
7637     * @param separator  String containing the String to be used as a delimiter,
7638     *  {@code null} splits on whitespace
7639     * @param max  the maximum number of elements to include in the returned
7640     *  array. A zero or negative value implies no limit.
7641     * @param preserveAllTokens if {@code true}, adjacent separators are
7642     * treated as empty token separators; if {@code false}, adjacent
7643     * separators are treated as one separator.
7644     * @return an array of parsed Strings, {@code null} if null String input
7645     * @since 2.4
7646     */
7647    private static String[] splitByWholeSeparatorWorker(
7648            final String str, final String separator, final int max, final boolean preserveAllTokens) {
7649        if (str == null) {
7650            return null;
7651        }
7652
7653        final int len = str.length();
7654
7655        if (len == 0) {
7656            return ArrayUtils.EMPTY_STRING_ARRAY;
7657        }
7658
7659        if (separator == null || EMPTY.equals(separator)) {
7660            // Split on whitespace.
7661            return splitWorker(str, null, max, preserveAllTokens);
7662        }
7663
7664        final int separatorLength = separator.length();
7665
7666        final ArrayList<String> substrings = new ArrayList<>();
7667        int numberOfSubstrings = 0;
7668        int beg = 0;
7669        int end = 0;
7670        while (end < len) {
7671            end = str.indexOf(separator, beg);
7672
7673            if (end > -1) {
7674                if (end > beg) {
7675                    numberOfSubstrings += 1;
7676
7677                    if (numberOfSubstrings == max) {
7678                        end = len;
7679                        substrings.add(str.substring(beg));
7680                    } else {
7681                        // The following is OK, because String.substring( beg, end ) excludes
7682                        // the character at the position 'end'.
7683                        substrings.add(str.substring(beg, end));
7684
7685                        // Set the starting point for the next search.
7686                        // The following is equivalent to beg = end + (separatorLength - 1) + 1,
7687                        // which is the right calculation:
7688                        beg = end + separatorLength;
7689                    }
7690                } else {
7691                    // We found a consecutive occurrence of the separator, so skip it.
7692                    if (preserveAllTokens) {
7693                        numberOfSubstrings += 1;
7694                        if (numberOfSubstrings == max) {
7695                            end = len;
7696                            substrings.add(str.substring(beg));
7697                        } else {
7698                            substrings.add(EMPTY);
7699                        }
7700                    }
7701                    beg = end + separatorLength;
7702                }
7703            } else {
7704                // String.substring( beg ) goes from 'beg' to the end of the String.
7705                substrings.add(str.substring(beg));
7706                end = len;
7707            }
7708        }
7709
7710        return substrings.toArray(ArrayUtils.EMPTY_STRING_ARRAY);
7711    }
7712
7713    /**
7714     * Splits the provided text into an array, using whitespace as the
7715     * separator, preserving all tokens, including empty tokens created by
7716     * adjacent separators. This is an alternative to using StringTokenizer.
7717     * Whitespace is defined by {@link Character#isWhitespace(char)}.
7718     *
7719     * <p>The separator is not included in the returned String array.
7720     * Adjacent separators are treated as separators for empty tokens.
7721     * For more control over the split use the StrTokenizer class.</p>
7722     *
7723     * <p>A {@code null} input String returns {@code null}.</p>
7724     *
7725     * <pre>
7726     * StringUtils.splitPreserveAllTokens(null)       = null
7727     * StringUtils.splitPreserveAllTokens("")         = []
7728     * StringUtils.splitPreserveAllTokens("abc def")  = ["abc", "def"]
7729     * StringUtils.splitPreserveAllTokens("abc  def") = ["abc", "", "def"]
7730     * StringUtils.splitPreserveAllTokens(" abc ")    = ["", "abc", ""]
7731     * </pre>
7732     *
7733     * @param str  the String to parse, may be {@code null}
7734     * @return an array of parsed Strings, {@code null} if null String input
7735     * @since 2.1
7736     */
7737    public static String[] splitPreserveAllTokens(final String str) {
7738        return splitWorker(str, null, -1, true);
7739    }
7740
7741    /**
7742     * Splits the provided text into an array, separator specified,
7743     * preserving all tokens, including empty tokens created by adjacent
7744     * separators. This is an alternative to using StringTokenizer.
7745     *
7746     * <p>The separator is not included in the returned String array.
7747     * Adjacent separators are treated as separators for empty tokens.
7748     * For more control over the split use the StrTokenizer class.</p>
7749     *
7750     * <p>A {@code null} input String returns {@code null}.</p>
7751     *
7752     * <pre>
7753     * StringUtils.splitPreserveAllTokens(null, *)         = null
7754     * StringUtils.splitPreserveAllTokens("", *)           = []
7755     * StringUtils.splitPreserveAllTokens("a.b.c", '.')    = ["a", "b", "c"]
7756     * StringUtils.splitPreserveAllTokens("a..b.c", '.')   = ["a", "", "b", "c"]
7757     * StringUtils.splitPreserveAllTokens("a:b:c", '.')    = ["a:b:c"]
7758     * StringUtils.splitPreserveAllTokens("a\tb\nc", null) = ["a", "b", "c"]
7759     * StringUtils.splitPreserveAllTokens("a b c", ' ')    = ["a", "b", "c"]
7760     * StringUtils.splitPreserveAllTokens("a b c ", ' ')   = ["a", "b", "c", ""]
7761     * StringUtils.splitPreserveAllTokens("a b c  ", ' ')  = ["a", "b", "c", "", ""]
7762     * StringUtils.splitPreserveAllTokens(" a b c", ' ')   = ["", "a", "b", "c"]
7763     * StringUtils.splitPreserveAllTokens("  a b c", ' ')  = ["", "", "a", "b", "c"]
7764     * StringUtils.splitPreserveAllTokens(" a b c ", ' ')  = ["", "a", "b", "c", ""]
7765     * </pre>
7766     *
7767     * @param str  the String to parse, may be {@code null}
7768     * @param separatorChar  the character used as the delimiter,
7769     *  {@code null} splits on whitespace
7770     * @return an array of parsed Strings, {@code null} if null String input
7771     * @since 2.1
7772     */
7773    public static String[] splitPreserveAllTokens(final String str, final char separatorChar) {
7774        return splitWorker(str, separatorChar, true);
7775    }
7776
7777    /**
7778     * Splits the provided text into an array, separators specified,
7779     * preserving all tokens, including empty tokens created by adjacent
7780     * separators. This is an alternative to using StringTokenizer.
7781     *
7782     * <p>The separator is not included in the returned String array.
7783     * Adjacent separators are treated as separators for empty tokens.
7784     * For more control over the split use the StrTokenizer class.</p>
7785     *
7786     * <p>A {@code null} input String returns {@code null}.
7787     * A {@code null} separatorChars splits on whitespace.</p>
7788     *
7789     * <pre>
7790     * StringUtils.splitPreserveAllTokens(null, *)           = null
7791     * StringUtils.splitPreserveAllTokens("", *)             = []
7792     * StringUtils.splitPreserveAllTokens("abc def", null)   = ["abc", "def"]
7793     * StringUtils.splitPreserveAllTokens("abc def", " ")    = ["abc", "def"]
7794     * StringUtils.splitPreserveAllTokens("abc  def", " ")   = ["abc", "", "def"]
7795     * StringUtils.splitPreserveAllTokens("ab:cd:ef", ":")   = ["ab", "cd", "ef"]
7796     * StringUtils.splitPreserveAllTokens("ab:cd:ef:", ":")  = ["ab", "cd", "ef", ""]
7797     * StringUtils.splitPreserveAllTokens("ab:cd:ef::", ":") = ["ab", "cd", "ef", "", ""]
7798     * StringUtils.splitPreserveAllTokens("ab::cd:ef", ":")  = ["ab", "", "cd", "ef"]
7799     * StringUtils.splitPreserveAllTokens(":cd:ef", ":")     = ["", "cd", "ef"]
7800     * StringUtils.splitPreserveAllTokens("::cd:ef", ":")    = ["", "", "cd", "ef"]
7801     * StringUtils.splitPreserveAllTokens(":cd:ef:", ":")    = ["", "cd", "ef", ""]
7802     * </pre>
7803     *
7804     * @param str  the String to parse, may be {@code null}
7805     * @param separatorChars  the characters used as the delimiters,
7806     *  {@code null} splits on whitespace
7807     * @return an array of parsed Strings, {@code null} if null String input
7808     * @since 2.1
7809     */
7810    public static String[] splitPreserveAllTokens(final String str, final String separatorChars) {
7811        return splitWorker(str, separatorChars, -1, true);
7812    }
7813
7814    /**
7815     * Splits the provided text into an array with a maximum length,
7816     * separators specified, preserving all tokens, including empty tokens
7817     * created by adjacent separators.
7818     *
7819     * <p>The separator is not included in the returned String array.
7820     * Adjacent separators are treated as separators for empty tokens.
7821     * Adjacent separators are treated as one separator.</p>
7822     *
7823     * <p>A {@code null} input String returns {@code null}.
7824     * A {@code null} separatorChars splits on whitespace.</p>
7825     *
7826     * <p>If more than {@code max} delimited substrings are found, the last
7827     * returned string includes all characters after the first {@code max - 1}
7828     * returned strings (including separator characters).</p>
7829     *
7830     * <pre>
7831     * StringUtils.splitPreserveAllTokens(null, *, *)            = null
7832     * StringUtils.splitPreserveAllTokens("", *, *)              = []
7833     * StringUtils.splitPreserveAllTokens("ab de fg", null, 0)   = ["ab", "de", "fg"]
7834     * StringUtils.splitPreserveAllTokens("ab   de fg", null, 0) = ["ab", "", "", "de", "fg"]
7835     * StringUtils.splitPreserveAllTokens("ab:cd:ef", ":", 0)    = ["ab", "cd", "ef"]
7836     * StringUtils.splitPreserveAllTokens("ab:cd:ef", ":", 2)    = ["ab", "cd:ef"]
7837     * StringUtils.splitPreserveAllTokens("ab   de fg", null, 2) = ["ab", "  de fg"]
7838     * StringUtils.splitPreserveAllTokens("ab   de fg", null, 3) = ["ab", "", " de fg"]
7839     * StringUtils.splitPreserveAllTokens("ab   de fg", null, 4) = ["ab", "", "", "de fg"]
7840     * </pre>
7841     *
7842     * @param str  the String to parse, may be {@code null}
7843     * @param separatorChars  the characters used as the delimiters,
7844     *  {@code null} splits on whitespace
7845     * @param max  the maximum number of elements to include in the
7846     *  array. A zero or negative value implies no limit
7847     * @return an array of parsed Strings, {@code null} if null String input
7848     * @since 2.1
7849     */
7850    public static String[] splitPreserveAllTokens(final String str, final String separatorChars, final int max) {
7851        return splitWorker(str, separatorChars, max, true);
7852    }
7853
7854    /**
7855     * Performs the logic for the {@code split} and
7856     * {@code splitPreserveAllTokens} methods that do not return a
7857     * maximum array length.
7858     *
7859     * @param str  the String to parse, may be {@code null}
7860     * @param separatorChar the separate character
7861     * @param preserveAllTokens if {@code true}, adjacent separators are
7862     * treated as empty token separators; if {@code false}, adjacent
7863     * separators are treated as one separator.
7864     * @return an array of parsed Strings, {@code null} if null String input
7865     */
7866    private static String[] splitWorker(final String str, final char separatorChar, final boolean preserveAllTokens) {
7867        // Performance tuned for 2.0 (JDK1.4)
7868        if (str == null) {
7869            return null;
7870        }
7871        final int len = str.length();
7872        if (len == 0) {
7873            return ArrayUtils.EMPTY_STRING_ARRAY;
7874        }
7875        final List<String> list = new ArrayList<>();
7876        int i = 0;
7877        int start = 0;
7878        boolean match = false;
7879        boolean lastMatch = false;
7880        while (i < len) {
7881            if (str.charAt(i) == separatorChar) {
7882                if (match || preserveAllTokens) {
7883                    list.add(str.substring(start, i));
7884                    match = false;
7885                    lastMatch = true;
7886                }
7887                start = ++i;
7888                continue;
7889            }
7890            lastMatch = false;
7891            match = true;
7892            i++;
7893        }
7894        if (match || preserveAllTokens && lastMatch) {
7895            list.add(str.substring(start, i));
7896        }
7897        return list.toArray(ArrayUtils.EMPTY_STRING_ARRAY);
7898    }
7899
7900    /**
7901     * Performs the logic for the {@code split} and
7902     * {@code splitPreserveAllTokens} methods that return a maximum array
7903     * length.
7904     *
7905     * @param str  the String to parse, may be {@code null}
7906     * @param separatorChars the separate character
7907     * @param max  the maximum number of elements to include in the
7908     *  array. A zero or negative value implies no limit.
7909     * @param preserveAllTokens if {@code true}, adjacent separators are
7910     * treated as empty token separators; if {@code false}, adjacent
7911     * separators are treated as one separator.
7912     * @return an array of parsed Strings, {@code null} if null String input
7913     */
7914    private static String[] splitWorker(final String str, final String separatorChars, final int max, final boolean preserveAllTokens) {
7915        // Performance tuned for 2.0 (JDK1.4)
7916        // Direct code is quicker than StringTokenizer.
7917        // Also, StringTokenizer uses isSpace() not isWhitespace()
7918
7919        if (str == null) {
7920            return null;
7921        }
7922        final int len = str.length();
7923        if (len == 0) {
7924            return ArrayUtils.EMPTY_STRING_ARRAY;
7925        }
7926        final List<String> list = new ArrayList<>();
7927        int sizePlus1 = 1;
7928        int i = 0;
7929        int start = 0;
7930        boolean match = false;
7931        boolean lastMatch = false;
7932        if (separatorChars == null) {
7933            // Null separator means use whitespace
7934            while (i < len) {
7935                if (Character.isWhitespace(str.charAt(i))) {
7936                    if (match || preserveAllTokens) {
7937                        lastMatch = true;
7938                        if (sizePlus1++ == max) {
7939                            i = len;
7940                            lastMatch = false;
7941                        }
7942                        list.add(str.substring(start, i));
7943                        match = false;
7944                    }
7945                    start = ++i;
7946                    continue;
7947                }
7948                lastMatch = false;
7949                match = true;
7950                i++;
7951            }
7952        } else if (separatorChars.length() == 1) {
7953            // Optimise 1 character case
7954            final char sep = separatorChars.charAt(0);
7955            while (i < len) {
7956                if (str.charAt(i) == sep) {
7957                    if (match || preserveAllTokens) {
7958                        lastMatch = true;
7959                        if (sizePlus1++ == max) {
7960                            i = len;
7961                            lastMatch = false;
7962                        }
7963                        list.add(str.substring(start, i));
7964                        match = false;
7965                    }
7966                    start = ++i;
7967                    continue;
7968                }
7969                lastMatch = false;
7970                match = true;
7971                i++;
7972            }
7973        } else {
7974            // standard case
7975            while (i < len) {
7976                if (separatorChars.indexOf(str.charAt(i)) >= 0) {
7977                    if (match || preserveAllTokens) {
7978                        lastMatch = true;
7979                        if (sizePlus1++ == max) {
7980                            i = len;
7981                            lastMatch = false;
7982                        }
7983                        list.add(str.substring(start, i));
7984                        match = false;
7985                    }
7986                    start = ++i;
7987                    continue;
7988                }
7989                lastMatch = false;
7990                match = true;
7991                i++;
7992            }
7993        }
7994        if (match || preserveAllTokens && lastMatch) {
7995            list.add(str.substring(start, i));
7996        }
7997        return list.toArray(ArrayUtils.EMPTY_STRING_ARRAY);
7998    }
7999
8000    /**
8001     * Check if a CharSequence starts with a specified prefix.
8002     *
8003     * <p>{@code null}s are handled without exceptions. Two {@code null}
8004     * references are considered to be equal. The comparison is case-sensitive.</p>
8005     *
8006     * <pre>
8007     * StringUtils.startsWith(null, null)      = true
8008     * StringUtils.startsWith(null, "abc")     = false
8009     * StringUtils.startsWith("abcdef", null)  = false
8010     * StringUtils.startsWith("abcdef", "abc") = true
8011     * StringUtils.startsWith("ABCDEF", "abc") = false
8012     * </pre>
8013     *
8014     * @see String#startsWith(String)
8015     * @param str  the CharSequence to check, may be null
8016     * @param prefix the prefix to find, may be null
8017     * @return {@code true} if the CharSequence starts with the prefix, case-sensitive, or
8018     *  both {@code null}
8019     * @since 2.4
8020     * @since 3.0 Changed signature from startsWith(String, String) to startsWith(CharSequence, CharSequence)
8021     */
8022    public static boolean startsWith(final CharSequence str, final CharSequence prefix) {
8023        return startsWith(str, prefix, false);
8024    }
8025
8026    /**
8027     * Check if a CharSequence starts with a specified prefix (optionally case-insensitive).
8028     *
8029     * @see String#startsWith(String)
8030     * @param str  the CharSequence to check, may be null
8031     * @param prefix the prefix to find, may be null
8032     * @param ignoreCase indicates whether the compare should ignore case
8033     *  (case-insensitive) or not.
8034     * @return {@code true} if the CharSequence starts with the prefix or
8035     *  both {@code null}
8036     */
8037    private static boolean startsWith(final CharSequence str, final CharSequence prefix, final boolean ignoreCase) {
8038        if (str == null || prefix == null) {
8039            return str == prefix;
8040        }
8041        // Get length once instead of twice in the unlikely case that it changes.
8042        final int preLen = prefix.length();
8043        if (preLen > str.length()) {
8044            return false;
8045        }
8046        return CharSequenceUtils.regionMatches(str, ignoreCase, 0, prefix, 0, preLen);
8047    }
8048
8049    /**
8050     * Check if a CharSequence starts with any of the provided case-sensitive prefixes.
8051     *
8052     * <pre>
8053     * StringUtils.startsWithAny(null, null)      = false
8054     * StringUtils.startsWithAny(null, new String[] {"abc"})  = false
8055     * StringUtils.startsWithAny("abcxyz", null)     = false
8056     * StringUtils.startsWithAny("abcxyz", new String[] {""}) = true
8057     * StringUtils.startsWithAny("abcxyz", new String[] {"abc"}) = true
8058     * StringUtils.startsWithAny("abcxyz", new String[] {null, "xyz", "abc"}) = true
8059     * StringUtils.startsWithAny("abcxyz", null, "xyz", "ABCX") = false
8060     * StringUtils.startsWithAny("ABCXYZ", null, "xyz", "abc") = false
8061     * </pre>
8062     *
8063     * @param sequence the CharSequence to check, may be null
8064     * @param searchStrings the case-sensitive CharSequence prefixes, may be empty or contain {@code null}
8065     * @see StringUtils#startsWith(CharSequence, CharSequence)
8066     * @return {@code true} if the input {@code sequence} is {@code null} AND no {@code searchStrings} are provided, or
8067     *   the input {@code sequence} begins with any of the provided case-sensitive {@code searchStrings}.
8068     * @since 2.5
8069     * @since 3.0 Changed signature from startsWithAny(String, String[]) to startsWithAny(CharSequence, CharSequence...)
8070     */
8071    public static boolean startsWithAny(final CharSequence sequence, final CharSequence... searchStrings) {
8072        if (isEmpty(sequence) || ArrayUtils.isEmpty(searchStrings)) {
8073            return false;
8074        }
8075        for (final CharSequence searchString : searchStrings) {
8076            if (startsWith(sequence, searchString)) {
8077                return true;
8078            }
8079        }
8080        return false;
8081    }
8082
8083    /**
8084     * Case-insensitive check if a CharSequence starts with a specified prefix.
8085     *
8086     * <p>{@code null}s are handled without exceptions. Two {@code null}
8087     * references are considered to be equal. The comparison is case insensitive.</p>
8088     *
8089     * <pre>
8090     * StringUtils.startsWithIgnoreCase(null, null)      = true
8091     * StringUtils.startsWithIgnoreCase(null, "abc")     = false
8092     * StringUtils.startsWithIgnoreCase("abcdef", null)  = false
8093     * StringUtils.startsWithIgnoreCase("abcdef", "abc") = true
8094     * StringUtils.startsWithIgnoreCase("ABCDEF", "abc") = true
8095     * </pre>
8096     *
8097     * @see String#startsWith(String)
8098     * @param str  the CharSequence to check, may be null
8099     * @param prefix the prefix to find, may be null
8100     * @return {@code true} if the CharSequence starts with the prefix, case-insensitive, or
8101     *  both {@code null}
8102     * @since 2.4
8103     * @since 3.0 Changed signature from startsWithIgnoreCase(String, String) to startsWithIgnoreCase(CharSequence, CharSequence)
8104     */
8105    public static boolean startsWithIgnoreCase(final CharSequence str, final CharSequence prefix) {
8106        return startsWith(str, prefix, true);
8107    }
8108
8109    /**
8110     * Strips whitespace from the start and end of a String.
8111     *
8112     * <p>This is similar to {@link #trim(String)} but removes whitespace.
8113     * Whitespace is defined by {@link Character#isWhitespace(char)}.</p>
8114     *
8115     * <p>A {@code null} input String returns {@code null}.</p>
8116     *
8117     * <pre>
8118     * StringUtils.strip(null)     = null
8119     * StringUtils.strip("")       = ""
8120     * StringUtils.strip("   ")    = ""
8121     * StringUtils.strip("abc")    = "abc"
8122     * StringUtils.strip("  abc")  = "abc"
8123     * StringUtils.strip("abc  ")  = "abc"
8124     * StringUtils.strip(" abc ")  = "abc"
8125     * StringUtils.strip(" ab c ") = "ab c"
8126     * </pre>
8127     *
8128     * @param str  the String to remove whitespace from, may be null
8129     * @return the stripped String, {@code null} if null String input
8130     */
8131    public static String strip(final String str) {
8132        return strip(str, null);
8133    }
8134
8135    /**
8136     * Strips any of a set of characters from the start and end of a String.
8137     * This is similar to {@link String#trim()} but allows the characters
8138     * to be stripped to be controlled.
8139     *
8140     * <p>A {@code null} input String returns {@code null}.
8141     * An empty string ("") input returns the empty string.</p>
8142     *
8143     * <p>If the stripChars String is {@code null}, whitespace is
8144     * stripped as defined by {@link Character#isWhitespace(char)}.
8145     * Alternatively use {@link #strip(String)}.</p>
8146     *
8147     * <pre>
8148     * StringUtils.strip(null, *)          = null
8149     * StringUtils.strip("", *)            = ""
8150     * StringUtils.strip("abc", null)      = "abc"
8151     * StringUtils.strip("  abc", null)    = "abc"
8152     * StringUtils.strip("abc  ", null)    = "abc"
8153     * StringUtils.strip(" abc ", null)    = "abc"
8154     * StringUtils.strip("  abcyx", "xyz") = "  abc"
8155     * </pre>
8156     *
8157     * @param str  the String to remove characters from, may be null
8158     * @param stripChars  the characters to remove, null treated as whitespace
8159     * @return the stripped String, {@code null} if null String input
8160     */
8161    public static String strip(String str, final String stripChars) {
8162        str = stripStart(str, stripChars);
8163        return stripEnd(str, stripChars);
8164    }
8165
8166    /**
8167     * Removes diacritics (~= accents) from a string. The case will not be altered.
8168     * <p>For instance, '&agrave;' will be replaced by 'a'.</p>
8169     * <p>Decomposes ligatures and digraphs per the KD column in the
8170     * <a href = "https://www.unicode.org/charts/normalization/">Unicode Normalization Chart.</a></p>
8171     *
8172     * <pre>
8173     * StringUtils.stripAccents(null)                = null
8174     * StringUtils.stripAccents("")                  = ""
8175     * StringUtils.stripAccents("control")           = "control"
8176     * StringUtils.stripAccents("&eacute;clair")     = "eclair"
8177     * </pre>
8178     *
8179     * @param input String to be stripped
8180     * @return input text with diacritics removed
8181     *
8182     * @since 3.0
8183     */
8184    // See also Lucene's ASCIIFoldingFilter (Lucene 2.9) that replaces accented characters by their unaccented equivalent (and uncommitted bug fix: https://issues.apache.org/jira/browse/LUCENE-1343?focusedCommentId=12858907&page=com.atlassian.jira.plugin.system.issuetabpanels%3Acomment-tabpanel#action_12858907).
8185    public static String stripAccents(final String input) {
8186        if (isEmpty(input)) {
8187            return input;
8188        }
8189        final StringBuilder decomposed = new StringBuilder(Normalizer.normalize(input, Normalizer.Form.NFKD));
8190        convertRemainingAccentCharacters(decomposed);
8191        return STRIP_ACCENTS_PATTERN.matcher(decomposed).replaceAll(EMPTY);
8192    }
8193
8194    /**
8195     * Strips whitespace from the start and end of every String in an array.
8196     * Whitespace is defined by {@link Character#isWhitespace(char)}.
8197     *
8198     * <p>A new array is returned each time, except for length zero.
8199     * A {@code null} array will return {@code null}.
8200     * An empty array will return itself.
8201     * A {@code null} array entry will be ignored.</p>
8202     *
8203     * <pre>
8204     * StringUtils.stripAll(null)             = null
8205     * StringUtils.stripAll([])               = []
8206     * StringUtils.stripAll(["abc", "  abc"]) = ["abc", "abc"]
8207     * StringUtils.stripAll(["abc  ", null])  = ["abc", null]
8208     * </pre>
8209     *
8210     * @param strs  the array to remove whitespace from, may be null
8211     * @return the stripped Strings, {@code null} if null array input
8212     */
8213    public static String[] stripAll(final String... strs) {
8214        return stripAll(strs, null);
8215    }
8216
8217    /**
8218     * Strips any of a set of characters from the start and end of every
8219     * String in an array.
8220     * <p>Whitespace is defined by {@link Character#isWhitespace(char)}.</p>
8221     *
8222     * <p>A new array is returned each time, except for length zero.
8223     * A {@code null} array will return {@code null}.
8224     * An empty array will return itself.
8225     * A {@code null} array entry will be ignored.
8226     * A {@code null} stripChars will strip whitespace as defined by
8227     * {@link Character#isWhitespace(char)}.</p>
8228     *
8229     * <pre>
8230     * StringUtils.stripAll(null, *)                = null
8231     * StringUtils.stripAll([], *)                  = []
8232     * StringUtils.stripAll(["abc", "  abc"], null) = ["abc", "abc"]
8233     * StringUtils.stripAll(["abc  ", null], null)  = ["abc", null]
8234     * StringUtils.stripAll(["abc  ", null], "yz")  = ["abc  ", null]
8235     * StringUtils.stripAll(["yabcz", null], "yz")  = ["abc", null]
8236     * </pre>
8237     *
8238     * @param strs  the array to remove characters from, may be null
8239     * @param stripChars  the characters to remove, null treated as whitespace
8240     * @return the stripped Strings, {@code null} if null array input
8241     */
8242    public static String[] stripAll(final String[] strs, final String stripChars) {
8243        final int strsLen = ArrayUtils.getLength(strs);
8244        if (strsLen == 0) {
8245            return strs;
8246        }
8247        final String[] newArr = new String[strsLen];
8248        Arrays.setAll(newArr, i -> strip(strs[i], stripChars));
8249        return newArr;
8250    }
8251
8252    /**
8253     * Strips any of a set of characters from the end of a String.
8254     *
8255     * <p>A {@code null} input String returns {@code null}.
8256     * An empty string ("") input returns the empty string.</p>
8257     *
8258     * <p>If the stripChars String is {@code null}, whitespace is
8259     * stripped as defined by {@link Character#isWhitespace(char)}.</p>
8260     *
8261     * <pre>
8262     * StringUtils.stripEnd(null, *)          = null
8263     * StringUtils.stripEnd("", *)            = ""
8264     * StringUtils.stripEnd("abc", "")        = "abc"
8265     * StringUtils.stripEnd("abc", null)      = "abc"
8266     * StringUtils.stripEnd("  abc", null)    = "  abc"
8267     * StringUtils.stripEnd("abc  ", null)    = "abc"
8268     * StringUtils.stripEnd(" abc ", null)    = " abc"
8269     * StringUtils.stripEnd("  abcyx", "xyz") = "  abc"
8270     * StringUtils.stripEnd("120.00", ".0")   = "12"
8271     * </pre>
8272     *
8273     * @param str  the String to remove characters from, may be null
8274     * @param stripChars  the set of characters to remove, null treated as whitespace
8275     * @return the stripped String, {@code null} if null String input
8276     */
8277    public static String stripEnd(final String str, final String stripChars) {
8278        int end = length(str);
8279        if (end == 0) {
8280            return str;
8281        }
8282
8283        if (stripChars == null) {
8284            while (end != 0 && Character.isWhitespace(str.charAt(end - 1))) {
8285                end--;
8286            }
8287        } else if (stripChars.isEmpty()) {
8288            return str;
8289        } else {
8290            while (end != 0 && stripChars.indexOf(str.charAt(end - 1)) != INDEX_NOT_FOUND) {
8291                end--;
8292            }
8293        }
8294        return str.substring(0, end);
8295    }
8296
8297    /**
8298     * Strips any of a set of characters from the start of a String.
8299     *
8300     * <p>A {@code null} input String returns {@code null}.
8301     * An empty string ("") input returns the empty string.</p>
8302     *
8303     * <p>If the stripChars String is {@code null}, whitespace is
8304     * stripped as defined by {@link Character#isWhitespace(char)}.</p>
8305     *
8306     * <pre>
8307     * StringUtils.stripStart(null, *)          = null
8308     * StringUtils.stripStart("", *)            = ""
8309     * StringUtils.stripStart("abc", "")        = "abc"
8310     * StringUtils.stripStart("abc", null)      = "abc"
8311     * StringUtils.stripStart("  abc", null)    = "abc"
8312     * StringUtils.stripStart("abc  ", null)    = "abc  "
8313     * StringUtils.stripStart(" abc ", null)    = "abc "
8314     * StringUtils.stripStart("yxabc  ", "xyz") = "abc  "
8315     * </pre>
8316     *
8317     * @param str  the String to remove characters from, may be null
8318     * @param stripChars  the characters to remove, null treated as whitespace
8319     * @return the stripped String, {@code null} if null String input
8320     */
8321    public static String stripStart(final String str, final String stripChars) {
8322        final int strLen = length(str);
8323        if (strLen == 0) {
8324            return str;
8325        }
8326        int start = 0;
8327        if (stripChars == null) {
8328            while (start != strLen && Character.isWhitespace(str.charAt(start))) {
8329                start++;
8330            }
8331        } else if (stripChars.isEmpty()) {
8332            return str;
8333        } else {
8334            while (start != strLen && stripChars.indexOf(str.charAt(start)) != INDEX_NOT_FOUND) {
8335                start++;
8336            }
8337        }
8338        return str.substring(start);
8339    }
8340
8341    /**
8342     * Strips whitespace from the start and end of a String  returning
8343     * an empty String if {@code null} input.
8344     *
8345     * <p>This is similar to {@link #trimToEmpty(String)} but removes whitespace.
8346     * Whitespace is defined by {@link Character#isWhitespace(char)}.</p>
8347     *
8348     * <pre>
8349     * StringUtils.stripToEmpty(null)     = ""
8350     * StringUtils.stripToEmpty("")       = ""
8351     * StringUtils.stripToEmpty("   ")    = ""
8352     * StringUtils.stripToEmpty("abc")    = "abc"
8353     * StringUtils.stripToEmpty("  abc")  = "abc"
8354     * StringUtils.stripToEmpty("abc  ")  = "abc"
8355     * StringUtils.stripToEmpty(" abc ")  = "abc"
8356     * StringUtils.stripToEmpty(" ab c ") = "ab c"
8357     * </pre>
8358     *
8359     * @param str  the String to be stripped, may be null
8360     * @return the trimmed String, or an empty String if {@code null} input
8361     * @since 2.0
8362     */
8363    public static String stripToEmpty(final String str) {
8364        return str == null ? EMPTY : strip(str, null);
8365    }
8366
8367    /**
8368     * Strips whitespace from the start and end of a String  returning
8369     * {@code null} if the String is empty ("") after the strip.
8370     *
8371     * <p>This is similar to {@link #trimToNull(String)} but removes whitespace.
8372     * Whitespace is defined by {@link Character#isWhitespace(char)}.</p>
8373     *
8374     * <pre>
8375     * StringUtils.stripToNull(null)     = null
8376     * StringUtils.stripToNull("")       = null
8377     * StringUtils.stripToNull("   ")    = null
8378     * StringUtils.stripToNull("abc")    = "abc"
8379     * StringUtils.stripToNull("  abc")  = "abc"
8380     * StringUtils.stripToNull("abc  ")  = "abc"
8381     * StringUtils.stripToNull(" abc ")  = "abc"
8382     * StringUtils.stripToNull(" ab c ") = "ab c"
8383     * </pre>
8384     *
8385     * @param str  the String to be stripped, may be null
8386     * @return the stripped String,
8387     *  {@code null} if whitespace, empty or null String input
8388     * @since 2.0
8389     */
8390    public static String stripToNull(String str) {
8391        if (str == null) {
8392            return null;
8393        }
8394        str = strip(str, null);
8395        return str.isEmpty() ? null : str; // NOSONARLINT str cannot be null here
8396    }
8397
8398    /**
8399     * Gets a substring from the specified String avoiding exceptions.
8400     *
8401     * <p>A negative start position can be used to start {@code n}
8402     * characters from the end of the String.</p>
8403     *
8404     * <p>A {@code null} String will return {@code null}.
8405     * An empty ("") String will return "".</p>
8406     *
8407     * <pre>
8408     * StringUtils.substring(null, *)   = null
8409     * StringUtils.substring("", *)     = ""
8410     * StringUtils.substring("abc", 0)  = "abc"
8411     * StringUtils.substring("abc", 2)  = "c"
8412     * StringUtils.substring("abc", 4)  = ""
8413     * StringUtils.substring("abc", -2) = "bc"
8414     * StringUtils.substring("abc", -4) = "abc"
8415     * </pre>
8416     *
8417     * @param str  the String to get the substring from, may be null
8418     * @param start  the position to start from, negative means
8419     *  count back from the end of the String by this many characters
8420     * @return substring from start position, {@code null} if null String input
8421     */
8422    public static String substring(final String str, int start) {
8423        if (str == null) {
8424            return null;
8425        }
8426
8427        // handle negatives, which means last n characters
8428        if (start < 0) {
8429            start = str.length() + start; // remember start is negative
8430        }
8431
8432        if (start < 0) {
8433            start = 0;
8434        }
8435        if (start > str.length()) {
8436            return EMPTY;
8437        }
8438
8439        return str.substring(start);
8440    }
8441
8442    /**
8443     * Gets a substring from the specified String avoiding exceptions.
8444     *
8445     * <p>A negative start position can be used to start/end {@code n}
8446     * characters from the end of the String.</p>
8447     *
8448     * <p>The returned substring starts with the character in the {@code start}
8449     * position and ends before the {@code end} position. All position counting is
8450     * zero-based -- i.e., to start at the beginning of the string use
8451     * {@code start = 0}. Negative start and end positions can be used to
8452     * specify offsets relative to the end of the String.</p>
8453     *
8454     * <p>If {@code start} is not strictly to the left of {@code end}, ""
8455     * is returned.</p>
8456     *
8457     * <pre>
8458     * StringUtils.substring(null, *, *)    = null
8459     * StringUtils.substring("", * ,  *)    = "";
8460     * StringUtils.substring("abc", 0, 2)   = "ab"
8461     * StringUtils.substring("abc", 2, 0)   = ""
8462     * StringUtils.substring("abc", 2, 4)   = "c"
8463     * StringUtils.substring("abc", 4, 6)   = ""
8464     * StringUtils.substring("abc", 2, 2)   = ""
8465     * StringUtils.substring("abc", -2, -1) = "b"
8466     * StringUtils.substring("abc", -4, 2)  = "ab"
8467     * </pre>
8468     *
8469     * @param str  the String to get the substring from, may be null
8470     * @param start  the position to start from, negative means
8471     *  count back from the end of the String by this many characters
8472     * @param end  the position to end at (exclusive), negative means
8473     *  count back from the end of the String by this many characters
8474     * @return substring from start position to end position,
8475     *  {@code null} if null String input
8476     */
8477    public static String substring(final String str, int start, int end) {
8478        if (str == null) {
8479            return null;
8480        }
8481
8482        // handle negatives
8483        if (end < 0) {
8484            end = str.length() + end; // remember end is negative
8485        }
8486        if (start < 0) {
8487            start = str.length() + start; // remember start is negative
8488        }
8489
8490        // check length next
8491        if (end > str.length()) {
8492            end = str.length();
8493        }
8494
8495        // if start is greater than end, return ""
8496        if (start > end) {
8497            return EMPTY;
8498        }
8499
8500        if (start < 0) {
8501            start = 0;
8502        }
8503        if (end < 0) {
8504            end = 0;
8505        }
8506
8507        return str.substring(start, end);
8508    }
8509
8510    /**
8511     * Gets the substring after the first occurrence of a separator.
8512     * The separator is not returned.
8513     *
8514     * <p>A {@code null} string input will return {@code null}.
8515     * An empty ("") string input will return the empty string.
8516     *
8517     * <p>If nothing is found, the empty string is returned.</p>
8518     *
8519     * <pre>
8520     * StringUtils.substringAfter(null, *)      = null
8521     * StringUtils.substringAfter("", *)        = ""
8522     * StringUtils.substringAfter("abc", 'a')   = "bc"
8523     * StringUtils.substringAfter("abcba", 'b') = "cba"
8524     * StringUtils.substringAfter("abc", 'c')   = ""
8525     * StringUtils.substringAfter("abc", 'd')   = ""
8526     * StringUtils.substringAfter(" abc", 32)   = "abc"
8527     * </pre>
8528     *
8529     * @param str  the String to get a substring from, may be null
8530     * @param separator  the character (Unicode code point) to search.
8531     * @return the substring after the first occurrence of the separator,
8532     *  {@code null} if null String input
8533     * @since 3.11
8534     */
8535    public static String substringAfter(final String str, final int separator) {
8536        if (isEmpty(str)) {
8537            return str;
8538        }
8539        final int pos = str.indexOf(separator);
8540        if (pos == INDEX_NOT_FOUND) {
8541            return EMPTY;
8542        }
8543        return str.substring(pos + 1);
8544    }
8545
8546    /**
8547     * Gets the substring after the first occurrence of a separator.
8548     * The separator is not returned.
8549     *
8550     * <p>A {@code null} string input will return {@code null}.
8551     * An empty ("") string input will return the empty string.
8552     * A {@code null} separator will return the empty string if the
8553     * input string is not {@code null}.</p>
8554     *
8555     * <p>If nothing is found, the empty string is returned.</p>
8556     *
8557     * <pre>
8558     * StringUtils.substringAfter(null, *)      = null
8559     * StringUtils.substringAfter("", *)        = ""
8560     * StringUtils.substringAfter(*, null)      = ""
8561     * StringUtils.substringAfter("abc", "a")   = "bc"
8562     * StringUtils.substringAfter("abcba", "b") = "cba"
8563     * StringUtils.substringAfter("abc", "c")   = ""
8564     * StringUtils.substringAfter("abc", "d")   = ""
8565     * StringUtils.substringAfter("abc", "")    = "abc"
8566     * </pre>
8567     *
8568     * @param str  the String to get a substring from, may be null
8569     * @param separator  the String to search for, may be null
8570     * @return the substring after the first occurrence of the separator,
8571     *  {@code null} if null String input
8572     * @since 2.0
8573     */
8574    public static String substringAfter(final String str, final String separator) {
8575        if (isEmpty(str)) {
8576            return str;
8577        }
8578        if (separator == null) {
8579            return EMPTY;
8580        }
8581        final int pos = str.indexOf(separator);
8582        if (pos == INDEX_NOT_FOUND) {
8583            return EMPTY;
8584        }
8585        return str.substring(pos + separator.length());
8586    }
8587
8588    /**
8589     * Gets the substring after the last occurrence of a separator.
8590     * The separator is not returned.
8591     *
8592     * <p>A {@code null} string input will return {@code null}.
8593     * An empty ("") string input will return the empty string.
8594     *
8595     * <p>If nothing is found, the empty string is returned.</p>
8596     *
8597     * <pre>
8598     * StringUtils.substringAfterLast(null, *)      = null
8599     * StringUtils.substringAfterLast("", *)        = ""
8600     * StringUtils.substringAfterLast("abc", 'a')   = "bc"
8601     * StringUtils.substringAfterLast(" bc", 32)    = "bc"
8602     * StringUtils.substringAfterLast("abcba", 'b') = "a"
8603     * StringUtils.substringAfterLast("abc", 'c')   = ""
8604     * StringUtils.substringAfterLast("a", 'a')     = ""
8605     * StringUtils.substringAfterLast("a", 'z')     = ""
8606     * </pre>
8607     *
8608     * @param str  the String to get a substring from, may be null
8609     * @param separator  the character (Unicode code point) to search.
8610     * @return the substring after the last occurrence of the separator,
8611     *  {@code null} if null String input
8612     * @since 3.11
8613     */
8614    public static String substringAfterLast(final String str, final int separator) {
8615        if (isEmpty(str)) {
8616            return str;
8617        }
8618        final int pos = str.lastIndexOf(separator);
8619        if (pos == INDEX_NOT_FOUND || pos == str.length() - 1) {
8620            return EMPTY;
8621        }
8622        return str.substring(pos + 1);
8623    }
8624
8625    /**
8626     * Gets the substring after the last occurrence of a separator.
8627     * The separator is not returned.
8628     *
8629     * <p>A {@code null} string input will return {@code null}.
8630     * An empty ("") string input will return the empty string.
8631     * An empty or {@code null} separator will return the empty string if
8632     * the input string is not {@code null}.</p>
8633     *
8634     * <p>If nothing is found, the empty string is returned.</p>
8635     *
8636     * <pre>
8637     * StringUtils.substringAfterLast(null, *)      = null
8638     * StringUtils.substringAfterLast("", *)        = ""
8639     * StringUtils.substringAfterLast(*, "")        = ""
8640     * StringUtils.substringAfterLast(*, null)      = ""
8641     * StringUtils.substringAfterLast("abc", "a")   = "bc"
8642     * StringUtils.substringAfterLast("abcba", "b") = "a"
8643     * StringUtils.substringAfterLast("abc", "c")   = ""
8644     * StringUtils.substringAfterLast("a", "a")     = ""
8645     * StringUtils.substringAfterLast("a", "z")     = ""
8646     * </pre>
8647     *
8648     * @param str  the String to get a substring from, may be null
8649     * @param separator  the String to search for, may be null
8650     * @return the substring after the last occurrence of the separator,
8651     *  {@code null} if null String input
8652     * @since 2.0
8653     */
8654    public static String substringAfterLast(final String str, final String separator) {
8655        if (isEmpty(str)) {
8656            return str;
8657        }
8658        if (isEmpty(separator)) {
8659            return EMPTY;
8660        }
8661        final int pos = str.lastIndexOf(separator);
8662        if (pos == INDEX_NOT_FOUND || pos == str.length() - separator.length()) {
8663            return EMPTY;
8664        }
8665        return str.substring(pos + separator.length());
8666    }
8667
8668    /**
8669     * Gets the substring before the first occurrence of a separator. The separator is not returned.
8670     *
8671     * <p>
8672     * A {@code null} string input will return {@code null}. An empty ("") string input will return the empty string.
8673     * </p>
8674     *
8675     * <p>
8676     * If nothing is found, the string input is returned.
8677     * </p>
8678     *
8679     * <pre>
8680     * StringUtils.substringBefore(null, *)      = null
8681     * StringUtils.substringBefore("", *)        = ""
8682     * StringUtils.substringBefore("abc", 'a')   = ""
8683     * StringUtils.substringBefore("abcba", 'b') = "a"
8684     * StringUtils.substringBefore("abc", 'c')   = "ab"
8685     * StringUtils.substringBefore("abc", 'd')   = "abc"
8686     * </pre>
8687     *
8688     * @param str the String to get a substring from, may be null
8689     * @param separator the character (Unicode code point) to search.
8690     * @return the substring before the first occurrence of the separator, {@code null} if null String input
8691     * @since 3.12.0
8692     */
8693    public static String substringBefore(final String str, final int separator) {
8694        if (isEmpty(str)) {
8695            return str;
8696        }
8697        final int pos = str.indexOf(separator);
8698        if (pos == INDEX_NOT_FOUND) {
8699            return str;
8700        }
8701        return str.substring(0, pos);
8702    }
8703
8704    /**
8705     * Gets the substring before the first occurrence of a separator.
8706     * The separator is not returned.
8707     *
8708     * <p>A {@code null} string input will return {@code null}.
8709     * An empty ("") string input will return the empty string.
8710     * A {@code null} separator will return the input string.</p>
8711     *
8712     * <p>If nothing is found, the string input is returned.</p>
8713     *
8714     * <pre>
8715     * StringUtils.substringBefore(null, *)      = null
8716     * StringUtils.substringBefore("", *)        = ""
8717     * StringUtils.substringBefore("abc", "a")   = ""
8718     * StringUtils.substringBefore("abcba", "b") = "a"
8719     * StringUtils.substringBefore("abc", "c")   = "ab"
8720     * StringUtils.substringBefore("abc", "d")   = "abc"
8721     * StringUtils.substringBefore("abc", "")    = ""
8722     * StringUtils.substringBefore("abc", null)  = "abc"
8723     * </pre>
8724     *
8725     * @param str  the String to get a substring from, may be null
8726     * @param separator  the String to search for, may be null
8727     * @return the substring before the first occurrence of the separator,
8728     *  {@code null} if null String input
8729     * @since 2.0
8730     */
8731    public static String substringBefore(final String str, final String separator) {
8732        if (isEmpty(str) || separator == null) {
8733            return str;
8734        }
8735        if (separator.isEmpty()) {
8736            return EMPTY;
8737        }
8738        final int pos = str.indexOf(separator);
8739        if (pos == INDEX_NOT_FOUND) {
8740            return str;
8741        }
8742        return str.substring(0, pos);
8743    }
8744
8745    /**
8746     * Gets the substring before the last occurrence of a separator.
8747     * The separator is not returned.
8748     *
8749     * <p>A {@code null} string input will return {@code null}.
8750     * An empty ("") string input will return the empty string.
8751     * An empty or {@code null} separator will return the input string.</p>
8752     *
8753     * <p>If nothing is found, the string input is returned.</p>
8754     *
8755     * <pre>
8756     * StringUtils.substringBeforeLast(null, *)      = null
8757     * StringUtils.substringBeforeLast("", *)        = ""
8758     * StringUtils.substringBeforeLast("abcba", "b") = "abc"
8759     * StringUtils.substringBeforeLast("abc", "c")   = "ab"
8760     * StringUtils.substringBeforeLast("a", "a")     = ""
8761     * StringUtils.substringBeforeLast("a", "z")     = "a"
8762     * StringUtils.substringBeforeLast("a", null)    = "a"
8763     * StringUtils.substringBeforeLast("a", "")      = "a"
8764     * </pre>
8765     *
8766     * @param str  the String to get a substring from, may be null
8767     * @param separator  the String to search for, may be null
8768     * @return the substring before the last occurrence of the separator,
8769     *  {@code null} if null String input
8770     * @since 2.0
8771     */
8772    public static String substringBeforeLast(final String str, final String separator) {
8773        if (isEmpty(str) || isEmpty(separator)) {
8774            return str;
8775        }
8776        final int pos = str.lastIndexOf(separator);
8777        if (pos == INDEX_NOT_FOUND) {
8778            return str;
8779        }
8780        return str.substring(0, pos);
8781    }
8782
8783    /**
8784     * Gets the String that is nested in between two instances of the
8785     * same String.
8786     *
8787     * <p>A {@code null} input String returns {@code null}.
8788     * A {@code null} tag returns {@code null}.</p>
8789     *
8790     * <pre>
8791     * StringUtils.substringBetween(null, *)            = null
8792     * StringUtils.substringBetween("", "")             = ""
8793     * StringUtils.substringBetween("", "tag")          = null
8794     * StringUtils.substringBetween("tagabctag", null)  = null
8795     * StringUtils.substringBetween("tagabctag", "")    = ""
8796     * StringUtils.substringBetween("tagabctag", "tag") = "abc"
8797     * </pre>
8798     *
8799     * @param str  the String containing the substring, may be null
8800     * @param tag  the String before and after the substring, may be null
8801     * @return the substring, {@code null} if no match
8802     * @since 2.0
8803     */
8804    public static String substringBetween(final String str, final String tag) {
8805        return substringBetween(str, tag, tag);
8806    }
8807
8808    /**
8809     * Gets the String that is nested in between two Strings.
8810     * Only the first match is returned.
8811     *
8812     * <p>A {@code null} input String returns {@code null}.
8813     * A {@code null} open/close returns {@code null} (no match).
8814     * An empty ("") open and close returns an empty string.</p>
8815     *
8816     * <pre>
8817     * StringUtils.substringBetween("wx[b]yz", "[", "]") = "b"
8818     * StringUtils.substringBetween(null, *, *)          = null
8819     * StringUtils.substringBetween(*, null, *)          = null
8820     * StringUtils.substringBetween(*, *, null)          = null
8821     * StringUtils.substringBetween("", "", "")          = ""
8822     * StringUtils.substringBetween("", "", "]")         = null
8823     * StringUtils.substringBetween("", "[", "]")        = null
8824     * StringUtils.substringBetween("yabcz", "", "")     = ""
8825     * StringUtils.substringBetween("yabcz", "y", "z")   = "abc"
8826     * StringUtils.substringBetween("yabczyabcz", "y", "z")   = "abc"
8827     * </pre>
8828     *
8829     * @param str  the String containing the substring, may be null
8830     * @param open  the String before the substring, may be null
8831     * @param close  the String after the substring, may be null
8832     * @return the substring, {@code null} if no match
8833     * @since 2.0
8834     */
8835    public static String substringBetween(final String str, final String open, final String close) {
8836        if (!ObjectUtils.allNotNull(str, open, close)) {
8837            return null;
8838        }
8839        final int start = str.indexOf(open);
8840        if (start != INDEX_NOT_FOUND) {
8841            final int end = str.indexOf(close, start + open.length());
8842            if (end != INDEX_NOT_FOUND) {
8843                return str.substring(start + open.length(), end);
8844            }
8845        }
8846        return null;
8847    }
8848
8849    /**
8850     * Searches a String for substrings delimited by a start and end tag,
8851     * returning all matching substrings in an array.
8852     *
8853     * <p>A {@code null} input String returns {@code null}.
8854     * A {@code null} open/close returns {@code null} (no match).
8855     * An empty ("") open/close returns {@code null} (no match).</p>
8856     *
8857     * <pre>
8858     * StringUtils.substringsBetween("[a][b][c]", "[", "]") = ["a","b","c"]
8859     * StringUtils.substringsBetween(null, *, *)            = null
8860     * StringUtils.substringsBetween(*, null, *)            = null
8861     * StringUtils.substringsBetween(*, *, null)            = null
8862     * StringUtils.substringsBetween("", "[", "]")          = []
8863     * </pre>
8864     *
8865     * @param str  the String containing the substrings, null returns null, empty returns empty
8866     * @param open  the String identifying the start of the substring, empty returns null
8867     * @param close  the String identifying the end of the substring, empty returns null
8868     * @return a String Array of substrings, or {@code null} if no match
8869     * @since 2.3
8870     */
8871    public static String[] substringsBetween(final String str, final String open, final String close) {
8872        if (str == null || isEmpty(open) || isEmpty(close)) {
8873            return null;
8874        }
8875        final int strLen = str.length();
8876        if (strLen == 0) {
8877            return ArrayUtils.EMPTY_STRING_ARRAY;
8878        }
8879        final int closeLen = close.length();
8880        final int openLen = open.length();
8881        final List<String> list = new ArrayList<>();
8882        int pos = 0;
8883        while (pos < strLen - closeLen) {
8884            int start = str.indexOf(open, pos);
8885            if (start < 0) {
8886                break;
8887            }
8888            start += openLen;
8889            final int end = str.indexOf(close, start);
8890            if (end < 0) {
8891                break;
8892            }
8893            list.add(str.substring(start, end));
8894            pos = end + closeLen;
8895        }
8896        if (list.isEmpty()) {
8897            return null;
8898        }
8899        return list.toArray(ArrayUtils.EMPTY_STRING_ARRAY);
8900    }
8901
8902    /**
8903     * Swaps the case of a String changing upper and title case to
8904     * lower case, and lower case to upper case.
8905     *
8906     * <ul>
8907     *  <li>Upper case character converts to Lower case</li>
8908     *  <li>Title case character converts to Lower case</li>
8909     *  <li>Lower case character converts to Upper case</li>
8910     * </ul>
8911     *
8912     * <p>For a word based algorithm, see {@link org.apache.commons.text.WordUtils#swapCase(String)}.
8913     * A {@code null} input String returns {@code null}.</p>
8914     *
8915     * <pre>
8916     * StringUtils.swapCase(null)                 = null
8917     * StringUtils.swapCase("")                   = ""
8918     * StringUtils.swapCase("The dog has a BONE") = "tHE DOG HAS A bone"
8919     * </pre>
8920     *
8921     * <p>NOTE: This method changed in Lang version 2.0.
8922     * It no longer performs a word based algorithm.
8923     * If you only use ASCII, you will notice no change.
8924     * That functionality is available in org.apache.commons.lang3.text.WordUtils.</p>
8925     *
8926     * @param str  the String to swap case, may be null
8927     * @return the changed String, {@code null} if null String input
8928     */
8929    public static String swapCase(final String str) {
8930        if (isEmpty(str)) {
8931            return str;
8932        }
8933
8934        final int strLen = str.length();
8935        final int[] newCodePoints = new int[strLen]; // cannot be longer than the char array
8936        int outOffset = 0;
8937        for (int i = 0; i < strLen; ) {
8938            final int oldCodepoint = str.codePointAt(i);
8939            final int newCodePoint;
8940            if (Character.isUpperCase(oldCodepoint) || Character.isTitleCase(oldCodepoint)) {
8941                newCodePoint = Character.toLowerCase(oldCodepoint);
8942            } else if (Character.isLowerCase(oldCodepoint)) {
8943                newCodePoint = Character.toUpperCase(oldCodepoint);
8944            } else {
8945                newCodePoint = oldCodepoint;
8946            }
8947            newCodePoints[outOffset++] = newCodePoint;
8948            i += Character.charCount(newCodePoint);
8949         }
8950        return new String(newCodePoints, 0, outOffset);
8951    }
8952
8953    /**
8954     * Converts a {@link CharSequence} into an array of code points.
8955     *
8956     * <p>Valid pairs of surrogate code units will be converted into a single supplementary
8957     * code point. Isolated surrogate code units (i.e. a high surrogate not followed by a low surrogate or
8958     * a low surrogate not preceded by a high surrogate) will be returned as-is.</p>
8959     *
8960     * <pre>
8961     * StringUtils.toCodePoints(null)   =  null
8962     * StringUtils.toCodePoints("")     =  []  // empty array
8963     * </pre>
8964     *
8965     * @param cs the character sequence to convert
8966     * @return an array of code points
8967     * @since 3.6
8968     */
8969    public static int[] toCodePoints(final CharSequence cs) {
8970        if (cs == null) {
8971            return null;
8972        }
8973        if (cs.length() == 0) {
8974            return ArrayUtils.EMPTY_INT_ARRAY;
8975        }
8976
8977        final String s = cs.toString();
8978        final int[] result = new int[s.codePointCount(0, s.length())];
8979        int index = 0;
8980        for (int i = 0; i < result.length; i++) {
8981            result[i] = s.codePointAt(index);
8982            index += Character.charCount(result[i]);
8983        }
8984        return result;
8985    }
8986
8987    /**
8988     * Converts a {@code byte[]} to a String using the specified character encoding.
8989     *
8990     * @param bytes
8991     *            the byte array to read from
8992     * @param charset
8993     *            the encoding to use, if null then use the platform default
8994     * @return a new String
8995     * @throws NullPointerException
8996     *             if {@code bytes} is null
8997     * @since 3.2
8998     * @since 3.3 No longer throws {@link UnsupportedEncodingException}.
8999     */
9000    public static String toEncodedString(final byte[] bytes, final Charset charset) {
9001        return new String(bytes, Charsets.toCharset(charset));
9002    }
9003
9004    /**
9005     * Converts the given source String as a lower-case using the {@link Locale#ROOT} locale in a null-safe manner.
9006     *
9007     * @param source A source String or null.
9008     * @return the given source String as a lower-case using the {@link Locale#ROOT} locale or null.
9009     * @since 3.10
9010     */
9011    public static String toRootLowerCase(final String source) {
9012        return source == null ? null : source.toLowerCase(Locale.ROOT);
9013    }
9014
9015    /**
9016     * Converts the given source String as an upper-case using the {@link Locale#ROOT} locale in a null-safe manner.
9017     *
9018     * @param source A source String or null.
9019     * @return the given source String as an upper-case using the {@link Locale#ROOT} locale or null.
9020     * @since 3.10
9021     */
9022    public static String toRootUpperCase(final String source) {
9023        return source == null ? null : source.toUpperCase(Locale.ROOT);
9024    }
9025
9026    /**
9027     * Converts a {@code byte[]} to a String using the specified character encoding.
9028     *
9029     * @param bytes
9030     *            the byte array to read from
9031     * @param charsetName
9032     *            the encoding to use, if null then use the platform default
9033     * @return a new String
9034     * @throws NullPointerException
9035     *             if the input is null
9036     * @deprecated use {@link StringUtils#toEncodedString(byte[], Charset)} instead of String constants in your code
9037     * @since 3.1
9038     */
9039    @Deprecated
9040    public static String toString(final byte[] bytes, final String charsetName) {
9041        return new String(bytes, Charsets.toCharset(charsetName));
9042    }
9043
9044    private static String toStringOrEmpty(final Object obj) {
9045        return Objects.toString(obj, EMPTY);
9046    }
9047
9048    /**
9049     * Removes control characters (char &lt;= 32) from both
9050     * ends of this String, handling {@code null} by returning
9051     * {@code null}.
9052     *
9053     * <p>The String is trimmed using {@link String#trim()}.
9054     * Trim removes start and end characters &lt;= 32.
9055     * To strip whitespace use {@link #strip(String)}.</p>
9056     *
9057     * <p>To trim your choice of characters, use the
9058     * {@link #strip(String, String)} methods.</p>
9059     *
9060     * <pre>
9061     * StringUtils.trim(null)          = null
9062     * StringUtils.trim("")            = ""
9063     * StringUtils.trim("     ")       = ""
9064     * StringUtils.trim("abc")         = "abc"
9065     * StringUtils.trim("    abc    ") = "abc"
9066     * </pre>
9067     *
9068     * @param str  the String to be trimmed, may be null
9069     * @return the trimmed string, {@code null} if null String input
9070     */
9071    public static String trim(final String str) {
9072        return str == null ? null : str.trim();
9073    }
9074
9075    /**
9076     * Removes control characters (char &lt;= 32) from both
9077     * ends of this String returning an empty String ("") if the String
9078     * is empty ("") after the trim or if it is {@code null}.
9079     *
9080     * <p>The String is trimmed using {@link String#trim()}.
9081     * Trim removes start and end characters &lt;= 32.
9082     * To strip whitespace use {@link #stripToEmpty(String)}.
9083     *
9084     * <pre>
9085     * StringUtils.trimToEmpty(null)          = ""
9086     * StringUtils.trimToEmpty("")            = ""
9087     * StringUtils.trimToEmpty("     ")       = ""
9088     * StringUtils.trimToEmpty("abc")         = "abc"
9089     * StringUtils.trimToEmpty("    abc    ") = "abc"
9090     * </pre>
9091     *
9092     * @param str  the String to be trimmed, may be null
9093     * @return the trimmed String, or an empty String if {@code null} input
9094     * @since 2.0
9095     */
9096    public static String trimToEmpty(final String str) {
9097        return str == null ? EMPTY : str.trim();
9098    }
9099
9100    /**
9101     * Removes control characters (char &lt;= 32) from both
9102     * ends of this String returning {@code null} if the String is
9103     * empty ("") after the trim or if it is {@code null}.
9104     *
9105     * <p>The String is trimmed using {@link String#trim()}.
9106     * Trim removes start and end characters &lt;= 32.
9107     * To strip whitespace use {@link #stripToNull(String)}.
9108     *
9109     * <pre>
9110     * StringUtils.trimToNull(null)          = null
9111     * StringUtils.trimToNull("")            = null
9112     * StringUtils.trimToNull("     ")       = null
9113     * StringUtils.trimToNull("abc")         = "abc"
9114     * StringUtils.trimToNull("    abc    ") = "abc"
9115     * </pre>
9116     *
9117     * @param str  the String to be trimmed, may be null
9118     * @return the trimmed String,
9119     *  {@code null} if only chars &lt;= 32, empty or null String input
9120     * @since 2.0
9121     */
9122    public static String trimToNull(final String str) {
9123        final String ts = trim(str);
9124        return isEmpty(ts) ? null : ts;
9125    }
9126
9127    /**
9128     * Truncates a String. This will turn
9129     * "Now is the time for all good men" into "Now is the time for".
9130     *
9131     * <p>Specifically:</p>
9132     * <ul>
9133     *   <li>If {@code str} is less than {@code maxWidth} characters
9134     *       long, return it.</li>
9135     *   <li>Else truncate it to {@code substring(str, 0, maxWidth)}.</li>
9136     *   <li>If {@code maxWidth} is less than {@code 0}, throw an
9137     *       {@link IllegalArgumentException}.</li>
9138     *   <li>In no case will it return a String of length greater than
9139     *       {@code maxWidth}.</li>
9140     * </ul>
9141     *
9142     * <pre>
9143     * StringUtils.truncate(null, 0)       = null
9144     * StringUtils.truncate(null, 2)       = null
9145     * StringUtils.truncate("", 4)         = ""
9146     * StringUtils.truncate("abcdefg", 4)  = "abcd"
9147     * StringUtils.truncate("abcdefg", 6)  = "abcdef"
9148     * StringUtils.truncate("abcdefg", 7)  = "abcdefg"
9149     * StringUtils.truncate("abcdefg", 8)  = "abcdefg"
9150     * StringUtils.truncate("abcdefg", -1) = throws an IllegalArgumentException
9151     * </pre>
9152     *
9153     * @param str  the String to truncate, may be null
9154     * @param maxWidth  maximum length of result String, must be positive
9155     * @return truncated String, {@code null} if null String input
9156     * @throws IllegalArgumentException If {@code maxWidth} is less than {@code 0}
9157     * @since 3.5
9158     */
9159    public static String truncate(final String str, final int maxWidth) {
9160        return truncate(str, 0, maxWidth);
9161    }
9162
9163    /**
9164     * Truncates a String. This will turn
9165     * "Now is the time for all good men" into "is the time for all".
9166     *
9167     * <p>Works like {@code truncate(String, int)}, but allows you to specify
9168     * a "left edge" offset.
9169     *
9170     * <p>Specifically:</p>
9171     * <ul>
9172     *   <li>If {@code str} is less than {@code maxWidth} characters
9173     *       long, return it.</li>
9174     *   <li>Else truncate it to {@code substring(str, offset, maxWidth)}.</li>
9175     *   <li>If {@code maxWidth} is less than {@code 0}, throw an
9176     *       {@link IllegalArgumentException}.</li>
9177     *   <li>If {@code offset} is less than {@code 0}, throw an
9178     *       {@link IllegalArgumentException}.</li>
9179     *   <li>In no case will it return a String of length greater than
9180     *       {@code maxWidth}.</li>
9181     * </ul>
9182     *
9183     * <pre>
9184     * StringUtils.truncate(null, 0, 0) = null
9185     * StringUtils.truncate(null, 2, 4) = null
9186     * StringUtils.truncate("", 0, 10) = ""
9187     * StringUtils.truncate("", 2, 10) = ""
9188     * StringUtils.truncate("abcdefghij", 0, 3) = "abc"
9189     * StringUtils.truncate("abcdefghij", 5, 6) = "fghij"
9190     * StringUtils.truncate("raspberry peach", 10, 15) = "peach"
9191     * StringUtils.truncate("abcdefghijklmno", 0, 10) = "abcdefghij"
9192     * StringUtils.truncate("abcdefghijklmno", -1, 10) = throws an IllegalArgumentException
9193     * StringUtils.truncate("abcdefghijklmno", Integer.MIN_VALUE, 10) = throws an IllegalArgumentException
9194     * StringUtils.truncate("abcdefghijklmno", Integer.MIN_VALUE, Integer.MAX_VALUE) = throws an IllegalArgumentException
9195     * StringUtils.truncate("abcdefghijklmno", 0, Integer.MAX_VALUE) = "abcdefghijklmno"
9196     * StringUtils.truncate("abcdefghijklmno", 1, 10) = "bcdefghijk"
9197     * StringUtils.truncate("abcdefghijklmno", 2, 10) = "cdefghijkl"
9198     * StringUtils.truncate("abcdefghijklmno", 3, 10) = "defghijklm"
9199     * StringUtils.truncate("abcdefghijklmno", 4, 10) = "efghijklmn"
9200     * StringUtils.truncate("abcdefghijklmno", 5, 10) = "fghijklmno"
9201     * StringUtils.truncate("abcdefghijklmno", 5, 5) = "fghij"
9202     * StringUtils.truncate("abcdefghijklmno", 5, 3) = "fgh"
9203     * StringUtils.truncate("abcdefghijklmno", 10, 3) = "klm"
9204     * StringUtils.truncate("abcdefghijklmno", 10, Integer.MAX_VALUE) = "klmno"
9205     * StringUtils.truncate("abcdefghijklmno", 13, 1) = "n"
9206     * StringUtils.truncate("abcdefghijklmno", 13, Integer.MAX_VALUE) = "no"
9207     * StringUtils.truncate("abcdefghijklmno", 14, 1) = "o"
9208     * StringUtils.truncate("abcdefghijklmno", 14, Integer.MAX_VALUE) = "o"
9209     * StringUtils.truncate("abcdefghijklmno", 15, 1) = ""
9210     * StringUtils.truncate("abcdefghijklmno", 15, Integer.MAX_VALUE) = ""
9211     * StringUtils.truncate("abcdefghijklmno", Integer.MAX_VALUE, Integer.MAX_VALUE) = ""
9212     * StringUtils.truncate("abcdefghij", 3, -1) = throws an IllegalArgumentException
9213     * StringUtils.truncate("abcdefghij", -2, 4) = throws an IllegalArgumentException
9214     * </pre>
9215     *
9216     * @param str  the String to truncate, may be null
9217     * @param offset  left edge of source String
9218     * @param maxWidth  maximum length of result String, must be positive
9219     * @return truncated String, {@code null} if null String input
9220     * @throws IllegalArgumentException If {@code offset} or {@code maxWidth} is less than {@code 0}
9221     * @since 3.5
9222     */
9223    public static String truncate(final String str, final int offset, final int maxWidth) {
9224        if (offset < 0) {
9225            throw new IllegalArgumentException("offset cannot be negative");
9226        }
9227        if (maxWidth < 0) {
9228            throw new IllegalArgumentException("maxWith cannot be negative");
9229        }
9230        if (str == null) {
9231            return null;
9232        }
9233        if (offset > str.length()) {
9234            return EMPTY;
9235        }
9236        if (str.length() > maxWidth) {
9237            final int ix = Math.min(offset + maxWidth, str.length());
9238            return str.substring(offset, ix);
9239        }
9240        return str.substring(offset);
9241    }
9242
9243    /**
9244     * Uncapitalizes a String, changing the first character to lower case as
9245     * per {@link Character#toLowerCase(int)}. No other characters are changed.
9246     *
9247     * <p>For a word based algorithm, see {@link org.apache.commons.text.WordUtils#uncapitalize(String)}.
9248     * A {@code null} input String returns {@code null}.</p>
9249     *
9250     * <pre>
9251     * StringUtils.uncapitalize(null)  = null
9252     * StringUtils.uncapitalize("")    = ""
9253     * StringUtils.uncapitalize("cat") = "cat"
9254     * StringUtils.uncapitalize("Cat") = "cat"
9255     * StringUtils.uncapitalize("CAT") = "cAT"
9256     * </pre>
9257     *
9258     * @param str the String to uncapitalize, may be null
9259     * @return the uncapitalized String, {@code null} if null String input
9260     * @see org.apache.commons.text.WordUtils#uncapitalize(String)
9261     * @see #capitalize(String)
9262     * @since 2.0
9263     */
9264    public static String uncapitalize(final String str) {
9265        final int strLen = length(str);
9266        if (strLen == 0) {
9267            return str;
9268        }
9269
9270        final int firstCodePoint = str.codePointAt(0);
9271        final int newCodePoint = Character.toLowerCase(firstCodePoint);
9272        if (firstCodePoint == newCodePoint) {
9273            // already capitalized
9274            return str;
9275        }
9276
9277        final int[] newCodePoints = new int[strLen]; // cannot be longer than the char array
9278        int outOffset = 0;
9279        newCodePoints[outOffset++] = newCodePoint; // copy the first code point
9280        for (int inOffset = Character.charCount(firstCodePoint); inOffset < strLen; ) {
9281            final int codePoint = str.codePointAt(inOffset);
9282            newCodePoints[outOffset++] = codePoint; // copy the remaining ones
9283            inOffset += Character.charCount(codePoint);
9284         }
9285        return new String(newCodePoints, 0, outOffset);
9286    }
9287
9288    /**
9289     * Unwraps a given string from a character.
9290     *
9291     * <pre>
9292     * StringUtils.unwrap(null, null)         = null
9293     * StringUtils.unwrap(null, '\0')         = null
9294     * StringUtils.unwrap(null, '1')          = null
9295     * StringUtils.unwrap("a", 'a')           = "a"
9296     * StringUtils.unwrap("aa", 'a')           = ""
9297     * StringUtils.unwrap("\'abc\'", '\'')    = "abc"
9298     * StringUtils.unwrap("AABabcBAA", 'A')   = "ABabcBA"
9299     * StringUtils.unwrap("A", '#')           = "A"
9300     * StringUtils.unwrap("#A", '#')          = "#A"
9301     * StringUtils.unwrap("A#", '#')          = "A#"
9302     * </pre>
9303     *
9304     * @param str
9305     *          the String to be unwrapped, can be null
9306     * @param wrapChar
9307     *          the character used to unwrap
9308     * @return unwrapped String or the original string
9309     *          if it is not quoted properly with the wrapChar
9310     * @since 3.6
9311     */
9312    public static String unwrap(final String str, final char wrapChar) {
9313        if (isEmpty(str) || wrapChar == CharUtils.NUL || str.length() == 1) {
9314            return str;
9315        }
9316
9317        if (str.charAt(0) == wrapChar && str.charAt(str.length() - 1) == wrapChar) {
9318            final int startIndex = 0;
9319            final int endIndex = str.length() - 1;
9320
9321            return str.substring(startIndex + 1, endIndex);
9322        }
9323
9324        return str;
9325    }
9326
9327    /**
9328     * Unwraps a given string from another string.
9329     *
9330     * <pre>
9331     * StringUtils.unwrap(null, null)         = null
9332     * StringUtils.unwrap(null, "")           = null
9333     * StringUtils.unwrap(null, "1")          = null
9334     * StringUtils.unwrap("a", "a")           = "a"
9335     * StringUtils.unwrap("aa", "a")          = ""
9336     * StringUtils.unwrap("\'abc\'", "\'")    = "abc"
9337     * StringUtils.unwrap("\"abc\"", "\"")    = "abc"
9338     * StringUtils.unwrap("AABabcBAA", "AA")  = "BabcB"
9339     * StringUtils.unwrap("A", "#")           = "A"
9340     * StringUtils.unwrap("#A", "#")          = "#A"
9341     * StringUtils.unwrap("A#", "#")          = "A#"
9342     * </pre>
9343     *
9344     * @param str
9345     *          the String to be unwrapped, can be null
9346     * @param wrapToken
9347     *          the String used to unwrap
9348     * @return unwrapped String or the original string
9349     *          if it is not quoted properly with the wrapToken
9350     * @since 3.6
9351     */
9352    public static String unwrap(final String str, final String wrapToken) {
9353        if (isEmpty(str) || isEmpty(wrapToken) || str.length() < 2 * wrapToken.length()) {
9354            return str;
9355        }
9356
9357        if (startsWith(str, wrapToken) && endsWith(str, wrapToken)) {
9358            return str.substring(wrapToken.length(), str.lastIndexOf(wrapToken));
9359        }
9360
9361        return str;
9362    }
9363
9364    /**
9365     * Converts a String to upper case as per {@link String#toUpperCase()}.
9366     *
9367     * <p>A {@code null} input String returns {@code null}.</p>
9368     *
9369     * <pre>
9370     * StringUtils.upperCase(null)  = null
9371     * StringUtils.upperCase("")    = ""
9372     * StringUtils.upperCase("aBc") = "ABC"
9373     * </pre>
9374     *
9375     * <p><strong>Note:</strong> As described in the documentation for {@link String#toUpperCase()},
9376     * the result of this method is affected by the current locale.
9377     * For platform-independent case transformations, the method {@link #upperCase(String, Locale)}
9378     * should be used with a specific locale (e.g. {@link Locale#ENGLISH}).</p>
9379     *
9380     * @param str  the String to upper case, may be null
9381     * @return the upper-cased String, {@code null} if null String input
9382     */
9383    public static String upperCase(final String str) {
9384        if (str == null) {
9385            return null;
9386        }
9387        return str.toUpperCase();
9388    }
9389
9390    /**
9391     * Converts a String to upper case as per {@link String#toUpperCase(Locale)}.
9392     *
9393     * <p>A {@code null} input String returns {@code null}.</p>
9394     *
9395     * <pre>
9396     * StringUtils.upperCase(null, Locale.ENGLISH)  = null
9397     * StringUtils.upperCase("", Locale.ENGLISH)    = ""
9398     * StringUtils.upperCase("aBc", Locale.ENGLISH) = "ABC"
9399     * </pre>
9400     *
9401     * @param str  the String to upper case, may be null
9402     * @param locale  the locale that defines the case transformation rules, must not be null
9403     * @return the upper-cased String, {@code null} if null String input
9404     * @since 2.5
9405     */
9406    public static String upperCase(final String str, final Locale locale) {
9407        if (str == null) {
9408            return null;
9409        }
9410        return str.toUpperCase(LocaleUtils.toLocale(locale));
9411    }
9412
9413    /**
9414     * Returns the string representation of the {@code char} array or null.
9415     *
9416     * @param value the character array.
9417     * @return a String or null
9418     * @see String#valueOf(char[])
9419     * @since 3.9
9420     */
9421    public static String valueOf(final char[] value) {
9422        return value == null ? null : String.valueOf(value);
9423    }
9424
9425    /**
9426     * Wraps a string with a char.
9427     *
9428     * <pre>
9429     * StringUtils.wrap(null, *)        = null
9430     * StringUtils.wrap("", *)          = ""
9431     * StringUtils.wrap("ab", '\0')     = "ab"
9432     * StringUtils.wrap("ab", 'x')      = "xabx"
9433     * StringUtils.wrap("ab", '\'')     = "'ab'"
9434     * StringUtils.wrap("\"ab\"", '\"') = "\"\"ab\"\""
9435     * </pre>
9436     *
9437     * @param str
9438     *            the string to be wrapped, may be {@code null}
9439     * @param wrapWith
9440     *            the char that will wrap {@code str}
9441     * @return the wrapped string, or {@code null} if {@code str == null}
9442     * @since 3.4
9443     */
9444    public static String wrap(final String str, final char wrapWith) {
9445
9446        if (isEmpty(str) || wrapWith == CharUtils.NUL) {
9447            return str;
9448        }
9449
9450        return wrapWith + str + wrapWith;
9451    }
9452
9453    /**
9454     * Wraps a String with another String.
9455     *
9456     * <p>
9457     * A {@code null} input String returns {@code null}.
9458     * </p>
9459     *
9460     * <pre>
9461     * StringUtils.wrap(null, *)         = null
9462     * StringUtils.wrap("", *)           = ""
9463     * StringUtils.wrap("ab", null)      = "ab"
9464     * StringUtils.wrap("ab", "x")       = "xabx"
9465     * StringUtils.wrap("ab", "\"")      = "\"ab\""
9466     * StringUtils.wrap("\"ab\"", "\"")  = "\"\"ab\"\""
9467     * StringUtils.wrap("ab", "'")       = "'ab'"
9468     * StringUtils.wrap("'abcd'", "'")   = "''abcd''"
9469     * StringUtils.wrap("\"abcd\"", "'") = "'\"abcd\"'"
9470     * StringUtils.wrap("'abcd'", "\"")  = "\"'abcd'\""
9471     * </pre>
9472     *
9473     * @param str
9474     *            the String to be wrapper, may be null
9475     * @param wrapWith
9476     *            the String that will wrap str
9477     * @return wrapped String, {@code null} if null String input
9478     * @since 3.4
9479     */
9480    public static String wrap(final String str, final String wrapWith) {
9481
9482        if (isEmpty(str) || isEmpty(wrapWith)) {
9483            return str;
9484        }
9485
9486        return wrapWith.concat(str).concat(wrapWith);
9487    }
9488
9489    /**
9490     * Wraps a string with a char if that char is missing from the start or end of the given string.
9491     *
9492     * <p>A new {@link String} will not be created if {@code str} is already wrapped.</p>
9493     *
9494     * <pre>
9495     * StringUtils.wrapIfMissing(null, *)        = null
9496     * StringUtils.wrapIfMissing("", *)          = ""
9497     * StringUtils.wrapIfMissing("ab", '\0')     = "ab"
9498     * StringUtils.wrapIfMissing("ab", 'x')      = "xabx"
9499     * StringUtils.wrapIfMissing("ab", '\'')     = "'ab'"
9500     * StringUtils.wrapIfMissing("\"ab\"", '\"') = "\"ab\""
9501     * StringUtils.wrapIfMissing("/", '/')  = "/"
9502     * StringUtils.wrapIfMissing("a/b/c", '/')  = "/a/b/c/"
9503     * StringUtils.wrapIfMissing("/a/b/c", '/')  = "/a/b/c/"
9504     * StringUtils.wrapIfMissing("a/b/c/", '/')  = "/a/b/c/"
9505     * </pre>
9506     *
9507     * @param str
9508