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 *      https://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.CharBuffer;
021import java.nio.charset.Charset;
022import java.text.Normalizer;
023import java.util.ArrayList;
024import java.util.Arrays;
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;
032import java.util.stream.Collectors;
033
034import org.apache.commons.lang3.function.Suppliers;
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><strong>IsEmpty/IsBlank</strong>
044 *      - checks if a String contains text</li>
045 *  <li><strong>Trim/Strip</strong>
046 *      - removes leading and trailing whitespace</li>
047 *  <li><strong>Equals/Compare</strong>
048 *      - compares two strings in a null-safe manner</li>
049 *  <li><strong>startsWith</strong>
050 *      - check if a String starts with a prefix in a null-safe manner</li>
051 *  <li><strong>endsWith</strong>
052 *      - check if a String ends with a suffix in a null-safe manner</li>
053 *  <li><strong>IndexOf/LastIndexOf/Contains</strong>
054 *      - null-safe index-of checks
055 *  <li><strong>IndexOfAny/LastIndexOfAny/IndexOfAnyBut/LastIndexOfAnyBut</strong>
056 *      - index-of any of a set of Strings</li>
057 *  <li><strong>ContainsOnly/ContainsNone/ContainsAny</strong>
058 *      - checks if String contains only/none/any of these characters</li>
059 *  <li><strong>Substring/Left/Right/Mid</strong>
060 *      - null-safe substring extractions</li>
061 *  <li><strong>SubstringBefore/SubstringAfter/SubstringBetween</strong>
062 *      - substring extraction relative to other strings</li>
063 *  <li><strong>Split/Join</strong>
064 *      - splits a String into an array of substrings and vice versa</li>
065 *  <li><strong>Remove/Delete</strong>
066 *      - removes part of a String</li>
067 *  <li><strong>Replace/Overlay</strong>
068 *      - Searches a String and replaces one String with another</li>
069 *  <li><strong>Chomp/Chop</strong>
070 *      - removes the last part of a String</li>
071 *  <li><strong>AppendIfMissing</strong>
072 *      - appends a suffix to the end of the String if not present</li>
073 *  <li><strong>PrependIfMissing</strong>
074 *      - prepends a prefix to the start of the String if not present</li>
075 *  <li><strong>LeftPad/RightPad/Center/Repeat</strong>
076 *      - pads a String</li>
077 *  <li><strong>UpperCase/LowerCase/SwapCase/Capitalize/Uncapitalize</strong>
078 *      - changes the case of a String</li>
079 *  <li><strong>CountMatches</strong>
080 *      - counts the number of occurrences of one String in another</li>
081 *  <li><strong>IsAlpha/IsNumeric/IsWhitespace/IsAsciiPrintable</strong>
082 *      - checks the characters in a String</li>
083 *  <li><strong>DefaultString</strong>
084 *      - protects against a null input String</li>
085 *  <li><strong>Rotate</strong>
086 *      - rotate (circular shift) a String</li>
087 *  <li><strong>Reverse/ReverseDelimited</strong>
088 *      - reverses a String</li>
089 *  <li><strong>Abbreviate</strong>
090 *      - abbreviates a string using ellipses or another given String</li>
091 *  <li><strong>Difference</strong>
092 *      - compares Strings and reports on their differences</li>
093 *  <li><strong>LevenshteinDistance</strong>
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     * This is a 3 character version of an ellipsis. There is a Unicode character for a HORIZONTAL ELLIPSIS, U+2026 … this isn't it.
145     */
146    private static final String ELLIPSIS3 = "...";
147
148    /**
149     * A String for a space character.
150     *
151     * @since 3.2
152     */
153    public static final String SPACE = " ";
154
155    /**
156     * The empty String {@code ""}.
157     * @since 2.0
158     */
159    public static final String EMPTY = "";
160
161    /**
162     * The null String {@code null}. Package-private only.
163     */
164    static final String NULL = null;
165
166    /**
167     * A String for linefeed LF ("\n").
168     *
169     * @see <a href="https://docs.oracle.com/javase/specs/jls/se8/html/jls-3.html#jls-3.10.6">JLF: Escape Sequences
170     *      for Character and String Literals</a>
171     * @since 3.2
172     */
173    public static final String LF = "\n";
174
175    /**
176     * A String for carriage return CR ("\r").
177     *
178     * @see <a href="https://docs.oracle.com/javase/specs/jls/se8/html/jls-3.html#jls-3.10.6">JLF: Escape Sequences
179     *      for Character and String Literals</a>
180     * @since 3.2
181     */
182    public static final String CR = "\r";
183
184    /**
185     * Represents a failed index search.
186     * @since 2.1
187     */
188    public static final int INDEX_NOT_FOUND = -1;
189
190    /**
191     * The maximum size to which the padding constant(s) can expand.
192     */
193    private static final int PAD_LIMIT = 8192;
194
195    /**
196     * The default maximum depth at which recursive replacement will continue until no further search replacements are possible.
197     */
198    private static final int DEFAULT_TTL = 5;
199
200    /**
201     * Pattern used in {@link #stripAccents(String)}.
202     */
203    private static final Pattern STRIP_ACCENTS_PATTERN = Pattern.compile("\\p{InCombiningDiacriticalMarks}+"); //$NON-NLS-1$
204
205    /**
206     * Abbreviates a String using ellipses. This will turn
207     * "Now is the time for all good men" into "Now is the time for..."
208     *
209     * <p>Specifically:</p>
210     * <ul>
211     *   <li>If the number of characters in {@code str} is less than or equal to
212     *       {@code maxWidth}, return {@code str}.</li>
213     *   <li>Else abbreviate it to {@code (substring(str, 0, max-3) + "...")}.</li>
214     *   <li>If {@code maxWidth} is less than {@code 4}, throw an
215     *       {@link IllegalArgumentException}.</li>
216     *   <li>In no case will it return a String of length greater than
217     *       {@code maxWidth}.</li>
218     * </ul>
219     *
220     * <pre>
221     * StringUtils.abbreviate(null, *)      = null
222     * StringUtils.abbreviate("", 4)        = ""
223     * StringUtils.abbreviate("abcdefg", 6) = "abc..."
224     * StringUtils.abbreviate("abcdefg", 7) = "abcdefg"
225     * StringUtils.abbreviate("abcdefg", 8) = "abcdefg"
226     * StringUtils.abbreviate("abcdefg", 4) = "a..."
227     * StringUtils.abbreviate("abcdefg", 3) = IllegalArgumentException
228     * </pre>
229     *
230     * @param str  the String to check, may be null.
231     * @param maxWidth  maximum length of result String, must be at least 4.
232     * @return abbreviated String, {@code null} if null String input.
233     * @throws IllegalArgumentException if the width is too small.
234     * @since 2.0
235     */
236    public static String abbreviate(final String str, final int maxWidth) {
237        return abbreviate(str, ELLIPSIS3, 0, maxWidth);
238    }
239
240    /**
241     * Abbreviates a String using ellipses. This will turn "Now is the time for all good men" into "...is the time for..."
242     *
243     * <p>
244     * Works like {@code abbreviate(String, int)}, but allows you to specify a "left edge" offset. Note that this left edge is not necessarily going to be the
245     * leftmost character in the result, or the first character following the ellipses, but it will appear somewhere in the result.
246     *
247     * <p>
248     * In no case will it return a String of length greater than {@code maxWidth}.
249     * </p>
250     *
251     * <pre>
252     * StringUtils.abbreviate(null, *, *)                = null
253     * StringUtils.abbreviate("", 0, 4)                  = ""
254     * StringUtils.abbreviate("abcdefghijklmno", -1, 10) = "abcdefg..."
255     * StringUtils.abbreviate("abcdefghijklmno", 0, 10)  = "abcdefg..."
256     * StringUtils.abbreviate("abcdefghijklmno", 1, 10)  = "abcdefg..."
257     * StringUtils.abbreviate("abcdefghijklmno", 4, 10)  = "abcdefg..."
258     * StringUtils.abbreviate("abcdefghijklmno", 5, 10)  = "...fghi..."
259     * StringUtils.abbreviate("abcdefghijklmno", 6, 10)  = "...ghij..."
260     * StringUtils.abbreviate("abcdefghijklmno", 8, 10)  = "...ijklmno"
261     * StringUtils.abbreviate("abcdefghijklmno", 10, 10) = "...ijklmno"
262     * StringUtils.abbreviate("abcdefghijklmno", 12, 10) = "...ijklmno"
263     * StringUtils.abbreviate("abcdefghij", 0, 3)        = IllegalArgumentException
264     * StringUtils.abbreviate("abcdefghij", 5, 6)        = IllegalArgumentException
265     * </pre>
266     *
267     * @param str      the String to check, may be null.
268     * @param offset   left edge of source String.
269     * @param maxWidth maximum length of result String, must be at least 4.
270     * @return abbreviated String, {@code null} if null String input.
271     * @throws IllegalArgumentException if the width is too small.
272     * @since 2.0
273     */
274    public static String abbreviate(final String str, final int offset, final int maxWidth) {
275        return abbreviate(str, ELLIPSIS3, offset, maxWidth);
276    }
277
278    /**
279     * Abbreviates a String using another given String as replacement marker. This will turn "Now is the time for all good men" into "Now is the time for..." if
280     * "..." was defined as the replacement marker.
281     *
282     * <p>
283     * Specifically:
284     * </p>
285     * <ul>
286     * <li>If the number of characters in {@code str} is less than or equal to {@code maxWidth}, return {@code str}.</li>
287     * <li>Else abbreviate it to {@code (substring(str, 0, max-abbrevMarker.length) + abbrevMarker)}.</li>
288     * <li>If {@code maxWidth} is less than {@code abbrevMarker.length + 1}, throw an {@link IllegalArgumentException}.</li>
289     * <li>In no case will it return a String of length greater than {@code maxWidth}.</li>
290     * </ul>
291     *
292     * <pre>
293     * StringUtils.abbreviate(null, "...", *)      = null
294     * StringUtils.abbreviate("abcdefg", null, *)  = "abcdefg"
295     * StringUtils.abbreviate("", "...", 4)        = ""
296     * StringUtils.abbreviate("abcdefg", ".", 5)   = "abcd."
297     * StringUtils.abbreviate("abcdefg", ".", 7)   = "abcdefg"
298     * StringUtils.abbreviate("abcdefg", ".", 8)   = "abcdefg"
299     * StringUtils.abbreviate("abcdefg", "..", 4)  = "ab.."
300     * StringUtils.abbreviate("abcdefg", "..", 3)  = "a.."
301     * StringUtils.abbreviate("abcdefg", "..", 2)  = IllegalArgumentException
302     * StringUtils.abbreviate("abcdefg", "...", 3) = IllegalArgumentException
303     * </pre>
304     *
305     * @param str          the String to check, may be null.
306     * @param abbrevMarker the String used as replacement marker.
307     * @param maxWidth     maximum length of result String, must be at least {@code abbrevMarker.length + 1}.
308     * @return abbreviated String, {@code null} if null String input.
309     * @throws IllegalArgumentException if the width is too small.
310     * @since 3.6
311     */
312    public static String abbreviate(final String str, final String abbrevMarker, final int maxWidth) {
313        return abbreviate(str, abbrevMarker, 0, maxWidth);
314    }
315
316    /**
317     * Abbreviates a String using a given replacement marker. This will turn "Now is the time for all good men" into "...is the time for..." if "..." was
318     * defined as the replacement marker.
319     *
320     * <p>
321     * Works like {@code abbreviate(String, String, int)}, but allows you to specify a "left edge" offset. Note that this left edge is not necessarily going to
322     * be the leftmost character in the result, or the first character following the replacement marker, but it will appear somewhere in the result.
323     *
324     * <p>
325     * In no case will it return a String of length greater than {@code maxWidth}.
326     * </p>
327     *
328     * <pre>
329     * StringUtils.abbreviate(null, null, *, *)                 = null
330     * StringUtils.abbreviate("abcdefghijklmno", null, *, *)    = "abcdefghijklmno"
331     * StringUtils.abbreviate("", "...", 0, 4)                  = ""
332     * StringUtils.abbreviate("abcdefghijklmno", "---", -1, 10) = "abcdefg---"
333     * StringUtils.abbreviate("abcdefghijklmno", ",", 0, 10)    = "abcdefghi,"
334     * StringUtils.abbreviate("abcdefghijklmno", ",", 1, 10)    = "abcdefghi,"
335     * StringUtils.abbreviate("abcdefghijklmno", ",", 2, 10)    = "abcdefghi,"
336     * StringUtils.abbreviate("abcdefghijklmno", "::", 4, 10)   = "::efghij::"
337     * StringUtils.abbreviate("abcdefghijklmno", "...", 6, 10)  = "...ghij..."
338     * StringUtils.abbreviate("abcdefghijklmno", "*", 9, 10)    = "*ghijklmno"
339     * StringUtils.abbreviate("abcdefghijklmno", "'", 10, 10)   = "'ghijklmno"
340     * StringUtils.abbreviate("abcdefghijklmno", "!", 12, 10)   = "!ghijklmno"
341     * StringUtils.abbreviate("abcdefghij", "abra", 0, 4)       = IllegalArgumentException
342     * StringUtils.abbreviate("abcdefghij", "...", 5, 6)        = IllegalArgumentException
343     * </pre>
344     *
345     * @param str          the String to check, may be null.
346     * @param abbrevMarker the String used as replacement marker.
347     * @param offset       left edge of source String.
348     * @param maxWidth     maximum length of result String, must be at least 4.
349     * @return abbreviated String, {@code null} if null String input.
350     * @throws IllegalArgumentException if the width is too small.
351     * @since 3.6
352     */
353    public static String abbreviate(final String str, final String abbrevMarker, int offset, final int maxWidth) {
354        if (isNotEmpty(str) && EMPTY.equals(abbrevMarker) && maxWidth > 0) {
355            return substring(str, 0, maxWidth);
356        }
357        if (isAnyEmpty(str, abbrevMarker)) {
358            return str;
359        }
360        final int abbrevMarkerLength = abbrevMarker.length();
361        final int minAbbrevWidth = abbrevMarkerLength + 1;
362        final int minAbbrevWidthOffset = abbrevMarkerLength + abbrevMarkerLength + 1;
363
364        if (maxWidth < minAbbrevWidth) {
365            throw new IllegalArgumentException(String.format("Minimum abbreviation width is %d", minAbbrevWidth));
366        }
367        final int strLen = str.length();
368        if (strLen <= maxWidth) {
369            return str;
370        }
371        if (offset > strLen) {
372            offset = strLen;
373        }
374        if (strLen - offset < maxWidth - abbrevMarkerLength) {
375            offset = strLen - (maxWidth - abbrevMarkerLength);
376        }
377        if (offset <= abbrevMarkerLength + 1) {
378            return str.substring(0, maxWidth - abbrevMarkerLength) + abbrevMarker;
379        }
380        if (maxWidth < minAbbrevWidthOffset) {
381            throw new IllegalArgumentException(String.format("Minimum abbreviation width with offset is %d", minAbbrevWidthOffset));
382        }
383        if (offset + maxWidth - abbrevMarkerLength < strLen) {
384            return abbrevMarker + abbreviate(str.substring(offset), abbrevMarker, maxWidth - abbrevMarkerLength);
385        }
386        return abbrevMarker + str.substring(strLen - (maxWidth - abbrevMarkerLength));
387    }
388
389    /**
390     * Abbreviates a String to the length passed, replacing the middle characters with the supplied replacement String.
391     *
392     * <p>
393     * This abbreviation only occurs if the following criteria is met:
394     * </p>
395     * <ul>
396     * <li>Neither the String for abbreviation nor the replacement String are null or empty</li>
397     * <li>The length to truncate to is less than the length of the supplied String</li>
398     * <li>The length to truncate to is greater than 0</li>
399     * <li>The abbreviated String will have enough room for the length supplied replacement String and the first and last characters of the supplied String for
400     * abbreviation</li>
401     * </ul>
402     * <p>
403     * Otherwise, the returned String will be the same as the supplied String for abbreviation.
404     * </p>
405     *
406     * <pre>
407     * StringUtils.abbreviateMiddle(null, null, 0)    = null
408     * StringUtils.abbreviateMiddle("abc", null, 0)   = "abc"
409     * StringUtils.abbreviateMiddle("abc", ".", 0)    = "abc"
410     * StringUtils.abbreviateMiddle("abc", ".", 3)    = "abc"
411     * StringUtils.abbreviateMiddle("abcdef", ".", 4) = "ab.f"
412     * </pre>
413     *
414     * @param str    the String to abbreviate, may be null.
415     * @param middle the String to replace the middle characters with, may be null.
416     * @param length the length to abbreviate {@code str} to.
417     * @return the abbreviated String if the above criteria is met, or the original String supplied for abbreviation.
418     * @since 2.5
419     */
420    public static String abbreviateMiddle(final String str, final String middle, final int length) {
421        if (isAnyEmpty(str, middle) || length >= str.length() || length < middle.length() + 2) {
422            return str;
423        }
424        final int targetSting = length - middle.length();
425        final int startOffset = targetSting / 2 + targetSting % 2;
426        final int endOffset = str.length() - targetSting / 2;
427        return str.substring(0, startOffset) + middle + str.substring(endOffset);
428    }
429
430    /**
431     * Appends the suffix to the end of the string if the string does not already end with any of the suffixes.
432     *
433     * <pre>
434     * StringUtils.appendIfMissing(null, null)      = null
435     * StringUtils.appendIfMissing("abc", null)     = "abc"
436     * StringUtils.appendIfMissing("", "xyz"        = "xyz"
437     * StringUtils.appendIfMissing("abc", "xyz")    = "abcxyz"
438     * StringUtils.appendIfMissing("abcxyz", "xyz") = "abcxyz"
439     * StringUtils.appendIfMissing("abcXYZ", "xyz") = "abcXYZxyz"
440     * </pre>
441     * <p>
442     * With additional suffixes,
443     * </p>
444     *
445     * <pre>
446     * StringUtils.appendIfMissing(null, null, null)       = null
447     * StringUtils.appendIfMissing("abc", null, null)      = "abc"
448     * StringUtils.appendIfMissing("", "xyz", null)        = "xyz"
449     * StringUtils.appendIfMissing("abc", "xyz", new CharSequence[]{null}) = "abcxyz"
450     * StringUtils.appendIfMissing("abc", "xyz", "")       = "abc"
451     * StringUtils.appendIfMissing("abc", "xyz", "mno")    = "abcxyz"
452     * StringUtils.appendIfMissing("abcxyz", "xyz", "mno") = "abcxyz"
453     * StringUtils.appendIfMissing("abcmno", "xyz", "mno") = "abcmno"
454     * StringUtils.appendIfMissing("abcXYZ", "xyz", "mno") = "abcXYZxyz"
455     * StringUtils.appendIfMissing("abcMNO", "xyz", "mno") = "abcMNOxyz"
456     * </pre>
457     *
458     * @param str      The string.
459     * @param suffix   The suffix to append to the end of the string.
460     * @param suffixes Additional suffixes that are valid terminators.
461     * @return A new String if suffix was appended, the same string otherwise.
462     * @since 3.2
463     * @deprecated Use {@link Strings#appendIfMissing(String, CharSequence, CharSequence...) Strings.CS.appendIfMissing(String, CharSequence, CharSequence...)}
464     */
465    @Deprecated
466    public static String appendIfMissing(final String str, final CharSequence suffix, final CharSequence... suffixes) {
467        return Strings.CS.appendIfMissing(str, suffix, suffixes);
468    }
469
470    /**
471     * Appends the suffix to the end of the string if the string does not
472     * already end, case-insensitive, with any of the suffixes.
473     *
474     * <pre>
475     * StringUtils.appendIfMissingIgnoreCase(null, null)      = null
476     * StringUtils.appendIfMissingIgnoreCase("abc", null)     = "abc"
477     * StringUtils.appendIfMissingIgnoreCase("", "xyz")       = "xyz"
478     * StringUtils.appendIfMissingIgnoreCase("abc", "xyz")    = "abcxyz"
479     * StringUtils.appendIfMissingIgnoreCase("abcxyz", "xyz") = "abcxyz"
480     * StringUtils.appendIfMissingIgnoreCase("abcXYZ", "xyz") = "abcXYZ"
481     * </pre>
482     * <p>With additional suffixes,</p>
483     * <pre>
484     * StringUtils.appendIfMissingIgnoreCase(null, null, null)       = null
485     * StringUtils.appendIfMissingIgnoreCase("abc", null, null)      = "abc"
486     * StringUtils.appendIfMissingIgnoreCase("", "xyz", null)        = "xyz"
487     * StringUtils.appendIfMissingIgnoreCase("abc", "xyz", new CharSequence[]{null}) = "abcxyz"
488     * StringUtils.appendIfMissingIgnoreCase("abc", "xyz", "")       = "abc"
489     * StringUtils.appendIfMissingIgnoreCase("abc", "xyz", "mno")    = "abcxyz"
490     * StringUtils.appendIfMissingIgnoreCase("abcxyz", "xyz", "mno") = "abcxyz"
491     * StringUtils.appendIfMissingIgnoreCase("abcmno", "xyz", "mno") = "abcmno"
492     * StringUtils.appendIfMissingIgnoreCase("abcXYZ", "xyz", "mno") = "abcXYZ"
493     * StringUtils.appendIfMissingIgnoreCase("abcMNO", "xyz", "mno") = "abcMNO"
494     * </pre>
495     *
496     * @param str The string.
497     * @param suffix The suffix to append to the end of the string.
498     * @param suffixes Additional suffixes that are valid terminators.
499     * @return A new String if suffix was appended, the same string otherwise.
500     * @since 3.2
501     * @deprecated Use {@link Strings#appendIfMissing(String, CharSequence, CharSequence...) Strings.CI.appendIfMissing(String, CharSequence, CharSequence...)}
502     */
503    @Deprecated
504    public static String appendIfMissingIgnoreCase(final String str, final CharSequence suffix, final CharSequence... suffixes) {
505        return Strings.CI.appendIfMissing(str, suffix, suffixes);
506    }
507
508    /**
509     * Capitalizes a String changing the first character to title case as per {@link Character#toTitleCase(int)}. No other characters are changed.
510     *
511     * <p>
512     * For a word based algorithm, see {@link org.apache.commons.text.WordUtils#capitalize(String)}. A {@code null} input String returns {@code null}.
513     * </p>
514     *
515     * <pre>
516     * StringUtils.capitalize(null)    = null
517     * StringUtils.capitalize("")      = ""
518     * StringUtils.capitalize("cat")   = "Cat"
519     * StringUtils.capitalize("cAt")   = "CAt"
520     * StringUtils.capitalize("'cat'") = "'cat'"
521     * </pre>
522     *
523     * @param str the String to capitalize, may be null.
524     * @return the capitalized String, {@code null} if null String input.
525     * @see org.apache.commons.text.WordUtils#capitalize(String)
526     * @see #uncapitalize(String)
527     * @since 2.0
528     */
529    public static String capitalize(final String str) {
530        if (isEmpty(str)) {
531            return str;
532        }
533        final int firstCodepoint = str.codePointAt(0);
534        final int newCodePoint = Character.toTitleCase(firstCodepoint);
535        if (firstCodepoint == newCodePoint) {
536            // already capitalized
537            return str;
538        }
539        final int[] newCodePoints = str.codePoints().toArray();
540        newCodePoints[0] = newCodePoint; // copy the first code point
541        return new String(newCodePoints, 0, newCodePoints.length);
542    }
543
544    /**
545     * Centers a String in a larger String of size {@code size} using the space character (' ').
546     *
547     * <p>
548     * If the size is less than the String length, the original String is returned. A {@code null} String returns {@code null}. A negative size is treated as
549     * zero.
550     * </p>
551     *
552     * <p>
553     * Equivalent to {@code center(str, size, " ")}.
554     * </p>
555     *
556     * <pre>
557     * StringUtils.center(null, *)   = null
558     * StringUtils.center("", 4)     = "    "
559     * StringUtils.center("ab", -1)  = "ab"
560     * StringUtils.center("ab", 4)   = " ab "
561     * StringUtils.center("abcd", 2) = "abcd"
562     * StringUtils.center("a", 4)    = " a  "
563     * </pre>
564     *
565     * @param str  the String to center, may be null.
566     * @param size the int size of new String, negative treated as zero.
567     * @return centered String, {@code null} if null String input.
568     */
569    public static String center(final String str, final int size) {
570        return center(str, size, ' ');
571    }
572
573    /**
574     * Centers a String in a larger String of size {@code size}. Uses a supplied character as the value to pad the String with.
575     *
576     * <p>
577     * If the size is less than the String length, the String is returned. A {@code null} String returns {@code null}. A negative size is treated as zero.
578     * </p>
579     *
580     * <pre>
581     * StringUtils.center(null, *, *)     = null
582     * StringUtils.center("", 4, ' ')     = "    "
583     * StringUtils.center("ab", -1, ' ')  = "ab"
584     * StringUtils.center("ab", 4, ' ')   = " ab "
585     * StringUtils.center("abcd", 2, ' ') = "abcd"
586     * StringUtils.center("a", 4, ' ')    = " a  "
587     * StringUtils.center("a", 4, 'y')    = "yayy"
588     * </pre>
589     *
590     * @param str     the String to center, may be null.
591     * @param size    the int size of new String, negative treated as zero.
592     * @param padChar the character to pad the new String with.
593     * @return centered String, {@code null} if null String input.
594     * @since 2.0
595     */
596    public static String center(String str, final int size, final char padChar) {
597        if (str == null || size <= 0) {
598            return str;
599        }
600        final int strLen = str.length();
601        final int pads = size - strLen;
602        if (pads <= 0) {
603            return str;
604        }
605        str = leftPad(str, strLen + pads / 2, padChar);
606        return rightPad(str, size, padChar);
607    }
608
609    /**
610     * Centers a String in a larger String of size {@code size}. Uses a supplied String as the value to pad the String with.
611     *
612     * <p>
613     * If the size is less than the String length, the String is returned. A {@code null} String returns {@code null}. A negative size is treated as zero.
614     * </p>
615     *
616     * <pre>
617     * StringUtils.center(null, *, *)     = null
618     * StringUtils.center("", 4, " ")     = "    "
619     * StringUtils.center("ab", -1, " ")  = "ab"
620     * StringUtils.center("ab", 4, " ")   = " ab "
621     * StringUtils.center("abcd", 2, " ") = "abcd"
622     * StringUtils.center("a", 4, " ")    = " a  "
623     * StringUtils.center("a", 4, "yz")   = "yayz"
624     * StringUtils.center("abc", 7, null) = "  abc  "
625     * StringUtils.center("abc", 7, "")   = "  abc  "
626     * </pre>
627     *
628     * @param str    the String to center, may be null.
629     * @param size   the int size of new String, negative treated as zero.
630     * @param padStr the String to pad the new String with, must not be null or empty.
631     * @return centered String, {@code null} if null String input.
632     * @throws IllegalArgumentException if padStr is {@code null} or empty.
633     */
634    public static String center(String str, final int size, String padStr) {
635        if (str == null || size <= 0) {
636            return str;
637        }
638        if (isEmpty(padStr)) {
639            padStr = SPACE;
640        }
641        final int strLen = str.length();
642        final int pads = size - strLen;
643        if (pads <= 0) {
644            return str;
645        }
646        str = leftPad(str, strLen + pads / 2, padStr);
647        return rightPad(str, size, padStr);
648    }
649
650    /**
651     * Removes one newline from end of a String if it's there, otherwise leave it alone. A newline is &quot;{@code \n}&quot;, &quot;{@code \r}&quot;, or
652     * &quot;{@code \r\n}&quot;.
653     *
654     * <p>
655     * NOTE: This method changed in 2.0. It now more closely matches Perl chomp.
656     * </p>
657     *
658     * <pre>
659     * StringUtils.chomp(null)          = null
660     * StringUtils.chomp("")            = ""
661     * StringUtils.chomp("abc \r")      = "abc "
662     * StringUtils.chomp("abc\n")       = "abc"
663     * StringUtils.chomp("abc\r\n")     = "abc"
664     * StringUtils.chomp("abc\r\n\r\n") = "abc\r\n"
665     * StringUtils.chomp("abc\n\r")     = "abc\n"
666     * StringUtils.chomp("abc\n\rabc")  = "abc\n\rabc"
667     * StringUtils.chomp("\r")          = ""
668     * StringUtils.chomp("\n")          = ""
669     * StringUtils.chomp("\r\n")        = ""
670     * </pre>
671     *
672     * @param str the String to chomp a newline from, may be null.
673     * @return String without newline, {@code null} if null String input.
674     */
675    public static String chomp(final String str) {
676        if (isEmpty(str)) {
677            return str;
678        }
679        if (str.length() == 1) {
680            final char ch = str.charAt(0);
681            if (ch == CharUtils.CR || ch == CharUtils.LF) {
682                return EMPTY;
683            }
684            return str;
685        }
686        int lastIdx = str.length() - 1;
687        final char last = str.charAt(lastIdx);
688        if (last == CharUtils.LF) {
689            if (str.charAt(lastIdx - 1) == CharUtils.CR) {
690                lastIdx--;
691            }
692        } else if (last != CharUtils.CR) {
693            lastIdx++;
694        }
695        return str.substring(0, lastIdx);
696    }
697
698    /**
699     * Removes {@code separator} from the end of {@code str} if it's there, otherwise leave it alone.
700     *
701     * <p>
702     * NOTE: This method changed in version 2.0. It now more closely matches Perl chomp. For the previous behavior, use
703     * {@link #substringBeforeLast(String, String)}. This method uses {@link String#endsWith(String)}.
704     * </p>
705     *
706     * <pre>
707     * StringUtils.chomp(null, *)         = null
708     * StringUtils.chomp("", *)           = ""
709     * StringUtils.chomp("foobar", "bar") = "foo"
710     * StringUtils.chomp("foobar", "baz") = "foobar"
711     * StringUtils.chomp("foo", "foo")    = ""
712     * StringUtils.chomp("foo ", "foo")   = "foo "
713     * StringUtils.chomp(" foo", "foo")   = " "
714     * StringUtils.chomp("foo", "foooo")  = "foo"
715     * StringUtils.chomp("foo", "")       = "foo"
716     * StringUtils.chomp("foo", null)     = "foo"
717     * </pre>
718     *
719     * @param str       the String to chomp from, may be null.
720     * @param separator separator String, may be null.
721     * @return String without trailing separator, {@code null} if null String input.
722     * @deprecated This feature will be removed in Lang 4, use {@link StringUtils#removeEnd(String, String)} instead.
723     */
724    @Deprecated
725    public static String chomp(final String str, final String separator) {
726        return Strings.CS.removeEnd(str, separator);
727    }
728
729    /**
730     * Removes the last character from a String.
731     *
732     * <p>
733     * If the String ends in {@code \r\n}, then remove both of them.
734     * </p>
735     *
736     * <pre>
737     * StringUtils.chop(null)          = null
738     * StringUtils.chop("")            = ""
739     * StringUtils.chop("abc \r")      = "abc "
740     * StringUtils.chop("abc\n")       = "abc"
741     * StringUtils.chop("abc\r\n")     = "abc"
742     * StringUtils.chop("abc")         = "ab"
743     * StringUtils.chop("abc\nabc")    = "abc\nab"
744     * StringUtils.chop("a")           = ""
745     * StringUtils.chop("\r")          = ""
746     * StringUtils.chop("\n")          = ""
747     * StringUtils.chop("\r\n")        = ""
748     * </pre>
749     *
750     * @param str the String to chop last character from, may be null.
751     * @return String without last character, {@code null} if null String input.
752     */
753    public static String chop(final String str) {
754        if (str == null) {
755            return null;
756        }
757        final int strLen = str.length();
758        if (strLen < 2) {
759            return EMPTY;
760        }
761        final int lastIdx = strLen - 1;
762        final String ret = str.substring(0, lastIdx);
763        final char last = str.charAt(lastIdx);
764        if (last == CharUtils.LF && ret.charAt(lastIdx - 1) == CharUtils.CR) {
765            return ret.substring(0, lastIdx - 1);
766        }
767        return ret;
768    }
769
770    /**
771     * Compares two Strings lexicographically, as per {@link String#compareTo(String)}, returning :
772     * <ul>
773     * <li>{@code int = 0}, if {@code str1} is equal to {@code str2} (or both {@code null})</li>
774     * <li>{@code int < 0}, if {@code str1} is less than {@code str2}</li>
775     * <li>{@code int > 0}, if {@code str1} is greater than {@code str2}</li>
776     * </ul>
777     *
778     * <p>
779     * This is a {@code null} safe version of:
780     * </p>
781     *
782     * <pre>
783     * str1.compareTo(str2)
784     * </pre>
785     *
786     * <p>
787     * {@code null} value is considered less than non-{@code null} value. Two {@code null} references are considered equal.
788     * </p>
789     *
790     * <pre>{@code
791     * StringUtils.compare(null, null)   = 0
792     * StringUtils.compare(null , "a")   < 0
793     * StringUtils.compare("a", null)   > 0
794     * StringUtils.compare("abc", "abc") = 0
795     * StringUtils.compare("a", "b")     < 0
796     * StringUtils.compare("b", "a")     > 0
797     * StringUtils.compare("a", "B")     > 0
798     * StringUtils.compare("ab", "abc")  < 0
799     * }</pre>
800     *
801     * @param str1 the String to compare from.
802     * @param str2 the String to compare to
803     * @return &lt; 0, 0, &gt; 0, if {@code str1} is respectively less, equal or greater than {@code str2}
804     * @see #compare(String, String, boolean)
805     * @see String#compareTo(String)
806     * @since 3.5
807     * @deprecated Use {@link Strings#compare(String, String) Strings.CS.compare(String, String)}
808     */
809    @Deprecated
810    public static int compare(final String str1, final String str2) {
811        return Strings.CS.compare(str1, str2);
812    }
813
814    /**
815     * Compares two Strings lexicographically, as per {@link String#compareTo(String)}, returning :
816     * <ul>
817     * <li>{@code int = 0}, if {@code str1} is equal to {@code str2} (or both {@code null})</li>
818     * <li>{@code int < 0}, if {@code str1} is less than {@code str2}</li>
819     * <li>{@code int > 0}, if {@code str1} is greater than {@code str2}</li>
820     * </ul>
821     *
822     * <p>
823     * This is a {@code null} safe version of :
824     * </p>
825     *
826     * <pre>
827     * str1.compareTo(str2)
828     * </pre>
829     *
830     * <p>
831     * {@code null} inputs are handled according to the {@code nullIsLess} parameter. Two {@code null} references are considered equal.
832     * </p>
833     *
834     * <pre>{@code
835     * StringUtils.compare(null, null, *)     = 0
836     * StringUtils.compare(null , "a", true)  < 0
837     * StringUtils.compare(null , "a", false) > 0
838     * StringUtils.compare("a", null, true)   > 0
839     * StringUtils.compare("a", null, false)  < 0
840     * StringUtils.compare("abc", "abc", *)   = 0
841     * StringUtils.compare("a", "b", *)       < 0
842     * StringUtils.compare("b", "a", *)       > 0
843     * StringUtils.compare("a", "B", *)       > 0
844     * StringUtils.compare("ab", "abc", *)    < 0
845     * }</pre>
846     *
847     * @param str1       the String to compare from.
848     * @param str2       the String to compare to.
849     * @param nullIsLess whether consider {@code null} value less than non-{@code null} value.
850     * @return &lt; 0, 0, &gt; 0, if {@code str1} is respectively less, equal ou greater than {@code str2}.
851     * @see String#compareTo(String)
852     * @since 3.5
853     */
854    public static int compare(final String str1, final String str2, final boolean nullIsLess) {
855        if (str1 == str2) { // NOSONARLINT this intentionally uses == to allow for both null
856            return 0;
857        }
858        if (str1 == null) {
859            return nullIsLess ? -1 : 1;
860        }
861        if (str2 == null) {
862            return nullIsLess ? 1 : - 1;
863        }
864        return str1.compareTo(str2);
865    }
866
867    /**
868     * Compares two Strings lexicographically, ignoring case differences, as per {@link String#compareToIgnoreCase(String)}, returning :
869     * <ul>
870     * <li>{@code int = 0}, if {@code str1} is equal to {@code str2} (or both {@code null})</li>
871     * <li>{@code int < 0}, if {@code str1} is less than {@code str2}</li>
872     * <li>{@code int > 0}, if {@code str1} is greater than {@code str2}</li>
873     * </ul>
874     *
875     * <p>
876     * This is a {@code null} safe version of:
877     * </p>
878     *
879     * <pre>
880     * str1.compareToIgnoreCase(str2)
881     * </pre>
882     *
883     * <p>
884     * {@code null} value is considered less than non-{@code null} value. Two {@code null} references are considered equal. Comparison is case insensitive.
885     * </p>
886     *
887     * <pre>{@code
888     * StringUtils.compareIgnoreCase(null, null)   = 0
889     * StringUtils.compareIgnoreCase(null , "a")   < 0
890     * StringUtils.compareIgnoreCase("a", null)    > 0
891     * StringUtils.compareIgnoreCase("abc", "abc") = 0
892     * StringUtils.compareIgnoreCase("abc", "ABC") = 0
893     * StringUtils.compareIgnoreCase("a", "b")     < 0
894     * StringUtils.compareIgnoreCase("b", "a")     > 0
895     * StringUtils.compareIgnoreCase("a", "B")     < 0
896     * StringUtils.compareIgnoreCase("A", "b")     < 0
897     * StringUtils.compareIgnoreCase("ab", "ABC")  < 0
898     * }</pre>
899     *
900     * @param str1 the String to compare from.
901     * @param str2 the String to compare to.
902     * @return &lt; 0, 0, &gt; 0, if {@code str1} is respectively less, equal ou greater than {@code str2}, ignoring case differences.
903     * @see #compareIgnoreCase(String, String, boolean)
904     * @see String#compareToIgnoreCase(String)
905     * @since 3.5
906     * @deprecated Use {@link Strings#compare(String, String) Strings.CI.compare(String, String)}
907     */
908    @Deprecated
909    public static int compareIgnoreCase(final String str1, final String str2) {
910        return Strings.CI.compare(str1, str2);
911    }
912
913    /**
914     * Compares two Strings lexicographically, ignoring case differences, as per {@link String#compareToIgnoreCase(String)}, returning :
915     * <ul>
916     * <li>{@code int = 0}, if {@code str1} is equal to {@code str2} (or both {@code null})</li>
917     * <li>{@code int < 0}, if {@code str1} is less than {@code str2}</li>
918     * <li>{@code int > 0}, if {@code str1} is greater than {@code str2}</li>
919     * </ul>
920     *
921     * <p>
922     * This is a {@code null} safe version of :
923     * </p>
924     * <pre>
925     * str1.compareToIgnoreCase(str2)
926     * </pre>
927     *
928     * <p>
929     * {@code null} inputs are handled according to the {@code nullIsLess} parameter. Two {@code null} references are considered equal. Comparison is case
930     * insensitive.
931     * </p>
932     *
933     * <pre>{@code
934     * StringUtils.compareIgnoreCase(null, null, *)     = 0
935     * StringUtils.compareIgnoreCase(null , "a", true)  < 0
936     * StringUtils.compareIgnoreCase(null , "a", false) > 0
937     * StringUtils.compareIgnoreCase("a", null, true)   > 0
938     * StringUtils.compareIgnoreCase("a", null, false)  < 0
939     * StringUtils.compareIgnoreCase("abc", "abc", *)   = 0
940     * StringUtils.compareIgnoreCase("abc", "ABC", *)   = 0
941     * StringUtils.compareIgnoreCase("a", "b", *)       < 0
942     * StringUtils.compareIgnoreCase("b", "a", *)       > 0
943     * StringUtils.compareIgnoreCase("a", "B", *)       < 0
944     * StringUtils.compareIgnoreCase("A", "b", *)       < 0
945     * StringUtils.compareIgnoreCase("ab", "abc", *)    < 0
946     * }</pre>
947     *
948     * @param str1       the String to compare from.
949     * @param str2       the String to compare to.
950     * @param nullIsLess whether consider {@code null} value less than non-{@code null} value.
951     * @return &lt; 0, 0, &gt; 0, if {@code str1} is respectively less, equal ou greater than {@code str2}, ignoring case differences.
952     * @see String#compareToIgnoreCase(String)
953     * @since 3.5
954     */
955    public static int compareIgnoreCase(final String str1, final String str2, final boolean nullIsLess) {
956        if (str1 == str2) { // NOSONARLINT this intentionally uses == to allow for both null
957            return 0;
958        }
959        if (str1 == null) {
960            return nullIsLess ? -1 : 1;
961        }
962        if (str2 == null) {
963            return nullIsLess ? 1 : - 1;
964        }
965        return str1.compareToIgnoreCase(str2);
966    }
967
968    /**
969     * Tests if CharSequence contains a search CharSequence, handling {@code null}.
970     * This method uses {@link String#indexOf(String)} if possible.
971     *
972     * <p>A {@code null} CharSequence will return {@code false}.</p>
973     *
974     * <pre>
975     * StringUtils.contains(null, *)     = false
976     * StringUtils.contains(*, null)     = false
977     * StringUtils.contains("", "")      = true
978     * StringUtils.contains("abc", "")   = true
979     * StringUtils.contains("abc", "a")  = true
980     * StringUtils.contains("abc", "z")  = false
981     * </pre>
982     *
983     * @param seq  the CharSequence to check, may be null
984     * @param searchSeq  the CharSequence to find, may be null
985     * @return true if the CharSequence contains the search CharSequence,
986     *  false if not or {@code null} string input
987     * @since 2.0
988     * @since 3.0 Changed signature from contains(String, String) to contains(CharSequence, CharSequence)
989     * @deprecated Use {@link Strings#contains(CharSequence, CharSequence) Strings.CS.contains(CharSequence, CharSequence)}
990     */
991    @Deprecated
992    public static boolean contains(final CharSequence seq, final CharSequence searchSeq) {
993        return Strings.CS.contains(seq, searchSeq);
994    }
995
996    /**
997     * Tests if CharSequence contains a search character, handling {@code null}. This method uses {@link String#indexOf(int)} if possible.
998     *
999     * <p>
1000     * A {@code null} or empty ("") CharSequence will return {@code false}.
1001     * </p>
1002     *
1003     * <pre>
1004     * StringUtils.contains(null, *)    = false
1005     * StringUtils.contains("", *)      = false
1006     * StringUtils.contains("abc", 'a') = true
1007     * StringUtils.contains("abc", 'z') = false
1008     * </pre>
1009     *
1010     * @param seq        the CharSequence to check, may be null
1011     * @param searchChar the character to find
1012     * @return true if the CharSequence contains the search character, false if not or {@code null} string input
1013     * @since 2.0
1014     * @since 3.0 Changed signature from contains(String, int) to contains(CharSequence, int)
1015     */
1016    public static boolean contains(final CharSequence seq, final int searchChar) {
1017        if (isEmpty(seq)) {
1018            return false;
1019        }
1020        return CharSequenceUtils.indexOf(seq, searchChar, 0) >= 0;
1021    }
1022
1023    /**
1024     * Tests if the CharSequence contains any character in the given set of characters.
1025     *
1026     * <p>
1027     * A {@code null} CharSequence will return {@code false}. A {@code null} or zero length search array will return {@code false}.
1028     * </p>
1029     *
1030     * <pre>
1031     * StringUtils.containsAny(null, *)                  = false
1032     * StringUtils.containsAny("", *)                    = false
1033     * StringUtils.containsAny(*, null)                  = false
1034     * StringUtils.containsAny(*, [])                    = false
1035     * StringUtils.containsAny("zzabyycdxx", ['z', 'a']) = true
1036     * StringUtils.containsAny("zzabyycdxx", ['b', 'y']) = true
1037     * StringUtils.containsAny("zzabyycdxx", ['z', 'y']) = true
1038     * StringUtils.containsAny("aba", ['z'])             = false
1039     * </pre>
1040     *
1041     * @param cs          the CharSequence to check, may be null.
1042     * @param searchChars the chars to search for, may be null.
1043     * @return the {@code true} if any of the chars are found, {@code false} if no match or null input.
1044     * @since 2.4
1045     * @since 3.0 Changed signature from containsAny(String, char[]) to containsAny(CharSequence, char...)
1046     */
1047    public static boolean containsAny(final CharSequence cs, final char... searchChars) {
1048        if (isEmpty(cs) || ArrayUtils.isEmpty(searchChars)) {
1049            return false;
1050        }
1051        final int csLength = cs.length();
1052        final int searchLength = searchChars.length;
1053        final int csLast = csLength - 1;
1054        final int searchLast = searchLength - 1;
1055        for (int i = 0; i < csLength; i++) {
1056            final char ch = cs.charAt(i);
1057            for (int j = 0; j < searchLength; j++) {
1058                if (searchChars[j] == ch) {
1059                    if (!Character.isHighSurrogate(ch) || j == searchLast || i < csLast && searchChars[j + 1] == cs.charAt(i + 1)) {
1060                        return true;
1061                    }
1062                }
1063            }
1064        }
1065        return false;
1066    }
1067
1068    /**
1069     * Tests if the CharSequence contains any character in the given set of characters.
1070     *
1071     * <p>
1072     * A {@code null} CharSequence will return {@code false}. A {@code null} search CharSequence will return {@code false}.
1073     * </p>
1074     *
1075     * <pre>
1076     * StringUtils.containsAny(null, *)               = false
1077     * StringUtils.containsAny("", *)                 = false
1078     * StringUtils.containsAny(*, null)               = false
1079     * StringUtils.containsAny(*, "")                 = false
1080     * StringUtils.containsAny("zzabyycdxx", "za")    = true
1081     * StringUtils.containsAny("zzabyycdxx", "by")    = true
1082     * StringUtils.containsAny("zzabyycdxx", "zy")    = true
1083     * StringUtils.containsAny("zzabyycdxx", "\tx")   = true
1084     * StringUtils.containsAny("zzabyycdxx", "$.#yF") = true
1085     * StringUtils.containsAny("aba", "z")            = false
1086     * </pre>
1087     *
1088     * @param cs          the CharSequence to check, may be null.
1089     * @param searchChars the chars to search for, may be null.
1090     * @return the {@code true} if any of the chars are found, {@code false} if no match or null input.
1091     * @since 2.4
1092     * @since 3.0 Changed signature from containsAny(String, String) to containsAny(CharSequence, CharSequence)
1093     */
1094    public static boolean containsAny(final CharSequence cs, final CharSequence searchChars) {
1095        if (searchChars == null) {
1096            return false;
1097        }
1098        return containsAny(cs, CharSequenceUtils.toCharArray(searchChars));
1099    }
1100
1101    /**
1102     * Tests if the CharSequence contains any of the CharSequences in the given array.
1103     *
1104     * <p>
1105     * A {@code null} {@code cs} CharSequence will return {@code false}. A {@code null} or zero length search array will
1106     * return {@code false}.
1107     * </p>
1108     *
1109     * <pre>
1110     * StringUtils.containsAny(null, *)            = false
1111     * StringUtils.containsAny("", *)              = false
1112     * StringUtils.containsAny(*, null)            = false
1113     * StringUtils.containsAny(*, [])              = false
1114     * StringUtils.containsAny("abcd", "ab", null) = true
1115     * StringUtils.containsAny("abcd", "ab", "cd") = true
1116     * StringUtils.containsAny("abc", "d", "abc")  = true
1117     * </pre>
1118     *
1119     * @param cs The CharSequence to check, may be null.
1120     * @param searchCharSequences The array of CharSequences to search for, may be null. Individual CharSequences may be
1121     *        null as well.
1122     * @return {@code true} if any of the search CharSequences are found, {@code false} otherwise.
1123     * @since 3.4
1124     * @deprecated Use {@link Strings#containsAny(CharSequence, CharSequence...) Strings.CS.containsAny(CharSequence, CharSequence...)}
1125     */
1126    @Deprecated
1127    public static boolean containsAny(final CharSequence cs, final CharSequence... searchCharSequences) {
1128        return Strings.CS.containsAny(cs, searchCharSequences);
1129    }
1130
1131    /**
1132     * Tests if the CharSequence contains any of the CharSequences in the given array, ignoring case.
1133     *
1134     * <p>
1135     * A {@code null} {@code cs} CharSequence will return {@code false}. A {@code null} or zero length search array will
1136     * return {@code false}.
1137     * </p>
1138     *
1139     * <pre>
1140     * StringUtils.containsAny(null, *)            = false
1141     * StringUtils.containsAny("", *)              = false
1142     * StringUtils.containsAny(*, null)            = false
1143     * StringUtils.containsAny(*, [])              = false
1144     * StringUtils.containsAny("abcd", "ab", null) = true
1145     * StringUtils.containsAny("abcd", "ab", "cd") = true
1146     * StringUtils.containsAny("abc", "d", "abc")  = true
1147     * StringUtils.containsAny("abc", "D", "ABC")  = true
1148     * StringUtils.containsAny("ABC", "d", "abc")  = true
1149     * </pre>
1150     *
1151     * @param cs The CharSequence to check, may be null.
1152     * @param searchCharSequences The array of CharSequences to search for, may be null. Individual CharSequences may be
1153     *        null as well.
1154     * @return {@code true} if any of the search CharSequences are found, {@code false} otherwise
1155     * @since 3.12.0
1156     * @deprecated Use {@link Strings#containsAny(CharSequence, CharSequence...) Strings.CI.containsAny(CharSequence, CharSequence...)}
1157     */
1158    @Deprecated
1159    public static boolean containsAnyIgnoreCase(final CharSequence cs, final CharSequence... searchCharSequences) {
1160        return Strings.CI.containsAny(cs, searchCharSequences);
1161    }
1162
1163    /**
1164     * Tests if CharSequence contains a search CharSequence irrespective of case, handling {@code null}. Case-insensitivity is defined as by
1165     * {@link String#equalsIgnoreCase(String)}.
1166     *
1167     * <p>
1168     * A {@code null} CharSequence will return {@code false}.
1169     *
1170     * <pre>
1171     * StringUtils.containsIgnoreCase(null, *)    = false
1172     * StringUtils.containsIgnoreCase(*, null)    = false
1173     * StringUtils.containsIgnoreCase("", "")     = true
1174     * StringUtils.containsIgnoreCase("abc", "")  = true
1175     * StringUtils.containsIgnoreCase("abc", "a") = true
1176     * StringUtils.containsIgnoreCase("abc", "z") = false
1177     * StringUtils.containsIgnoreCase("abc", "A") = true
1178     * StringUtils.containsIgnoreCase("abc", "Z") = false
1179     * </pre>
1180     *
1181     * @param str       the CharSequence to check, may be null.
1182     * @param searchStr the CharSequence to find, may be null.
1183     * @return true if the CharSequence contains the search CharSequence irrespective of case or false if not or {@code null} string input.
1184     * @since 3.0 Changed signature from containsIgnoreCase(String, String) to containsIgnoreCase(CharSequence, CharSequence).
1185     * @deprecated Use {@link Strings#contains(CharSequence, CharSequence) Strings.CI.contains(CharSequence, CharSequence)}
1186     */
1187    @Deprecated
1188    public static boolean containsIgnoreCase(final CharSequence str, final CharSequence searchStr) {
1189        return Strings.CI.contains(str, searchStr);
1190    }
1191
1192    /**
1193     * Tests that the CharSequence does not contain certain characters.
1194     *
1195     * <p>
1196     * A {@code null} CharSequence will return {@code true}. A {@code null} invalid character array will return {@code true}. An empty CharSequence (length()=0)
1197     * always returns true.
1198     * </p>
1199     *
1200     * <pre>
1201     * StringUtils.containsNone(null, *)       = true
1202     * StringUtils.containsNone(*, null)       = true
1203     * StringUtils.containsNone("", *)         = true
1204     * StringUtils.containsNone("ab", '')      = true
1205     * StringUtils.containsNone("abab", 'xyz') = true
1206     * StringUtils.containsNone("ab1", 'xyz')  = true
1207     * StringUtils.containsNone("abz", 'xyz')  = false
1208     * </pre>
1209     *
1210     * @param cs          the CharSequence to check, may be null.
1211     * @param searchChars an array of invalid chars, may be null.
1212     * @return true if it contains none of the invalid chars, or is null.
1213     * @since 2.0
1214     * @since 3.0 Changed signature from containsNone(String, char[]) to containsNone(CharSequence, char...)
1215     */
1216    public static boolean containsNone(final CharSequence cs, final char... searchChars) {
1217        if (cs == null || searchChars == null) {
1218            return true;
1219        }
1220        final int csLen = cs.length();
1221        final int csLast = csLen - 1;
1222        final int searchLen = searchChars.length;
1223        final int searchLast = searchLen - 1;
1224        for (int i = 0; i < csLen; i++) {
1225            final char ch = cs.charAt(i);
1226            for (int j = 0; j < searchLen; j++) {
1227                if (searchChars[j] == ch) {
1228                    if (!Character.isHighSurrogate(ch) || j == searchLast || i < csLast && searchChars[j + 1] == cs.charAt(i + 1)) {
1229                        return false;
1230                    }
1231                }
1232            }
1233        }
1234        return true;
1235    }
1236
1237    /**
1238     * Tests that the CharSequence does not contain certain characters.
1239     *
1240     * <p>
1241     * A {@code null} CharSequence will return {@code true}. A {@code null} invalid character array will return {@code true}. An empty String ("") always
1242     * returns true.
1243     * </p>
1244     *
1245     * <pre>
1246     * StringUtils.containsNone(null, *)       = true
1247     * StringUtils.containsNone(*, null)       = true
1248     * StringUtils.containsNone("", *)         = true
1249     * StringUtils.containsNone("ab", "")      = true
1250     * StringUtils.containsNone("abab", "xyz") = true
1251     * StringUtils.containsNone("ab1", "xyz")  = true
1252     * StringUtils.containsNone("abz", "xyz")  = false
1253     * </pre>
1254     *
1255     * @param cs           the CharSequence to check, may be null.
1256     * @param invalidChars a String of invalid chars, may be null.
1257     * @return true if it contains none of the invalid chars, or is null.
1258     * @since 2.0
1259     * @since 3.0 Changed signature from containsNone(String, String) to containsNone(CharSequence, String)
1260     */
1261    public static boolean containsNone(final CharSequence cs, final String invalidChars) {
1262        if (invalidChars == null) {
1263            return true;
1264        }
1265        return containsNone(cs, invalidChars.toCharArray());
1266    }
1267
1268    /**
1269     * Tests if the CharSequence contains only certain characters.
1270     *
1271     * <p>
1272     * A {@code null} CharSequence will return {@code false}. A {@code null} valid character array will return {@code false}. An empty CharSequence (length()=0)
1273     * always returns {@code true}.
1274     * </p>
1275     *
1276     * <pre>
1277     * StringUtils.containsOnly(null, *)       = false
1278     * StringUtils.containsOnly(*, null)       = false
1279     * StringUtils.containsOnly("", *)         = true
1280     * StringUtils.containsOnly("ab", '')      = false
1281     * StringUtils.containsOnly("abab", 'abc') = true
1282     * StringUtils.containsOnly("ab1", 'abc')  = false
1283     * StringUtils.containsOnly("abz", 'abc')  = false
1284     * </pre>
1285     *
1286     * @param cs    the String to check, may be null.
1287     * @param valid an array of valid chars, may be null.
1288     * @return true if it only contains valid chars and is non-null.
1289     * @since 3.0 Changed signature from containsOnly(String, char[]) to containsOnly(CharSequence, char...)
1290     */
1291    public static boolean containsOnly(final CharSequence cs, final char... valid) {
1292        // All these pre-checks are to maintain API with an older version
1293        if (valid == null || cs == null) {
1294            return false;
1295        }
1296        if (cs.length() == 0) {
1297            return true;
1298        }
1299        if (valid.length == 0) {
1300            return false;
1301        }
1302        return indexOfAnyBut(cs, valid) == INDEX_NOT_FOUND;
1303    }
1304
1305    /**
1306     * Tests if the CharSequence contains only certain characters.
1307     *
1308     * <p>
1309     * A {@code null} CharSequence will return {@code false}. A {@code null} valid character String will return {@code false}. An empty String (length()=0)
1310     * always returns {@code true}.
1311     * </p>
1312     *
1313     * <pre>
1314     * StringUtils.containsOnly(null, *)       = false
1315     * StringUtils.containsOnly(*, null)       = false
1316     * StringUtils.containsOnly("", *)         = true
1317     * StringUtils.containsOnly("ab", "")      = false
1318     * StringUtils.containsOnly("abab", "abc") = true
1319     * StringUtils.containsOnly("ab1", "abc")  = false
1320     * StringUtils.containsOnly("abz", "abc")  = false
1321     * </pre>
1322     *
1323     * @param cs         the CharSequence to check, may be null.
1324     * @param validChars a String of valid chars, may be null.
1325     * @return true if it only contains valid chars and is non-null.
1326     * @since 2.0
1327     * @since 3.0 Changed signature from containsOnly(String, String) to containsOnly(CharSequence, String)
1328     */
1329    public static boolean containsOnly(final CharSequence cs, final String validChars) {
1330        if (cs == null || validChars == null) {
1331            return false;
1332        }
1333        return containsOnly(cs, validChars.toCharArray());
1334    }
1335
1336    /**
1337     * Tests whether the given CharSequence contains any whitespace characters.
1338     *
1339     * <p>
1340     * Whitespace is defined by {@link Character#isWhitespace(char)}.
1341     * </p>
1342     *
1343     * <pre>
1344     * StringUtils.containsWhitespace(null)       = false
1345     * StringUtils.containsWhitespace("")         = false
1346     * StringUtils.containsWhitespace("ab")       = false
1347     * StringUtils.containsWhitespace(" ab")      = true
1348     * StringUtils.containsWhitespace("a b")      = true
1349     * StringUtils.containsWhitespace("ab ")      = true
1350     * </pre>
1351     *
1352     * @param seq the CharSequence to check (may be {@code null}).
1353     * @return {@code true} if the CharSequence is not empty and contains at least 1 (breaking) whitespace character.
1354     * @since 3.0
1355     */
1356    public static boolean containsWhitespace(final CharSequence seq) {
1357        if (isEmpty(seq)) {
1358            return false;
1359        }
1360        final int strLen = seq.length();
1361        for (int i = 0; i < strLen; i++) {
1362            if (Character.isWhitespace(seq.charAt(i))) {
1363                return true;
1364            }
1365        }
1366        return false;
1367    }
1368
1369    private static void convertRemainingAccentCharacters(final StringBuilder decomposed) {
1370        for (int i = 0; i < decomposed.length(); i++) {
1371            final char charAt = decomposed.charAt(i);
1372            switch (charAt) {
1373            case '\u0141':
1374                decomposed.setCharAt(i, 'L');
1375                break;
1376            case '\u0142':
1377                decomposed.setCharAt(i, 'l');
1378                break;
1379            // D with stroke
1380            case '\u0110':
1381                // LATIN CAPITAL LETTER D WITH STROKE
1382                decomposed.setCharAt(i, 'D');
1383                break;
1384            case '\u0111':
1385                // LATIN SMALL LETTER D WITH STROKE
1386                decomposed.setCharAt(i, 'd');
1387                break;
1388            // I with bar
1389            case '\u0197':
1390                decomposed.setCharAt(i, 'I');
1391                break;
1392            case '\u0268':
1393                decomposed.setCharAt(i, 'i');
1394                break;
1395            case '\u1D7B':
1396                decomposed.setCharAt(i, 'I');
1397                break;
1398            case '\u1DA4':
1399                decomposed.setCharAt(i, 'i');
1400                break;
1401            case '\u1DA7':
1402                decomposed.setCharAt(i, 'I');
1403                break;
1404            // U with bar
1405            case '\u0244':
1406                // LATIN CAPITAL LETTER U BAR
1407                decomposed.setCharAt(i, 'U');
1408                break;
1409            case '\u0289':
1410                // LATIN SMALL LETTER U BAR
1411                decomposed.setCharAt(i, 'u');
1412                break;
1413            case '\u1D7E':
1414                // LATIN SMALL CAPITAL LETTER U WITH STROKE
1415                decomposed.setCharAt(i, 'U');
1416                break;
1417            case '\u1DB6':
1418                // MODIFIER LETTER SMALL U BAR
1419                decomposed.setCharAt(i, 'u');
1420                break;
1421            // T with stroke
1422            case '\u0166':
1423                // LATIN CAPITAL LETTER T WITH STROKE
1424                decomposed.setCharAt(i, 'T');
1425                break;
1426            case '\u0167':
1427                // LATIN SMALL LETTER T WITH STROKE
1428                decomposed.setCharAt(i, 't');
1429                break;
1430            default:
1431                break;
1432            }
1433        }
1434    }
1435
1436    /**
1437     * Counts how many times the char appears in the given string.
1438     *
1439     * <p>
1440     * A {@code null} or empty ("") String input returns {@code 0}.
1441     * </p>
1442     *
1443     * <pre>
1444     * StringUtils.countMatches(null, *)     = 0
1445     * StringUtils.countMatches("", *)       = 0
1446     * StringUtils.countMatches("abba", 0)   = 0
1447     * StringUtils.countMatches("abba", 'a') = 2
1448     * StringUtils.countMatches("abba", 'b') = 2
1449     * StringUtils.countMatches("abba", 'x') = 0
1450     * </pre>
1451     *
1452     * @param str the CharSequence to check, may be null.
1453     * @param ch  the char to count.
1454     * @return the number of occurrences, 0 if the CharSequence is {@code null}.
1455     * @since 3.4
1456     */
1457    public static int countMatches(final CharSequence str, final char ch) {
1458        if (isEmpty(str)) {
1459            return 0;
1460        }
1461        int count = 0;
1462        // We could also call str.toCharArray() for faster lookups but that would generate more garbage.
1463        for (int i = 0; i < str.length(); i++) {
1464            if (ch == str.charAt(i)) {
1465                count++;
1466            }
1467        }
1468        return count;
1469    }
1470
1471    /**
1472     * Counts how many times the substring appears in the larger string. Note that the code only counts non-overlapping matches.
1473     *
1474     * <p>
1475     * A {@code null} or empty ("") String input returns {@code 0}.
1476     * </p>
1477     *
1478     * <pre>
1479     * StringUtils.countMatches(null, *)        = 0
1480     * StringUtils.countMatches("", *)          = 0
1481     * StringUtils.countMatches("abba", null)   = 0
1482     * StringUtils.countMatches("abba", "")     = 0
1483     * StringUtils.countMatches("abba", "a")    = 2
1484     * StringUtils.countMatches("abba", "ab")   = 1
1485     * StringUtils.countMatches("abba", "xxx")  = 0
1486     * StringUtils.countMatches("ababa", "aba") = 1
1487     * </pre>
1488     *
1489     * @param str the CharSequence to check, may be null.
1490     * @param sub the substring to count, may be null.
1491     * @return the number of occurrences, 0 if either CharSequence is {@code null}.
1492     * @since 3.0 Changed signature from countMatches(String, String) to countMatches(CharSequence, CharSequence)
1493     */
1494    public static int countMatches(final CharSequence str, final CharSequence sub) {
1495        if (isEmpty(str) || isEmpty(sub)) {
1496            return 0;
1497        }
1498        int count = 0;
1499        int idx = 0;
1500        while ((idx = CharSequenceUtils.indexOf(str, sub, idx)) != INDEX_NOT_FOUND) {
1501            count++;
1502            idx += sub.length();
1503        }
1504        return count;
1505    }
1506
1507    /**
1508     * Returns either the passed in CharSequence, or if the CharSequence is {@link #isBlank(CharSequence) blank} (whitespaces, empty ({@code ""}) or
1509     * {@code null}), the value of {@code defaultStr}.
1510     *
1511     * <p>
1512     * Whitespace is defined by {@link Character#isWhitespace(char)}.
1513     * </p>
1514     *
1515     * <pre>
1516     * StringUtils.defaultIfBlank(null, "NULL")  = "NULL"
1517     * StringUtils.defaultIfBlank("", "NULL")    = "NULL"
1518     * StringUtils.defaultIfBlank(" ", "NULL")   = "NULL"
1519     * StringUtils.defaultIfBlank("bat", "NULL") = "bat"
1520     * StringUtils.defaultIfBlank("", null)      = null
1521     * </pre>
1522     *
1523     * @param <T>        the specific kind of CharSequence.
1524     * @param str        the CharSequence to check, may be null.
1525     * @param defaultStr the default CharSequence to return if {@code str} is {@link #isBlank(CharSequence) blank} (whitespaces, empty ({@code""}) or
1526     *                   {@code null}); may be null.
1527     * @return the passed in CharSequence, or the default.
1528     * @see StringUtils#defaultString(String, String)
1529     * @see #isBlank(CharSequence)
1530     */
1531    public static <T extends CharSequence> T defaultIfBlank(final T str, final T defaultStr) {
1532        return isBlank(str) ? defaultStr : str;
1533    }
1534
1535    /**
1536     * Returns either the passed in CharSequence, or if the CharSequence is empty or {@code null}, the value of {@code defaultStr}.
1537     *
1538     * <pre>
1539     * StringUtils.defaultIfEmpty(null, "NULL")  = "NULL"
1540     * StringUtils.defaultIfEmpty("", "NULL")    = "NULL"
1541     * StringUtils.defaultIfEmpty(" ", "NULL")   = " "
1542     * StringUtils.defaultIfEmpty("bat", "NULL") = "bat"
1543     * StringUtils.defaultIfEmpty("", null)      = null
1544     * </pre>
1545     *
1546     * @param <T>        the specific kind of CharSequence.
1547     * @param str        the CharSequence to check, may be null.
1548     * @param defaultStr the default CharSequence to return if the input is empty ("") or {@code null}, may be null.
1549     * @return the passed in CharSequence, or the default.
1550     * @see StringUtils#defaultString(String, String)
1551     */
1552    public static <T extends CharSequence> T defaultIfEmpty(final T str, final T defaultStr) {
1553        return isEmpty(str) ? defaultStr : str;
1554    }
1555
1556    /**
1557     * Returns either the passed in String, or if the String is {@code null}, an empty String ("").
1558     *
1559     * <pre>
1560     * StringUtils.defaultString(null)  = ""
1561     * StringUtils.defaultString("")    = ""
1562     * StringUtils.defaultString("bat") = "bat"
1563     * </pre>
1564     *
1565     * @param str the String to check, may be null.
1566     * @return the passed in String, or the empty String if it was {@code null}.
1567     * @see Objects#toString(Object, String)
1568     * @see String#valueOf(Object)
1569     */
1570    public static String defaultString(final String str) {
1571        return Objects.toString(str, EMPTY);
1572    }
1573
1574    /**
1575     * Returns either the given String, or if the String is {@code null}, {@code nullDefault}.
1576     *
1577     * <pre>
1578     * StringUtils.defaultString(null, "NULL")  = "NULL"
1579     * StringUtils.defaultString("", "NULL")    = ""
1580     * StringUtils.defaultString("bat", "NULL") = "bat"
1581     * </pre>
1582     * <p>
1583     * Since this is now provided by Java, instead call {@link Objects#toString(Object, String)}:
1584     * </p>
1585     *
1586     * <pre>
1587     * Objects.toString(null, "NULL")  = "NULL"
1588     * Objects.toString("", "NULL")    = ""
1589     * Objects.toString("bat", "NULL") = "bat"
1590     * </pre>
1591     *
1592     * @param str         the String to check, may be null.
1593     * @param nullDefault the default String to return if the input is {@code null}, may be null.
1594     * @return the passed in String, or the default if it was {@code null}.
1595     * @see Objects#toString(Object, String)
1596     * @see String#valueOf(Object)
1597     * @deprecated Use {@link Objects#toString(Object, String)}
1598     */
1599    @Deprecated
1600    public static String defaultString(final String str, final String nullDefault) {
1601        return Objects.toString(str, nullDefault);
1602    }
1603
1604    /**
1605     * Deletes all whitespaces from a String as defined by {@link Character#isWhitespace(char)}.
1606     *
1607     * <pre>
1608     * StringUtils.deleteWhitespace(null)         = null
1609     * StringUtils.deleteWhitespace("")           = ""
1610     * StringUtils.deleteWhitespace("abc")        = "abc"
1611     * StringUtils.deleteWhitespace("   ab  c  ") = "abc"
1612     * </pre>
1613     *
1614     * @param str the String to delete whitespace from, may be null.
1615     * @return the String without whitespaces, {@code null} if null String input.
1616     */
1617    public static String deleteWhitespace(final String str) {
1618        if (isEmpty(str)) {
1619            return str;
1620        }
1621        final int sz = str.length();
1622        final char[] chs = new char[sz];
1623        int count = 0;
1624        for (int i = 0; i < sz; i++) {
1625            if (!Character.isWhitespace(str.charAt(i))) {
1626                chs[count++] = str.charAt(i);
1627            }
1628        }
1629        if (count == sz) {
1630            return str;
1631        }
1632        if (count == 0) {
1633            return EMPTY;
1634        }
1635        return new String(chs, 0, count);
1636    }
1637
1638    /**
1639     * Compares two Strings, and returns the portion where they differ. More precisely, return the remainder of the second String, starting from where it's
1640     * different from the first. This means that the difference between "abc" and "ab" is the empty String and not "c".
1641     *
1642     * <p>
1643     * For example, {@code difference("i am a machine", "i am a robot") -> "robot"}.
1644     * </p>
1645     *
1646     * <pre>
1647     * StringUtils.difference(null, null)       = null
1648     * StringUtils.difference("", "")           = ""
1649     * StringUtils.difference("", "abc")        = "abc"
1650     * StringUtils.difference("abc", "")        = ""
1651     * StringUtils.difference("abc", "abc")     = ""
1652     * StringUtils.difference("abc", "ab")      = ""
1653     * StringUtils.difference("ab", "abxyz")    = "xyz"
1654     * StringUtils.difference("abcde", "abxyz") = "xyz"
1655     * StringUtils.difference("abcde", "xyz")   = "xyz"
1656     * </pre>
1657     *
1658     * @param str1 the first String, may be null.
1659     * @param str2 the second String, may be null.
1660     * @return the portion of str2 where it differs from str1; returns the empty String if they are equal.
1661     * @see #indexOfDifference(CharSequence,CharSequence)
1662     * @since 2.0
1663     */
1664    public static String difference(final String str1, final String str2) {
1665        if (str1 == null) {
1666            return str2;
1667        }
1668        if (str2 == null) {
1669            return str1;
1670        }
1671        final int at = indexOfDifference(str1, str2);
1672        if (at == INDEX_NOT_FOUND) {
1673            return EMPTY;
1674        }
1675        return str2.substring(at);
1676    }
1677
1678    /**
1679     * Tests if a CharSequence ends with a specified suffix.
1680     *
1681     * <p>
1682     * {@code null}s are handled without exceptions. Two {@code null} references are considered to be equal. The comparison is case-sensitive.
1683     * </p>
1684     *
1685     * <pre>
1686     * StringUtils.endsWith(null, null)      = true
1687     * StringUtils.endsWith(null, "def")     = false
1688     * StringUtils.endsWith("abcdef", null)  = false
1689     * StringUtils.endsWith("abcdef", "def") = true
1690     * StringUtils.endsWith("ABCDEF", "def") = false
1691     * StringUtils.endsWith("ABCDEF", "cde") = false
1692     * StringUtils.endsWith("ABCDEF", "")    = true
1693     * </pre>
1694     *
1695     * @param str    the CharSequence to check, may be null.
1696     * @param suffix the suffix to find, may be null.
1697     * @return {@code true} if the CharSequence ends with the suffix, case-sensitive, or both {@code null}.
1698     * @see String#endsWith(String)
1699     * @since 2.4
1700     * @since 3.0 Changed signature from endsWith(String, String) to endsWith(CharSequence, CharSequence)
1701     * @deprecated Use {@link Strings#endsWith(CharSequence, CharSequence) Strings.CS.endsWith(CharSequence, CharSequence)}
1702     */
1703    @Deprecated
1704    public static boolean endsWith(final CharSequence str, final CharSequence suffix) {
1705        return Strings.CS.endsWith(str, suffix);
1706    }
1707
1708    /**
1709     * Tests if a CharSequence ends with any of the provided case-sensitive suffixes.
1710     *
1711     * <pre>
1712     * StringUtils.endsWithAny(null, null)                  = false
1713     * StringUtils.endsWithAny(null, new String[] {"abc"})  = false
1714     * StringUtils.endsWithAny("abcxyz", null)              = false
1715     * StringUtils.endsWithAny("abcxyz", new String[] {""}) = true
1716     * StringUtils.endsWithAny("abcxyz", new String[] {"xyz"}) = true
1717     * StringUtils.endsWithAny("abcxyz", new String[] {null, "xyz", "abc"}) = true
1718     * StringUtils.endsWithAny("abcXYZ", "def", "XYZ")      = true
1719     * StringUtils.endsWithAny("abcXYZ", "def", "xyz")      = false
1720     * </pre>
1721     *
1722     * @param sequence      the CharSequence to check, may be null.
1723     * @param searchStrings the case-sensitive CharSequences to find, may be empty or contain {@code null}.
1724     * @return {@code true} if the input {@code sequence} is {@code null} AND no {@code searchStrings} are provided, or the input {@code sequence} ends in any
1725     *         of the provided case-sensitive {@code searchStrings}.
1726     * @see StringUtils#endsWith(CharSequence, CharSequence)
1727     * @since 3.0
1728     * @deprecated Use {@link Strings#endsWithAny(CharSequence, CharSequence...) Strings.CS.endsWithAny(CharSequence, CharSequence...)}
1729     */
1730    @Deprecated
1731    public static boolean endsWithAny(final CharSequence sequence, final CharSequence... searchStrings) {
1732        return Strings.CS.endsWithAny(sequence, searchStrings);
1733    }
1734
1735    /**
1736     * Case-insensitive check if a CharSequence ends with a specified suffix.
1737     *
1738     * <p>
1739     * {@code null}s are handled without exceptions. Two {@code null} references are considered to be equal. The comparison is case insensitive.
1740     * </p>
1741     *
1742     * <pre>
1743     * StringUtils.endsWithIgnoreCase(null, null)      = true
1744     * StringUtils.endsWithIgnoreCase(null, "def")     = false
1745     * StringUtils.endsWithIgnoreCase("abcdef", null)  = false
1746     * StringUtils.endsWithIgnoreCase("abcdef", "def") = true
1747     * StringUtils.endsWithIgnoreCase("ABCDEF", "def") = true
1748     * StringUtils.endsWithIgnoreCase("ABCDEF", "cde") = false
1749     * </pre>
1750     *
1751     * @param str    the CharSequence to check, may be null
1752     * @param suffix the suffix to find, may be null
1753     * @return {@code true} if the CharSequence ends with the suffix, case-insensitive, or both {@code null}
1754     * @see String#endsWith(String)
1755     * @since 2.4
1756     * @since 3.0 Changed signature from endsWithIgnoreCase(String, String) to endsWithIgnoreCase(CharSequence, CharSequence)
1757     * @deprecated Use {@link Strings#endsWith(CharSequence, CharSequence) Strings.CI.endsWith(CharSequence, CharSequence)}
1758     */
1759    @Deprecated
1760    public static boolean endsWithIgnoreCase(final CharSequence str, final CharSequence suffix) {
1761        return Strings.CI.endsWith(str, suffix);
1762    }
1763
1764    /**
1765     * Compares two CharSequences, returning {@code true} if they represent equal sequences of characters.
1766     *
1767     * <p>
1768     * {@code null}s are handled without exceptions. Two {@code null} references are considered to be equal. The comparison is <strong>case-sensitive</strong>.
1769     * </p>
1770     *
1771     * <pre>
1772     * StringUtils.equals(null, null)   = true
1773     * StringUtils.equals(null, "abc")  = false
1774     * StringUtils.equals("abc", null)  = false
1775     * StringUtils.equals("abc", "abc") = true
1776     * StringUtils.equals("abc", "ABC") = false
1777     * </pre>
1778     *
1779     * @param cs1 the first CharSequence, may be {@code null}.
1780     * @param cs2 the second CharSequence, may be {@code null}.
1781     * @return {@code true} if the CharSequences are equal (case-sensitive), or both {@code null}.
1782     * @since 3.0 Changed signature from equals(String, String) to equals(CharSequence, CharSequence)
1783     * @see Object#equals(Object)
1784     * @see #equalsIgnoreCase(CharSequence, CharSequence)
1785     * @deprecated Use {@link Strings#equals(CharSequence, CharSequence) Strings.CS.equals(CharSequence, CharSequence)}
1786     */
1787    @Deprecated
1788    public static boolean equals(final CharSequence cs1, final CharSequence cs2) {
1789        return Strings.CS.equals(cs1, cs2);
1790    }
1791
1792    /**
1793     * Compares given {@code string} to a CharSequences vararg of {@code searchStrings}, returning {@code true} if the {@code string} is equal to any of the
1794     * {@code searchStrings}.
1795     *
1796     * <pre>
1797     * StringUtils.equalsAny(null, (CharSequence[]) null) = false
1798     * StringUtils.equalsAny(null, null, null)    = true
1799     * StringUtils.equalsAny(null, "abc", "def")  = false
1800     * StringUtils.equalsAny("abc", null, "def")  = false
1801     * StringUtils.equalsAny("abc", "abc", "def") = true
1802     * StringUtils.equalsAny("abc", "ABC", "DEF") = false
1803     * </pre>
1804     *
1805     * @param string        to compare, may be {@code null}.
1806     * @param searchStrings a vararg of strings, may be {@code null}.
1807     * @return {@code true} if the string is equal (case-sensitive) to any other element of {@code searchStrings}; {@code false} if {@code searchStrings} is
1808     *         null or contains no matches.
1809     * @since 3.5
1810     * @deprecated Use {@link Strings#equalsAny(CharSequence, CharSequence...) Strings.CS.equalsAny(CharSequence, CharSequence...)}
1811     */
1812    @Deprecated
1813    public static boolean equalsAny(final CharSequence string, final CharSequence... searchStrings) {
1814        return Strings.CS.equalsAny(string, searchStrings);
1815    }
1816
1817    /**
1818     * Compares given {@code string} to a CharSequences vararg of {@code searchStrings},
1819     * returning {@code true} if the {@code string} is equal to any of the {@code searchStrings}, ignoring case.
1820     *
1821     * <pre>
1822     * StringUtils.equalsAnyIgnoreCase(null, (CharSequence[]) null) = false
1823     * StringUtils.equalsAnyIgnoreCase(null, null, null)    = true
1824     * StringUtils.equalsAnyIgnoreCase(null, "abc", "def")  = false
1825     * StringUtils.equalsAnyIgnoreCase("abc", null, "def")  = false
1826     * StringUtils.equalsAnyIgnoreCase("abc", "abc", "def") = true
1827     * StringUtils.equalsAnyIgnoreCase("abc", "ABC", "DEF") = true
1828     * </pre>
1829     *
1830     * @param string to compare, may be {@code null}.
1831     * @param searchStrings a vararg of strings, may be {@code null}.
1832     * @return {@code true} if the string is equal (case-insensitive) to any other element of {@code searchStrings};
1833     * {@code false} if {@code searchStrings} is null or contains no matches.
1834     * @since 3.5
1835     * @deprecated Use {@link Strings#equalsAny(CharSequence, CharSequence...) Strings.CI-.equalsAny(CharSequence, CharSequence...)}
1836     */
1837    @Deprecated
1838    public static boolean equalsAnyIgnoreCase(final CharSequence string, final CharSequence... searchStrings) {
1839        return Strings.CI.equalsAny(string, searchStrings);
1840    }
1841
1842    /**
1843     * Compares two CharSequences, returning {@code true} if they represent equal sequences of characters, ignoring case.
1844     *
1845     * <p>
1846     * {@code null}s are handled without exceptions. Two {@code null} references are considered equal. The comparison is <strong>case insensitive</strong>.
1847     * </p>
1848     *
1849     * <pre>
1850     * StringUtils.equalsIgnoreCase(null, null)   = true
1851     * StringUtils.equalsIgnoreCase(null, "abc")  = false
1852     * StringUtils.equalsIgnoreCase("abc", null)  = false
1853     * StringUtils.equalsIgnoreCase("abc", "abc") = true
1854     * StringUtils.equalsIgnoreCase("abc", "ABC") = true
1855     * </pre>
1856     *
1857     * @param cs1 the first CharSequence, may be {@code null}.
1858     * @param cs2 the second CharSequence, may be {@code null}.
1859     * @return {@code true} if the CharSequences are equal (case-insensitive), or both {@code null}.
1860     * @since 3.0 Changed signature from equalsIgnoreCase(String, String) to equalsIgnoreCase(CharSequence, CharSequence)
1861     * @see #equals(CharSequence, CharSequence)
1862     * @deprecated Use {@link Strings#equals(CharSequence, CharSequence) Strings.CI.equals(CharSequence, CharSequence)}
1863     */
1864    @Deprecated
1865    public static boolean equalsIgnoreCase(final CharSequence cs1, final CharSequence cs2) {
1866        return Strings.CI.equals(cs1, cs2);
1867    }
1868
1869    /**
1870     * Returns the first value in the array which is not empty (""), {@code null} or whitespace only.
1871     *
1872     * <p>
1873     * Whitespace is defined by {@link Character#isWhitespace(char)}.
1874     * </p>
1875     *
1876     * <p>
1877     * If all values are blank or the array is {@code null} or empty then {@code null} is returned.
1878     * </p>
1879     *
1880     * <pre>
1881     * StringUtils.firstNonBlank(null, null, null)     = null
1882     * StringUtils.firstNonBlank(null, "", " ")        = null
1883     * StringUtils.firstNonBlank("abc")                = "abc"
1884     * StringUtils.firstNonBlank(null, "xyz")          = "xyz"
1885     * StringUtils.firstNonBlank(null, "", " ", "xyz") = "xyz"
1886     * StringUtils.firstNonBlank(null, "xyz", "abc")   = "xyz"
1887     * StringUtils.firstNonBlank()                     = null
1888     * </pre>
1889     *
1890     * @param <T>    the specific kind of CharSequence.
1891     * @param values the values to test, may be {@code null} or empty.
1892     * @return the first value from {@code values} which is not blank, or {@code null} if there are no non-blank values.
1893     * @since 3.8
1894     */
1895    @SafeVarargs
1896    public static <T extends CharSequence> T firstNonBlank(final T... values) {
1897        if (values != null) {
1898            for (final T val : values) {
1899                if (isNotBlank(val)) {
1900                    return val;
1901                }
1902            }
1903        }
1904        return null;
1905    }
1906
1907    /**
1908     * Returns the first value in the array which is not empty.
1909     *
1910     * <p>
1911     * If all values are empty or the array is {@code null} or empty then {@code null} is returned.
1912     * </p>
1913     *
1914     * <pre>
1915     * StringUtils.firstNonEmpty(null, null, null)   = null
1916     * StringUtils.firstNonEmpty(null, null, "")     = null
1917     * StringUtils.firstNonEmpty(null, "", " ")      = " "
1918     * StringUtils.firstNonEmpty("abc")              = "abc"
1919     * StringUtils.firstNonEmpty(null, "xyz")        = "xyz"
1920     * StringUtils.firstNonEmpty("", "xyz")          = "xyz"
1921     * StringUtils.firstNonEmpty(null, "xyz", "abc") = "xyz"
1922     * StringUtils.firstNonEmpty()                   = null
1923     * </pre>
1924     *
1925     * @param <T>    the specific kind of CharSequence.
1926     * @param values the values to test, may be {@code null} or empty.
1927     * @return the first value from {@code values} which is not empty, or {@code null} if there are no non-empty values.
1928     * @since 3.8
1929     */
1930    @SafeVarargs
1931    public static <T extends CharSequence> T firstNonEmpty(final T... values) {
1932        if (values != null) {
1933            for (final T val : values) {
1934                if (isNotEmpty(val)) {
1935                    return val;
1936                }
1937            }
1938        }
1939        return null;
1940    }
1941
1942    /**
1943     * Calls {@link String#getBytes(Charset)} in a null-safe manner.
1944     *
1945     * @param string input string.
1946     * @param charset The {@link Charset} to encode the {@link String}. If null, then use the default Charset.
1947     * @return The empty byte[] if {@code string} is null, the result of {@link String#getBytes(Charset)} otherwise.
1948     * @see String#getBytes(Charset)
1949     * @since 3.10
1950     */
1951    public static byte[] getBytes(final String string, final Charset charset) {
1952        return string == null ? ArrayUtils.EMPTY_BYTE_ARRAY : string.getBytes(Charsets.toCharset(charset));
1953    }
1954
1955    /**
1956     * Calls {@link String#getBytes(String)} in a null-safe manner.
1957     *
1958     * @param string input string.
1959     * @param charset The {@link Charset} name to encode the {@link String}. If null, then use the default Charset.
1960     * @return The empty byte[] if {@code string} is null, the result of {@link String#getBytes(String)} otherwise.
1961     * @throws UnsupportedEncodingException Thrown when the named charset is not supported.
1962     * @see String#getBytes(String)
1963     * @since 3.10
1964     */
1965    public static byte[] getBytes(final String string, final String charset) throws UnsupportedEncodingException {
1966        return string == null ? ArrayUtils.EMPTY_BYTE_ARRAY : string.getBytes(Charsets.toCharsetName(charset));
1967    }
1968
1969    /**
1970     * Compares all Strings in an array and returns the initial sequence of characters that is common to all of them.
1971     *
1972     * <p>
1973     * For example, {@code getCommonPrefix("i am a machine", "i am a robot") -&gt; "i am a "}
1974     * </p>
1975     *
1976     * <pre>
1977     * StringUtils.getCommonPrefix(null)                             = ""
1978     * StringUtils.getCommonPrefix(new String[] {})                  = ""
1979     * StringUtils.getCommonPrefix(new String[] {"abc"})             = "abc"
1980     * StringUtils.getCommonPrefix(new String[] {null, null})        = ""
1981     * StringUtils.getCommonPrefix(new String[] {"", ""})            = ""
1982     * StringUtils.getCommonPrefix(new String[] {"", null})          = ""
1983     * StringUtils.getCommonPrefix(new String[] {"abc", null, null}) = ""
1984     * StringUtils.getCommonPrefix(new String[] {null, null, "abc"}) = ""
1985     * StringUtils.getCommonPrefix(new String[] {"", "abc"})         = ""
1986     * StringUtils.getCommonPrefix(new String[] {"abc", ""})         = ""
1987     * StringUtils.getCommonPrefix(new String[] {"abc", "abc"})      = "abc"
1988     * StringUtils.getCommonPrefix(new String[] {"abc", "a"})        = "a"
1989     * StringUtils.getCommonPrefix(new String[] {"ab", "abxyz"})     = "ab"
1990     * StringUtils.getCommonPrefix(new String[] {"abcde", "abxyz"})  = "ab"
1991     * StringUtils.getCommonPrefix(new String[] {"abcde", "xyz"})    = ""
1992     * StringUtils.getCommonPrefix(new String[] {"xyz", "abcde"})    = ""
1993     * StringUtils.getCommonPrefix(new String[] {"i am a machine", "i am a robot"}) = "i am a "
1994     * </pre>
1995     *
1996     * @param strs array of String objects, entries may be null.
1997     * @return the initial sequence of characters that are common to all Strings in the array; empty String if the array is null, the elements are all null or
1998     *         if there is no common prefix.
1999     * @since 2.4
2000     */
2001    public static String getCommonPrefix(final String... strs) {
2002        if (ArrayUtils.isEmpty(strs)) {
2003            return EMPTY;
2004        }
2005        final int smallestIndexOfDiff = indexOfDifference(strs);
2006        if (smallestIndexOfDiff == INDEX_NOT_FOUND) {
2007            // all strings were identical
2008            if (strs[0] == null) {
2009                return EMPTY;
2010            }
2011            return strs[0];
2012        }
2013        if (smallestIndexOfDiff == 0) {
2014            // there were no common initial characters
2015            return EMPTY;
2016        }
2017        // we found a common initial character sequence
2018        return strs[0].substring(0, smallestIndexOfDiff);
2019    }
2020
2021    /**
2022     * Checks if a String {@code str} contains Unicode digits, if yes then concatenate all the digits in {@code str} and return it as a String.
2023     *
2024     * <p>
2025     * An empty ("") String will be returned if no digits found in {@code str}.
2026     * </p>
2027     *
2028     * <pre>
2029     * StringUtils.getDigits(null)                 = null
2030     * StringUtils.getDigits("")                   = ""
2031     * StringUtils.getDigits("abc")                = ""
2032     * StringUtils.getDigits("1000$")              = "1000"
2033     * StringUtils.getDigits("1123~45")            = "112345"
2034     * StringUtils.getDigits("(541) 754-3010")     = "5417543010"
2035     * StringUtils.getDigits("\u0967\u0968\u0969") = "\u0967\u0968\u0969"
2036     * </pre>
2037     *
2038     * @param str the String to extract digits from, may be null.
2039     * @return String with only digits, or an empty ("") String if no digits found, or {@code null} String if {@code str} is null.
2040     * @since 3.6
2041     */
2042    public static String getDigits(final String str) {
2043        if (isEmpty(str)) {
2044            return str;
2045        }
2046        final int sz = str.length();
2047        final StringBuilder strDigits = new StringBuilder(sz);
2048        for (int i = 0; i < sz; i++) {
2049            final char tempChar = str.charAt(i);
2050            if (Character.isDigit(tempChar)) {
2051                strDigits.append(tempChar);
2052            }
2053        }
2054        return strDigits.toString();
2055    }
2056
2057    /**
2058     * Gets the Fuzzy Distance which indicates the similarity score between two Strings.
2059     *
2060     * <p>
2061     * This string matching algorithm is similar to the algorithms of editors such as Sublime Text, TextMate, Atom and others. One point is given for every
2062     * matched character. Subsequent matches yield two bonus points. A higher score indicates a higher similarity.
2063     * </p>
2064     *
2065     * <pre>
2066     * StringUtils.getFuzzyDistance(null, null, null)                                    = IllegalArgumentException
2067     * StringUtils.getFuzzyDistance("", "", Locale.ENGLISH)                              = 0
2068     * StringUtils.getFuzzyDistance("Workshop", "b", Locale.ENGLISH)                     = 0
2069     * StringUtils.getFuzzyDistance("Room", "o", Locale.ENGLISH)                         = 1
2070     * StringUtils.getFuzzyDistance("Workshop", "w", Locale.ENGLISH)                     = 1
2071     * StringUtils.getFuzzyDistance("Workshop", "ws", Locale.ENGLISH)                    = 2
2072     * StringUtils.getFuzzyDistance("Workshop", "wo", Locale.ENGLISH)                    = 4
2073     * StringUtils.getFuzzyDistance("Apache Software Foundation", "asf", Locale.ENGLISH) = 3
2074     * </pre>
2075     *
2076     * @param term   a full term that should be matched against, must not be null.
2077     * @param query  the query that will be matched against a term, must not be null.
2078     * @param locale This string matching logic is case-insensitive. A locale is necessary to normalize both Strings to lower case.
2079     * @return result score.
2080     * @throws IllegalArgumentException if either String input {@code null} or Locale input {@code null}.
2081     * @since 3.4
2082     * @deprecated As of 3.6, use Apache Commons Text
2083     *             <a href="https://commons.apache.org/proper/commons-text/javadocs/api-release/org/apache/commons/text/similarity/FuzzyScore.html">
2084     *             FuzzyScore</a> instead
2085     */
2086    @Deprecated
2087    public static int getFuzzyDistance(final CharSequence term, final CharSequence query, final Locale locale) {
2088        if (term == null || query == null) {
2089            throw new IllegalArgumentException("Strings must not be null");
2090        }
2091        if (locale == null) {
2092            throw new IllegalArgumentException("Locale must not be null");
2093        }
2094        // fuzzy logic is case-insensitive. We normalize the Strings to lower
2095        // case right from the start. Turning characters to lower case
2096        // via Character.toLowerCase(char) is unfortunately insufficient
2097        // as it does not accept a locale.
2098        final String termLowerCase = term.toString().toLowerCase(locale);
2099        final String queryLowerCase = query.toString().toLowerCase(locale);
2100        // the resulting score
2101        int score = 0;
2102        // the position in the term which will be scanned next for potential
2103        // query character matches
2104        int termIndex = 0;
2105        // index of the previously matched character in the term
2106        int previousMatchingCharacterIndex = Integer.MIN_VALUE;
2107        for (int queryIndex = 0; queryIndex < queryLowerCase.length(); queryIndex++) {
2108            final char queryChar = queryLowerCase.charAt(queryIndex);
2109            boolean termCharacterMatchFound = false;
2110            for (; termIndex < termLowerCase.length() && !termCharacterMatchFound; termIndex++) {
2111                final char termChar = termLowerCase.charAt(termIndex);
2112                if (queryChar == termChar) {
2113                    // simple character matches result in one point
2114                    score++;
2115                    // subsequent character matches further improve
2116                    // the score.
2117                    if (previousMatchingCharacterIndex + 1 == termIndex) {
2118                        score += 2;
2119                    }
2120                    previousMatchingCharacterIndex = termIndex;
2121                    // we can leave the nested loop. Every character in the
2122                    // query can match at most one character in the term.
2123                    termCharacterMatchFound = true;
2124                }
2125            }
2126        }
2127        return score;
2128    }
2129
2130    /**
2131     * Returns either the passed in CharSequence, or if the CharSequence is {@link #isBlank(CharSequence) blank} (whitespaces, empty ({@code ""}) or
2132     * {@code null}), the value supplied by {@code defaultStrSupplier}.
2133     *
2134     * <p>
2135     * Whitespace is defined by {@link Character#isWhitespace(char)}.
2136     * </p>
2137     *
2138     * <p>
2139     * Caller responsible for thread-safety and exception handling of default value supplier
2140     * </p>
2141     *
2142     * <pre>
2143     * {@code
2144     * StringUtils.getIfBlank(null, () -> "NULL")   = "NULL"
2145     * StringUtils.getIfBlank("", () -> "NULL")     = "NULL"
2146     * StringUtils.getIfBlank(" ", () -> "NULL")    = "NULL"
2147     * StringUtils.getIfBlank("bat", () -> "NULL")  = "bat"
2148     * StringUtils.getIfBlank("", () -> null)       = null
2149     * StringUtils.getIfBlank("", null)             = null
2150     * }</pre>
2151     *
2152     * @param <T>             the specific kind of CharSequence.
2153     * @param str             the CharSequence to check, may be null.
2154     * @param defaultSupplier the supplier of default CharSequence to return if the input is {@link #isBlank(CharSequence) blank} (whitespaces, empty
2155     *                        ({@code ""}) or {@code null}); may be null.
2156     * @return the passed in CharSequence, or the default
2157     * @see StringUtils#defaultString(String, String)
2158     * @see #isBlank(CharSequence)
2159     * @since 3.10
2160     */
2161    public static <T extends CharSequence> T getIfBlank(final T str, final Supplier<T> defaultSupplier) {
2162        return isBlank(str) ? Suppliers.get(defaultSupplier) : str;
2163    }
2164
2165    /**
2166     * Returns either the passed in CharSequence, or if the CharSequence is empty or {@code null}, the value supplied by {@code defaultStrSupplier}.
2167     *
2168     * <p>
2169     * Caller responsible for thread-safety and exception handling of default value supplier
2170     * </p>
2171     *
2172     * <pre>
2173     * {@code
2174     * StringUtils.getIfEmpty(null, () -> "NULL")    = "NULL"
2175     * StringUtils.getIfEmpty("", () -> "NULL")      = "NULL"
2176     * StringUtils.getIfEmpty(" ", () -> "NULL")     = " "
2177     * StringUtils.getIfEmpty("bat", () -> "NULL")   = "bat"
2178     * StringUtils.getIfEmpty("", () -> null)        = null
2179     * StringUtils.getIfEmpty("", null)              = null
2180     * }
2181     * </pre>
2182     *
2183     * @param <T>             the specific kind of CharSequence.
2184     * @param str             the CharSequence to check, may be null.
2185     * @param defaultSupplier the supplier of default CharSequence to return if the input is empty ("") or {@code null}, may be null.
2186     * @return the passed in CharSequence, or the default.
2187     * @see StringUtils#defaultString(String, String)
2188     * @since 3.10
2189     */
2190    public static <T extends CharSequence> T getIfEmpty(final T str, final Supplier<T> defaultSupplier) {
2191        return isEmpty(str) ? Suppliers.get(defaultSupplier) : str;
2192    }
2193
2194    /**
2195     * Gets the Jaro Winkler Distance which indicates the similarity score between two Strings.
2196     *
2197     * <p>
2198     * The Jaro measure is the weighted sum of percentage of matched characters from each file and transposed characters. Winkler increased this measure for
2199     * matching initial characters.
2200     * </p>
2201     *
2202     * <p>
2203     * This implementation is based on the Jaro Winkler similarity algorithm from
2204     * <a href="https://en.wikipedia.org/wiki/Jaro%E2%80%93Winkler_distance">https://en.wikipedia.org/wiki/Jaro%E2%80%93Winkler_distance</a>.
2205     * </p>
2206     *
2207     * <pre>
2208     * StringUtils.getJaroWinklerDistance(null, null)          = IllegalArgumentException
2209     * StringUtils.getJaroWinklerDistance("", "")              = 0.0
2210     * StringUtils.getJaroWinklerDistance("", "a")             = 0.0
2211     * StringUtils.getJaroWinklerDistance("aaapppp", "")       = 0.0
2212     * StringUtils.getJaroWinklerDistance("frog", "fog")       = 0.93
2213     * StringUtils.getJaroWinklerDistance("fly", "ant")        = 0.0
2214     * StringUtils.getJaroWinklerDistance("elephant", "hippo") = 0.44
2215     * StringUtils.getJaroWinklerDistance("hippo", "elephant") = 0.44
2216     * StringUtils.getJaroWinklerDistance("hippo", "zzzzzzzz") = 0.0
2217     * StringUtils.getJaroWinklerDistance("hello", "hallo")    = 0.88
2218     * StringUtils.getJaroWinklerDistance("ABC Corporation", "ABC Corp") = 0.93
2219     * StringUtils.getJaroWinklerDistance("D N H Enterprises Inc", "D &amp; H Enterprises, Inc.") = 0.95
2220     * StringUtils.getJaroWinklerDistance("My Gym Children's Fitness Center", "My Gym. Childrens Fitness") = 0.92
2221     * StringUtils.getJaroWinklerDistance("PENNSYLVANIA", "PENNCISYLVNIA") = 0.88
2222     * </pre>
2223     *
2224     * @param first  the first String, must not be null.
2225     * @param second the second String, must not be null.
2226     * @return result distance.
2227     * @throws IllegalArgumentException if either String input {@code null}.
2228     * @since 3.3
2229     * @deprecated As of 3.6, use Apache Commons Text
2230     *             <a href="https://commons.apache.org/proper/commons-text/javadocs/api-release/org/apache/commons/text/similarity/JaroWinklerDistance.html">
2231     *             JaroWinklerDistance</a> instead
2232     */
2233    @Deprecated
2234    public static double getJaroWinklerDistance(final CharSequence first, final CharSequence second) {
2235        final double DEFAULT_SCALING_FACTOR = 0.1;
2236
2237        if (first == null || second == null) {
2238            throw new IllegalArgumentException("Strings must not be null");
2239        }
2240
2241        final int[] mtp = matches(first, second);
2242        final double m = mtp[0];
2243        if (m == 0) {
2244            return 0D;
2245        }
2246        final double j = (m / first.length() + m / second.length() + (m - mtp[1]) / m) / 3;
2247        final double jw = j < 0.7D ? j : j + Math.min(DEFAULT_SCALING_FACTOR, 1D / mtp[3]) * mtp[2] * (1D - j);
2248        return Math.round(jw * 100.0D) / 100.0D;
2249    }
2250
2251    /**
2252     * Gets the Levenshtein distance between two Strings.
2253     *
2254     * <p>
2255     * This is the number of changes needed to change one String into another, where each change is a single character modification (deletion, insertion or
2256     * substitution).
2257     * </p>
2258     *
2259     * <p>
2260     * The implementation uses a single-dimensional array of length s.length() + 1. See
2261     * <a href="https://blog.softwx.net/2014/12/optimizing-levenshtein-algorithm-in-c.html">
2262     * https://blog.softwx.net/2014/12/optimizing-levenshtein-algorithm-in-c.html</a> for details.
2263     * </p>
2264     *
2265     * <pre>
2266     * StringUtils.getLevenshteinDistance(null, *)             = IllegalArgumentException
2267     * StringUtils.getLevenshteinDistance(*, null)             = IllegalArgumentException
2268     * StringUtils.getLevenshteinDistance("", "")              = 0
2269     * StringUtils.getLevenshteinDistance("", "a")             = 1
2270     * StringUtils.getLevenshteinDistance("aaapppp", "")       = 7
2271     * StringUtils.getLevenshteinDistance("frog", "fog")       = 1
2272     * StringUtils.getLevenshteinDistance("fly", "ant")        = 3
2273     * StringUtils.getLevenshteinDistance("elephant", "hippo") = 7
2274     * StringUtils.getLevenshteinDistance("hippo", "elephant") = 7
2275     * StringUtils.getLevenshteinDistance("hippo", "zzzzzzzz") = 8
2276     * StringUtils.getLevenshteinDistance("hello", "hallo")    = 1
2277     * </pre>
2278     *
2279     * @param s the first String, must not be null.
2280     * @param t the second String, must not be null.
2281     * @return result distance.
2282     * @throws IllegalArgumentException if either String input {@code null}.
2283     * @since 3.0 Changed signature from getLevenshteinDistance(String, String) to getLevenshteinDistance(CharSequence, CharSequence)
2284     * @deprecated As of 3.6, use Apache Commons Text
2285     *             <a href="https://commons.apache.org/proper/commons-text/javadocs/api-release/org/apache/commons/text/similarity/LevenshteinDistance.html">
2286     *             LevenshteinDistance</a> instead
2287     */
2288    @Deprecated
2289    public static int getLevenshteinDistance(CharSequence s, CharSequence t) {
2290        if (s == null || t == null) {
2291            throw new IllegalArgumentException("Strings must not be null");
2292        }
2293
2294        int n = s.length();
2295        int m = t.length();
2296
2297        if (n == 0) {
2298            return m;
2299        }
2300        if (m == 0) {
2301            return n;
2302        }
2303
2304        if (n > m) {
2305            // swap the input strings to consume less memory
2306            final CharSequence tmp = s;
2307            s = t;
2308            t = tmp;
2309            n = m;
2310            m = t.length();
2311        }
2312
2313        final int[] p = new int[n + 1];
2314        // indexes into strings s and t
2315        int i; // iterates through s
2316        int j; // iterates through t
2317        int upperleft;
2318        int upper;
2319
2320        char jOfT; // jth character of t
2321        int cost;
2322
2323        for (i = 0; i <= n; i++) {
2324            p[i] = i;
2325        }
2326
2327        for (j = 1; j <= m; j++) {
2328            upperleft = p[0];
2329            jOfT = t.charAt(j - 1);
2330            p[0] = j;
2331
2332            for (i = 1; i <= n; i++) {
2333                upper = p[i];
2334                cost = s.charAt(i - 1) == jOfT ? 0 : 1;
2335                // minimum of cell to the left+1, to the top+1, diagonally left and up +cost
2336                p[i] = Math.min(Math.min(p[i - 1] + 1, p[i] + 1), upperleft + cost);
2337                upperleft = upper;
2338            }
2339        }
2340
2341        return p[n];
2342    }
2343
2344    /**
2345     * Gets the Levenshtein distance between two Strings if it's less than or equal to a given threshold.
2346     *
2347     * <p>
2348     * This is the number of changes needed to change one String into another, where each change is a single character modification (deletion, insertion or
2349     * substitution).
2350     * </p>
2351     *
2352     * <p>
2353     * This implementation follows from Algorithms on Strings, Trees and Sequences by Dan Gusfield and Chas Emerick's implementation of the Levenshtein distance
2354     * algorithm from <a href="https://web.archive.org/web/20120212021906/http%3A//www.merriampark.com/ld.htm">http://www.merriampark.com/ld.htm</a>
2355     * </p>
2356     *
2357     * <pre>
2358     * StringUtils.getLevenshteinDistance(null, *, *)             = IllegalArgumentException
2359     * StringUtils.getLevenshteinDistance(*, null, *)             = IllegalArgumentException
2360     * StringUtils.getLevenshteinDistance(*, *, -1)               = IllegalArgumentException
2361     * StringUtils.getLevenshteinDistance("", "", 0)              = 0
2362     * StringUtils.getLevenshteinDistance("aaapppp", "", 8)       = 7
2363     * StringUtils.getLevenshteinDistance("aaapppp", "", 7)       = 7
2364     * StringUtils.getLevenshteinDistance("aaapppp", "", 6))      = -1
2365     * StringUtils.getLevenshteinDistance("elephant", "hippo", 7) = 7
2366     * StringUtils.getLevenshteinDistance("elephant", "hippo", 6) = -1
2367     * StringUtils.getLevenshteinDistance("hippo", "elephant", 7) = 7
2368     * StringUtils.getLevenshteinDistance("hippo", "elephant", 6) = -1
2369     * </pre>
2370     *
2371     * @param s         the first String, must not be null.
2372     * @param t         the second String, must not be null.
2373     * @param threshold the target threshold, must not be negative.
2374     * @return result distance, or {@code -1} if the distance would be greater than the threshold.
2375     * @throws IllegalArgumentException if either String input {@code null} or negative threshold.
2376     * @deprecated As of 3.6, use Apache Commons Text
2377     *             <a href="https://commons.apache.org/proper/commons-text/javadocs/api-release/org/apache/commons/text/similarity/LevenshteinDistance.html">
2378     *             LevenshteinDistance</a> instead
2379     */
2380    @Deprecated
2381    public static int getLevenshteinDistance(CharSequence s, CharSequence t, final int threshold) {
2382        if (s == null || t == null) {
2383            throw new IllegalArgumentException("Strings must not be null");
2384        }
2385        if (threshold < 0) {
2386            throw new IllegalArgumentException("Threshold must not be negative");
2387        }
2388
2389        /*
2390        This implementation only computes the distance if it's less than or equal to the
2391        threshold value, returning -1 if it's greater.  The advantage is performance: unbounded
2392        distance is O(nm), but a bound of k allows us to reduce it to O(km) time by only
2393        computing a diagonal stripe of width 2k + 1 of the cost table.
2394        It is also possible to use this to compute the unbounded Levenshtein distance by starting
2395        the threshold at 1 and doubling each time until the distance is found; this is O(dm), where
2396        d is the distance.
2397
2398        One subtlety comes from needing to ignore entries on the border of our stripe
2399        eg.
2400        p[] = |#|#|#|*
2401        d[] =  *|#|#|#|
2402        We must ignore the entry to the left of the leftmost member
2403        We must ignore the entry above the rightmost member
2404
2405        Another subtlety comes from our stripe running off the matrix if the strings aren't
2406        of the same size.  Since string s is always swapped to be the shorter of the two,
2407        the stripe will always run off to the upper right instead of the lower left of the matrix.
2408
2409        As a concrete example, suppose s is of length 5, t is of length 7, and our threshold is 1.
2410        In this case we're going to walk a stripe of length 3.  The matrix would look like so:
2411
2412           1 2 3 4 5
2413        1 |#|#| | | |
2414        2 |#|#|#| | |
2415        3 | |#|#|#| |
2416        4 | | |#|#|#|
2417        5 | | | |#|#|
2418        6 | | | | |#|
2419        7 | | | | | |
2420
2421        Note how the stripe leads off the table as there is no possible way to turn a string of length 5
2422        into one of length 7 in edit distance of 1.
2423
2424        Additionally, this implementation decreases memory usage by using two
2425        single-dimensional arrays and swapping them back and forth instead of allocating
2426        an entire n by m matrix.  This requires a few minor changes, such as immediately returning
2427        when it's detected that the stripe has run off the matrix and initially filling the arrays with
2428        large values so that entries we don't compute are ignored.
2429
2430        See Algorithms on Strings, Trees and Sequences by Dan Gusfield for some discussion.
2431         */
2432
2433        int n = s.length(); // length of s
2434        int m = t.length(); // length of t
2435
2436        // if one string is empty, the edit distance is necessarily the length of the other
2437        if (n == 0) {
2438            return m <= threshold ? m : -1;
2439        }
2440        if (m == 0) {
2441            return n <= threshold ? n : -1;
2442        }
2443        if (Math.abs(n - m) > threshold) {
2444            // no need to calculate the distance if the length difference is greater than the threshold
2445            return -1;
2446        }
2447
2448        if (n > m) {
2449            // swap the two strings to consume less memory
2450            final CharSequence tmp = s;
2451            s = t;
2452            t = tmp;
2453            n = m;
2454            m = t.length();
2455        }
2456
2457        int[] p = new int[n + 1]; // 'previous' cost array, horizontally
2458        int[] d = new int[n + 1]; // cost array, horizontally
2459        int[] tmp; // placeholder to assist in swapping p and d
2460
2461        // fill in starting table values
2462        final int boundary = Math.min(n, threshold) + 1;
2463        for (int i = 0; i < boundary; i++) {
2464            p[i] = i;
2465        }
2466        // these fills ensure that the value above the rightmost entry of our
2467        // stripe will be ignored in following loop iterations
2468        Arrays.fill(p, boundary, p.length, Integer.MAX_VALUE);
2469        Arrays.fill(d, Integer.MAX_VALUE);
2470
2471        // iterates through t
2472        for (int j = 1; j <= m; j++) {
2473            final char jOfT = t.charAt(j - 1); // jth character of t
2474            d[0] = j;
2475
2476            // compute stripe indices, constrain to array size
2477            final int min = Math.max(1, j - threshold);
2478            final int max = j > Integer.MAX_VALUE - threshold ? n : Math.min(n, j + threshold);
2479
2480            // the stripe may lead off of the table if s and t are of different sizes
2481            if (min > max) {
2482                return -1;
2483            }
2484
2485            // ignore entry left of leftmost
2486            if (min > 1) {
2487                d[min - 1] = Integer.MAX_VALUE;
2488            }
2489
2490            // iterates through [min, max] in s
2491            for (int i = min; i <= max; i++) {
2492                if (s.charAt(i - 1) == jOfT) {
2493                    // diagonally left and up
2494                    d[i] = p[i - 1];
2495                } else {
2496                    // 1 + minimum of cell to the left, to the top, diagonally left and up
2497                    d[i] = 1 + Math.min(Math.min(d[i - 1], p[i]), p[i - 1]);
2498                }
2499            }
2500
2501            // copy current distance counts to 'previous row' distance counts
2502            tmp = p;
2503            p = d;
2504            d = tmp;
2505        }
2506
2507        // if p[n] is greater than the threshold, there's no guarantee on it being the correct
2508        // distance
2509        if (p[n] <= threshold) {
2510            return p[n];
2511        }
2512        return -1;
2513    }
2514
2515    /**
2516     * Finds the first index within a CharSequence, handling {@code null}. This method uses {@link String#indexOf(String, int)} if possible.
2517     *
2518     * <p>
2519     * A {@code null} CharSequence will return {@code -1}.
2520     * </p>
2521     *
2522     * <pre>
2523     * StringUtils.indexOf(null, *)          = -1
2524     * StringUtils.indexOf(*, null)          = -1
2525     * StringUtils.indexOf("", "")           = 0
2526     * StringUtils.indexOf("", *)            = -1 (except when * = "")
2527     * StringUtils.indexOf("aabaabaa", "a")  = 0
2528     * StringUtils.indexOf("aabaabaa", "b")  = 2
2529     * StringUtils.indexOf("aabaabaa", "ab") = 1
2530     * StringUtils.indexOf("aabaabaa", "")   = 0
2531     * </pre>
2532     *
2533     * @param seq       the CharSequence to check, may be null.
2534     * @param searchSeq the CharSequence to find, may be null.
2535     * @return the first index of the search CharSequence, -1 if no match or {@code null} string input.
2536     * @since 2.0
2537     * @since 3.0 Changed signature from indexOf(String, String) to indexOf(CharSequence, CharSequence)
2538     * @deprecated Use {@link Strings#indexOf(CharSequence, CharSequence) Strings.CS.indexOf(CharSequence, CharSequence)}
2539     */
2540    @Deprecated
2541    public static int indexOf(final CharSequence seq, final CharSequence searchSeq) {
2542        return Strings.CS.indexOf(seq, searchSeq);
2543    }
2544
2545    /**
2546     * Finds the first index within a CharSequence, handling {@code null}. This method uses {@link String#indexOf(String, int)} if possible.
2547     *
2548     * <p>
2549     * A {@code null} CharSequence will return {@code -1}. A negative start position is treated as zero. An empty ("") search CharSequence always matches. A
2550     * start position greater than the string length only matches an empty search CharSequence.
2551     * </p>
2552     *
2553     * <pre>
2554     * StringUtils.indexOf(null, *, *)          = -1
2555     * StringUtils.indexOf(*, null, *)          = -1
2556     * StringUtils.indexOf("", "", 0)           = 0
2557     * StringUtils.indexOf("", *, 0)            = -1 (except when * = "")
2558     * StringUtils.indexOf("aabaabaa", "a", 0)  = 0
2559     * StringUtils.indexOf("aabaabaa", "b", 0)  = 2
2560     * StringUtils.indexOf("aabaabaa", "ab", 0) = 1
2561     * StringUtils.indexOf("aabaabaa", "b", 3)  = 5
2562     * StringUtils.indexOf("aabaabaa", "b", 9)  = -1
2563     * StringUtils.indexOf("aabaabaa", "b", -1) = 2
2564     * StringUtils.indexOf("aabaabaa", "", 2)   = 2
2565     * StringUtils.indexOf("abc", "", 9)        = 3
2566     * </pre>
2567     *
2568     * @param seq       the CharSequence to check, may be null.
2569     * @param searchSeq the CharSequence to find, may be null.
2570     * @param startPos  the start position, negative treated as zero.
2571     * @return the first index of the search CharSequence (always &ge; startPos), -1 if no match or {@code null} string input.
2572     * @since 2.0
2573     * @since 3.0 Changed signature from indexOf(String, String, int) to indexOf(CharSequence, CharSequence, int)
2574     * @deprecated Use {@link Strings#indexOf(CharSequence, CharSequence, int) Strings.CS.indexOf(CharSequence, CharSequence, int)}
2575     */
2576    @Deprecated
2577    public static int indexOf(final CharSequence seq, final CharSequence searchSeq, final int startPos) {
2578        return Strings.CS.indexOf(seq, searchSeq, startPos);
2579    }
2580
2581    /**
2582     * Returns the index within {@code seq} of the first occurrence of the specified character. If a character with value {@code searchChar} occurs in the
2583     * character sequence represented by {@code seq} {@link CharSequence} object, then the index (in Unicode code units) of the first such occurrence is
2584     * returned. For values of {@code searchChar} in the range from 0 to 0xFFFF (inclusive), this is the smallest value <em>k</em> such that:
2585     *
2586     * <pre>
2587     * this.charAt(<em>k</em>) == searchChar
2588     * </pre>
2589     *
2590     * <p>
2591     * is true. For other values of {@code searchChar}, it is the smallest value <em>k</em> such that:
2592     * </p>
2593     *
2594     * <pre>
2595     * this.codePointAt(<em>k</em>) == searchChar
2596     * </pre>
2597     *
2598     * <p>
2599     * is true. In either case, if no such character occurs in {@code seq}, then {@code INDEX_NOT_FOUND (-1)} is returned.
2600     * </p>
2601     *
2602     * <p>
2603     * Furthermore, a {@code null} or empty ("") CharSequence will return {@code INDEX_NOT_FOUND (-1)}.
2604     * </p>
2605     *
2606     * <pre>
2607     * StringUtils.indexOf(null, *)         = -1
2608     * StringUtils.indexOf("", *)           = -1
2609     * StringUtils.indexOf("aabaabaa", 'a') = 0
2610     * StringUtils.indexOf("aabaabaa", 'b') = 2
2611     * StringUtils.indexOf("aaaaaaaa", 'Z') = -1
2612     * </pre>
2613     *
2614     * @param seq        the CharSequence to check, may be null.
2615     * @param searchChar the character to find.
2616     * @return the first index of the search character, -1 if no match or {@code null} string input.
2617     * @since 2.0
2618     * @since 3.0 Changed signature from indexOf(String, int) to indexOf(CharSequence, int)
2619     * @since 3.6 Updated {@link CharSequenceUtils} call to behave more like {@link String}
2620     */
2621    public static int indexOf(final CharSequence seq, final int searchChar) {
2622        if (isEmpty(seq)) {
2623            return INDEX_NOT_FOUND;
2624        }
2625        return CharSequenceUtils.indexOf(seq, searchChar, 0);
2626    }
2627
2628    /**
2629     * Returns the index within {@code seq} of the first occurrence of the specified character, starting the search at the specified index.
2630     * <p>
2631     * If a character with value {@code searchChar} occurs in the character sequence represented by the {@code seq} {@link CharSequence} object at an index no
2632     * smaller than {@code startPos}, then the index of the first such occurrence is returned. For values of {@code searchChar} in the range from 0 to 0xFFFF
2633     * (inclusive), this is the smallest value <em>k</em> such that:
2634     * </p>
2635     *
2636     * <pre>
2637     * (this.charAt(<em>k</em>) == searchChar) &amp;&amp; (<em>k</em> &gt;= startPos)
2638     * </pre>
2639     *
2640     * <p>
2641     * is true. For other values of {@code searchChar}, it is the smallest value <em>k</em> such that:
2642     * </p>
2643     *
2644     * <pre>
2645     * (this.codePointAt(<em>k</em>) == searchChar) &amp;&amp; (<em>k</em> &gt;= startPos)
2646     * </pre>
2647     *
2648     * <p>
2649     * is true. In either case, if no such character occurs in {@code seq} at or after position {@code startPos}, then {@code -1} is returned.
2650     * </p>
2651     *
2652     * <p>
2653     * There is no restriction on the value of {@code startPos}. If it is negative, it has the same effect as if it were zero: this entire string may be
2654     * searched. If it is greater than the length of this string, it has the same effect as if it were equal to the length of this string:
2655     * {@code (INDEX_NOT_FOUND) -1} is returned. Furthermore, a {@code null} or empty ("") CharSequence will return {@code (INDEX_NOT_FOUND) -1}.
2656     * </p>
2657     * <p>
2658     * All indices are specified in {@code char} values (Unicode code units).
2659     *
2660     * <pre>
2661     * StringUtils.indexOf(null, *, *)          = -1
2662     * StringUtils.indexOf("", *, *)            = -1
2663     * StringUtils.indexOf("aabaabaa", 'b', 0)  = 2
2664     * StringUtils.indexOf("aabaabaa", 'b', 3)  = 5
2665     * StringUtils.indexOf("aabaabaa", 'b', 9)  = -1
2666     * StringUtils.indexOf("aabaabaa", 'b', -1) = 2
2667     * </pre>
2668     *
2669     * @param seq        the CharSequence to check, may be null.
2670     * @param searchChar the character to find.
2671     * @param startPos   the start position, negative treated as zero.
2672     * @return the first index of the search character (always &ge; startPos), -1 if no match or {@code null} string input.
2673     * @since 2.0
2674     * @since 3.0 Changed signature from indexOf(String, int, int) to indexOf(CharSequence, int, int)
2675     * @since 3.6 Updated {@link CharSequenceUtils} call to behave more like {@link String}
2676     */
2677    public static int indexOf(final CharSequence seq, final int searchChar, final int startPos) {
2678        if (isEmpty(seq)) {
2679            return INDEX_NOT_FOUND;
2680        }
2681        return CharSequenceUtils.indexOf(seq, searchChar, startPos);
2682    }
2683
2684    /**
2685     * Search a CharSequence to find the first index of any character in the given set of characters.
2686     *
2687     * <p>
2688     * A {@code null} String will return {@code -1}. A {@code null} or zero length search array will return {@code -1}.
2689     * </p>
2690     *
2691     * <pre>
2692     * StringUtils.indexOfAny(null, *)                  = -1
2693     * StringUtils.indexOfAny("", *)                    = -1
2694     * StringUtils.indexOfAny(*, null)                  = -1
2695     * StringUtils.indexOfAny(*, [])                    = -1
2696     * StringUtils.indexOfAny("zzabyycdxx", ['z', 'a']) = 0
2697     * StringUtils.indexOfAny("zzabyycdxx", ['b', 'y']) = 3
2698     * StringUtils.indexOfAny("aba", ['z'])             = -1
2699     * </pre>
2700     *
2701     * @param cs          the CharSequence to check, may be null.
2702     * @param searchChars the chars to search for, may be null.
2703     * @return the index of any of the chars, -1 if no match or null input.
2704     * @since 2.0
2705     * @since 3.0 Changed signature from indexOfAny(String, char[]) to indexOfAny(CharSequence, char...)
2706     */
2707    public static int indexOfAny(final CharSequence cs, final char... searchChars) {
2708        if (isEmpty(cs) || ArrayUtils.isEmpty(searchChars)) {
2709            return INDEX_NOT_FOUND;
2710        }
2711        final int csLen = cs.length();
2712        final int csLast = csLen - 1;
2713        final int searchLen = searchChars.length;
2714        final int searchLast = searchLen - 1;
2715        for (int i = 0; i < csLen; i++) {
2716            final char ch = cs.charAt(i);
2717            for (int j = 0; j < searchLen; j++) {
2718                if (searchChars[j] == ch) {
2719                    // ch is a supplementary character
2720                    if (i >= csLast || j >= searchLast || !Character.isHighSurrogate(ch) || searchChars[j + 1] == cs.charAt(i + 1)) {
2721                        return i;
2722                    }
2723                }
2724            }
2725        }
2726        return INDEX_NOT_FOUND;
2727    }
2728
2729    /**
2730     * Find the first index of any of a set of potential substrings.
2731     *
2732     * <p>
2733     * A {@code null} CharSequence will return {@code -1}. A {@code null} or zero length search array will return {@code -1}. A {@code null} search array entry
2734     * will be ignored, but a search array containing "" will return {@code 0} if {@code str} is not null. This method uses {@link String#indexOf(String)} if
2735     * possible.
2736     * </p>
2737     *
2738     * <pre>
2739     * StringUtils.indexOfAny(null, *)                      = -1
2740     * StringUtils.indexOfAny(*, null)                      = -1
2741     * StringUtils.indexOfAny(*, [])                        = -1
2742     * StringUtils.indexOfAny("zzabyycdxx", ["ab", "cd"])   = 2
2743     * StringUtils.indexOfAny("zzabyycdxx", ["cd", "ab"])   = 2
2744     * StringUtils.indexOfAny("zzabyycdxx", ["mn", "op"])   = -1
2745     * StringUtils.indexOfAny("zzabyycdxx", ["zab", "aby"]) = 1
2746     * StringUtils.indexOfAny("zzabyycdxx", [""])           = 0
2747     * StringUtils.indexOfAny("", [""])                     = 0
2748     * StringUtils.indexOfAny("", ["a"])                    = -1
2749     * </pre>
2750     *
2751     * @param str        the CharSequence to check, may be null.
2752     * @param searchStrs the CharSequences to search for, may be null.
2753     * @return the first index of any of the searchStrs in str, -1 if no match.
2754     * @since 3.0 Changed signature from indexOfAny(String, String[]) to indexOfAny(CharSequence, CharSequence...)
2755     */
2756    public static int indexOfAny(final CharSequence str, final CharSequence... searchStrs) {
2757        if (str == null || searchStrs == null) {
2758            return INDEX_NOT_FOUND;
2759        }
2760        // String's can't have a MAX_VALUEth index.
2761        int ret = Integer.MAX_VALUE;
2762        int tmp;
2763        for (final CharSequence search : searchStrs) {
2764            if (search == null) {
2765                continue;
2766            }
2767            tmp = CharSequenceUtils.indexOf(str, search, 0);
2768            if (tmp == INDEX_NOT_FOUND) {
2769                continue;
2770            }
2771            if (tmp < ret) {
2772                ret = tmp;
2773            }
2774        }
2775        return ret == Integer.MAX_VALUE ? INDEX_NOT_FOUND : ret;
2776    }
2777
2778    /**
2779     * Search a CharSequence to find the first index of any character in the given set of characters.
2780     *
2781     * <p>
2782     * A {@code null} String will return {@code -1}. A {@code null} search string will return {@code -1}.
2783     * </p>
2784     *
2785     * <pre>
2786     * StringUtils.indexOfAny(null, *)            = -1
2787     * StringUtils.indexOfAny("", *)              = -1
2788     * StringUtils.indexOfAny(*, null)            = -1
2789     * StringUtils.indexOfAny(*, "")              = -1
2790     * StringUtils.indexOfAny("zzabyycdxx", "za") = 0
2791     * StringUtils.indexOfAny("zzabyycdxx", "by") = 3
2792     * StringUtils.indexOfAny("aba", "z")         = -1
2793     * </pre>
2794     *
2795     * @param cs          the CharSequence to check, may be null.
2796     * @param searchChars the chars to search for, may be null.
2797     * @return the index of any of the chars, -1 if no match or null input.
2798     * @since 2.0
2799     * @since 3.0 Changed signature from indexOfAny(String, String) to indexOfAny(CharSequence, String)
2800     */
2801    public static int indexOfAny(final CharSequence cs, final String searchChars) {
2802        if (isEmpty(cs) || isEmpty(searchChars)) {
2803            return INDEX_NOT_FOUND;
2804        }
2805        return indexOfAny(cs, searchChars.toCharArray());
2806    }
2807
2808    /**
2809     * Searches a CharSequence to find the first index of any character not in the given set of characters, i.e., find index i of first char in cs such that
2810     * (cs.codePointAt(i) ∉ { x ∈ codepoints(searchChars) })
2811     *
2812     * <p>
2813     * A {@code null} CharSequence will return {@code -1}. A {@code null} or zero length search array will return {@code -1}.
2814     * </p>
2815     *
2816     * <pre>
2817     * StringUtils.indexOfAnyBut(null, *)                              = -1
2818     * StringUtils.indexOfAnyBut("", *)                                = -1
2819     * StringUtils.indexOfAnyBut(*, null)                              = -1
2820     * StringUtils.indexOfAnyBut(*, [])                                = -1
2821     * StringUtils.indexOfAnyBut("zzabyycdxx", new char[] {'z', 'a'} ) = 3
2822     * StringUtils.indexOfAnyBut("aba", new char[] {'z'} )             = 0
2823     * StringUtils.indexOfAnyBut("aba", new char[] {'a', 'b'} )        = -1
2824     * </pre>
2825     *
2826     * @param cs          the CharSequence to check, may be null.
2827     * @param searchChars the chars to search for, may be null.
2828     * @return the index of any of the chars, -1 if no match or null input.
2829     * @since 2.0
2830     * @since 3.0 Changed signature from indexOfAnyBut(String, char[]) to indexOfAnyBut(CharSequence, char...)
2831     */
2832    public static int indexOfAnyBut(final CharSequence cs, final char... searchChars) {
2833        if (isEmpty(cs) || ArrayUtils.isEmpty(searchChars)) {
2834            return INDEX_NOT_FOUND;
2835        }
2836        return indexOfAnyBut(cs, CharBuffer.wrap(searchChars));
2837    }
2838
2839    /**
2840     * Search a CharSequence to find the first index of any character not in the given set of characters, i.e., find index i of first char in seq such that
2841     * (seq.codePointAt(i) ∉ { x ∈ codepoints(searchChars) })
2842     *
2843     * <p>
2844     * A {@code null} CharSequence will return {@code -1}. A {@code null} or empty search string will return {@code -1}.
2845     * </p>
2846     *
2847     * <pre>
2848     * StringUtils.indexOfAnyBut(null, *)            = -1
2849     * StringUtils.indexOfAnyBut("", *)              = -1
2850     * StringUtils.indexOfAnyBut(*, null)            = -1
2851     * StringUtils.indexOfAnyBut(*, "")              = -1
2852     * StringUtils.indexOfAnyBut("zzabyycdxx", "za") = 3
2853     * StringUtils.indexOfAnyBut("zzabyycdxx", "")   = -1
2854     * StringUtils.indexOfAnyBut("aba", "ab")        = -1
2855     * </pre>
2856     *
2857     * @param seq         the CharSequence to check, may be null.
2858     * @param searchChars the chars to search for, may be null.
2859     * @return the index of any of the chars, -1 if no match or null input.
2860     * @since 2.0
2861     * @since 3.0 Changed signature from indexOfAnyBut(String, String) to indexOfAnyBut(CharSequence, CharSequence)
2862     */
2863    public static int indexOfAnyBut(final CharSequence seq, final CharSequence searchChars) {
2864        if (isEmpty(seq) || isEmpty(searchChars)) {
2865            return INDEX_NOT_FOUND;
2866        }
2867        final Set<Integer> searchSetCodePoints = searchChars.codePoints()
2868                .boxed().collect(Collectors.toSet());
2869        // advance character index from one interpreted codepoint to the next
2870        for (int curSeqCharIdx = 0; curSeqCharIdx < seq.length();) {
2871            final int curSeqCodePoint = Character.codePointAt(seq, curSeqCharIdx);
2872            if (!searchSetCodePoints.contains(curSeqCodePoint)) {
2873                return curSeqCharIdx;
2874            }
2875            curSeqCharIdx += Character.charCount(curSeqCodePoint); // skip indices to paired low-surrogates
2876        }
2877        return INDEX_NOT_FOUND;
2878    }
2879
2880    /**
2881     * Compares all CharSequences in an array and returns the index at which the CharSequences begin to differ.
2882     *
2883     * <p>
2884     * For example, {@code indexOfDifference(new String[] {"i am a machine", "i am a robot"}) -> 7}
2885     * </p>
2886     *
2887     * <pre>
2888     * StringUtils.indexOfDifference(null)                             = -1
2889     * StringUtils.indexOfDifference(new String[] {})                  = -1
2890     * StringUtils.indexOfDifference(new String[] {"abc"})             = -1
2891     * StringUtils.indexOfDifference(new String[] {null, null})        = -1
2892     * StringUtils.indexOfDifference(new String[] {"", ""})            = -1
2893     * StringUtils.indexOfDifference(new String[] {"", null})          = 0
2894     * StringUtils.indexOfDifference(new String[] {"abc", null, null}) = 0
2895     * StringUtils.indexOfDifference(new String[] {null, null, "abc"}) = 0
2896     * StringUtils.indexOfDifference(new String[] {"", "abc"})         = 0
2897     * StringUtils.indexOfDifference(new String[] {"abc", ""})         = 0
2898     * StringUtils.indexOfDifference(new String[] {"abc", "abc"})      = -1
2899     * StringUtils.indexOfDifference(new String[] {"abc", "a"})        = 1
2900     * StringUtils.indexOfDifference(new String[] {"ab", "abxyz"})     = 2
2901     * StringUtils.indexOfDifference(new String[] {"abcde", "abxyz"})  = 2
2902     * StringUtils.indexOfDifference(new String[] {"abcde", "xyz"})    = 0
2903     * StringUtils.indexOfDifference(new String[] {"xyz", "abcde"})    = 0
2904     * StringUtils.indexOfDifference(new String[] {"i am a machine", "i am a robot"}) = 7
2905     * </pre>
2906     *
2907     * @param css array of CharSequences, entries may be null.
2908     * @return the index where the strings begin to differ; -1 if they are all equal.
2909     * @since 2.4
2910     * @since 3.0 Changed signature from indexOfDifference(String...) to indexOfDifference(CharSequence...)
2911     */
2912    public static int indexOfDifference(final CharSequence... css) {
2913        if (ArrayUtils.getLength(css) <= 1) {
2914            return INDEX_NOT_FOUND;
2915        }
2916        boolean anyStringNull = false;
2917        boolean allStringsNull = true;
2918        final int arrayLen = css.length;
2919        int shortestStrLen = Integer.MAX_VALUE;
2920        int longestStrLen = 0;
2921        // find the min and max string lengths; this avoids checking to make
2922        // sure we are not exceeding the length of the string each time through
2923        // the bottom loop.
2924        for (final CharSequence cs : css) {
2925            if (cs == null) {
2926                anyStringNull = true;
2927                shortestStrLen = 0;
2928            } else {
2929                allStringsNull = false;
2930                shortestStrLen = Math.min(cs.length(), shortestStrLen);
2931                longestStrLen = Math.max(cs.length(), longestStrLen);
2932            }
2933        }
2934        // handle lists containing all nulls or all empty strings
2935        if (allStringsNull || longestStrLen == 0 && !anyStringNull) {
2936            return INDEX_NOT_FOUND;
2937        }
2938        // handle lists containing some nulls or some empty strings
2939        if (shortestStrLen == 0) {
2940            return 0;
2941        }
2942        // find the position with the first difference across all strings
2943        int firstDiff = -1;
2944        for (int stringPos = 0; stringPos < shortestStrLen; stringPos++) {
2945            final char comparisonChar = css[0].charAt(stringPos);
2946            for (int arrayPos = 1; arrayPos < arrayLen; arrayPos++) {
2947                if (css[arrayPos].charAt(stringPos) != comparisonChar) {
2948                    firstDiff = stringPos;
2949                    break;
2950                }
2951            }
2952            if (firstDiff != -1) {
2953                break;
2954            }
2955        }
2956        if (firstDiff == -1 && shortestStrLen != longestStrLen) {
2957            // we compared all of the characters up to the length of the
2958            // shortest string and didn't find a match, but the string lengths
2959            // vary, so return the length of the shortest string.
2960            return shortestStrLen;
2961        }
2962        return firstDiff;
2963    }
2964
2965    /**
2966     * Compares two CharSequences, and returns the index at which the CharSequences begin to differ.
2967     *
2968     * <p>
2969     * For example, {@code indexOfDifference("i am a machine", "i am a robot") -> 7}
2970     * </p>
2971     *
2972     * <pre>
2973     * StringUtils.indexOfDifference(null, null)       = -1
2974     * StringUtils.indexOfDifference("", "")           = -1
2975     * StringUtils.indexOfDifference("", "abc")        = 0
2976     * StringUtils.indexOfDifference("abc", "")        = 0
2977     * StringUtils.indexOfDifference("abc", "abc")     = -1
2978     * StringUtils.indexOfDifference("ab", "abxyz")    = 2
2979     * StringUtils.indexOfDifference("abcde", "abxyz") = 2
2980     * StringUtils.indexOfDifference("abcde", "xyz")   = 0
2981     * </pre>
2982     *
2983     * @param cs1 the first CharSequence, may be null.
2984     * @param cs2 the second CharSequence, may be null.
2985     * @return the index where cs1 and cs2 begin to differ; -1 if they are equal.
2986     * @since 2.0
2987     * @since 3.0 Changed signature from indexOfDifference(String, String) to indexOfDifference(CharSequence, CharSequence)
2988     */
2989    public static int indexOfDifference(final CharSequence cs1, final CharSequence cs2) {
2990        if (cs1 == cs2) {
2991            return INDEX_NOT_FOUND;
2992        }
2993        if (cs1 == null || cs2 == null) {
2994            return 0;
2995        }
2996        int i;
2997        for (i = 0; i < cs1.length() && i < cs2.length(); ++i) {
2998            if (cs1.charAt(i) != cs2.charAt(i)) {
2999                break;
3000            }
3001        }
3002        if (i < cs2.length() || i < cs1.length()) {
3003            return i;
3004        }
3005        return INDEX_NOT_FOUND;
3006    }
3007
3008    /**
3009     * Case in-sensitive find of the first index within a CharSequence.
3010     *
3011     * <p>
3012     * A {@code null} CharSequence will return {@code -1}. A negative start position is treated as zero. An empty ("") search CharSequence always matches. A
3013     * start position greater than the string length only matches an empty search CharSequence.
3014     * </p>
3015     *
3016     * <pre>
3017     * StringUtils.indexOfIgnoreCase(null, *)          = -1
3018     * StringUtils.indexOfIgnoreCase(*, null)          = -1
3019     * StringUtils.indexOfIgnoreCase("", "")           = 0
3020     * StringUtils.indexOfIgnoreCase(" ", " ")         = 0
3021     * StringUtils.indexOfIgnoreCase("aabaabaa", "a")  = 0
3022     * StringUtils.indexOfIgnoreCase("aabaabaa", "b")  = 2
3023     * StringUtils.indexOfIgnoreCase("aabaabaa", "ab") = 1
3024     * </pre>
3025     *
3026     * @param str       the CharSequence to check, may be null.
3027     * @param searchStr the CharSequence to find, may be null.
3028     * @return the first index of the search CharSequence, -1 if no match or {@code null} string input.
3029     * @since 2.5
3030     * @since 3.0 Changed signature from indexOfIgnoreCase(String, String) to indexOfIgnoreCase(CharSequence, CharSequence)
3031     * @deprecated Use {@link Strings#indexOf(CharSequence, CharSequence) Strings.CI.indexOf(CharSequence, CharSequence)}
3032     */
3033    @Deprecated
3034    public static int indexOfIgnoreCase(final CharSequence str, final CharSequence searchStr) {
3035        return Strings.CI.indexOf(str, searchStr);
3036    }
3037
3038    /**
3039     * Case in-sensitive find of the first index within a CharSequence from the specified position.
3040     *
3041     * <p>
3042     * A {@code null} CharSequence will return {@code -1}. A negative start position is treated as zero. An empty ("") search CharSequence always matches. A
3043     * start position greater than the string length only matches an empty search CharSequence.
3044     * </p>
3045     *
3046     * <pre>
3047     * StringUtils.indexOfIgnoreCase(null, *, *)          = -1
3048     * StringUtils.indexOfIgnoreCase(*, null, *)          = -1
3049     * StringUtils.indexOfIgnoreCase("", "", 0)           = 0
3050     * StringUtils.indexOfIgnoreCase("aabaabaa", "A", 0)  = 0
3051     * StringUtils.indexOfIgnoreCase("aabaabaa", "B", 0)  = 2
3052     * StringUtils.indexOfIgnoreCase("aabaabaa", "AB", 0) = 1
3053     * StringUtils.indexOfIgnoreCase("aabaabaa", "B", 3)  = 5
3054     * StringUtils.indexOfIgnoreCase("aabaabaa", "B", 9)  = -1
3055     * StringUtils.indexOfIgnoreCase("aabaabaa", "B", -1) = 2
3056     * StringUtils.indexOfIgnoreCase("aabaabaa", "", 2)   = 2
3057     * StringUtils.indexOfIgnoreCase("abc", "", 9)        = -1
3058     * </pre>
3059     *
3060     * @param str       the CharSequence to check, may be null.
3061     * @param searchStr the CharSequence to find, may be null.
3062     * @param startPos  the start position, negative treated as zero.
3063     * @return the first index of the search CharSequence (always &ge; startPos), -1 if no match or {@code null} string input.
3064     * @since 2.5
3065     * @since 3.0 Changed signature from indexOfIgnoreCase(String, String, int) to indexOfIgnoreCase(CharSequence, CharSequence, int)
3066     * @deprecated Use {@link Strings#indexOf(CharSequence, CharSequence, int) Strings.CI.indexOf(CharSequence, CharSequence, int)}
3067     */
3068    @Deprecated
3069    public static int indexOfIgnoreCase(final CharSequence str, final CharSequence searchStr, final int startPos) {
3070        return Strings.CI.indexOf(str, searchStr, startPos);
3071    }
3072
3073    /**
3074     * Tests if all of the CharSequences are empty (""), null or whitespace only.
3075     *
3076     * <p>
3077     * Whitespace is defined by {@link Character#isWhitespace(char)}.
3078     * </p>
3079     *
3080     * <pre>
3081     * StringUtils.isAllBlank(null)             = true
3082     * StringUtils.isAllBlank(null, "foo")      = false
3083     * StringUtils.isAllBlank(null, null)       = true
3084     * StringUtils.isAllBlank("", "bar")        = false
3085     * StringUtils.isAllBlank("bob", "")        = false
3086     * StringUtils.isAllBlank("  bob  ", null)  = false
3087     * StringUtils.isAllBlank(" ", "bar")       = false
3088     * StringUtils.isAllBlank("foo", "bar")     = false
3089     * StringUtils.isAllBlank(new String[] {})  = true
3090     * </pre>
3091     *
3092     * @param css the CharSequences to check, may be null or empty.
3093     * @return {@code true} if all of the CharSequences are empty or null or whitespace only.
3094     * @since 3.6
3095     */
3096    public static boolean isAllBlank(final CharSequence... css) {
3097        if (ArrayUtils.isEmpty(css)) {
3098            return true;
3099        }
3100        for (final CharSequence cs : css) {
3101            if (isNotBlank(cs)) {
3102               return false;
3103            }
3104        }
3105        return true;
3106    }
3107
3108    /**
3109     * Tests if all of the CharSequences are empty ("") or null.
3110     *
3111     * <pre>
3112     * StringUtils.isAllEmpty(null)             = true
3113     * StringUtils.isAllEmpty(null, "")         = true
3114     * StringUtils.isAllEmpty(new String[] {})  = true
3115     * StringUtils.isAllEmpty(null, "foo")      = false
3116     * StringUtils.isAllEmpty("", "bar")        = false
3117     * StringUtils.isAllEmpty("bob", "")        = false
3118     * StringUtils.isAllEmpty("  bob  ", null)  = false
3119     * StringUtils.isAllEmpty(" ", "bar")       = false
3120     * StringUtils.isAllEmpty("foo", "bar")     = false
3121     * </pre>
3122     *
3123     * @param css the CharSequences to check, may be null or empty.
3124     * @return {@code true} if all of the CharSequences are empty or null.
3125     * @since 3.6
3126     */
3127    public static boolean isAllEmpty(final CharSequence... css) {
3128        if (ArrayUtils.isEmpty(css)) {
3129            return true;
3130        }
3131        for (final CharSequence cs : css) {
3132            if (isNotEmpty(cs)) {
3133                return false;
3134            }
3135        }
3136        return true;
3137    }
3138
3139    /**
3140     * Tests if the CharSequence contains only lowercase characters.
3141     *
3142     * <p>
3143     * {@code null} will return {@code false}. An empty CharSequence (length()=0) will return {@code false}.
3144     * </p>
3145     *
3146     * <pre>
3147     * StringUtils.isAllLowerCase(null)   = false
3148     * StringUtils.isAllLowerCase("")     = false
3149     * StringUtils.isAllLowerCase("  ")   = false
3150     * StringUtils.isAllLowerCase("abc")  = true
3151     * StringUtils.isAllLowerCase("abC")  = false
3152     * StringUtils.isAllLowerCase("ab c") = false
3153     * StringUtils.isAllLowerCase("ab1c") = false
3154     * StringUtils.isAllLowerCase("ab/c") = false
3155     * </pre>
3156     *
3157     * @param cs the CharSequence to check, may be null.
3158     * @return {@code true} if only contains lowercase characters, and is non-null.
3159     * @since 2.5
3160     * @since 3.0 Changed signature from isAllLowerCase(String) to isAllLowerCase(CharSequence)
3161     */
3162    public static boolean isAllLowerCase(final CharSequence cs) {
3163        if (isEmpty(cs)) {
3164            return false;
3165        }
3166        final int sz = cs.length();
3167        for (int i = 0; i < sz; i++) {
3168            if (!Character.isLowerCase(cs.charAt(i))) {
3169                return false;
3170            }
3171        }
3172        return true;
3173    }
3174
3175    /**
3176     * Tests if the CharSequence contains only uppercase characters.
3177     *
3178     * <p>{@code null} will return {@code false}.
3179     * An empty String (length()=0) will return {@code false}.</p>
3180     *
3181     * <pre>
3182     * StringUtils.isAllUpperCase(null)   = false
3183     * StringUtils.isAllUpperCase("")     = false
3184     * StringUtils.isAllUpperCase("  ")   = false
3185     * StringUtils.isAllUpperCase("ABC")  = true
3186     * StringUtils.isAllUpperCase("aBC")  = false
3187     * StringUtils.isAllUpperCase("A C")  = false
3188     * StringUtils.isAllUpperCase("A1C")  = false
3189     * StringUtils.isAllUpperCase("A/C")  = false
3190     * </pre>
3191     *
3192     * @param cs the CharSequence to check, may be null.
3193     * @return {@code true} if only contains uppercase characters, and is non-null.
3194     * @since 2.5
3195     * @since 3.0 Changed signature from isAllUpperCase(String) to isAllUpperCase(CharSequence)
3196     */
3197    public static boolean isAllUpperCase(final CharSequence cs) {
3198        if (isEmpty(cs)) {
3199            return false;
3200        }
3201        final int sz = cs.length();
3202        for (int i = 0; i < sz; i++) {
3203            if (!Character.isUpperCase(cs.charAt(i))) {
3204                return false;
3205            }
3206        }
3207        return true;
3208    }
3209
3210    /**
3211     * Tests if the CharSequence contains only Unicode letters.
3212     *
3213     * <p>
3214     * {@code null} will return {@code false}. An empty CharSequence (length()=0) will return {@code false}.
3215     * </p>
3216     *
3217     * <pre>
3218     * StringUtils.isAlpha(null)   = false
3219     * StringUtils.isAlpha("")     = false
3220     * StringUtils.isAlpha("  ")   = false
3221     * StringUtils.isAlpha("abc")  = true
3222     * StringUtils.isAlpha("ab2c") = false
3223     * StringUtils.isAlpha("ab-c") = false
3224     * </pre>
3225     *
3226     * @param cs the CharSequence to check, may be null.
3227     * @return {@code true} if only contains letters, and is non-null.
3228     * @since 3.0 Changed signature from isAlpha(String) to isAlpha(CharSequence)
3229     * @since 3.0 Changed "" to return false and not true
3230     */
3231    public static boolean isAlpha(final CharSequence cs) {
3232        if (isEmpty(cs)) {
3233            return false;
3234        }
3235        final int sz = cs.length();
3236        for (int i = 0; i < sz; i++) {
3237            if (!Character.isLetter(cs.charAt(i))) {
3238                return false;
3239            }
3240        }
3241        return true;
3242    }
3243
3244    /**
3245     * Tests if the CharSequence contains only Unicode letters or digits.
3246     *
3247     * <p>
3248     * {@code null} will return {@code false}. An empty CharSequence (length()=0) will return {@code false}.
3249     * </p>
3250     *
3251     * <pre>
3252     * StringUtils.isAlphanumeric(null)   = false
3253     * StringUtils.isAlphanumeric("")     = false
3254     * StringUtils.isAlphanumeric("  ")   = false
3255     * StringUtils.isAlphanumeric("abc")  = true
3256     * StringUtils.isAlphanumeric("ab c") = false
3257     * StringUtils.isAlphanumeric("ab2c") = true
3258     * StringUtils.isAlphanumeric("ab-c") = false
3259     * </pre>
3260     *
3261     * @param cs the CharSequence to check, may be null.
3262     * @return {@code true} if only contains letters or digits, and is non-null.
3263     * @since 3.0 Changed signature from isAlphanumeric(String) to isAlphanumeric(CharSequence)
3264     * @since 3.0 Changed "" to return false and not true
3265     */
3266    public static boolean isAlphanumeric(final CharSequence cs) {
3267        if (isEmpty(cs)) {
3268            return false;
3269        }
3270        final int sz = cs.length();
3271        for (int i = 0; i < sz; i++) {
3272            if (!Character.isLetterOrDigit(cs.charAt(i))) {
3273                return false;
3274            }
3275        }
3276        return true;
3277    }
3278
3279    /**
3280     * Tests if the CharSequence contains only Unicode letters, digits or space ({@code ' '}).
3281     *
3282     * <p>
3283     * {@code null} will return {@code false}. An empty CharSequence (length()=0) will return {@code true}.
3284     * </p>
3285     *
3286     * <pre>
3287     * StringUtils.isAlphanumericSpace(null)   = false
3288     * StringUtils.isAlphanumericSpace("")     = true
3289     * StringUtils.isAlphanumericSpace("  ")   = true
3290     * StringUtils.isAlphanumericSpace("abc")  = true
3291     * StringUtils.isAlphanumericSpace("ab c") = true
3292     * StringUtils.isAlphanumericSpace("ab2c") = true
3293     * StringUtils.isAlphanumericSpace("ab-c") = false
3294     * </pre>
3295     *
3296     * @param cs the CharSequence to check, may be null.
3297     * @return {@code true} if only contains letters, digits or space, and is non-null.
3298     * @since 3.0 Changed signature from isAlphanumericSpace(String) to isAlphanumericSpace(CharSequence)
3299     */
3300    public static boolean isAlphanumericSpace(final CharSequence cs) {
3301        if (cs == null) {
3302            return false;
3303        }
3304        final int sz = cs.length();
3305        for (int i = 0; i < sz; i++) {
3306            final char nowChar = cs.charAt(i);
3307            if (nowChar != ' ' && !Character.isLetterOrDigit(nowChar)) {
3308                return false;
3309            }
3310        }
3311        return true;
3312    }
3313
3314    /**
3315     * Tests if the CharSequence contains only Unicode letters and space (' ').
3316     *
3317     * <p>
3318     * {@code null} will return {@code false} An empty CharSequence (length()=0) will return {@code true}.
3319     * </p>
3320     *
3321     * <pre>
3322     * StringUtils.isAlphaSpace(null)   = false
3323     * StringUtils.isAlphaSpace("")     = true
3324     * StringUtils.isAlphaSpace("  ")   = true
3325     * StringUtils.isAlphaSpace("abc")  = true
3326     * StringUtils.isAlphaSpace("ab c") = true
3327     * StringUtils.isAlphaSpace("ab2c") = false
3328     * StringUtils.isAlphaSpace("ab-c") = false
3329     * </pre>
3330     *
3331     * @param cs the CharSequence to check, may be null.
3332     * @return {@code true} if only contains letters and space, and is non-null.
3333     * @since 3.0 Changed signature from isAlphaSpace(String) to isAlphaSpace(CharSequence)
3334     */
3335    public static boolean isAlphaSpace(final CharSequence cs) {
3336        if (cs == null) {
3337            return false;
3338        }
3339        final int sz = cs.length();
3340        for (int i = 0; i < sz; i++) {
3341            final char nowChar = cs.charAt(i);
3342            if (nowChar != ' ' && !Character.isLetter(nowChar)) {
3343                return false;
3344            }
3345        }
3346        return true;
3347    }
3348
3349    /**
3350     * Tests if any of the CharSequences are {@link #isBlank(CharSequence) blank} (whitespaces, empty ({@code ""}) or {@code null}).
3351     *
3352     * <p>
3353     * Whitespace is defined by {@link Character#isWhitespace(char)}.
3354     * </p>
3355     *
3356     * <pre>
3357     * StringUtils.isAnyBlank((String) null)    = true
3358     * StringUtils.isAnyBlank((String[]) null)  = false
3359     * StringUtils.isAnyBlank(null, "foo")      = true
3360     * StringUtils.isAnyBlank(null, null)       = true
3361     * StringUtils.isAnyBlank("", "bar")        = true
3362     * StringUtils.isAnyBlank("bob", "")        = true
3363     * StringUtils.isAnyBlank("  bob  ", null)  = true
3364     * StringUtils.isAnyBlank(" ", "bar")       = true
3365     * StringUtils.isAnyBlank(new String[] {})  = false
3366     * StringUtils.isAnyBlank(new String[]{""}) = true
3367     * StringUtils.isAnyBlank("foo", "bar")     = false
3368     * </pre>
3369     *
3370     * @param css the CharSequences to check, may be null or empty.
3371     * @return {@code true} if any of the CharSequences are {@link #isBlank(CharSequence) blank} (whitespaces, empty ({@code ""}) or {@code null}).
3372     * @see #isBlank(CharSequence)
3373     * @since 3.2
3374     */
3375    public static boolean isAnyBlank(final CharSequence... css) {
3376        if (ArrayUtils.isEmpty(css)) {
3377            return false;
3378        }
3379        for (final CharSequence cs : css) {
3380            if (isBlank(cs)) {
3381                return true;
3382            }
3383        }
3384        return false;
3385    }
3386
3387    /**
3388     * Tests if any of the CharSequences are empty ("") or null.
3389     *
3390     * <pre>
3391     * StringUtils.isAnyEmpty((String) null)    = true
3392     * StringUtils.isAnyEmpty((String[]) null)  = false
3393     * StringUtils.isAnyEmpty(null, "foo")      = true
3394     * StringUtils.isAnyEmpty("", "bar")        = true
3395     * StringUtils.isAnyEmpty("bob", "")        = true
3396     * StringUtils.isAnyEmpty("  bob  ", null)  = true
3397     * StringUtils.isAnyEmpty(" ", "bar")       = false
3398     * StringUtils.isAnyEmpty("foo", "bar")     = false
3399     * StringUtils.isAnyEmpty(new String[]{})   = false
3400     * StringUtils.isAnyEmpty(new String[]{""}) = true
3401     * </pre>
3402     *
3403     * @param css  the CharSequences to check, may be null or empty.
3404     * @return {@code true} if any of the CharSequences are empty or null.
3405     * @since 3.2
3406     */
3407    public static boolean isAnyEmpty(final CharSequence... css) {
3408        if (ArrayUtils.isEmpty(css)) {
3409            return false;
3410        }
3411        for (final CharSequence cs : css) {
3412            if (isEmpty(cs)) {
3413                return true;
3414            }
3415        }
3416        return false;
3417    }
3418
3419    /**
3420     * Tests if the CharSequence contains only ASCII printable characters.
3421     *
3422     * <p>
3423     * {@code null} will return {@code false}. An empty CharSequence (length()=0) will return {@code true}.
3424     * </p>
3425     *
3426     * <pre>
3427     * StringUtils.isAsciiPrintable(null)     = false
3428     * StringUtils.isAsciiPrintable("")       = true
3429     * StringUtils.isAsciiPrintable(" ")      = true
3430     * StringUtils.isAsciiPrintable("Ceki")   = true
3431     * StringUtils.isAsciiPrintable("ab2c")   = true
3432     * StringUtils.isAsciiPrintable("!ab-c~") = true
3433     * StringUtils.isAsciiPrintable("\u0020") = true
3434     * StringUtils.isAsciiPrintable("\u0021") = true
3435     * StringUtils.isAsciiPrintable("\u007e") = true
3436     * StringUtils.isAsciiPrintable("\u007f") = false
3437     * StringUtils.isAsciiPrintable("Ceki G\u00fclc\u00fc") = false
3438     * </pre>
3439     *
3440     * @param cs the CharSequence to check, may be null.
3441     * @return {@code true} if every character is in the range 32 through 126.
3442     * @since 2.1
3443     * @since 3.0 Changed signature from isAsciiPrintable(String) to isAsciiPrintable(CharSequence)
3444     */
3445    public static boolean isAsciiPrintable(final CharSequence cs) {
3446        if (cs == null) {
3447            return false;
3448        }
3449        final int sz = cs.length();
3450        for (int i = 0; i < sz; i++) {
3451            if (!CharUtils.isAsciiPrintable(cs.charAt(i))) {
3452                return false;
3453            }
3454        }
3455        return true;
3456    }
3457
3458    /**
3459     * Tests if a CharSequence is empty ({@code "")}, null, or contains only whitespace as defined by {@link Character#isWhitespace(char)}.
3460     *
3461     * <pre>
3462     * StringUtils.isBlank(null)      = true
3463     * StringUtils.isBlank("")        = true
3464     * StringUtils.isBlank(" ")       = true
3465     * StringUtils.isBlank("bob")     = false
3466     * StringUtils.isBlank("  bob  ") = false
3467     * </pre>
3468     *
3469     * @param cs the CharSequence to check, may be null.
3470     * @return {@code true} if the CharSequence is null, empty or whitespace only.
3471     * @since 2.0
3472     * @since 3.0 Changed signature from isBlank(String) to isBlank(CharSequence)
3473     */
3474    public static boolean isBlank(final CharSequence cs) {
3475        final int strLen = length(cs);
3476        if (strLen == 0) {
3477            return true;
3478        }
3479        for (int i = 0; i < strLen; i++) {
3480            if (!Character.isWhitespace(cs.charAt(i))) {
3481                return false;
3482            }
3483        }
3484        return true;
3485    }
3486
3487    /**
3488     * Tests if a CharSequence is empty ("") or null.
3489     *
3490     * <pre>
3491     * StringUtils.isEmpty(null)      = true
3492     * StringUtils.isEmpty("")        = true
3493     * StringUtils.isEmpty(" ")       = false
3494     * StringUtils.isEmpty("bob")     = false
3495     * StringUtils.isEmpty("  bob  ") = false
3496     * </pre>
3497     *
3498     * <p>
3499     * NOTE: This method changed in Lang version 2.0. It no longer trims the CharSequence. That functionality is available in isBlank().
3500     * </p>
3501     *
3502     * @param cs the CharSequence to check, may be null.
3503     * @return {@code true} if the CharSequence is empty or null.
3504     * @since 3.0 Changed signature from isEmpty(String) to isEmpty(CharSequence)
3505     */
3506    public static boolean isEmpty(final CharSequence cs) {
3507        return cs == null || cs.length() == 0;
3508    }
3509
3510    /**
3511     * Tests if the CharSequence contains mixed casing of both uppercase and lowercase characters.
3512     *
3513     * <p>
3514     * {@code null} will return {@code false}. An empty CharSequence ({@code length()=0}) will return {@code false}.
3515     * </p>
3516     *
3517     * <pre>
3518     * StringUtils.isMixedCase(null)    = false
3519     * StringUtils.isMixedCase("")      = false
3520     * StringUtils.isMixedCase(" ")     = false
3521     * StringUtils.isMixedCase("ABC")   = false
3522     * StringUtils.isMixedCase("abc")   = false
3523     * StringUtils.isMixedCase("aBc")   = true
3524     * StringUtils.isMixedCase("A c")   = true
3525     * StringUtils.isMixedCase("A1c")   = true
3526     * StringUtils.isMixedCase("a/C")   = true
3527     * StringUtils.isMixedCase("aC\t")  = true
3528     * </pre>
3529     *
3530     * @param cs the CharSequence to check, may be null.
3531     * @return {@code true} if the CharSequence contains both uppercase and lowercase characters.
3532     * @since 3.5
3533     */
3534    public static boolean isMixedCase(final CharSequence cs) {
3535        if (isEmpty(cs) || cs.length() == 1) {
3536            return false;
3537        }
3538        boolean containsUppercase = false;
3539        boolean containsLowercase = false;
3540        final int sz = cs.length();
3541        for (int i = 0; i < sz; i++) {
3542            final char nowChar = cs.charAt(i);
3543            if (Character.isUpperCase(nowChar)) {
3544                containsUppercase = true;
3545            } else if (Character.isLowerCase(nowChar)) {
3546                containsLowercase = true;
3547            }
3548            if (containsUppercase && containsLowercase) {
3549                return true;
3550            }
3551        }
3552        return false;
3553    }
3554
3555    /**
3556     * Tests if none of the CharSequences are empty (""), null or whitespace only.
3557     *
3558     * <p>
3559     * Whitespace is defined by {@link Character#isWhitespace(char)}.
3560     * </p>
3561     *
3562     * <pre>
3563     * StringUtils.isNoneBlank((String) null)    = false
3564     * StringUtils.isNoneBlank((String[]) null)  = true
3565     * StringUtils.isNoneBlank(null, "foo")      = false
3566     * StringUtils.isNoneBlank(null, null)       = false
3567     * StringUtils.isNoneBlank("", "bar")        = false
3568     * StringUtils.isNoneBlank("bob", "")        = false
3569     * StringUtils.isNoneBlank("  bob  ", null)  = false
3570     * StringUtils.isNoneBlank(" ", "bar")       = false
3571     * StringUtils.isNoneBlank(new String[] {})  = true
3572     * StringUtils.isNoneBlank(new String[]{""}) = false
3573     * StringUtils.isNoneBlank("foo", "bar")     = true
3574     * </pre>
3575     *
3576     * @param css the CharSequences to check, may be null or empty.
3577     * @return {@code true} if none of the CharSequences are empty or null or whitespace only.
3578     * @since 3.2
3579     */
3580    public static boolean isNoneBlank(final CharSequence... css) {
3581      return !isAnyBlank(css);
3582    }
3583
3584    /**
3585     * Tests if none of the CharSequences are empty ("") or null.
3586     *
3587     * <pre>
3588     * StringUtils.isNoneEmpty((String) null)    = false
3589     * StringUtils.isNoneEmpty((String[]) null)  = true
3590     * StringUtils.isNoneEmpty(null, "foo")      = false
3591     * StringUtils.isNoneEmpty("", "bar")        = false
3592     * StringUtils.isNoneEmpty("bob", "")        = false
3593     * StringUtils.isNoneEmpty("  bob  ", null)  = false
3594     * StringUtils.isNoneEmpty(new String[] {})  = true
3595     * StringUtils.isNoneEmpty(new String[]{""}) = false
3596     * StringUtils.isNoneEmpty(" ", "bar")       = true
3597     * StringUtils.isNoneEmpty("foo", "bar")     = true
3598     * </pre>
3599     *
3600     * @param css  the CharSequences to check, may be null or empty.
3601     * @return {@code true} if none of the CharSequences are empty or null.
3602     * @since 3.2
3603     */
3604    public static boolean isNoneEmpty(final CharSequence... css) {
3605      return !isAnyEmpty(css);
3606    }
3607
3608    /**
3609     * Tests if a CharSequence is not {@link #isBlank(CharSequence) blank} (whitespaces, empty ({@code ""}) or {@code null}).
3610     *
3611     * <p>
3612     * Whitespace is defined by {@link Character#isWhitespace(char)}.
3613     * </p>
3614     *
3615     * <pre>
3616     * StringUtils.isNotBlank(null)      = false
3617     * StringUtils.isNotBlank("")        = false
3618     * StringUtils.isNotBlank(" ")       = false
3619     * StringUtils.isNotBlank("bob")     = true
3620     * StringUtils.isNotBlank("  bob  ") = true
3621     * </pre>
3622     *
3623     * @param cs the CharSequence to check, may be null.
3624     * @return {@code true} if the CharSequence is not {@link #isBlank(CharSequence) blank} (whitespaces, empty ({@code ""}) or {@code null}).
3625     * @see #isBlank(CharSequence)
3626     * @since 2.0
3627     * @since 3.0 Changed signature from isNotBlank(String) to isNotBlank(CharSequence)
3628     */
3629    public static boolean isNotBlank(final CharSequence cs) {
3630        return !isBlank(cs);
3631    }
3632
3633    /**
3634     * Tests if a CharSequence is not empty ("") and not null.
3635     *
3636     * <pre>
3637     * StringUtils.isNotEmpty(null)      = false
3638     * StringUtils.isNotEmpty("")        = false
3639     * StringUtils.isNotEmpty(" ")       = true
3640     * StringUtils.isNotEmpty("bob")     = true
3641     * StringUtils.isNotEmpty("  bob  ") = true
3642     * </pre>
3643     *
3644     * @param cs  the CharSequence to check, may be null.
3645     * @return {@code true} if the CharSequence is not empty and not null.
3646     * @since 3.0 Changed signature from isNotEmpty(String) to isNotEmpty(CharSequence)
3647     */
3648    public static boolean isNotEmpty(final CharSequence cs) {
3649        return !isEmpty(cs);
3650    }
3651
3652    /**
3653     * Tests if the CharSequence contains only Unicode digits. A decimal point is not a Unicode digit and returns false.
3654     *
3655     * <p>
3656     * {@code null} will return {@code false}. An empty CharSequence (length()=0) will return {@code false}.
3657     * </p>
3658     *
3659     * <p>
3660     * Note that the method does not allow for a leading sign, either positive or negative. Also, if a String passes the numeric test, it may still generate a
3661     * NumberFormatException when parsed by Integer.parseInt or Long.parseLong, e.g. if the value is outside the range for int or long respectively.
3662     * </p>
3663     *
3664     * <pre>
3665     * StringUtils.isNumeric(null)   = false
3666     * StringUtils.isNumeric("")     = false
3667     * StringUtils.isNumeric("  ")   = false
3668     * StringUtils.isNumeric("123")  = true
3669     * StringUtils.isNumeric("\u0967\u0968\u0969")  = true
3670     * StringUtils.isNumeric("12 3") = false
3671     * StringUtils.isNumeric("ab2c") = false
3672     * StringUtils.isNumeric("12-3") = false
3673     * StringUtils.isNumeric("12.3") = false
3674     * StringUtils.isNumeric("-123") = false
3675     * StringUtils.isNumeric("+123") = false
3676     * </pre>
3677     *
3678     * @param cs the CharSequence to check, may be null.
3679     * @return {@code true} if only contains digits, and is non-null.
3680     * @since 3.0 Changed signature from isNumeric(String) to isNumeric(CharSequence)
3681     * @since 3.0 Changed "" to return false and not true
3682     */
3683    public static boolean isNumeric(final CharSequence cs) {
3684        if (isEmpty(cs)) {
3685            return false;
3686        }
3687        final int sz = cs.length();
3688        for (int i = 0; i < sz; i++) {
3689            if (!Character.isDigit(cs.charAt(i))) {
3690                return false;
3691            }
3692        }
3693        return true;
3694    }
3695
3696    /**
3697     * Tests if the CharSequence contains only Unicode digits or space ({@code ' '}). A decimal point is not a Unicode digit and returns false.
3698     *
3699     * <p>
3700     * {@code null} will return {@code false}. An empty CharSequence (length()=0) will return {@code true}.
3701     * </p>
3702     *
3703     * <pre>
3704     * StringUtils.isNumericSpace(null)   = false
3705     * StringUtils.isNumericSpace("")     = true
3706     * StringUtils.isNumericSpace("  ")   = true
3707     * StringUtils.isNumericSpace("123")  = true
3708     * StringUtils.isNumericSpace("12 3") = true
3709     * StringUtils.isNumericSpace("\u0967\u0968\u0969")   = true
3710     * StringUtils.isNumericSpace("\u0967\u0968 \u0969")  = true
3711     * StringUtils.isNumericSpace("ab2c") = false
3712     * StringUtils.isNumericSpace("12-3") = false
3713     * StringUtils.isNumericSpace("12.3") = false
3714     * </pre>
3715     *
3716     * @param cs the CharSequence to check, may be null.
3717     * @return {@code true} if only contains digits or space, and is non-null.
3718     * @since 3.0 Changed signature from isNumericSpace(String) to isNumericSpace(CharSequence)
3719     */
3720    public static boolean isNumericSpace(final CharSequence cs) {
3721        if (cs == null) {
3722            return false;
3723        }
3724        final int sz = cs.length();
3725        for (int i = 0; i < sz; i++) {
3726            final char nowChar = cs.charAt(i);
3727            if (nowChar != ' ' && !Character.isDigit(nowChar)) {
3728                return false;
3729            }
3730        }
3731        return true;
3732    }
3733
3734    /**
3735     * Tests if the CharSequence contains only whitespace.
3736     *
3737     * <p>
3738     * Whitespace is defined by {@link Character#isWhitespace(char)}.
3739     * </p>
3740     *
3741     * <p>
3742     * {@code null} will return {@code false}. An empty CharSequence (length()=0) will return {@code true}.
3743     * </p>
3744     *
3745     * <pre>
3746     * StringUtils.isWhitespace(null)   = false
3747     * StringUtils.isWhitespace("")     = true
3748     * StringUtils.isWhitespace("  ")   = true
3749     * StringUtils.isWhitespace("abc")  = false
3750     * StringUtils.isWhitespace("ab2c") = false
3751     * StringUtils.isWhitespace("ab-c") = false
3752     * </pre>
3753     *
3754     * @param cs the CharSequence to check, may be null.
3755     * @return {@code true} if only contains whitespace, and is non-null.
3756     * @since 2.0
3757     * @since 3.0 Changed signature from isWhitespace(String) to isWhitespace(CharSequence)
3758     */
3759    public static boolean isWhitespace(final CharSequence cs) {
3760        if (cs == null) {
3761            return false;
3762        }
3763        final int sz = cs.length();
3764        for (int i = 0; i < sz; i++) {
3765            if (!Character.isWhitespace(cs.charAt(i))) {
3766                return false;
3767            }
3768        }
3769        return true;
3770    }
3771
3772    /**
3773     * Joins the elements of the provided array into a single String containing the provided list of elements.
3774     *
3775     * <p>
3776     * No delimiter is added before or after the list. Null objects or empty strings within the array are represented by empty strings.
3777     * </p>
3778     *
3779     * <pre>
3780     * StringUtils.join(null, *)             = null
3781     * StringUtils.join([], *)               = ""
3782     * StringUtils.join([null], *)           = ""
3783     * StringUtils.join([false, false], ';') = "false;false"
3784     * </pre>
3785     *
3786     * @param array     the array of values to join together, may be null.
3787     * @param delimiter the separator character to use.
3788     * @return the joined String, {@code null} if null array input.
3789     * @since 3.12.0
3790     */
3791    public static String join(final boolean[] array, final char delimiter) {
3792        if (array == null) {
3793            return null;
3794        }
3795        return join(array, delimiter, 0, array.length);
3796    }
3797
3798    /**
3799     * Joins the elements of the provided array into a single String containing the provided list of elements.
3800     *
3801     * <p>
3802     * No delimiter is added before or after the list. Null objects or empty strings within the array are represented
3803     * by empty strings.
3804     * </p>
3805     *
3806     * <pre>
3807     * StringUtils.join(null, *)                  = null
3808     * StringUtils.join([], *)                    = ""
3809     * StringUtils.join([null], *)                = ""
3810     * StringUtils.join([true, false, true], ';') = "true;false;true"
3811     * </pre>
3812     *
3813     * @param array
3814     *            the array of values to join together, may be null.
3815     * @param delimiter
3816     *            the separator character to use.
3817     * @param startIndex
3818     *            the first index to start joining from. It is an error to pass in a start index past the end of the
3819     *            array.
3820     * @param endIndex
3821     *            the index to stop joining from (exclusive). It is an error to pass in an end index past the end of
3822     *            the array.
3823     * @return the joined String, {@code null} if null array input.
3824     * @since 3.12.0
3825     */
3826    public static String join(final boolean[] array, final char delimiter, final int startIndex, final int endIndex) {
3827        if (array == null) {
3828            return null;
3829        }
3830        if (endIndex - startIndex <= 0) {
3831            return EMPTY;
3832        }
3833        final StringBuilder stringBuilder = new StringBuilder(array.length * 5 + array.length - 1);
3834        for (int i = startIndex; i < endIndex; i++) {
3835            stringBuilder
3836                    .append(array[i])
3837                    .append(delimiter);
3838        }
3839        return stringBuilder.substring(0, stringBuilder.length() - 1);
3840    }
3841
3842    /**
3843     * Joins the elements of the provided array into a single String containing the provided list of elements.
3844     *
3845     * <p>
3846     * No delimiter is added before or after the list. Null objects or empty strings within the array are represented
3847     * by empty strings.
3848     * </p>
3849     *
3850     * <pre>
3851     * StringUtils.join(null, *)         = null
3852     * StringUtils.join([], *)           = ""
3853     * StringUtils.join([null], *)       = ""
3854     * StringUtils.join([1, 2, 3], ';')  = "1;2;3"
3855     * StringUtils.join([1, 2, 3], null) = "123"
3856     * </pre>
3857     *
3858     * @param array
3859     *            the array of values to join together, may be null.
3860     * @param delimiter
3861     *            the separator character to use.
3862     * @return the joined String, {@code null} if null array input.
3863     * @since 3.2
3864     */
3865    public static String join(final byte[] array, final char delimiter) {
3866        if (array == null) {
3867            return null;
3868        }
3869        return join(array, delimiter, 0, array.length);
3870    }
3871
3872    /**
3873     * Joins the elements of the provided array into a single String containing the provided list of elements.
3874     *
3875     * <p>
3876     * No delimiter is added before or after the list. Null objects or empty strings within the array are represented
3877     * by empty strings.
3878     * </p>
3879     *
3880     * <pre>
3881     * StringUtils.join(null, *)         = null
3882     * StringUtils.join([], *)           = ""
3883     * StringUtils.join([null], *)       = ""
3884     * StringUtils.join([1, 2, 3], ';')  = "1;2;3"
3885     * StringUtils.join([1, 2, 3], null) = "123"
3886     * </pre>
3887     *
3888     * @param array
3889     *            the array of values to join together, may be null.
3890     * @param delimiter
3891     *            the separator character to use.
3892     * @param startIndex
3893     *            the first index to start joining from. It is an error to pass in a start index past the end of the
3894     *            array.
3895     * @param endIndex
3896     *            the index to stop joining from (exclusive). It is an error to pass in an end index past the end of
3897     *            the array.
3898     * @return the joined String, {@code null} if null array input.
3899     * @since 3.2
3900     */
3901    public static String join(final byte[] array, final char delimiter, final int startIndex, final int endIndex) {
3902        if (array == null) {
3903            return null;
3904        }
3905        if (endIndex - startIndex <= 0) {
3906            return EMPTY;
3907        }
3908        final StringBuilder stringBuilder = new StringBuilder();
3909        for (int i = startIndex; i < endIndex; i++) {
3910            stringBuilder
3911                    .append(array[i])
3912                    .append(delimiter);
3913        }
3914        return stringBuilder.substring(0, stringBuilder.length() - 1);
3915    }
3916
3917    /**
3918     * Joins the elements of the provided array into a single String containing the provided list of elements.
3919     *
3920     * <p>
3921     * No delimiter is added before or after the list. Null objects or empty strings within the array are represented
3922     * by empty strings.
3923     * </p>
3924     *
3925     * <pre>
3926     * StringUtils.join(null, *)         = null
3927     * StringUtils.join([], *)           = ""
3928     * StringUtils.join([null], *)       = ""
3929     * StringUtils.join([1, 2, 3], ';')  = "1;2;3"
3930     * StringUtils.join([1, 2, 3], null) = "123"
3931     * </pre>
3932     *
3933     * @param array
3934     *            the array of values to join together, may be null.
3935     * @param delimiter
3936     *            the separator character to use.
3937     * @return the joined String, {@code null} if null array input.
3938     * @since 3.2
3939     */
3940    public static String join(final char[] array, final char delimiter) {
3941        if (array == null) {
3942            return null;
3943        }
3944        return join(array, delimiter, 0, array.length);
3945    }
3946
3947    /**
3948     * Joins the elements of the provided array into a single String containing the provided list of elements.
3949     *
3950     * <p>
3951     * No delimiter is added before or after the list. Null objects or empty strings within the array are represented
3952     * by empty strings.
3953     * </p>
3954     *
3955     * <pre>
3956     * StringUtils.join(null, *)         = null
3957     * StringUtils.join([], *)           = ""
3958     * StringUtils.join([null], *)       = ""
3959     * StringUtils.join([1, 2, 3], ';')  = "1;2;3"
3960     * StringUtils.join([1, 2, 3], null) = "123"
3961     * </pre>
3962     *
3963     * @param array
3964     *            the array of values to join together, may be null.
3965     * @param delimiter
3966     *            the separator character to use.
3967     * @param startIndex
3968     *            the first index to start joining from. It is an error to pass in a start index past the end of the
3969     *            array.
3970     * @param endIndex
3971     *            the index to stop joining from (exclusive). It is an error to pass in an end index past the end of
3972     *            the array.
3973     * @return the joined String, {@code null} if null array input.
3974     * @since 3.2
3975     */
3976    public static String join(final char[] array, final char delimiter, final int startIndex, final int endIndex) {
3977        if (array == null) {
3978            return null;
3979        }
3980        if (endIndex - startIndex <= 0) {
3981            return EMPTY;
3982        }
3983        final StringBuilder stringBuilder = new StringBuilder(array.length * 2 - 1);
3984        for (int i = startIndex; i < endIndex; i++) {
3985            stringBuilder
3986                    .append(array[i])
3987                    .append(delimiter);
3988        }
3989        return stringBuilder.substring(0, stringBuilder.length() - 1);
3990    }
3991
3992    /**
3993     * Joins the elements of the provided array into a single String containing the provided list of elements.
3994     *
3995     * <p>
3996     * No delimiter is added before or after the list. Null objects or empty strings within the array are represented
3997     * by empty strings.
3998     * </p>
3999     *
4000     * <pre>
4001     * StringUtils.join(null, *)          = null
4002     * StringUtils.join([], *)            = ""
4003     * StringUtils.join([null], *)        = ""
4004     * StringUtils.join([1, 2, 3], ';')   = "1;2;3"
4005     * StringUtils.join([1, 2, 3], null)  = "123"
4006     * </pre>
4007     *
4008     * @param array
4009     *            the array of values to join together, may be null.
4010     * @param delimiter
4011     *            the separator character to use.
4012     * @return the joined String, {@code null} if null array input.
4013     * @since 3.2
4014     */
4015    public static String join(final double[] array, final char delimiter) {
4016        if (array == null) {
4017            return null;
4018        }
4019        return join(array, delimiter, 0, array.length);
4020    }
4021
4022    /**
4023     * Joins the elements of the provided array into a single String containing the provided list of elements.
4024     *
4025     * <p>
4026     * No delimiter is added before or after the list. Null objects or empty strings within the array are represented
4027     * by empty strings.
4028     * </p>
4029     *
4030     * <pre>
4031     * StringUtils.join(null, *)          = null
4032     * StringUtils.join([], *)            = ""
4033     * StringUtils.join([null], *)        = ""
4034     * StringUtils.join([1, 2, 3], ';')   = "1;2;3"
4035     * StringUtils.join([1, 2, 3], null)  = "123"
4036     * </pre>
4037     *
4038     * @param array
4039     *            the array of values to join together, may be null.
4040     * @param delimiter
4041     *            the separator character to use.
4042     * @param startIndex
4043     *            the first index to start joining from. It is an error to pass in a start index past the end of the
4044     *            array.
4045     * @param endIndex
4046     *            the index to stop joining from (exclusive). It is an error to pass in an end index past the end of
4047     *            the array.
4048     * @return the joined String, {@code null} if null array input.
4049     * @since 3.2
4050     */
4051    public static String join(final double[] array, final char delimiter, final int startIndex, final int endIndex) {
4052        if (array == null) {
4053            return null;
4054        }
4055        if (endIndex - startIndex <= 0) {
4056            return EMPTY;
4057        }
4058        final StringBuilder stringBuilder = new StringBuilder();
4059        for (int i = startIndex; i < endIndex; i++) {
4060            stringBuilder
4061                    .append(array[i])
4062                    .append(delimiter);
4063        }
4064        return stringBuilder.substring(0, stringBuilder.length() - 1);
4065    }
4066
4067    /**
4068     * Joins the elements of the provided array into a single String containing the provided list of elements.
4069     *
4070     * <p>
4071     * No delimiter is added before or after the list. Null objects or empty strings within the array are represented
4072     * by empty strings.
4073     * </p>
4074     *
4075     * <pre>
4076     * StringUtils.join(null, *)          = null
4077     * StringUtils.join([], *)            = ""
4078     * StringUtils.join([null], *)        = ""
4079     * StringUtils.join([1, 2, 3], ';')   = "1;2;3"
4080     * StringUtils.join([1, 2, 3], null)  = "123"
4081     * </pre>
4082     *
4083     * @param array
4084     *            the array of values to join together, may be null.
4085     * @param delimiter
4086     *            the separator character to use.
4087     * @return the joined String, {@code null} if null array input
4088     * @since 3.2
4089     */
4090    public static String join(final float[] array, final char delimiter) {
4091        if (array == null) {
4092            return null;
4093        }
4094        return join(array, delimiter, 0, array.length);
4095    }
4096
4097    /**
4098     * Joins the elements of the provided array into a single String containing the provided list of elements.
4099     *
4100     * <p>
4101     * No delimiter is added before or after the list. Null objects or empty strings within the array are represented
4102     * by empty strings.
4103     * </p>
4104     *
4105     * <pre>
4106     * StringUtils.join(null, *)          = null
4107     * StringUtils.join([], *)            = ""
4108     * StringUtils.join([null], *)        = ""
4109     * StringUtils.join([1, 2, 3], ';')   = "1;2;3"
4110     * StringUtils.join([1, 2, 3], null)  = "123"
4111     * </pre>
4112     *
4113     * @param array
4114     *            the array of values to join together, may be null.
4115     * @param delimiter
4116     *            the separator character to use.
4117     * @param startIndex
4118     *            the first index to start joining from. It is an error to pass in a start index past the end of the
4119     *            array.
4120     * @param endIndex
4121     *            the index to stop joining from (exclusive). It is an error to pass in an end index past the end of
4122     *            the array.
4123     * @return the joined String, {@code null} if null array input.
4124     * @since 3.2
4125     */
4126    public static String join(final float[] array, final char delimiter, final int startIndex, final int endIndex) {
4127        if (array == null) {
4128            return null;
4129        }
4130        if (endIndex - startIndex <= 0) {
4131            return EMPTY;
4132        }
4133        final StringBuilder stringBuilder = new StringBuilder();
4134        for (int i = startIndex; i < endIndex; i++) {
4135            stringBuilder
4136                    .append(array[i])
4137                    .append(delimiter);
4138        }
4139        return stringBuilder.substring(0, stringBuilder.length() - 1);
4140    }
4141
4142    /**
4143     * Joins the elements of the provided array into a single String containing the provided list of elements.
4144     *
4145     * <p>
4146     * No delimiter is added before or after the list. Null objects or empty strings within the array are represented
4147     * by empty strings.
4148     * </p>
4149     *
4150     * <pre>
4151     * StringUtils.join(null, *)          = null
4152     * StringUtils.join([], *)            = ""
4153     * StringUtils.join([null], *)        = ""
4154     * StringUtils.join([1, 2, 3], ';')   = "1;2;3"
4155     * StringUtils.join([1, 2, 3], null)  = "123"
4156     * </pre>
4157     *
4158     * @param array
4159     *            the array of values to join together, may be null.
4160     * @param separator
4161     *            the separator character to use.
4162     * @return the joined String, {@code null} if null array input.
4163     * @since 3.2
4164     */
4165    public static String join(final int[] array, final char separator) {
4166        if (array == null) {
4167            return null;
4168        }
4169        return join(array, separator, 0, array.length);
4170    }
4171
4172    /**
4173     * Joins the elements of the provided array into a single String containing the provided list of elements.
4174     *
4175     * <p>
4176     * No delimiter is added before or after the list. Null objects or empty strings within the array are represented
4177     * by empty strings.
4178     * </p>
4179     *
4180     * <pre>
4181     * StringUtils.join(null, *)          = null
4182     * StringUtils.join([], *)            = ""
4183     * StringUtils.join([null], *)        = ""
4184     * StringUtils.join([1, 2, 3], ';')   = "1;2;3"
4185     * StringUtils.join([1, 2, 3], null)  = "123"
4186     * </pre>
4187     *
4188     * @param array
4189     *            the array of values to join together, may be null.
4190     * @param delimiter
4191     *            the separator character to use.
4192     * @param startIndex
4193     *            the first index to start joining from. It is an error to pass in a start index past the end of the
4194     *            array.
4195     * @param endIndex
4196     *            the index to stop joining from (exclusive). It is an error to pass in an end index past the end of
4197     *            the array.
4198     * @return the joined String, {@code null} if null array input.
4199     * @since 3.2
4200     */
4201    public static String join(final int[] array, final char delimiter, final int startIndex, final int endIndex) {
4202        if (array == null) {
4203            return null;
4204        }
4205        if (endIndex - startIndex <= 0) {
4206            return EMPTY;
4207        }
4208        final StringBuilder stringBuilder = new StringBuilder();
4209        for (int i = startIndex; i < endIndex; i++) {
4210            stringBuilder
4211                    .append(array[i])
4212                    .append(delimiter);
4213        }
4214        return stringBuilder.substring(0, stringBuilder.length() - 1);
4215    }
4216
4217    /**
4218     * Joins the elements of the provided {@link Iterable} into a single String containing the provided elements.
4219     *
4220     * <p>
4221     * No delimiter is added before or after the list. Null objects or empty strings within the iteration are represented by empty strings.
4222     * </p>
4223     *
4224     * <p>
4225     * See the examples here: {@link #join(Object[],char)}.
4226     * </p>
4227     *
4228     * @param iterable  the {@link Iterable} providing the values to join together, may be null.
4229     * @param separator the separator character to use.
4230     * @return the joined String, {@code null} if null iterator input.
4231     * @since 2.3
4232     */
4233    public static String join(final Iterable<?> iterable, final char separator) {
4234        return iterable != null ? join(iterable.iterator(), separator) : null;
4235    }
4236
4237    /**
4238     * Joins the elements of the provided {@link Iterable} into a single String containing the provided elements.
4239     *
4240     * <p>
4241     * No delimiter is added before or after the list. A {@code null} separator is the same as an empty String ("").
4242     * </p>
4243     *
4244     * <p>
4245     * See the examples here: {@link #join(Object[],String)}.
4246     * </p>
4247     *
4248     * @param iterable  the {@link Iterable} providing the values to join together, may be null.
4249     * @param separator the separator character to use, null treated as "".
4250     * @return the joined String, {@code null} if null iterator input.
4251     * @since 2.3
4252     */
4253    public static String join(final Iterable<?> iterable, final String separator) {
4254        return iterable != null ? join(iterable.iterator(), separator) : null;
4255    }
4256
4257    /**
4258     * Joins the elements of the provided {@link Iterator} into a single String containing the provided elements.
4259     *
4260     * <p>
4261     * No delimiter is added before or after the list. Null objects or empty strings within the iteration are represented by empty strings.
4262     * </p>
4263     *
4264     * <p>
4265     * See the examples here: {@link #join(Object[],char)}.
4266     * </p>
4267     *
4268     * @param iterator  the {@link Iterator} of values to join together, may be null.
4269     * @param separator the separator character to use.
4270     * @return the joined String, {@code null} if null iterator input.
4271     * @since 2.0
4272     */
4273    public static String join(final Iterator<?> iterator, final char separator) {
4274        // handle null, zero and one elements before building a buffer
4275        if (iterator == null) {
4276            return null;
4277        }
4278        if (!iterator.hasNext()) {
4279            return EMPTY;
4280        }
4281        return Streams.of(iterator).collect(LangCollectors.joining(ObjectUtils.toString(String.valueOf(separator)), EMPTY, EMPTY, ObjectUtils::toString));
4282    }
4283
4284    /**
4285     * Joins the elements of the provided {@link Iterator} into a single String containing the provided elements.
4286     *
4287     * <p>
4288     * No delimiter is added before or after the list. A {@code null} separator is the same as an empty String ("").
4289     * </p>
4290     *
4291     * <p>
4292     * See the examples here: {@link #join(Object[],String)}.
4293     * </p>
4294     *
4295     * @param iterator  the {@link Iterator} of values to join together, may be null.
4296     * @param separator the separator character to use, null treated as "".
4297     * @return the joined String, {@code null} if null iterator input.
4298     */
4299    public static String join(final Iterator<?> iterator, final String separator) {
4300        // handle null, zero and one elements before building a buffer
4301        if (iterator == null) {
4302            return null;
4303        }
4304        if (!iterator.hasNext()) {
4305            return EMPTY;
4306        }
4307        return Streams.of(iterator).collect(LangCollectors.joining(ObjectUtils.toString(separator), EMPTY, EMPTY, ObjectUtils::toString));
4308    }
4309
4310    /**
4311     * Joins the elements of the provided {@link List} into a single String containing the provided list of elements.
4312     *
4313     * <p>
4314     * No delimiter is added before or after the list. Null objects or empty strings within the array are represented by empty strings.
4315     * </p>
4316     *
4317     * <pre>
4318     * StringUtils.join(null, *)               = null
4319     * StringUtils.join([], *)                 = ""
4320     * StringUtils.join([null], *)             = ""
4321     * StringUtils.join(["a", "b", "c"], ';')  = "a;b;c"
4322     * StringUtils.join(["a", "b", "c"], null) = "abc"
4323     * StringUtils.join([null, "", "a"], ';')  = ";;a"
4324     * </pre>
4325     *
4326     * @param list       the {@link List} of values to join together, may be null.
4327     * @param separator  the separator character to use.
4328     * @param startIndex the first index to start joining from. It is an error to pass in a start index past the end of the list.
4329     * @param endIndex   the index to stop joining from (exclusive). It is an error to pass in an end index past the end of the list.
4330     * @return the joined String, {@code null} if null list input.
4331     * @since 3.8
4332     */
4333    public static String join(final List<?> list, final char separator, final int startIndex, final int endIndex) {
4334        if (list == null) {
4335            return null;
4336        }
4337        final int noOfItems = endIndex - startIndex;
4338        if (noOfItems <= 0) {
4339            return EMPTY;
4340        }
4341        final List<?> subList = list.subList(startIndex, endIndex);
4342        return join(subList.iterator(), separator);
4343    }
4344
4345    /**
4346     * Joins the elements of the provided {@link List} into a single String containing the provided list of elements.
4347     *
4348     * <p>
4349     * No delimiter is added before or after the list. Null objects or empty strings within the array are represented by empty strings.
4350     * </p>
4351     *
4352     * <pre>
4353     * StringUtils.join(null, *)               = null
4354     * StringUtils.join([], *)                 = ""
4355     * StringUtils.join([null], *)             = ""
4356     * StringUtils.join(["a", "b", "c"], ';')  = "a;b;c"
4357     * StringUtils.join(["a", "b", "c"], null) = "abc"
4358     * StringUtils.join([null, "", "a"], ';')  = ";;a"
4359     * </pre>
4360     *
4361     * @param list       the {@link List} of values to join together, may be null.
4362     * @param separator  the separator character to use.
4363     * @param startIndex the first index to start joining from. It is an error to pass in a start index past the end of the list.
4364     * @param endIndex   the index to stop joining from (exclusive). It is an error to pass in an end index past the end of the list.
4365     * @return the joined String, {@code null} if null list input.
4366     * @since 3.8
4367     */
4368    public static String join(final List<?> list, final String separator, final int startIndex, final int endIndex) {
4369        if (list == null) {
4370            return null;
4371        }
4372        final int noOfItems = endIndex - startIndex;
4373        if (noOfItems <= 0) {
4374            return EMPTY;
4375        }
4376        final List<?> subList = list.subList(startIndex, endIndex);
4377        return join(subList.iterator(), separator);
4378    }
4379
4380    /**
4381     * Joins the elements of the provided array into a single String containing the provided list of elements.
4382     *
4383     * <p>
4384     * No delimiter is added before or after the list. Null objects or empty strings within the array are represented
4385     * by empty strings.
4386     * </p>
4387     *
4388     * <pre>
4389     * StringUtils.join(null, *)               = null
4390     * StringUtils.join([], *)                 = ""
4391     * StringUtils.join([null], *)             = ""
4392     * StringUtils.join([1, 2, 3], ';')  = "1;2;3"
4393     * StringUtils.join([1, 2, 3], null) = "123"
4394     * </pre>
4395     *
4396     * @param array
4397     *            the array of values to join together, may be null.
4398     * @param separator
4399     *            the separator character to use.
4400     * @return the joined String, {@code null} if null array input.
4401     * @since 3.2
4402     */
4403    public static String join(final long[] array, final char separator) {
4404        if (array == null) {
4405            return null;
4406        }
4407        return join(array, separator, 0, array.length);
4408    }
4409
4410    /**
4411     * Joins the elements of the provided array into a single String containing the provided list of elements.
4412     *
4413     * <p>
4414     * No delimiter is added before or after the list. Null objects or empty strings within the array are represented
4415     * by empty strings.
4416     * </p>
4417     *
4418     * <pre>
4419     * StringUtils.join(null, *)               = null
4420     * StringUtils.join([], *)                 = ""
4421     * StringUtils.join([null], *)             = ""
4422     * StringUtils.join([1, 2, 3], ';')  = "1;2;3"
4423     * StringUtils.join([1, 2, 3], null) = "123"
4424     * </pre>
4425     *
4426     * @param array
4427     *            the array of values to join together, may be null.
4428     * @param delimiter
4429     *            the separator character to use.
4430     * @param startIndex
4431     *            the first index to start joining from. It is an error to pass in a start index past the end of the
4432     *            array.
4433     * @param endIndex
4434     *            the index to stop joining from (exclusive). It is an error to pass in an end index past the end of
4435     *            the array.
4436     * @return the joined String, {@code null} if null array input.
4437     * @since 3.2
4438     */
4439    public static String join(final long[] array, final char delimiter, final int startIndex, final int endIndex) {
4440        if (array == null) {
4441            return null;
4442        }
4443        if (endIndex - startIndex <= 0) {
4444            return EMPTY;
4445        }
4446        final StringBuilder stringBuilder = new StringBuilder();
4447        for (int i = startIndex; i < endIndex; i++) {
4448            stringBuilder
4449                    .append(array[i])
4450                    .append(delimiter);
4451        }
4452        return stringBuilder.substring(0, stringBuilder.length() - 1);
4453    }
4454
4455    /**
4456     * Joins the elements of the provided array into a single String containing the provided list of elements.
4457     *
4458     * <p>
4459     * No delimiter is added before or after the list. Null objects or empty strings within the array are represented by empty strings.
4460     * </p>
4461     *
4462     * <pre>
4463     * StringUtils.join(null, *)               = null
4464     * StringUtils.join([], *)                 = ""
4465     * StringUtils.join([null], *)             = ""
4466     * StringUtils.join(["a", "b", "c"], ';')  = "a;b;c"
4467     * StringUtils.join(["a", "b", "c"], null) = "abc"
4468     * StringUtils.join([null, "", "a"], ';')  = ";;a"
4469     * </pre>
4470     *
4471     * @param array     the array of values to join together, may be null.
4472     * @param delimiter the separator character to use.
4473     * @return the joined String, {@code null} if null array input.
4474     * @since 2.0
4475     */
4476    public static String join(final Object[] array, final char delimiter) {
4477        if (array == null) {
4478            return null;
4479        }
4480        return join(array, delimiter, 0, array.length);
4481    }
4482
4483    /**
4484     * Joins the elements of the provided array into a single String containing the provided list of elements.
4485     *
4486     * <p>
4487     * No delimiter is added before or after the list. Null objects or empty strings within the array are represented by empty strings.
4488     * </p>
4489     *
4490     * <pre>
4491     * StringUtils.join(null, *)               = null
4492     * StringUtils.join([], *)                 = ""
4493     * StringUtils.join([null], *)             = ""
4494     * StringUtils.join(["a", "b", "c"], ';')  = "a;b;c"
4495     * StringUtils.join(["a", "b", "c"], null) = "abc"
4496     * StringUtils.join([null, "", "a"], ';')  = ";;a"
4497     * </pre>
4498     *
4499     * @param array      the array of values to join together, may be null.
4500     * @param delimiter  the separator character to use.
4501     * @param startIndex the first index to start joining from. It is an error to pass in a start index past the end of the array.
4502     * @param endIndex   the index to stop joining from (exclusive). It is an error to pass in an end index past the end of the array.
4503     * @return the joined String, {@code null} if null array input.
4504     * @since 2.0
4505     */
4506    public static String join(final Object[] array, final char delimiter, final int startIndex, final int endIndex) {
4507        return join(array, String.valueOf(delimiter), startIndex, endIndex);
4508    }
4509
4510    /**
4511     * Joins the elements of the provided array into a single String containing the provided list of elements.
4512     *
4513     * <p>
4514     * No delimiter is added before or after the list. A {@code null} separator is the same as an empty String (""). Null objects or empty strings within the
4515     * array are represented by empty strings.
4516     * </p>
4517     *
4518     * <pre>
4519     * StringUtils.join(null, *)                = null
4520     * StringUtils.join([], *)                  = ""
4521     * StringUtils.join([null], *)              = ""
4522     * StringUtils.join(["a", "b", "c"], "--")  = "a--b--c"
4523     * StringUtils.join(["a", "b", "c"], null)  = "abc"
4524     * StringUtils.join(["a", "b", "c"], "")    = "abc"
4525     * StringUtils.join([null, "", "a"], ',')   = ",,a"
4526     * </pre>
4527     *
4528     * @param array     the array of values to join together, may be null.
4529     * @param delimiter the separator character to use, null treated as "".
4530     * @return the joined String, {@code null} if null array input.
4531     */
4532    public static String join(final Object[] array, final String delimiter) {
4533        return array != null ? join(array, ObjectUtils.toString(delimiter), 0, array.length) : null;
4534    }
4535
4536    /**
4537     * Joins the elements of the provided array into a single String containing the provided list of elements.
4538     *
4539     * <p>
4540     * No delimiter is added before or after the list. A {@code null} separator is the same as an empty String (""). Null objects or empty strings within the
4541     * array are represented by empty strings.
4542     * </p>
4543     *
4544     * <pre>
4545     * StringUtils.join(null, *, *, *)                = null
4546     * StringUtils.join([], *, *, *)                  = ""
4547     * StringUtils.join([null], *, *, *)              = ""
4548     * StringUtils.join(["a", "b", "c"], "--", 0, 3)  = "a--b--c"
4549     * StringUtils.join(["a", "b", "c"], "--", 1, 3)  = "b--c"
4550     * StringUtils.join(["a", "b", "c"], "--", 2, 3)  = "c"
4551     * StringUtils.join(["a", "b", "c"], "--", 2, 2)  = ""
4552     * StringUtils.join(["a", "b", "c"], null, 0, 3)  = "abc"
4553     * StringUtils.join(["a", "b", "c"], "", 0, 3)    = "abc"
4554     * StringUtils.join([null, "", "a"], ',', 0, 3)   = ",,a"
4555     * </pre>
4556     *
4557     * @param array      the array of values to join together, may be null.
4558     * @param delimiter  the separator character to use, null treated as "".
4559     * @param startIndex the first index to start joining from.
4560     * @param endIndex   the index to stop joining from (exclusive).
4561     * @return the joined String, {@code null} if null array input; or the empty string if {@code endIndex - startIndex <= 0}. The number of joined entries is
4562     *         given by {@code endIndex - startIndex}.
4563     * @throws ArrayIndexOutOfBoundsException ife<br>
4564     *                                        {@code startIndex < 0} or <br>
4565     *                                        {@code startIndex >= array.length()} or <br>
4566     *                                        {@code endIndex < 0} or <br>
4567     *                                        {@code endIndex > array.length()}
4568     */
4569    public static String join(final Object[] array, final String delimiter, final int startIndex, final int endIndex) {
4570        return array != null ? Streams.of(array).skip(startIndex).limit(Math.max(0, endIndex - startIndex))
4571                .collect(LangCollectors.joining(delimiter, EMPTY, EMPTY, ObjectUtils::toString)) : null;
4572    }
4573
4574    /**
4575     * Joins the elements of the provided array into a single String containing the provided list of elements.
4576     *
4577     * <p>
4578     * No delimiter is added before or after the list. Null objects or empty strings within the array are represented
4579     * by empty strings.
4580     * </p>
4581     *
4582     * <pre>
4583     * StringUtils.join(null, *)          = null
4584     * StringUtils.join([], *)            = ""
4585     * StringUtils.join([null], *)        = ""
4586     * StringUtils.join([1, 2, 3], ';')   = "1;2;3"
4587     * StringUtils.join([1, 2, 3], null)  = "123"
4588     * </pre>
4589     *
4590     * @param array
4591     *            the array of values to join together, may be null.
4592     * @param delimiter
4593     *            the separator character to use.
4594     * @return the joined String, {@code null} if null array input.
4595     * @since 3.2
4596     */
4597    public static String join(final short[] array, final char delimiter) {
4598        if (array == null) {
4599            return null;
4600        }
4601        return join(array, delimiter, 0, array.length);
4602    }
4603
4604    /**
4605     * Joins the elements of the provided array into a single String containing the provided list of elements.
4606     *
4607     * <p>
4608     * No delimiter is added before or after the list. Null objects or empty strings within the array are represented
4609     * by empty strings.
4610     * </p>
4611     *
4612     * <pre>
4613     * StringUtils.join(null, *)          = null
4614     * StringUtils.join([], *)            = ""
4615     * StringUtils.join([null], *)        = ""
4616     * StringUtils.join([1, 2, 3], ';')   = "1;2;3"
4617     * StringUtils.join([1, 2, 3], null)  = "123"
4618     * </pre>
4619     *
4620     * @param array
4621     *            the array of values to join together, may be null.
4622     * @param delimiter
4623     *            the separator character to use.
4624     * @param startIndex
4625     *            the first index to start joining from. It is an error to pass in a start index past the end of the
4626     *            array.
4627     * @param endIndex
4628     *            the index to stop joining from (exclusive). It is an error to pass in an end index past the end of
4629     *            the array.
4630     * @return the joined String, {@code null} if null array input.
4631     * @since 3.2
4632     */
4633    public static String join(final short[] array, final char delimiter, final int startIndex, final int endIndex) {
4634        if (array == null) {
4635            return null;
4636        }
4637        if (endIndex - startIndex <= 0) {
4638            return EMPTY;
4639        }
4640        final StringBuilder stringBuilder = new StringBuilder();
4641        for (int i = startIndex; i < endIndex; i++) {
4642            stringBuilder
4643                    .append(array[i])
4644                    .append(delimiter);
4645        }
4646        return stringBuilder.substring(0, stringBuilder.length() - 1);
4647    }
4648
4649    /**
4650     * Joins the elements of the provided array into a single String containing the provided list of elements.
4651     *
4652     * <p>
4653     * No separator is added to the joined String. Null objects or empty strings within the array are represented by empty strings.
4654     * </p>
4655     *
4656     * <pre>
4657     * StringUtils.join(null)            = null
4658     * StringUtils.join([])              = ""
4659     * StringUtils.join([null])          = ""
4660     * StringUtils.join(["a", "b", "c"]) = "abc"
4661     * StringUtils.join([null, "", "a"]) = "a"
4662     * </pre>
4663     *
4664     * @param <T>      the specific type of values to join together.
4665     * @param elements the values to join together, may be null.
4666     * @return the joined String, {@code null} if null array input.
4667     * @since 2.0
4668     * @since 3.0 Changed signature to use varargs
4669     */
4670    @SafeVarargs
4671    public static <T> String join(final T... elements) {
4672        return join(elements, null);
4673    }
4674
4675    /**
4676     * Joins the elements of the provided varargs into a single String containing the provided elements.
4677     *
4678     * <p>
4679     * No delimiter is added before or after the list. {@code null} elements and separator are treated as empty Strings ("").
4680     * </p>
4681     *
4682     * <pre>
4683     * StringUtils.joinWith(",", {"a", "b"})        = "a,b"
4684     * StringUtils.joinWith(",", {"a", "b",""})     = "a,b,"
4685     * StringUtils.joinWith(",", {"a", null, "b"})  = "a,,b"
4686     * StringUtils.joinWith(null, {"a", "b"})       = "ab"
4687     * </pre>
4688     *
4689     * @param delimiter the separator character to use, null treated as "".
4690     * @param array     the varargs providing the values to join together. {@code null} elements are treated as "".
4691     * @return the joined String.
4692     * @throws IllegalArgumentException if a null varargs is provided.
4693     * @since 3.5
4694     */
4695    public static String joinWith(final String delimiter, final Object... array) {
4696        if (array == null) {
4697            throw new IllegalArgumentException("Object varargs must not be null");
4698        }
4699        return join(array, delimiter);
4700    }
4701
4702    /**
4703     * Finds the last index within a CharSequence, handling {@code null}. This method uses {@link String#lastIndexOf(String)} if possible.
4704     *
4705     * <p>
4706     * A {@code null} CharSequence will return {@code -1}.
4707     * </p>
4708     *
4709     * <pre>
4710     * StringUtils.lastIndexOf(null, *)          = -1
4711     * StringUtils.lastIndexOf(*, null)          = -1
4712     * StringUtils.lastIndexOf("", "")           = 0
4713     * StringUtils.lastIndexOf("aabaabaa", "a")  = 7
4714     * StringUtils.lastIndexOf("aabaabaa", "b")  = 5
4715     * StringUtils.lastIndexOf("aabaabaa", "ab") = 4
4716     * StringUtils.lastIndexOf("aabaabaa", "")   = 8
4717     * </pre>
4718     *
4719     * @param seq       the CharSequence to check, may be null.
4720     * @param searchSeq the CharSequence to find, may be null.
4721     * @return the last index of the search String, -1 if no match or {@code null} string input.
4722     * @since 2.0
4723     * @since 3.0 Changed signature from lastIndexOf(String, String) to lastIndexOf(CharSequence, CharSequence)
4724     * @deprecated Use {@link Strings#lastIndexOf(CharSequence, CharSequence) Strings.CS.lastIndexOf(CharSequence, CharSequence)}
4725     */
4726    @Deprecated
4727    public static int lastIndexOf(final CharSequence seq, final CharSequence searchSeq) {
4728        return Strings.CS.lastIndexOf(seq, searchSeq);
4729    }
4730
4731    /**
4732     * Finds the last index within a CharSequence, handling {@code null}. This method uses {@link String#lastIndexOf(String, int)} if possible.
4733     *
4734     * <p>
4735     * A {@code null} CharSequence will return {@code -1}. A negative start position returns {@code -1}. An empty ("") search CharSequence always matches unless
4736     * the start position is negative. A start position greater than the string length searches the whole string. The search starts at the startPos and works
4737     * backwards; matches starting after the start position are ignored.
4738     * </p>
4739     *
4740     * <pre>
4741     * StringUtils.lastIndexOf(null, *, *)          = -1
4742     * StringUtils.lastIndexOf(*, null, *)          = -1
4743     * StringUtils.lastIndexOf("aabaabaa", "a", 8)  = 7
4744     * StringUtils.lastIndexOf("aabaabaa", "b", 8)  = 5
4745     * StringUtils.lastIndexOf("aabaabaa", "ab", 8) = 4
4746     * StringUtils.lastIndexOf("aabaabaa", "b", 9)  = 5
4747     * StringUtils.lastIndexOf("aabaabaa", "b", -1) = -1
4748     * StringUtils.lastIndexOf("aabaabaa", "a", 0)  = 0
4749     * StringUtils.lastIndexOf("aabaabaa", "b", 0)  = -1
4750     * StringUtils.lastIndexOf("aabaabaa", "b", 1)  = -1
4751     * StringUtils.lastIndexOf("aabaabaa", "b", 2)  = 2
4752     * StringUtils.lastIndexOf("aabaabaa", "ba", 2)  = 2
4753     * </pre>
4754     *
4755     * @param seq       the CharSequence to check, may be null.
4756     * @param searchSeq the CharSequence to find, may be null.
4757     * @param startPos  the start position, negative treated as zero.
4758     * @return the last index of the search CharSequence (always &le; startPos), -1 if no match or {@code null} string input.
4759     * @since 2.0
4760     * @since 3.0 Changed signature from lastIndexOf(String, String, int) to lastIndexOf(CharSequence, CharSequence, int)
4761     * @deprecated Use {@link Strings#lastIndexOf(CharSequence, CharSequence, int) Strings.CS.lastIndexOf(CharSequence, CharSequence, int)}
4762     */
4763    @Deprecated
4764    public static int lastIndexOf(final CharSequence seq, final CharSequence searchSeq, final int startPos) {
4765        return Strings.CS.lastIndexOf(seq, searchSeq, startPos);
4766    }
4767
4768    /**
4769     * Returns the index within {@code seq} of the last occurrence of the specified character. For values of {@code searchChar} in the range from 0 to 0xFFFF
4770     * (inclusive), the index (in Unicode code units) returned is the largest value <em>k</em> such that:
4771     *
4772     * <pre>
4773     * this.charAt(<em>k</em>) == searchChar
4774     * </pre>
4775     *
4776     * <p>
4777     * is true. For other values of {@code searchChar}, it is the largest value <em>k</em> such that:
4778     * </p>
4779     *
4780     * <pre>
4781     * this.codePointAt(<em>k</em>) == searchChar
4782     * </pre>
4783     *
4784     * <p>
4785     * is true. In either case, if no such character occurs in this string, then {@code -1} is returned. Furthermore, a {@code null} or empty ("")
4786     * {@link CharSequence} will return {@code -1}. The {@code seq} {@link CharSequence} object is searched backwards starting at the last character.
4787     * </p>
4788     *
4789     * <pre>
4790     * StringUtils.lastIndexOf(null, *)         = -1
4791     * StringUtils.lastIndexOf("", *)           = -1
4792     * StringUtils.lastIndexOf("aabaabaa", 'a') = 7
4793     * StringUtils.lastIndexOf("aabaabaa", 'b') = 5
4794     * </pre>
4795     *
4796     * @param seq        the {@link CharSequence} to check, may be null.
4797     * @param searchChar the character to find.
4798     * @return the last index of the search character, -1 if no match or {@code null} string input.
4799     * @since 2.0
4800     * @since 3.0 Changed signature from lastIndexOf(String, int) to lastIndexOf(CharSequence, int)
4801     * @since 3.6 Updated {@link CharSequenceUtils} call to behave more like {@link String}
4802     */
4803    public static int lastIndexOf(final CharSequence seq, final int searchChar) {
4804        if (isEmpty(seq)) {
4805            return INDEX_NOT_FOUND;
4806        }
4807        return CharSequenceUtils.lastIndexOf(seq, searchChar, seq.length());
4808    }
4809
4810    /**
4811     * Returns the index within {@code seq} of the last occurrence of the specified character, searching backward starting at the specified index. For values of
4812     * {@code searchChar} in the range from 0 to 0xFFFF (inclusive), the index returned is the largest value <em>k</em> such that:
4813     *
4814     * <pre>
4815     * (this.charAt(<em>k</em>) == searchChar) &amp;&amp; (<em>k</em> &lt;= startPos)
4816     * </pre>
4817     *
4818     * <p>
4819     * is true. For other values of {@code searchChar}, it is the largest value <em>k</em> such that:
4820     * </p>
4821     *
4822     * <pre>
4823     * (this.codePointAt(<em>k</em>) == searchChar) &amp;&amp; (<em>k</em> &lt;= startPos)
4824     * </pre>
4825     *
4826     * <p>
4827     * is true. In either case, if no such character occurs in {@code seq} at or before position {@code startPos}, then {@code -1} is returned. Furthermore, a
4828     * {@code null} or empty ("") {@link CharSequence} will return {@code -1}. A start position greater than the string length searches the whole string. The
4829     * search starts at the {@code startPos} and works backwards; matches starting after the start position are ignored.
4830     * </p>
4831     *
4832     * <p>
4833     * All indices are specified in {@code char} values (Unicode code units).
4834     * </p>
4835     *
4836     * <pre>
4837     * StringUtils.lastIndexOf(null, *, *)          = -1
4838     * StringUtils.lastIndexOf("", *,  *)           = -1
4839     * StringUtils.lastIndexOf("aabaabaa", 'b', 8)  = 5
4840     * StringUtils.lastIndexOf("aabaabaa", 'b', 4)  = 2
4841     * StringUtils.lastIndexOf("aabaabaa", 'b', 0)  = -1
4842     * StringUtils.lastIndexOf("aabaabaa", 'b', 9)  = 5
4843     * StringUtils.lastIndexOf("aabaabaa", 'b', -1) = -1
4844     * StringUtils.lastIndexOf("aabaabaa", 'a', 0)  = 0
4845     * </pre>
4846     *
4847     * @param seq        the CharSequence to check, may be null.
4848     * @param searchChar the character to find.
4849     * @param startPos   the start position.
4850     * @return the last index of the search character (always &le; startPos), -1 if no match or {@code null} string input.
4851     * @since 2.0
4852     * @since 3.0 Changed signature from lastIndexOf(String, int, int) to lastIndexOf(CharSequence, int, int)
4853     */
4854    public static int lastIndexOf(final CharSequence seq, final int searchChar, final int startPos) {
4855        if (isEmpty(seq)) {
4856            return INDEX_NOT_FOUND;
4857        }
4858        return CharSequenceUtils.lastIndexOf(seq, searchChar, startPos);
4859    }
4860
4861    /**
4862     * Finds the latest index of any substring in a set of potential substrings.
4863     *
4864     * <p>
4865     * A {@code null} CharSequence will return {@code -1}. A {@code null} search array will return {@code -1}. A {@code null} or zero length search array entry
4866     * will be ignored, but a search array containing "" will return the length of {@code str} if {@code str} is not null. This method uses
4867     * {@link String#indexOf(String)} if possible
4868     * </p>
4869     *
4870     * <pre>
4871     * StringUtils.lastIndexOfAny(null, *)                    = -1
4872     * StringUtils.lastIndexOfAny(*, null)                    = -1
4873     * StringUtils.lastIndexOfAny(*, [])                      = -1
4874     * StringUtils.lastIndexOfAny(*, [null])                  = -1
4875     * StringUtils.lastIndexOfAny("zzabyycdxx", ["ab", "cd"]) = 6
4876     * StringUtils.lastIndexOfAny("zzabyycdxx", ["cd", "ab"]) = 6
4877     * StringUtils.lastIndexOfAny("zzabyycdxx", ["mn", "op"]) = -1
4878     * StringUtils.lastIndexOfAny("zzabyycdxx", ["mn", "op"]) = -1
4879     * StringUtils.lastIndexOfAny("zzabyycdxx", ["mn", ""])   = 10
4880     * </pre>
4881     *
4882     * @param str        the CharSequence to check, may be null.
4883     * @param searchStrs the CharSequences to search for, may be null.
4884     * @return the last index of any of the CharSequences, -1 if no match.
4885     * @since 3.0 Changed signature from lastIndexOfAny(String, String[]) to lastIndexOfAny(CharSequence, CharSequence)
4886     */
4887    public static int lastIndexOfAny(final CharSequence str, final CharSequence... searchStrs) {
4888        if (str == null || searchStrs == null) {
4889            return INDEX_NOT_FOUND;
4890        }
4891        int ret = INDEX_NOT_FOUND;
4892        int tmp;
4893        for (final CharSequence search : searchStrs) {
4894            if (search == null) {
4895                continue;
4896            }
4897            tmp = CharSequenceUtils.lastIndexOf(str, search, str.length());
4898            if (tmp > ret) {
4899                ret = tmp;
4900            }
4901        }
4902        return ret;
4903    }
4904
4905    /**
4906     * Case in-sensitive find of the last index within a CharSequence.
4907     *
4908     * <p>
4909     * A {@code null} CharSequence will return {@code -1}. A negative start position returns {@code -1}. An empty ("") search CharSequence always matches unless
4910     * the start position is negative. A start position greater than the string length searches the whole string.
4911     * </p>
4912     *
4913     * <pre>
4914     * StringUtils.lastIndexOfIgnoreCase(null, *)          = -1
4915     * StringUtils.lastIndexOfIgnoreCase(*, null)          = -1
4916     * StringUtils.lastIndexOfIgnoreCase("aabaabaa", "A")  = 7
4917     * StringUtils.lastIndexOfIgnoreCase("aabaabaa", "B")  = 5
4918     * StringUtils.lastIndexOfIgnoreCase("aabaabaa", "AB") = 4
4919     * </pre>
4920     *
4921     * @param str       the CharSequence to check, may be null.
4922     * @param searchStr the CharSequence to find, may be null.
4923     * @return the first index of the search CharSequence, -1 if no match or {@code null} string input.
4924     * @since 2.5
4925     * @since 3.0 Changed signature from lastIndexOfIgnoreCase(String, String) to lastIndexOfIgnoreCase(CharSequence, CharSequence)
4926     * @deprecated Use {@link Strings#lastIndexOf(CharSequence, CharSequence) Strings.CI.lastIndexOf(CharSequence, CharSequence)}
4927     */
4928    @Deprecated
4929    public static int lastIndexOfIgnoreCase(final CharSequence str, final CharSequence searchStr) {
4930        return Strings.CI.lastIndexOf(str, searchStr);
4931    }
4932
4933    /**
4934     * Case in-sensitive find of the last index within a CharSequence from the specified position.
4935     *
4936     * <p>
4937     * A {@code null} CharSequence will return {@code -1}. A negative start position returns {@code -1}. An empty ("") search CharSequence always matches unless
4938     * the start position is negative. A start position greater than the string length searches the whole string. The search starts at the startPos and works
4939     * backwards; matches starting after the start position are ignored.
4940     * </p>
4941     *
4942     * <pre>
4943     * StringUtils.lastIndexOfIgnoreCase(null, *, *)          = -1
4944     * StringUtils.lastIndexOfIgnoreCase(*, null, *)          = -1
4945     * StringUtils.lastIndexOfIgnoreCase("aabaabaa", "A", 8)  = 7
4946     * StringUtils.lastIndexOfIgnoreCase("aabaabaa", "B", 8)  = 5
4947     * StringUtils.lastIndexOfIgnoreCase("aabaabaa", "AB", 8) = 4
4948     * StringUtils.lastIndexOfIgnoreCase("aabaabaa", "B", 9)  = 5
4949     * StringUtils.lastIndexOfIgnoreCase("aabaabaa", "B", -1) = -1
4950     * StringUtils.lastIndexOfIgnoreCase("aabaabaa", "A", 0)  = 0
4951     * StringUtils.lastIndexOfIgnoreCase("aabaabaa", "B", 0)  = -1
4952     * </pre>
4953     *
4954     * @param str       the CharSequence to check, may be null.
4955     * @param searchStr the CharSequence to find, may be null.
4956     * @param startPos  the start position.
4957     * @return the last index of the search CharSequence (always &le; startPos), -1 if no match or {@code null} input.
4958     * @since 2.5
4959     * @since 3.0 Changed signature from lastIndexOfIgnoreCase(String, String, int) to lastIndexOfIgnoreCase(CharSequence, CharSequence, int)
4960     * @deprecated Use {@link Strings#lastIndexOf(CharSequence, CharSequence, int) Strings.CI.lastIndexOf(CharSequence, CharSequence, int)}
4961     */
4962    @Deprecated
4963    public static int lastIndexOfIgnoreCase(final CharSequence str, final CharSequence searchStr, final int startPos) {
4964        return Strings.CI.lastIndexOf(str, searchStr, startPos);
4965    }
4966
4967    /**
4968     * Finds the n-th last index within a String, handling {@code null}. This method uses {@link String#lastIndexOf(String)}.
4969     *
4970     * <p>
4971     * A {@code null} String will return {@code -1}.
4972     * </p>
4973     *
4974     * <pre>
4975     * StringUtils.lastOrdinalIndexOf(null, *, *)          = -1
4976     * StringUtils.lastOrdinalIndexOf(*, null, *)          = -1
4977     * StringUtils.lastOrdinalIndexOf("", "", *)           = 0
4978     * StringUtils.lastOrdinalIndexOf("aabaabaa", "a", 1)  = 7
4979     * StringUtils.lastOrdinalIndexOf("aabaabaa", "a", 2)  = 6
4980     * StringUtils.lastOrdinalIndexOf("aabaabaa", "b", 1)  = 5
4981     * StringUtils.lastOrdinalIndexOf("aabaabaa", "b", 2)  = 2
4982     * StringUtils.lastOrdinalIndexOf("aabaabaa", "ab", 1) = 4
4983     * StringUtils.lastOrdinalIndexOf("aabaabaa", "ab", 2) = 1
4984     * StringUtils.lastOrdinalIndexOf("aabaabaa", "", 1)   = 8
4985     * StringUtils.lastOrdinalIndexOf("aabaabaa", "", 2)   = 8
4986     * </pre>
4987     *
4988     * <p>
4989     * Note that 'tail(CharSequence str, int n)' may be implemented as:
4990     * </p>
4991     *
4992     * <pre>
4993     * str.substring(lastOrdinalIndexOf(str, "\n", n) + 1)
4994     * </pre>
4995     *
4996     * @param str       the CharSequence to check, may be null.
4997     * @param searchStr the CharSequence to find, may be null.
4998     * @param ordinal   the n-th last {@code searchStr} to find.
4999     * @return the n-th last index of the search CharSequence, {@code -1} ({@code INDEX_NOT_FOUND}) if no match or {@code null} string input.
5000     * @since 2.5
5001     * @since 3.0 Changed signature from lastOrdinalIndexOf(String, String, int) to lastOrdinalIndexOf(CharSequence, CharSequence, int)
5002     */
5003    public static int lastOrdinalIndexOf(final CharSequence str, final CharSequence searchStr, final int ordinal) {
5004        return ordinalIndexOf(str, searchStr, ordinal, true);
5005    }
5006
5007    /**
5008     * Gets the leftmost {@code len} characters of a String.
5009     *
5010     * <p>
5011     * If {@code len} characters are not available, or the String is {@code null}, the String will be returned without an exception. An empty String is returned
5012     * if len is negative.
5013     * </p>
5014     *
5015     * <pre>
5016     * StringUtils.left(null, *)    = null
5017     * StringUtils.left(*, -ve)     = ""
5018     * StringUtils.left("", *)      = ""
5019     * StringUtils.left("abc", 0)   = ""
5020     * StringUtils.left("abc", 2)   = "ab"
5021     * StringUtils.left("abc", 4)   = "abc"
5022     * </pre>
5023     *
5024     * @param str the String to get the leftmost characters from, may be null.
5025     * @param len the length of the required String.
5026     * @return the leftmost characters, {@code null} if null String input.
5027     */
5028    public static String left(final String str, final int len) {
5029        if (str == null) {
5030            return null;
5031        }
5032        if (len < 0) {
5033            return EMPTY;
5034        }
5035        if (str.length() <= len) {
5036            return str;
5037        }
5038        return str.substring(0, len);
5039    }
5040
5041    /**
5042     * Left pad a String with spaces (' ').
5043     *
5044     * <p>
5045     * The String is padded to the size of {@code size}.
5046     * </p>
5047     *
5048     * <pre>
5049     * StringUtils.leftPad(null, *)   = null
5050     * StringUtils.leftPad("", 3)     = "   "
5051     * StringUtils.leftPad("bat", 3)  = "bat"
5052     * StringUtils.leftPad("bat", 5)  = "  bat"
5053     * StringUtils.leftPad("bat", 1)  = "bat"
5054     * StringUtils.leftPad("bat", -1) = "bat"
5055     * </pre>
5056     *
5057     * @param str  the String to pad out, may be null.
5058     * @param size the size to pad to.
5059     * @return left padded String or original String if no padding is necessary, {@code null} if null String input.
5060     */
5061    public static String leftPad(final String str, final int size) {
5062        return leftPad(str, size, ' ');
5063    }
5064
5065    /**
5066     * Left pad a String with a specified character.
5067     *
5068     * <p>
5069     * Pad to a size of {@code size}.
5070     * </p>
5071     *
5072     * <pre>
5073     * StringUtils.leftPad(null, *, *)     = null
5074     * StringUtils.leftPad("", 3, 'z')     = "zzz"
5075     * StringUtils.leftPad("bat", 3, 'z')  = "bat"
5076     * StringUtils.leftPad("bat", 5, 'z')  = "zzbat"
5077     * StringUtils.leftPad("bat", 1, 'z')  = "bat"
5078     * StringUtils.leftPad("bat", -1, 'z') = "bat"
5079     * </pre>
5080     *
5081     * @param str     the String to pad out, may be null.
5082     * @param size    the size to pad to.
5083     * @param padChar the character to pad with.
5084     * @return left padded String or original String if no padding is necessary, {@code null} if null String input.
5085     * @since 2.0
5086     */
5087    public static String leftPad(final String str, final int size, final char padChar) {
5088        if (str == null) {
5089            return null;
5090        }
5091        final int pads = size - str.length();
5092        if (pads <= 0) {
5093            return str; // returns original String when possible
5094        }
5095        if (pads > PAD_LIMIT) {
5096            return leftPad(str, size, String.valueOf(padChar));
5097        }
5098        return repeat(padChar, pads).concat(str);
5099    }
5100
5101    /**
5102     * Left pad a String with a specified String.
5103     *
5104     * <p>
5105     * Pad to a size of {@code size}.
5106     * </p>
5107     *
5108     * <pre>
5109     * StringUtils.leftPad(null, *, *)      = null
5110     * StringUtils.leftPad("", 3, "z")      = "zzz"
5111     * StringUtils.leftPad("bat", 3, "yz")  = "bat"
5112     * StringUtils.leftPad("bat", 5, "yz")  = "yzbat"
5113     * StringUtils.leftPad("bat", 8, "yz")  = "yzyzybat"
5114     * StringUtils.leftPad("bat", 1, "yz")  = "bat"
5115     * StringUtils.leftPad("bat", -1, "yz") = "bat"
5116     * StringUtils.leftPad("bat", 5, null)  = "  bat"
5117     * StringUtils.leftPad("bat", 5, "")    = "  bat"
5118     * </pre>
5119     *
5120     * @param str    the String to pad out, may be null.
5121     * @param size   the size to pad to.
5122     * @param padStr the String to pad with, null or empty treated as single space.
5123     * @return left padded String or original String if no padding is necessary, {@code null} if null String input.
5124     */
5125    public static String leftPad(final String str, final int size, String padStr) {
5126        if (str == null) {
5127            return null;
5128        }
5129        if (isEmpty(padStr)) {
5130            padStr = SPACE;
5131        }
5132        final int padLen = padStr.length();
5133        final int strLen = str.length();
5134        final int pads = size - strLen;
5135        if (pads <= 0) {
5136            return str; // returns original String when possible
5137        }
5138        if (padLen == 1 && pads <= PAD_LIMIT) {
5139            return leftPad(str, size, padStr.charAt(0));
5140        }
5141        if (pads == padLen) {
5142            return padStr.concat(str);
5143        }
5144        if (pads < padLen) {
5145            return padStr.substring(0, pads).concat(str);
5146        }
5147        final char[] padding = new char[pads];
5148        final char[] padChars = padStr.toCharArray();
5149        for (int i = 0; i < pads; i++) {
5150            padding[i] = padChars[i % padLen];
5151        }
5152        return new String(padding).concat(str);
5153    }
5154
5155    /**
5156     * Gets a CharSequence length or {@code 0} if the CharSequence is {@code null}.
5157     *
5158     * @param cs a CharSequence or {@code null}.
5159     * @return CharSequence length or {@code 0} if the CharSequence is {@code null}.
5160     * @since 2.4
5161     * @since 3.0 Changed signature from length(String) to length(CharSequence)
5162     */
5163    public static int length(final CharSequence cs) {
5164        return cs == null ? 0 : cs.length();
5165    }
5166
5167    /**
5168     * Converts a String to lower case as per {@link String#toLowerCase()}.
5169     *
5170     * <p>
5171     * A {@code null} input String returns {@code null}.
5172     * </p>
5173     *
5174     * <pre>
5175     * StringUtils.lowerCase(null)  = null
5176     * StringUtils.lowerCase("")    = ""
5177     * StringUtils.lowerCase("aBc") = "abc"
5178     * </pre>
5179     *
5180     * <p>
5181     * <strong>Note:</strong> As described in the documentation for {@link String#toLowerCase()}, the result of this method is affected by the current locale.
5182     * For platform-independent case transformations, the method {@link #lowerCase(String, Locale)} should be used with a specific locale (e.g.
5183     * {@link Locale#ENGLISH}).
5184     * </p>
5185     *
5186     * @param str the String to lower case, may be null.
5187     * @return the lower cased String, {@code null} if null String input.
5188     */
5189    public static String lowerCase(final String str) {
5190        if (str == null) {
5191            return null;
5192        }
5193        return str.toLowerCase();
5194    }
5195
5196    /**
5197     * Converts a String to lower case as per {@link String#toLowerCase(Locale)}.
5198     *
5199     * <p>
5200     * A {@code null} input String returns {@code null}.
5201     * </p>
5202     *
5203     * <pre>
5204     * StringUtils.lowerCase(null, Locale.ENGLISH)  = null
5205     * StringUtils.lowerCase("", Locale.ENGLISH)    = ""
5206     * StringUtils.lowerCase("aBc", Locale.ENGLISH) = "abc"
5207     * </pre>
5208     *
5209     * @param str    the String to lower case, may be null.
5210     * @param locale the locale that defines the case transformation rules, must not be null.
5211     * @return the lower cased String, {@code null} if null String input.
5212     * @since 2.5
5213     */
5214    public static String lowerCase(final String str, final Locale locale) {
5215        if (str == null) {
5216            return null;
5217        }
5218        return str.toLowerCase(LocaleUtils.toLocale(locale));
5219    }
5220
5221    private static int[] matches(final CharSequence first, final CharSequence second) {
5222        final CharSequence max;
5223        final CharSequence min;
5224        if (first.length() > second.length()) {
5225            max = first;
5226            min = second;
5227        } else {
5228            max = second;
5229            min = first;
5230        }
5231        final int range = Math.max(max.length() / 2 - 1, 0);
5232        final int[] matchIndexes = ArrayFill.fill(new int[min.length()], -1);
5233        final boolean[] matchFlags = new boolean[max.length()];
5234        int matches = 0;
5235        for (int mi = 0; mi < min.length(); mi++) {
5236            final char c1 = min.charAt(mi);
5237            for (int xi = Math.max(mi - range, 0), xn = Math.min(mi + range + 1, max.length()); xi < xn; xi++) {
5238                if (!matchFlags[xi] && c1 == max.charAt(xi)) {
5239                    matchIndexes[mi] = xi;
5240                    matchFlags[xi] = true;
5241                    matches++;
5242                    break;
5243                }
5244            }
5245        }
5246        final char[] ms1 = new char[matches];
5247        final char[] ms2 = new char[matches];
5248        for (int i = 0, si = 0; i < min.length(); i++) {
5249            if (matchIndexes[i] != -1) {
5250                ms1[si] = min.charAt(i);
5251                si++;
5252            }
5253        }
5254        for (int i = 0, si = 0; i < max.length(); i++) {
5255            if (matchFlags[i]) {
5256                ms2[si] = max.charAt(i);
5257                si++;
5258            }
5259        }
5260        int transpositions = 0;
5261        for (int mi = 0; mi < ms1.length; mi++) {
5262            if (ms1[mi] != ms2[mi]) {
5263                transpositions++;
5264            }
5265        }
5266        int prefix = 0;
5267        for (int mi = 0; mi < min.length(); mi++) {
5268            if (first.charAt(mi) != second.charAt(mi)) {
5269                break;
5270            }
5271            prefix++;
5272        }
5273        return new int[] { matches, transpositions / 2, prefix, max.length() };
5274    }
5275
5276    /**
5277     * Gets {@code len} characters from the middle of a String.
5278     *
5279     * <p>
5280     * If {@code len} characters are not available, the remainder of the String will be returned without an exception. If the String is {@code null},
5281     * {@code null} will be returned. An empty String is returned if len is negative or exceeds the length of {@code str}.
5282     * </p>
5283     *
5284     * <pre>
5285     * StringUtils.mid(null, *, *)    = null
5286     * StringUtils.mid(*, *, -ve)     = ""
5287     * StringUtils.mid("", 0, *)      = ""
5288     * StringUtils.mid("abc", 0, 2)   = "ab"
5289     * StringUtils.mid("abc", 0, 4)   = "abc"
5290     * StringUtils.mid("abc", 2, 4)   = "c"
5291     * StringUtils.mid("abc", 4, 2)   = ""
5292     * StringUtils.mid("abc", -2, 2)  = "ab"
5293     * </pre>
5294     *
5295     * @param str the String to get the characters from, may be null.
5296     * @param pos the position to start from, negative treated as zero.
5297     * @param len the length of the required String.
5298     * @return the middle characters, {@code null} if null String input.
5299     */
5300    public static String mid(final String str, int pos, final int len) {
5301        if (str == null) {
5302            return null;
5303        }
5304        if (len < 0 || pos > str.length()) {
5305            return EMPTY;
5306        }
5307        if (pos < 0) {
5308            pos = 0;
5309        }
5310        if (str.length() <= pos + len) {
5311            return str.substring(pos);
5312        }
5313        return str.substring(pos, pos + len);
5314    }
5315
5316    /**
5317     * Similar to <a href="https://www.w3.org/TR/xpath/#function-normalize-space">https://www.w3.org/TR/xpath/#function-normalize -space</a>
5318     *
5319     * <p>
5320     * The function returns the argument string with whitespace normalized by using {@code {@link #trim(String)}} to remove leading and trailing whitespace and
5321     * then replacing sequences of whitespace characters by a single space.
5322     * </p>
5323     * In XML Whitespace characters are the same as those allowed by the <a href="https://www.w3.org/TR/REC-xml/#NT-S">S</a> production, which is S ::= (#x20 |
5324     * #x9 | #xD | #xA)+
5325     * <p>
5326     * Java's regexp pattern \s defines whitespace as [ \t\n\x0B\f\r]
5327     * </p>
5328     * <p>
5329     * For reference:
5330     * </p>
5331     * <ul>
5332     * <li>\x0B = vertical tab</li>
5333     * <li>\f = #xC = form feed</li>
5334     * <li>#x20 = space</li>
5335     * <li>#x9 = \t</li>
5336     * <li>#xA = \n</li>
5337     * <li>#xD = \r</li>
5338     * </ul>
5339     *
5340     * <p>
5341     * The difference is that Java's whitespace includes vertical tab and form feed, which this functional will also normalize. Additionally {@code {@link
5342     * #trim(String)}} removes control characters (char &lt;= 32) from both ends of this String.
5343     * </p>
5344     *
5345     * @param str the source String to normalize whitespaces from, may be null.
5346     * @return the modified string with whitespace normalized, {@code null} if null String input.
5347     * @see Pattern
5348     * @see #trim(String)
5349     * @see <a href="https://www.w3.org/TR/xpath/#function-normalize-space">https://www.w3.org/TR/xpath/#function-normalize-space</a>
5350     * @since 3.0
5351     */
5352    public static String normalizeSpace(final String str) {
5353        // LANG-1020: Improved performance significantly by normalizing manually instead of using regex
5354        // See https://github.com/librucha/commons-lang-normalizespaces-benchmark for performance test
5355        if (isEmpty(str)) {
5356            return str;
5357        }
5358        final int size = str.length();
5359        final char[] newChars = new char[size];
5360        int count = 0;
5361        int whitespacesCount = 0;
5362        boolean startWhitespaces = true;
5363        for (int i = 0; i < size; i++) {
5364            final char actualChar = str.charAt(i);
5365            final boolean isWhitespace = Character.isWhitespace(actualChar);
5366            if (isWhitespace) {
5367                if (whitespacesCount == 0 && !startWhitespaces) {
5368                    newChars[count++] = SPACE.charAt(0);
5369                }
5370                whitespacesCount++;
5371            } else {
5372                startWhitespaces = false;
5373                newChars[count++] = actualChar == 160 ? 32 : actualChar;
5374                whitespacesCount = 0;
5375            }
5376        }
5377        if (startWhitespaces) {
5378            return EMPTY;
5379        }
5380        return new String(newChars, 0, count - (whitespacesCount > 0 ? 1 : 0)).trim();
5381    }
5382
5383    /**
5384     * Finds the n-th index within a CharSequence, handling {@code null}. This method uses {@link String#indexOf(String)} if possible.
5385     * <p>
5386     * <strong>Note:</strong> The code starts looking for a match at the start of the target, incrementing the starting index by one after each successful match
5387     * (unless {@code searchStr} is an empty string in which case the position is never incremented and {@code 0} is returned immediately). This means that
5388     * matches may overlap.
5389     * </p>
5390     * <p>
5391     * A {@code null} CharSequence will return {@code -1}.
5392     * </p>
5393     *
5394     * <pre>
5395     * StringUtils.ordinalIndexOf(null, *, *)          = -1
5396     * StringUtils.ordinalIndexOf(*, null, *)          = -1
5397     * StringUtils.ordinalIndexOf("", "", *)           = 0
5398     * StringUtils.ordinalIndexOf("aabaabaa", "a", 1)  = 0
5399     * StringUtils.ordinalIndexOf("aabaabaa", "a", 2)  = 1
5400     * StringUtils.ordinalIndexOf("aabaabaa", "b", 1)  = 2
5401     * StringUtils.ordinalIndexOf("aabaabaa", "b", 2)  = 5
5402     * StringUtils.ordinalIndexOf("aabaabaa", "ab", 1) = 1
5403     * StringUtils.ordinalIndexOf("aabaabaa", "ab", 2) = 4
5404     * StringUtils.ordinalIndexOf("aabaabaa", "", 1)   = 0
5405     * StringUtils.ordinalIndexOf("aabaabaa", "", 2)   = 0
5406     * </pre>
5407     *
5408     * <p>
5409     * Matches may overlap:
5410     * </p>
5411     *
5412     * <pre>
5413     * StringUtils.ordinalIndexOf("ababab", "aba", 1)   = 0
5414     * StringUtils.ordinalIndexOf("ababab", "aba", 2)   = 2
5415     * StringUtils.ordinalIndexOf("ababab", "aba", 3)   = -1
5416     *
5417     * StringUtils.ordinalIndexOf("abababab", "abab", 1) = 0
5418     * StringUtils.ordinalIndexOf("abababab", "abab", 2) = 2
5419     * StringUtils.ordinalIndexOf("abababab", "abab", 3) = 4
5420     * StringUtils.ordinalIndexOf("abababab", "abab", 4) = -1
5421     * </pre>
5422     *
5423     * <p>
5424     * Note that 'head(CharSequence str, int n)' may be implemented as:
5425     * </p>
5426     *
5427     * <pre>
5428     * str.substring(0, lastOrdinalIndexOf(str, "\n", n))
5429     * </pre>
5430     *
5431     * @param str       the CharSequence to check, may be null.
5432     * @param searchStr the CharSequence to find, may be null.
5433     * @param ordinal   the n-th {@code searchStr} to find.
5434     * @return the n-th index of the search CharSequence, {@code -1} ({@code INDEX_NOT_FOUND}) if no match or {@code null} string input.
5435     * @since 2.1
5436     * @since 3.0 Changed signature from ordinalIndexOf(String, String, int) to ordinalIndexOf(CharSequence, CharSequence, int)
5437     */
5438    public static int ordinalIndexOf(final CharSequence str, final CharSequence searchStr, final int ordinal) {
5439        return ordinalIndexOf(str, searchStr, ordinal, false);
5440    }
5441
5442    /**
5443     * Finds the n-th index within a String, handling {@code null}. This method uses {@link String#indexOf(String)} if possible.
5444     * <p>
5445     * Note that matches may overlap
5446     * <p>
5447     *
5448     * <p>
5449     * A {@code null} CharSequence will return {@code -1}.
5450     * </p>
5451     *
5452     * @param str       the CharSequence to check, may be null.
5453     * @param searchStr the CharSequence to find, may be null.
5454     * @param ordinal   the n-th {@code searchStr} to find, overlapping matches are allowed.
5455     * @param lastIndex true if lastOrdinalIndexOf() otherwise false if ordinalIndexOf().
5456     * @return the n-th index of the search CharSequence, {@code -1} ({@code INDEX_NOT_FOUND}) if no match or {@code null} string input.
5457     */
5458    // Shared code between ordinalIndexOf(String, String, int) and lastOrdinalIndexOf(String, String, int)
5459    private static int ordinalIndexOf(final CharSequence str, final CharSequence searchStr, final int ordinal, final boolean lastIndex) {
5460        if (str == null || searchStr == null || ordinal <= 0) {
5461            return INDEX_NOT_FOUND;
5462        }
5463        if (searchStr.length() == 0) {
5464            return lastIndex ? str.length() : 0;
5465        }
5466        int found = 0;
5467        // set the initial index beyond the end of the string
5468        // this is to allow for the initial index decrement/increment
5469        int index = lastIndex ? str.length() : INDEX_NOT_FOUND;
5470        do {
5471            if (lastIndex) {
5472                index = CharSequenceUtils.lastIndexOf(str, searchStr, index - 1); // step backwards through string
5473            } else {
5474                index = CharSequenceUtils.indexOf(str, searchStr, index + 1); // step forwards through string
5475            }
5476            if (index < 0) {
5477                return index;
5478            }
5479            found++;
5480        } while (found < ordinal);
5481        return index;
5482    }
5483
5484    /**
5485     * Overlays part of a String with another String.
5486     *
5487     * <p>
5488     * A {@code null} string input returns {@code null}. A negative index is treated as zero. An index greater than the string length is treated as the string
5489     * length. The start index is always the smaller of the two indices.
5490     * </p>
5491     *
5492     * <pre>
5493     * StringUtils.overlay(null, *, *, *)            = null
5494     * StringUtils.overlay("", "abc", 0, 0)          = "abc"
5495     * StringUtils.overlay("abcdef", null, 2, 4)     = "abef"
5496     * StringUtils.overlay("abcdef", "", 2, 4)       = "abef"
5497     * StringUtils.overlay("abcdef", "", 4, 2)       = "abef"
5498     * StringUtils.overlay("abcdef", "zzzz", 2, 4)   = "abzzzzef"
5499     * StringUtils.overlay("abcdef", "zzzz", 4, 2)   = "abzzzzef"
5500     * StringUtils.overlay("abcdef", "zzzz", -1, 4)  = "zzzzef"
5501     * StringUtils.overlay("abcdef", "zzzz", 2, 8)   = "abzzzz"
5502     * StringUtils.overlay("abcdef", "zzzz", -2, -3) = "zzzzabcdef"
5503     * StringUtils.overlay("abcdef", "zzzz", 8, 10)  = "abcdefzzzz"
5504     * </pre>
5505     *
5506     * @param str     the String to do overlaying in, may be null.
5507     * @param overlay the String to overlay, may be null.
5508     * @param start   the position to start overlaying at.
5509     * @param end     the position to stop overlaying before.
5510     * @return overlayed String, {@code null} if null String input.
5511     * @since 2.0
5512     */
5513    public static String overlay(final String str, String overlay, int start, int end) {
5514        if (str == null) {
5515            return null;
5516        }
5517        if (overlay == null) {
5518            overlay = EMPTY;
5519        }
5520        final int len = str.length();
5521        if (start < 0) {
5522            start = 0;
5523        }
5524        if (start > len) {
5525            start = len;
5526        }
5527        if (end < 0) {
5528            end = 0;
5529        }
5530        if (end > len) {
5531            end = len;
5532        }
5533        if (start > end) {
5534            final int temp = start;
5535            start = end;
5536            end = temp;
5537        }
5538        return str.substring(0, start) + overlay + str.substring(end);
5539    }
5540
5541    /**
5542     * Prepends the prefix to the start of the string if the string does not already start with any of the prefixes.
5543     *
5544     * <pre>
5545     * StringUtils.prependIfMissing(null, null) = null
5546     * StringUtils.prependIfMissing("abc", null) = "abc"
5547     * StringUtils.prependIfMissing("", "xyz") = "xyz"
5548     * StringUtils.prependIfMissing("abc", "xyz") = "xyzabc"
5549     * StringUtils.prependIfMissing("xyzabc", "xyz") = "xyzabc"
5550     * StringUtils.prependIfMissing("XYZabc", "xyz") = "xyzXYZabc"
5551     * </pre>
5552     * <p>
5553     * With additional prefixes,
5554     * </p>
5555     *
5556     * <pre>
5557     * StringUtils.prependIfMissing(null, null, null) = null
5558     * StringUtils.prependIfMissing("abc", null, null) = "abc"
5559     * StringUtils.prependIfMissing("", "xyz", null) = "xyz"
5560     * StringUtils.prependIfMissing("abc", "xyz", new CharSequence[]{null}) = "xyzabc"
5561     * StringUtils.prependIfMissing("abc", "xyz", "") = "abc"
5562     * StringUtils.prependIfMissing("abc", "xyz", "mno") = "xyzabc"
5563     * StringUtils.prependIfMissing("xyzabc", "xyz", "mno") = "xyzabc"
5564     * StringUtils.prependIfMissing("mnoabc", "xyz", "mno") = "mnoabc"
5565     * StringUtils.prependIfMissing("XYZabc", "xyz", "mno") = "xyzXYZabc"
5566     * StringUtils.prependIfMissing("MNOabc", "xyz", "mno") = "xyzMNOabc"
5567     * </pre>
5568     *
5569     * @param str      The string.
5570     * @param prefix   The prefix to prepend to the start of the string.
5571     * @param prefixes Additional prefixes that are valid.
5572     * @return A new String if prefix was prepended, the same string otherwise.
5573     * @since 3.2
5574     * @deprecated Use {@link Strings#prependIfMissing(String, CharSequence, CharSequence...) Strings.CS.prependIfMissing(String, CharSequence,
5575     *             CharSequence...)}
5576     */
5577    @Deprecated
5578    public static String prependIfMissing(final String str, final CharSequence prefix, final CharSequence... prefixes) {
5579        return Strings.CS.prependIfMissing(str, prefix, prefixes);
5580    }
5581
5582    /**
5583     * Prepends the prefix to the start of the string if the string does not already start, case-insensitive, with any of the prefixes.
5584     *
5585     * <pre>
5586     * StringUtils.prependIfMissingIgnoreCase(null, null) = null
5587     * StringUtils.prependIfMissingIgnoreCase("abc", null) = "abc"
5588     * StringUtils.prependIfMissingIgnoreCase("", "xyz") = "xyz"
5589     * StringUtils.prependIfMissingIgnoreCase("abc", "xyz") = "xyzabc"
5590     * StringUtils.prependIfMissingIgnoreCase("xyzabc", "xyz") = "xyzabc"
5591     * StringUtils.prependIfMissingIgnoreCase("XYZabc", "xyz") = "XYZabc"
5592     * </pre>
5593     * <p>
5594     * With additional prefixes,
5595     * </p>
5596     *
5597     * <pre>
5598     * StringUtils.prependIfMissingIgnoreCase(null, null, null) = null
5599     * StringUtils.prependIfMissingIgnoreCase("abc", null, null) = "abc"
5600     * StringUtils.prependIfMissingIgnoreCase("", "xyz", null) = "xyz"
5601     * StringUtils.prependIfMissingIgnoreCase("abc", "xyz", new CharSequence[]{null}) = "xyzabc"
5602     * StringUtils.prependIfMissingIgnoreCase("abc", "xyz", "") = "abc"
5603     * StringUtils.prependIfMissingIgnoreCase("abc", "xyz", "mno") = "xyzabc"
5604     * StringUtils.prependIfMissingIgnoreCase("xyzabc", "xyz", "mno") = "xyzabc"
5605     * StringUtils.prependIfMissingIgnoreCase("mnoabc", "xyz", "mno") = "mnoabc"
5606     * StringUtils.prependIfMissingIgnoreCase("XYZabc", "xyz", "mno") = "XYZabc"
5607     * StringUtils.prependIfMissingIgnoreCase("MNOabc", "xyz", "mno") = "MNOabc"
5608     * </pre>
5609     *
5610     * @param str      The string.
5611     * @param prefix   The prefix to prepend to the start of the string.
5612     * @param prefixes Additional prefixes that are valid (optional).
5613     * @return A new String if prefix was prepended, the same string otherwise.
5614     * @since 3.2
5615     * @deprecated Use {@link Strings#prependIfMissing(String, CharSequence, CharSequence...) Strings.CI.prependIfMissing(String, CharSequence,
5616     *             CharSequence...)}
5617     */
5618    @Deprecated
5619    public static String prependIfMissingIgnoreCase(final String str, final CharSequence prefix, final CharSequence... prefixes) {
5620        return Strings.CI.prependIfMissing(str, prefix, prefixes);
5621    }
5622
5623    /**
5624     * Removes all occurrences of a character from within the source string.
5625     *
5626     * <p>
5627     * A {@code null} source string will return {@code null}. An empty ("") source string will return the empty string.
5628     * </p>
5629     *
5630     * <pre>
5631     * StringUtils.remove(null, *)       = null
5632     * StringUtils.remove("", *)         = ""
5633     * StringUtils.remove("queued", 'u') = "qeed"
5634     * StringUtils.remove("queued", 'z') = "queued"
5635     * </pre>
5636     *
5637     * @param str    the source String to search, may be null.
5638     * @param remove the char to search for and remove, may be null.
5639     * @return the substring with the char removed if found, {@code null} if null String input.
5640     * @since 2.1
5641     */
5642    public static String remove(final String str, final char remove) {
5643        if (isEmpty(str) || str.indexOf(remove) == INDEX_NOT_FOUND) {
5644            return str;
5645        }
5646        final char[] chars = str.toCharArray();
5647        int pos = 0;
5648        for (int i = 0; i < chars.length; i++) {
5649            if (chars[i] != remove) {
5650                chars[pos++] = chars[i];
5651            }
5652        }
5653        return new String(chars, 0, pos);
5654    }
5655
5656    /**
5657     * Removes all occurrences of a substring from within the source string.
5658     *
5659     * <p>
5660     * A {@code null} source string will return {@code null}. An empty ("") source string will return the empty string. A {@code null} remove string will return
5661     * the source string. An empty ("") remove string will return the source string.
5662     * </p>
5663     *
5664     * <pre>
5665     * StringUtils.remove(null, *)        = null
5666     * StringUtils.remove("", *)          = ""
5667     * StringUtils.remove(*, null)        = *
5668     * StringUtils.remove(*, "")          = *
5669     * StringUtils.remove("queued", "ue") = "qd"
5670     * StringUtils.remove("queued", "zz") = "queued"
5671     * </pre>
5672     *
5673     * @param str    the source String to search, may be null.
5674     * @param remove the String to search for and remove, may be null.
5675     * @return the substring with the string removed if found, {@code null} if null String input.
5676     * @since 2.1
5677     * @deprecated Use {@link Strings#remove(String, String) Strings.CS.remove(String, String)}
5678     */
5679    @Deprecated
5680    public static String remove(final String str, final String remove) {
5681        return Strings.CS.remove(str, remove);
5682    }
5683
5684    /**
5685     * Removes each substring of the text String that matches the given regular expression.
5686     *
5687     * This method is a {@code null} safe equivalent to:
5688     * <ul>
5689     * <li>{@code text.replaceAll(regex, StringUtils.EMPTY)}</li>
5690     * <li>{@code Pattern.compile(regex).matcher(text).replaceAll(StringUtils.EMPTY)}</li>
5691     * </ul>
5692     *
5693     * <p>
5694     * A {@code null} reference passed to this method is a no-op.
5695     * </p>
5696     *
5697     * <p>
5698     * Unlike in the {@link #removePattern(String, String)} method, the {@link Pattern#DOTALL} option is NOT automatically added. To use the DOTALL option
5699     * prepend {@code "(?s)"} to the regex. DOTALL is also known as single-line mode in Perl.
5700     * </p>
5701     *
5702     * <pre>{@code
5703     * StringUtils.removeAll(null, *)      = null
5704     * StringUtils.removeAll("any", (String) null)  = "any"
5705     * StringUtils.removeAll("any", "")    = "any"
5706     * StringUtils.removeAll("any", ".*")  = ""
5707     * StringUtils.removeAll("any", ".+")  = ""
5708     * StringUtils.removeAll("abc", ".?")  = ""
5709     * StringUtils.removeAll("A<__>\n<__>B", "<.*>")      = "A\nB"
5710     * StringUtils.removeAll("A<__>\n<__>B", "(?s)<.*>")  = "AB"
5711     * StringUtils.removeAll("ABCabc123abc", "[a-z]")     = "ABC123"
5712     * }</pre>
5713     *
5714     * @param text  text to remove from, may be null.
5715     * @param regex the regular expression to which this string is to be matched.
5716     * @return the text with any removes processed, {@code null} if null String input.
5717     * @throws java.util.regex.PatternSyntaxException if the regular expression's syntax is invalid.
5718     * @see #replaceAll(String, String, String)
5719     * @see #removePattern(String, String)
5720     * @see String#replaceAll(String, String)
5721     * @see java.util.regex.Pattern
5722     * @see java.util.regex.Pattern#DOTALL
5723     * @since 3.5
5724     * @deprecated Moved to RegExUtils.
5725     */
5726    @Deprecated
5727    public static String removeAll(final String text, final String regex) {
5728        return RegExUtils.removeAll(text, regex);
5729    }
5730
5731    /**
5732     * Removes a substring only if it is at the end of a source string, otherwise returns the source string.
5733     *
5734     * <p>
5735     * A {@code null} source string will return {@code null}. An empty ("") source string will return the empty string. A {@code null} search string will return
5736     * the source string.
5737     * </p>
5738     *
5739     * <pre>
5740     * StringUtils.removeEnd(null, *)      = null
5741     * StringUtils.removeEnd("", *)        = ""
5742     * StringUtils.removeEnd(*, null)      = *
5743     * StringUtils.removeEnd("www.domain.com", ".com.")  = "www.domain.com"
5744     * StringUtils.removeEnd("www.domain.com", ".com")   = "www.domain"
5745     * StringUtils.removeEnd("www.domain.com", "domain") = "www.domain.com"
5746     * StringUtils.removeEnd("abc", "")    = "abc"
5747     * </pre>
5748     *
5749     * @param str    the source String to search, may be null.
5750     * @param remove the String to search for and remove, may be null.
5751     * @return the substring with the string removed if found, {@code null} if null String input.
5752     * @since 2.1
5753     * @deprecated Use {@link Strings#removeEnd(String, CharSequence) Strings.CS.removeEnd(String, CharSequence)}
5754     */
5755    @Deprecated
5756    public static String removeEnd(final String str, final String remove) {
5757        return Strings.CS.removeEnd(str, remove);
5758    }
5759
5760    /**
5761     * Case-insensitive removal of a substring if it is at the end of a source string, otherwise returns the source string.
5762     *
5763     * <p>
5764     * A {@code null} source string will return {@code null}. An empty ("") source string will return the empty string. A {@code null} search string will return
5765     * the source string.
5766     * </p>
5767     *
5768     * <pre>
5769     * StringUtils.removeEndIgnoreCase(null, *)      = null
5770     * StringUtils.removeEndIgnoreCase("", *)        = ""
5771     * StringUtils.removeEndIgnoreCase(*, null)      = *
5772     * StringUtils.removeEndIgnoreCase("www.domain.com", ".com.")  = "www.domain.com"
5773     * StringUtils.removeEndIgnoreCase("www.domain.com", ".com")   = "www.domain"
5774     * StringUtils.removeEndIgnoreCase("www.domain.com", "domain") = "www.domain.com"
5775     * StringUtils.removeEndIgnoreCase("abc", "")    = "abc"
5776     * StringUtils.removeEndIgnoreCase("www.domain.com", ".COM") = "www.domain")
5777     * StringUtils.removeEndIgnoreCase("www.domain.COM", ".com") = "www.domain")
5778     * </pre>
5779     *
5780     * @param str    the source String to search, may be null.
5781     * @param remove the String to search for (case-insensitive) and remove, may be null.
5782     * @return the substring with the string removed if found, {@code null} if null String input.
5783     * @since 2.4
5784     * @deprecated Use {@link Strings#removeEnd(String, CharSequence) Strings.CI.removeEnd(String, CharSequence)}
5785     */
5786    @Deprecated
5787    public static String removeEndIgnoreCase(final String str, final String remove) {
5788        return Strings.CI.removeEnd(str, remove);
5789    }
5790
5791    /**
5792     * Removes the first substring of the text string that matches the given regular expression.
5793     *
5794     * This method is a {@code null} safe equivalent to:
5795     * <ul>
5796     * <li>{@code text.replaceFirst(regex, StringUtils.EMPTY)}</li>
5797     * <li>{@code Pattern.compile(regex).matcher(text).replaceFirst(StringUtils.EMPTY)}</li>
5798     * </ul>
5799     *
5800     * <p>
5801     * A {@code null} reference passed to this method is a no-op.
5802     * </p>
5803     *
5804     * <p>
5805     * The {@link Pattern#DOTALL} option is NOT automatically added. To use the DOTALL option prepend {@code "(?s)"} to the regex. DOTALL is also known as
5806     * single-line mode in Perl.
5807     * </p>
5808     *
5809     * <pre>{@code
5810     * StringUtils.removeFirst(null, *)      = null
5811     * StringUtils.removeFirst("any", (String) null)  = "any"
5812     * StringUtils.removeFirst("any", "")    = "any"
5813     * StringUtils.removeFirst("any", ".*")  = ""
5814     * StringUtils.removeFirst("any", ".+")  = ""
5815     * StringUtils.removeFirst("abc", ".?")  = "bc"
5816     * StringUtils.removeFirst("A<__>\n<__>B", "<.*>")      = "A\n<__>B"
5817     * StringUtils.removeFirst("A<__>\n<__>B", "(?s)<.*>")  = "AB"
5818     * StringUtils.removeFirst("ABCabc123", "[a-z]")          = "ABCbc123"
5819     * StringUtils.removeFirst("ABCabc123abc", "[a-z]+")      = "ABC123abc"
5820     * }</pre>
5821     *
5822     * @param text  text to remove from, may be null.
5823     * @param regex the regular expression to which this string is to be matched.
5824     * @return the text with the first replacement processed, {@code null} if null String input.
5825     * @throws java.util.regex.PatternSyntaxException if the regular expression's syntax is invalid.
5826     * @see #replaceFirst(String, String, String)
5827     * @see String#replaceFirst(String, String)
5828     * @see java.util.regex.Pattern
5829     * @see java.util.regex.Pattern#DOTALL
5830     * @since 3.5
5831     * @deprecated Moved to RegExUtils.
5832     */
5833    @Deprecated
5834    public static String removeFirst(final String text, final String regex) {
5835        return replaceFirst(text, regex, EMPTY);
5836    }
5837
5838    /**
5839     * Case-insensitive removal of all occurrences of a substring from within the source string.
5840     *
5841     * <p>
5842     * A {@code null} source string will return {@code null}. An empty ("") source string will return the empty string. A {@code null} remove string will return
5843     * the source string. An empty ("") remove string will return the source string.
5844     * </p>
5845     *
5846     * <pre>
5847     * StringUtils.removeIgnoreCase(null, *)        = null
5848     * StringUtils.removeIgnoreCase("", *)          = ""
5849     * StringUtils.removeIgnoreCase(*, null)        = *
5850     * StringUtils.removeIgnoreCase(*, "")          = *
5851     * StringUtils.removeIgnoreCase("queued", "ue") = "qd"
5852     * StringUtils.removeIgnoreCase("queued", "zz") = "queued"
5853     * StringUtils.removeIgnoreCase("quEUed", "UE") = "qd"
5854     * StringUtils.removeIgnoreCase("queued", "zZ") = "queued"
5855     * </pre>
5856     *
5857     * @param str    the source String to search, may be null.
5858     * @param remove the String to search for (case-insensitive) and remove, may be null.
5859     * @return the substring with the string removed if found, {@code null} if null String input.
5860     * @since 3.5
5861     * @deprecated Use {@link Strings#remove(String, String) Strings.CI.remove(String, String)}
5862     */
5863    @Deprecated
5864    public static String removeIgnoreCase(final String str, final String remove) {
5865        return Strings.CI.remove(str, remove);
5866    }
5867
5868    /**
5869     * Removes each substring of the source String that matches the given regular expression using the DOTALL option.
5870     *
5871     * This call is a {@code null} safe equivalent to:
5872     * <ul>
5873     * <li>{@code source.replaceAll(&quot;(?s)&quot; + regex, StringUtils.EMPTY)}</li>
5874     * <li>{@code Pattern.compile(regex, Pattern.DOTALL).matcher(source).replaceAll(StringUtils.EMPTY)}</li>
5875     * </ul>
5876     *
5877     * <p>
5878     * A {@code null} reference passed to this method is a no-op.
5879     * </p>
5880     *
5881     * <pre>{@code
5882     * StringUtils.removePattern(null, *)       = null
5883     * StringUtils.removePattern("any", (String) null)   = "any"
5884     * StringUtils.removePattern("A<__>\n<__>B", "<.*>")  = "AB"
5885     * StringUtils.removePattern("ABCabc123", "[a-z]")    = "ABC123"
5886     * }</pre>
5887     *
5888     * @param source the source string.
5889     * @param regex  the regular expression to which this string is to be matched.
5890     * @return The resulting {@link String}.
5891     * @see #replacePattern(String, String, String)
5892     * @see String#replaceAll(String, String)
5893     * @see Pattern#DOTALL
5894     * @since 3.2
5895     * @since 3.5 Changed {@code null} reference passed to this method is a no-op.
5896     * @deprecated Moved to RegExUtils.
5897     */
5898    @Deprecated
5899    public static String removePattern(final String source, final String regex) {
5900        return RegExUtils.removePattern(source, regex);
5901    }
5902
5903    /**
5904     * Removes a char only if it is at the beginning of a source string, otherwise returns the source string.
5905     *
5906     * <p>
5907     * A {@code null} source string will return {@code null}. An empty ("") source string will return the empty string. A {@code null} search char will return
5908     * the source string.
5909     * </p>
5910     *
5911     * <pre>
5912     * StringUtils.removeStart(null, *)      = null
5913     * StringUtils.removeStart("", *)        = ""
5914     * StringUtils.removeStart(*, null)      = *
5915     * StringUtils.removeStart("/path", '/') = "path"
5916     * StringUtils.removeStart("path", '/')  = "path"
5917     * StringUtils.removeStart("path", 0)    = "path"
5918     * </pre>
5919     *
5920     * @param str    the source String to search, may be null.
5921     * @param remove the char to search for and remove.
5922     * @return the substring with the char removed if found, {@code null} if null String input.
5923     * @since 3.13.0
5924     */
5925    public static String removeStart(final String str, final char remove) {
5926        if (isEmpty(str)) {
5927            return str;
5928        }
5929        return str.charAt(0) == remove ? str.substring(1) : str;
5930    }
5931
5932    /**
5933     * Removes a substring only if it is at the beginning of a source string, otherwise returns the source string.
5934     *
5935     * <p>
5936     * A {@code null} source string will return {@code null}. An empty ("") source string will return the empty string. A {@code null} search string will return
5937     * the source string.
5938     * </p>
5939     *
5940     * <pre>
5941     * StringUtils.removeStart(null, *)                    = null
5942     * StringUtils.removeStart("", *)                      = ""
5943     * StringUtils.removeStart(*, null)                    = *
5944     * StringUtils.removeStart("www.domain.com", "www.")   = "domain.com"
5945     * StringUtils.removeStart("domain.com", "www.")       = "domain.com"
5946     * StringUtils.removeStart("www.domain.com", "domain") = "www.domain.com"
5947     * StringUtils.removeStart("abc", "")                  = "abc"
5948     * </pre>
5949     *
5950     * @param str    the source String to search, may be null.
5951     * @param remove the String to search for and remove, may be null.
5952     * @return the substring with the string removed if found, {@code null} if null String input.
5953     * @since 2.1
5954     * @deprecated Use {@link Strings#removeStart(String, CharSequence) Strings.CS.removeStart(String, CharSequence)}
5955     */
5956    @Deprecated
5957    public static String removeStart(final String str, final String remove) {
5958        return Strings.CS.removeStart(str, remove);
5959    }
5960
5961    /**
5962     * Case-insensitive removal of a substring if it is at the beginning of a source string, otherwise returns the source string.
5963     *
5964     * <p>
5965     * A {@code null} source string will return {@code null}. An empty ("") source string will return the empty string. A {@code null} search string will return
5966     * the source string.
5967     * </p>
5968     *
5969     * <pre>
5970     * StringUtils.removeStartIgnoreCase(null, *)                    = null
5971     * StringUtils.removeStartIgnoreCase("", *)                      = ""
5972     * StringUtils.removeStartIgnoreCase(*, null)                    = *
5973     * StringUtils.removeStartIgnoreCase("www.domain.com", "www.")   = "domain.com"
5974     * StringUtils.removeStartIgnoreCase("www.domain.com", "WWW.")   = "domain.com"
5975     * StringUtils.removeStartIgnoreCase("domain.com", "www.")       = "domain.com"
5976     * StringUtils.removeStartIgnoreCase("www.domain.com", "domain") = "www.domain.com"
5977     * StringUtils.removeStartIgnoreCase("abc", "")                  = "abc"
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, {@code null} if null String input.
5983     * @since 2.4
5984     * @deprecated Use {@link Strings#removeStart(String, CharSequence) Strings.CI.removeStart(String, CharSequence)}
5985     */
5986    @Deprecated
5987    public static String removeStartIgnoreCase(final String str, final String remove) {
5988        return Strings.CI.removeStart(str, remove);
5989    }
5990
5991    /**
5992     * Returns padding using the specified delimiter repeated to a given length.
5993     *
5994     * <pre>
5995     * StringUtils.repeat('e', 0)  = ""
5996     * StringUtils.repeat('e', 3)  = "eee"
5997     * StringUtils.repeat('e', -2) = ""
5998     * </pre>
5999     *
6000     * <p>
6001     * Note: this method does not support padding with <a href="https://www.unicode.org/glossary/#supplementary_character">Unicode Supplementary Characters</a>
6002     * as they require a pair of {@code char}s to be represented. If you are needing to support full I18N of your applications consider using
6003     * {@link #repeat(String, int)} instead.
6004     * </p>
6005     *
6006     * @param repeat character to repeat.
6007     * @param count  number of times to repeat char, negative treated as zero.
6008     * @return String with repeated character.
6009     * @see #repeat(String, int)
6010     */
6011    public static String repeat(final char repeat, final int count) {
6012        if (count <= 0) {
6013            return EMPTY;
6014        }
6015        return new String(ArrayFill.fill(new char[count], repeat));
6016    }
6017
6018    /**
6019     * Repeats a String {@code repeat} times to form a new String.
6020     *
6021     * <pre>
6022     * StringUtils.repeat(null, 2) = null
6023     * StringUtils.repeat("", 0)   = ""
6024     * StringUtils.repeat("", 2)   = ""
6025     * StringUtils.repeat("a", 3)  = "aaa"
6026     * StringUtils.repeat("ab", 2) = "abab"
6027     * StringUtils.repeat("a", -2) = ""
6028     * </pre>
6029     *
6030     * @param repeat the String to repeat, may be null.
6031     * @param count  number of times to repeat str, negative treated as zero.
6032     * @return a new String consisting of the original String repeated, {@code null} if null String input.
6033     */
6034    public static String repeat(final String repeat, final int count) {
6035        // Performance tuned for 2.0 (JDK1.4)
6036        if (repeat == null) {
6037            return null;
6038        }
6039        if (count <= 0) {
6040            return EMPTY;
6041        }
6042        final int inputLength = repeat.length();
6043        if (count == 1 || inputLength == 0) {
6044            return repeat;
6045        }
6046        if (inputLength == 1 && count <= PAD_LIMIT) {
6047            return repeat(repeat.charAt(0), count);
6048        }
6049        final int outputLength = inputLength * count;
6050        switch (inputLength) {
6051        case 1:
6052            return repeat(repeat.charAt(0), count);
6053        case 2:
6054            final char ch0 = repeat.charAt(0);
6055            final char ch1 = repeat.charAt(1);
6056            final char[] output2 = new char[outputLength];
6057            for (int i = count * 2 - 2; i >= 0; i--, i--) {
6058                output2[i] = ch0;
6059                output2[i + 1] = ch1;
6060            }
6061            return new String(output2);
6062        default:
6063            final StringBuilder buf = new StringBuilder(outputLength);
6064            for (int i = 0; i < count; i++) {
6065                buf.append(repeat);
6066            }
6067            return buf.toString();
6068        }
6069    }
6070
6071    /**
6072     * Repeats a String {@code repeat} times to form a new String, with a String separator injected each time.
6073     *
6074     * <pre>
6075     * StringUtils.repeat(null, null, 2) = null
6076     * StringUtils.repeat(null, "x", 2)  = null
6077     * StringUtils.repeat("", null, 0)   = ""
6078     * StringUtils.repeat("", "", 2)     = ""
6079     * StringUtils.repeat("", "x", 3)    = "xx"
6080     * StringUtils.repeat("?", ", ", 3)  = "?, ?, ?"
6081     * </pre>
6082     *
6083     * @param repeat    the String to repeat, may be null.
6084     * @param separator the String to inject, may be null.
6085     * @param count     number of times to repeat str, negative treated as zero.
6086     * @return a new String consisting of the original String repeated, {@code null} if null String input.
6087     * @since 2.5
6088     */
6089    public static String repeat(final String repeat, final String separator, final int count) {
6090        if (repeat == null || separator == null) {
6091            return repeat(repeat, count);
6092        }
6093        // given that repeat(String, int) is quite optimized, better to rely on it than try and splice this into it
6094        final String result = repeat(repeat + separator, count);
6095        return Strings.CS.removeEnd(result, separator);
6096    }
6097
6098    /**
6099     * Replaces all occurrences of a String within another String.
6100     *
6101     * <p>
6102     * A {@code null} reference passed to this method is a no-op.
6103     * </p>
6104     *
6105     * <pre>
6106     * StringUtils.replace(null, *, *)        = null
6107     * StringUtils.replace("", *, *)          = ""
6108     * StringUtils.replace("any", null, *)    = "any"
6109     * StringUtils.replace("any", *, null)    = "any"
6110     * StringUtils.replace("any", "", *)      = "any"
6111     * StringUtils.replace("aba", "a", null)  = "aba"
6112     * StringUtils.replace("aba", "a", "")    = "b"
6113     * StringUtils.replace("aba", "a", "z")   = "zbz"
6114     * </pre>
6115     *
6116     * @param text         text to search and replace in, may be null.
6117     * @param searchString the String to search for, may be null.
6118     * @param replacement  the String to replace it with, may be null.
6119     * @return the text with any replacements processed, {@code null} if null String input.
6120     * @see #replace(String text, String searchString, String replacement, int max)
6121     * @deprecated Use {@link Strings#replace(String, String, String) Strings.CS.replace(String, String, String)}
6122     */
6123    @Deprecated
6124    public static String replace(final String text, final String searchString, final String replacement) {
6125        return Strings.CS.replace(text, searchString, replacement);
6126    }
6127
6128    /**
6129     * Replaces a String with another String inside a larger String, for the first {@code max} values of the search String.
6130     *
6131     * <p>
6132     * A {@code null} reference passed to this method is a no-op.
6133     * </p>
6134     *
6135     * <pre>
6136     * StringUtils.replace(null, *, *, *)         = null
6137     * StringUtils.replace("", *, *, *)           = ""
6138     * StringUtils.replace("any", null, *, *)     = "any"
6139     * StringUtils.replace("any", *, null, *)     = "any"
6140     * StringUtils.replace("any", "", *, *)       = "any"
6141     * StringUtils.replace("any", *, *, 0)        = "any"
6142     * StringUtils.replace("abaa", "a", null, -1) = "abaa"
6143     * StringUtils.replace("abaa", "a", "", -1)   = "b"
6144     * StringUtils.replace("abaa", "a", "z", 0)   = "abaa"
6145     * StringUtils.replace("abaa", "a", "z", 1)   = "zbaa"
6146     * StringUtils.replace("abaa", "a", "z", 2)   = "zbza"
6147     * StringUtils.replace("abaa", "a", "z", -1)  = "zbzz"
6148     * </pre>
6149     *
6150     * @param text         text to search and replace in, may be null.
6151     * @param searchString the String to search for, may be null.
6152     * @param replacement  the String to replace it with, may be null.
6153     * @param max          maximum number of values to replace, or {@code -1} if no maximum.
6154     * @return the text with any replacements processed, {@code null} if null String input.
6155     * @deprecated Use {@link Strings#replace(String, String, String, int) Strings.CS.replace(String, String, String, int)}
6156     */
6157    @Deprecated
6158    public static String replace(final String text, final String searchString, final String replacement, final int max) {
6159        return Strings.CS.replace(text, searchString, replacement, max);
6160    }
6161
6162    /**
6163     * Replaces each substring of the text String that matches the given regular expression with the given replacement.
6164     *
6165     * This method is a {@code null} safe equivalent to:
6166     * <ul>
6167     * <li>{@code text.replaceAll(regex, replacement)}</li>
6168     * <li>{@code Pattern.compile(regex).matcher(text).replaceAll(replacement)}</li>
6169     * </ul>
6170     *
6171     * <p>
6172     * A {@code null} reference passed to this method is a no-op.
6173     * </p>
6174     *
6175     * <p>
6176     * Unlike in the {@link #replacePattern(String, String, String)} method, the {@link Pattern#DOTALL} option is NOT automatically added. To use the DOTALL
6177     * option prepend {@code "(?s)"} to the regex. DOTALL is also known as single-line mode in Perl.
6178     * </p>
6179     *
6180     * <pre>{@code
6181     * StringUtils.replaceAll(null, *, *)                                         = null
6182     * StringUtils.replaceAll("any", (String) null, *)                            = "any"
6183     * StringUtils.replaceAll("any", *, null)                                     = "any"
6184     * StringUtils.replaceAll("", "", "zzz")                                      = "zzz"
6185     * StringUtils.replaceAll("", ".*", "zzz")                                    = "zzz"
6186     * StringUtils.replaceAll("", ".+", "zzz")                                    = ""
6187     * StringUtils.replaceAll("abc", "", "ZZ")                                    = "ZZaZZbZZcZZ"
6188     * StringUtils.replaceAll("<__>\n<__>", "<.*>", "z")                          = "z\nz"
6189     * StringUtils.replaceAll("<__>\n<__>", "(?s)<.*>", "z")                      = "z"
6190     * StringUtils.replaceAll("ABCabc123", "[a-z]", "_")                          = "ABC___123"
6191     * StringUtils.replaceAll("ABCabc123", "[^A-Z0-9]+", "_")                     = "ABC_123"
6192     * StringUtils.replaceAll("ABCabc123", "[^A-Z0-9]+", "")                      = "ABC123"
6193     * StringUtils.replaceAll("Lorem ipsum  dolor   sit", "( +)([a-z]+)", "_$2")  = "Lorem_ipsum_dolor_sit"
6194     * }</pre>
6195     *
6196     * @param text        text to search and replace in, may be null.
6197     * @param regex       the regular expression to which this string is to be matched.
6198     * @param replacement the string to be substituted for each match.
6199     * @return the text with any replacements processed, {@code null} if null String input.
6200     * @throws java.util.regex.PatternSyntaxException if the regular expression's syntax is invalid.
6201     * @see #replacePattern(String, String, String)
6202     * @see String#replaceAll(String, String)
6203     * @see java.util.regex.Pattern
6204     * @see java.util.regex.Pattern#DOTALL
6205     * @since 3.5
6206     * @deprecated Moved to RegExUtils.
6207     */
6208    @Deprecated
6209    public static String replaceAll(final String text, final String regex, final String replacement) {
6210        return RegExUtils.replaceAll(text, regex, replacement);
6211    }
6212
6213    /**
6214     * Replaces all occurrences of a character in a String with another. This is a null-safe version of {@link String#replace(char, char)}.
6215     *
6216     * <p>
6217     * A {@code null} string input returns {@code null}. An empty ("") string input returns an empty string.
6218     * </p>
6219     *
6220     * <pre>
6221     * StringUtils.replaceChars(null, *, *)        = null
6222     * StringUtils.replaceChars("", *, *)          = ""
6223     * StringUtils.replaceChars("abcba", 'b', 'y') = "aycya"
6224     * StringUtils.replaceChars("abcba", 'z', 'y') = "abcba"
6225     * </pre>
6226     *
6227     * @param str         String to replace characters in, may be null.
6228     * @param searchChar  the character to search for, may be null.
6229     * @param replaceChar the character to replace, may be null.
6230     * @return modified String, {@code null} if null string input.
6231     * @since 2.0
6232     */
6233    public static String replaceChars(final String str, final char searchChar, final char replaceChar) {
6234        if (str == null) {
6235            return null;
6236        }
6237        return str.replace(searchChar, replaceChar);
6238    }
6239
6240    /**
6241     * Replaces multiple characters in a String in one go. This method can also be used to delete characters.
6242     *
6243     * <p>
6244     * For example:<br>
6245     * {@code replaceChars(&quot;hello&quot;, &quot;ho&quot;, &quot;jy&quot;) = jelly}.
6246     * </p>
6247     *
6248     * <p>
6249     * A {@code null} string input returns {@code null}. An empty ("") string input returns an empty string. A null or empty set of search characters returns
6250     * the input string.
6251     * </p>
6252     *
6253     * <p>
6254     * The length of the search characters should normally equal the length of the replace characters. If the search characters is longer, then the extra search
6255     * characters are deleted. If the search characters is shorter, then the extra replace characters are ignored.
6256     * </p>
6257     *
6258     * <pre>
6259     * StringUtils.replaceChars(null, *, *)           = null
6260     * StringUtils.replaceChars("", *, *)             = ""
6261     * StringUtils.replaceChars("abc", null, *)       = "abc"
6262     * StringUtils.replaceChars("abc", "", *)         = "abc"
6263     * StringUtils.replaceChars("abc", "b", null)     = "ac"
6264     * StringUtils.replaceChars("abc", "b", "")       = "ac"
6265     * StringUtils.replaceChars("abcba", "bc", "yz")  = "ayzya"
6266     * StringUtils.replaceChars("abcba", "bc", "y")   = "ayya"
6267     * StringUtils.replaceChars("abcba", "bc", "yzx") = "ayzya"
6268     * </pre>
6269     *
6270     * @param str          String to replace characters in, may be null.
6271     * @param searchChars  a set of characters to search for, may be null.
6272     * @param replaceChars a set of characters to replace, may be null.
6273     * @return modified String, {@code null} if null string input.
6274     * @since 2.0
6275     */
6276    public static String replaceChars(final String str, final String searchChars, String replaceChars) {
6277        if (isEmpty(str) || isEmpty(searchChars)) {
6278            return str;
6279        }
6280        replaceChars = ObjectUtils.toString(replaceChars);
6281        boolean modified = false;
6282        final int replaceCharsLength = replaceChars.length();
6283        final int strLength = str.length();
6284        final StringBuilder buf = new StringBuilder(strLength);
6285        for (int i = 0; i < strLength; i++) {
6286            final char ch = str.charAt(i);
6287            final int index = searchChars.indexOf(ch);
6288            if (index >= 0) {
6289                modified = true;
6290                if (index < replaceCharsLength) {
6291                    buf.append(replaceChars.charAt(index));
6292                }
6293            } else {
6294                buf.append(ch);
6295            }
6296        }
6297        if (modified) {
6298            return buf.toString();
6299        }
6300        return str;
6301    }
6302
6303    /**
6304     * Replaces all occurrences of Strings within another String.
6305     *
6306     * <p>
6307     * A {@code null} reference passed to this method is a no-op, or if any "search string" or "string to replace" is null, that replace will be ignored. This
6308     * will not repeat. For repeating replaces, call the overloaded method.
6309     * </p>
6310     *
6311     * <pre>
6312     *  StringUtils.replaceEach(null, *, *)                                                = null
6313     *  StringUtils.replaceEach("", *, *)                                                  = ""
6314     *  StringUtils.replaceEach("aba", null, null)                                         = "aba"
6315     *  StringUtils.replaceEach("aba", new String[0], null)                                = "aba"
6316     *  StringUtils.replaceEach("aba", null, new String[0])                                = "aba"
6317     *  StringUtils.replaceEach("aba", new String[]{"a"}, null)                            = "aba"
6318     *  StringUtils.replaceEach("aba", new String[]{"a"}, new String[]{""})                = "b"
6319     *  StringUtils.replaceEach("aba", new String[]{null}, new String[]{"a"})              = "aba"
6320     *  StringUtils.replaceEach("abcde", new String[]{"ab", "d"}, new String[]{"w", "t"})  = "wcte"
6321     *  (example of how it does not repeat)
6322     *  StringUtils.replaceEach("abcde", new String[]{"ab", "d"}, new String[]{"d", "t"})  = "dcte"
6323     * </pre>
6324     *
6325     * @param text            text to search and replace in, no-op if null.
6326     * @param searchList      the Strings to search for, no-op if null.
6327     * @param replacementList the Strings to replace them with, no-op if null.
6328     * @return the text with any replacements processed, {@code null} if null String input.
6329     * @throws IllegalArgumentException if the lengths of the arrays are not the same (null is ok, and/or size 0).
6330     * @since 2.4
6331     */
6332    public static String replaceEach(final String text, final String[] searchList, final String[] replacementList) {
6333        return replaceEach(text, searchList, replacementList, false, 0);
6334    }
6335
6336    /**
6337     * Replace all occurrences of Strings within another String. This is a private recursive helper method for
6338     * {@link #replaceEachRepeatedly(String, String[], String[])} and {@link #replaceEach(String, String[], String[])}
6339     *
6340     * <p>
6341     * A {@code null} reference passed to this method is a no-op, or if any "search string" or "string to replace" is null, that replace will be ignored.
6342     * </p>
6343     *
6344     * <pre>
6345     *  StringUtils.replaceEach(null, *, *, *, *)                                                     = null
6346     *  StringUtils.replaceEach("", *, *, *, *)                                                       = ""
6347     *  StringUtils.replaceEach("aba", null, null, *, *)                                              = "aba"
6348     *  StringUtils.replaceEach("aba", new String[0], null, *, *)                                     = "aba"
6349     *  StringUtils.replaceEach("aba", null, new String[0], *, *)                                     = "aba"
6350     *  StringUtils.replaceEach("aba", new String[]{"a"}, null, *, *)                                 = "aba"
6351     *  StringUtils.replaceEach("aba", new String[]{"a"}, new String[]{""}, *, >=0)                   = "b"
6352     *  StringUtils.replaceEach("aba", new String[]{null}, new String[]{"a"}, *, >=0)                 = "aba"
6353     *  StringUtils.replaceEach("abcde", new String[]{"ab", "d"}, new String[]{"w", "t"}, *, >=0)     = "wcte"
6354     *  (example of how it repeats)
6355     *  StringUtils.replaceEach("abcde", new String[]{"ab", "d"}, new String[]{"d", "t"}, false, >=0) = "dcte"
6356     *  StringUtils.replaceEach("abcde", new String[]{"ab", "d"}, new String[]{"d", "t"}, true, >=2)  = "tcte"
6357     *  StringUtils.replaceEach("abcde", new String[]{"ab", "d"}, new String[]{"d", "ab"}, *, *)      = IllegalStateException
6358     * </pre>
6359     *
6360     * @param text            text to search and replace in, no-op if null.
6361     * @param searchList      the Strings to search for, no-op if null.
6362     * @param replacementList the Strings to replace them with, no-op if null.
6363     * @param repeat          if true, then replace repeatedly until there are no more possible replacements or timeToLive < 0.
6364     * @param timeToLive      if less than 0 then there is a circular reference and endless loop.
6365     * @return the text with any replacements processed, {@code null} if null String input.
6366     * @throws IllegalStateException    if the search is repeating and there is an endless loop due to outputs of one being inputs to another.
6367     * @throws IllegalArgumentException if the lengths of the arrays are not the same (null is ok, and/or size 0).
6368     * @since 2.4
6369     */
6370    private static String replaceEach(
6371            final String text, final String[] searchList, final String[] replacementList, final boolean repeat, final int timeToLive) {
6372
6373        // mchyzer Performance note: This creates very few new objects (one major goal)
6374        // let me know if there are performance requests, we can create a harness to measure
6375        if (isEmpty(text) || ArrayUtils.isEmpty(searchList) || ArrayUtils.isEmpty(replacementList)) {
6376            return text;
6377        }
6378
6379        // if recursing, this shouldn't be less than 0
6380        if (timeToLive < 0) {
6381            throw new IllegalStateException("Aborting to protect against StackOverflowError - " +
6382                "output of one loop is the input of another");
6383        }
6384
6385        final int searchLength = searchList.length;
6386        final int replacementLength = replacementList.length;
6387
6388        // make sure lengths are ok, these need to be equal
6389        if (searchLength != replacementLength) {
6390            throw new IllegalArgumentException("Search and Replace array lengths don't match: "
6391                + searchLength
6392                + " vs "
6393                + replacementLength);
6394        }
6395
6396        // keep track of which still have matches
6397        final boolean[] noMoreMatchesForReplIndex = new boolean[searchLength];
6398
6399        // index on index that the match was found
6400        int textIndex = -1;
6401        int replaceIndex = -1;
6402        int tempIndex;
6403
6404        // index of replace array that will replace the search string found
6405        // NOTE: logic duplicated below START
6406        for (int i = 0; i < searchLength; i++) {
6407            if (noMoreMatchesForReplIndex[i] || isEmpty(searchList[i]) || replacementList[i] == null) {
6408                continue;
6409            }
6410            tempIndex = text.indexOf(searchList[i]);
6411
6412            // see if we need to keep searching for this
6413            if (tempIndex == -1) {
6414                noMoreMatchesForReplIndex[i] = true;
6415            } else if (textIndex == -1 || tempIndex < textIndex) {
6416                textIndex = tempIndex;
6417                replaceIndex = i;
6418            }
6419        }
6420        // NOTE: logic mostly below END
6421
6422        // no search strings found, we are done
6423        if (textIndex == -1) {
6424            return text;
6425        }
6426
6427        int start = 0;
6428
6429        // get a good guess on the size of the result buffer so it doesn't have to double if it goes over a bit
6430        int increase = 0;
6431
6432        // count the replacement text elements that are larger than their corresponding text being replaced
6433        for (int i = 0; i < searchList.length; i++) {
6434            if (searchList[i] == null || replacementList[i] == null) {
6435                continue;
6436            }
6437            final int greater = replacementList[i].length() - searchList[i].length();
6438            if (greater > 0) {
6439                increase += 3 * greater; // assume 3 matches
6440            }
6441        }
6442        // have upper-bound at 20% increase, then let Java take over
6443        increase = Math.min(increase, text.length() / 5);
6444
6445        final StringBuilder buf = new StringBuilder(text.length() + increase);
6446
6447        while (textIndex != -1) {
6448
6449            for (int i = start; i < textIndex; i++) {
6450                buf.append(text.charAt(i));
6451            }
6452            buf.append(replacementList[replaceIndex]);
6453
6454            start = textIndex + searchList[replaceIndex].length();
6455
6456            textIndex = -1;
6457            replaceIndex = -1;
6458            // find the next earliest match
6459            // NOTE: logic mostly duplicated above START
6460            for (int i = 0; i < searchLength; i++) {
6461                if (noMoreMatchesForReplIndex[i] || isEmpty(searchList[i]) || replacementList[i] == null) {
6462                    continue;
6463                }
6464                tempIndex = text.indexOf(searchList[i], start);
6465
6466                // see if we need to keep searching for this
6467                if (tempIndex == -1) {
6468                    noMoreMatchesForReplIndex[i] = true;
6469                } else if (textIndex == -1 || tempIndex < textIndex) {
6470                    textIndex = tempIndex;
6471                    replaceIndex = i;
6472                }
6473            }
6474            // NOTE: logic duplicated above END
6475
6476        }
6477        final int textLength = text.length();
6478        for (int i = start; i < textLength; i++) {
6479            buf.append(text.charAt(i));
6480        }
6481        final String result = buf.toString();
6482        if (!repeat) {
6483            return result;
6484        }
6485
6486        return replaceEach(result, searchList, replacementList, repeat, timeToLive - 1);
6487    }
6488
6489    /**
6490     * Replaces all occurrences of Strings within another String.
6491     *
6492     * <p>
6493     * A {@code null} reference passed to this method is a no-op, or if any "search string" or "string to replace" is null, that replace will be ignored.
6494     * </p>
6495     *
6496     * <pre>
6497     *  StringUtils.replaceEachRepeatedly(null, *, *)                                                = null
6498     *  StringUtils.replaceEachRepeatedly("", *, *)                                                  = ""
6499     *  StringUtils.replaceEachRepeatedly("aba", null, null)                                         = "aba"
6500     *  StringUtils.replaceEachRepeatedly("aba", new String[0], null)                                = "aba"
6501     *  StringUtils.replaceEachRepeatedly("aba", null, new String[0])                                = "aba"
6502     *  StringUtils.replaceEachRepeatedly("aba", new String[]{"a"}, null)                            = "aba"
6503     *  StringUtils.replaceEachRepeatedly("aba", new String[]{"a"}, new String[]{""})                = "b"
6504     *  StringUtils.replaceEachRepeatedly("aba", new String[]{null}, new String[]{"a"})              = "aba"
6505     *  StringUtils.replaceEachRepeatedly("abcde", new String[]{"ab", "d"}, new String[]{"w", "t"})  = "wcte"
6506     *  (example of how it repeats)
6507     *  StringUtils.replaceEachRepeatedly("abcde", new String[]{"ab", "d"}, new String[]{"d", "t"})  = "tcte"
6508     *  StringUtils.replaceEachRepeatedly("abcde", new String[]{"ab", "d"}, new String[]{"d", "ab"}) = IllegalStateException
6509     * </pre>
6510     *
6511     * @param text            text to search and replace in, no-op if null.
6512     * @param searchList      the Strings to search for, no-op if null.
6513     * @param replacementList the Strings to replace them with, no-op if null.
6514     * @return the text with any replacements processed, {@code null} if null String input.
6515     * @throws IllegalStateException    if the search is repeating and there is an endless loop due to outputs of one being inputs to another.
6516     * @throws IllegalArgumentException if the lengths of the arrays are not the same (null is ok, and/or size 0).
6517     * @since 2.4
6518     */
6519    public static String replaceEachRepeatedly(final String text, final String[] searchList, final String[] replacementList) {
6520        final int timeToLive = Math.max(ArrayUtils.getLength(searchList), DEFAULT_TTL);
6521        return replaceEach(text, searchList, replacementList, true, timeToLive);
6522    }
6523
6524    /**
6525     * Replaces the first substring of the text string that matches the given regular expression with the given replacement.
6526     *
6527     * This method is a {@code null} safe equivalent to:
6528     * <ul>
6529     * <li>{@code text.replaceFirst(regex, replacement)}</li>
6530     * <li>{@code Pattern.compile(regex).matcher(text).replaceFirst(replacement)}</li>
6531     * </ul>
6532     *
6533     * <p>
6534     * A {@code null} reference passed to this method is a no-op.
6535     * </p>
6536     *
6537     * <p>
6538     * The {@link Pattern#DOTALL} option is NOT automatically added. To use the DOTALL option prepend {@code "(?s)"} to the regex. DOTALL is also known as
6539     * single-line mode in Perl.
6540     * </p>
6541     *
6542     * <pre>{@code
6543     * StringUtils.replaceFirst(null, *, *)       = null
6544     * StringUtils.replaceFirst("any", (String) null, *)   = "any"
6545     * StringUtils.replaceFirst("any", *, null)   = "any"
6546     * StringUtils.replaceFirst("", "", "zzz")    = "zzz"
6547     * StringUtils.replaceFirst("", ".*", "zzz")  = "zzz"
6548     * StringUtils.replaceFirst("", ".+", "zzz")  = ""
6549     * StringUtils.replaceFirst("abc", "", "ZZ")  = "ZZabc"
6550     * StringUtils.replaceFirst("<__>\n<__>", "<.*>", "z")      = "z\n<__>"
6551     * StringUtils.replaceFirst("<__>\n<__>", "(?s)<.*>", "z")  = "z"
6552     * StringUtils.replaceFirst("ABCabc123", "[a-z]", "_")          = "ABC_bc123"
6553     * StringUtils.replaceFirst("ABCabc123abc", "[^A-Z0-9]+", "_")  = "ABC_123abc"
6554     * StringUtils.replaceFirst("ABCabc123abc", "[^A-Z0-9]+", "")   = "ABC123abc"
6555     * StringUtils.replaceFirst("Lorem ipsum  dolor   sit", "( +)([a-z]+)", "_$2")  = "Lorem_ipsum  dolor   sit"
6556     * }</pre>
6557     *
6558     * @param text        text to search and replace in, may be null.
6559     * @param regex       the regular expression to which this string is to be matched.
6560     * @param replacement the string to be substituted for the first match.
6561     * @return the text with the first replacement processed, {@code null} if null String input.
6562     * @throws java.util.regex.PatternSyntaxException if the regular expression's syntax is invalid.
6563     * @see String#replaceFirst(String, String)
6564     * @see java.util.regex.Pattern
6565     * @see java.util.regex.Pattern#DOTALL
6566     * @since 3.5
6567     * @deprecated Moved to RegExUtils.
6568     */
6569    @Deprecated
6570    public static String replaceFirst(final String text, final String regex, final String replacement) {
6571        return RegExUtils.replaceFirst(text, regex, replacement);
6572    }
6573
6574    /**
6575     * Case insensitively replaces all occurrences of a String within another String.
6576     *
6577     * <p>
6578     * A {@code null} reference passed to this method is a no-op.
6579     * </p>
6580     *
6581     * <pre>
6582     * StringUtils.replaceIgnoreCase(null, *, *)        = null
6583     * StringUtils.replaceIgnoreCase("", *, *)          = ""
6584     * StringUtils.replaceIgnoreCase("any", null, *)    = "any"
6585     * StringUtils.replaceIgnoreCase("any", *, null)    = "any"
6586     * StringUtils.replaceIgnoreCase("any", "", *)      = "any"
6587     * StringUtils.replaceIgnoreCase("aba", "a", null)  = "aba"
6588     * StringUtils.replaceIgnoreCase("abA", "A", "")    = "b"
6589     * StringUtils.replaceIgnoreCase("aba", "A", "z")   = "zbz"
6590     * </pre>
6591     *
6592     * @param text         text to search and replace in, may be null.
6593     * @param searchString the String to search for (case-insensitive), may be null.
6594     * @param replacement  the String to replace it with, may be null.
6595     * @return the text with any replacements processed, {@code null} if null String input.
6596     * @see #replaceIgnoreCase(String text, String searchString, String replacement, int max)
6597     * @since 3.5
6598     * @deprecated Use {@link Strings#replace(String, String, String) Strings.CI.replace(String, String, String)}
6599     */
6600    @Deprecated
6601    public static String replaceIgnoreCase(final String text, final String searchString, final String replacement) {
6602        return Strings.CI.replace(text, searchString, replacement);
6603    }
6604
6605    /**
6606     * Case insensitively replaces a String with another String inside a larger String, for the first {@code max} values of the search String.
6607     *
6608     * <p>
6609     * A {@code null} reference passed to this method is a no-op.
6610     * </p>
6611     *
6612     * <pre>
6613     * StringUtils.replaceIgnoreCase(null, *, *, *)         = null
6614     * StringUtils.replaceIgnoreCase("", *, *, *)           = ""
6615     * StringUtils.replaceIgnoreCase("any", null, *, *)     = "any"
6616     * StringUtils.replaceIgnoreCase("any", *, null, *)     = "any"
6617     * StringUtils.replaceIgnoreCase("any", "", *, *)       = "any"
6618     * StringUtils.replaceIgnoreCase("any", *, *, 0)        = "any"
6619     * StringUtils.replaceIgnoreCase("abaa", "a", null, -1) = "abaa"
6620     * StringUtils.replaceIgnoreCase("abaa", "a", "", -1)   = "b"
6621     * StringUtils.replaceIgnoreCase("abaa", "a", "z", 0)   = "abaa"
6622     * StringUtils.replaceIgnoreCase("abaa", "A", "z", 1)   = "zbaa"
6623     * StringUtils.replaceIgnoreCase("abAa", "a", "z", 2)   = "zbza"
6624     * StringUtils.replaceIgnoreCase("abAa", "a", "z", -1)  = "zbzz"
6625     * </pre>
6626     *
6627     * @param text         text to search and replace in, may be null.
6628     * @param searchString the String to search for (case-insensitive), may be null.
6629     * @param replacement  the String to replace it with, may be null.
6630     * @param max          maximum number of values to replace, or {@code -1} if no maximum.
6631     * @return the text with any replacements processed, {@code null} if null String input.
6632     * @since 3.5
6633     * @deprecated Use {@link Strings#replace(String, String, String, int) Strings.CI.replace(String, String, String, int)}
6634     */
6635    @Deprecated
6636    public static String replaceIgnoreCase(final String text, final String searchString, final String replacement, final int max) {
6637        return Strings.CI.replace(text, searchString, replacement, max);
6638    }
6639
6640    /**
6641     * Replaces a String with another String inside a larger String, once.
6642     *
6643     * <p>
6644     * A {@code null} reference passed to this method is a no-op.
6645     * </p>
6646     *
6647     * <pre>
6648     * StringUtils.replaceOnce(null, *, *)        = null
6649     * StringUtils.replaceOnce("", *, *)          = ""
6650     * StringUtils.replaceOnce("any", null, *)    = "any"
6651     * StringUtils.replaceOnce("any", *, null)    = "any"
6652     * StringUtils.replaceOnce("any", "", *)      = "any"
6653     * StringUtils.replaceOnce("aba", "a", null)  = "aba"
6654     * StringUtils.replaceOnce("aba", "a", "")    = "ba"
6655     * StringUtils.replaceOnce("aba", "a", "z")   = "zba"
6656     * </pre>
6657     *
6658     * @param text         text to search and replace in, may be null.
6659     * @param searchString the String to search for, may be null.
6660     * @param replacement  the String to replace with, may be null.
6661     * @return the text with any replacements processed, {@code null} if null String input.
6662     * @see #replace(String text, String searchString, String replacement, int max)
6663     * @deprecated Use {@link Strings#replaceOnce(String, String, String) Strings.CS.replaceOnce(String, String, String)}
6664     */
6665    @Deprecated
6666    public static String replaceOnce(final String text, final String searchString, final String replacement) {
6667        return Strings.CS.replaceOnce(text, searchString, replacement);
6668    }
6669
6670    /**
6671     * Case insensitively replaces a String with another String inside a larger String, once.
6672     *
6673     * <p>
6674     * A {@code null} reference passed to this method is a no-op.
6675     * </p>
6676     *
6677     * <pre>
6678     * StringUtils.replaceOnceIgnoreCase(null, *, *)        = null
6679     * StringUtils.replaceOnceIgnoreCase("", *, *)          = ""
6680     * StringUtils.replaceOnceIgnoreCase("any", null, *)    = "any"
6681     * StringUtils.replaceOnceIgnoreCase("any", *, null)    = "any"
6682     * StringUtils.replaceOnceIgnoreCase("any", "", *)      = "any"
6683     * StringUtils.replaceOnceIgnoreCase("aba", "a", null)  = "aba"
6684     * StringUtils.replaceOnceIgnoreCase("aba", "a", "")    = "ba"
6685     * StringUtils.replaceOnceIgnoreCase("aba", "a", "z")   = "zba"
6686     * StringUtils.replaceOnceIgnoreCase("FoOFoofoo", "foo", "") = "Foofoo"
6687     * </pre>
6688     *
6689     * @param text         text to search and replace in, may be null.
6690     * @param searchString the String to search for (case-insensitive), may be null.
6691     * @param replacement  the String to replace with, may be null.
6692     * @return the text with any replacements processed, {@code null} if null String input.
6693     * @see #replaceIgnoreCase(String text, String searchString, String replacement, int max)
6694     * @since 3.5
6695     * @deprecated Use {@link Strings#replaceOnce(String, String, String) Strings.CI.replaceOnce(String, String, String)}
6696     */
6697    @Deprecated
6698    public static String replaceOnceIgnoreCase(final String text, final String searchString, final String replacement) {
6699        return Strings.CI.replaceOnce(text, searchString, replacement);
6700    }
6701
6702    /**
6703     * Replaces each substring of the source String that matches the given regular expression with the given replacement using the {@link Pattern#DOTALL}
6704     * option. DOTALL is also known as single-line mode in Perl.
6705     *
6706     * This call is a {@code null} safe equivalent to:
6707     * <ul>
6708     * <li>{@code source.replaceAll(&quot;(?s)&quot; + regex, replacement)}</li>
6709     * <li>{@code Pattern.compile(regex, Pattern.DOTALL).matcher(source).replaceAll(replacement)}</li>
6710     * </ul>
6711     *
6712     * <p>
6713     * A {@code null} reference passed to this method is a no-op.
6714     * </p>
6715     *
6716     * <pre>{@code
6717     * StringUtils.replacePattern(null, *, *)                                         = null
6718     * StringUtils.replacePattern("any", (String) null, *)                            = "any"
6719     * StringUtils.replacePattern("any", *, null)                                     = "any"
6720     * StringUtils.replacePattern("", "", "zzz")                                      = "zzz"
6721     * StringUtils.replacePattern("", ".*", "zzz")                                    = "zzz"
6722     * StringUtils.replacePattern("", ".+", "zzz")                                    = ""
6723     * StringUtils.replacePattern("<__>\n<__>", "<.*>", "z")                          = "z"
6724     * StringUtils.replacePattern("ABCabc123", "[a-z]", "_")                          = "ABC___123"
6725     * StringUtils.replacePattern("ABCabc123", "[^A-Z0-9]+", "_")                     = "ABC_123"
6726     * StringUtils.replacePattern("ABCabc123", "[^A-Z0-9]+", "")                      = "ABC123"
6727     * StringUtils.replacePattern("Lorem ipsum  dolor   sit", "( +)([a-z]+)", "_$2")  = "Lorem_ipsum_dolor_sit"
6728     * }</pre>
6729     *
6730     * @param source      the source string.
6731     * @param regex       the regular expression to which this string is to be matched.
6732     * @param replacement the string to be substituted for each match.
6733     * @return The resulting {@link String}.
6734     * @see #replaceAll(String, String, String)
6735     * @see String#replaceAll(String, String)
6736     * @see Pattern#DOTALL
6737     * @since 3.2
6738     * @since 3.5 Changed {@code null} reference passed to this method is a no-op.
6739     * @deprecated Moved to RegExUtils.
6740     */
6741    @Deprecated
6742    public static String replacePattern(final String source, final String regex, final String replacement) {
6743        return RegExUtils.replacePattern(source, regex, replacement);
6744    }
6745
6746    /**
6747     * Reverses a String as per {@link StringBuilder#reverse()}.
6748     *
6749     * <p>
6750     * A {@code null} String returns {@code null}.
6751     * </p>
6752     *
6753     * <pre>
6754     * StringUtils.reverse(null)  = null
6755     * StringUtils.reverse("")    = ""
6756     * StringUtils.reverse("bat") = "tab"
6757     * </pre>
6758     *
6759     * @param str the String to reverse, may be null.
6760     * @return the reversed String, {@code null} if null String input.
6761     */
6762    public static String reverse(final String str) {
6763        if (str == null) {
6764            return null;
6765        }
6766        return new StringBuilder(str).reverse().toString();
6767    }
6768
6769    /**
6770     * Reverses a String that is delimited by a specific character.
6771     *
6772     * <p>
6773     * The Strings between the delimiters are not reversed. Thus java.lang.String becomes String.lang.java (if the delimiter is {@code '.'}).
6774     * </p>
6775     *
6776     * <pre>
6777     * StringUtils.reverseDelimited(null, *)      = null
6778     * StringUtils.reverseDelimited("", *)        = ""
6779     * StringUtils.reverseDelimited("a.b.c", 'x') = "a.b.c"
6780     * StringUtils.reverseDelimited("a.b.c", ".") = "c.b.a"
6781     * </pre>
6782     *
6783     * @param str           the String to reverse, may be null.
6784     * @param separatorChar the separator character to use.
6785     * @return the reversed String, {@code null} if null String input.
6786     * @since 2.0
6787     */
6788    public static String reverseDelimited(final String str, final char separatorChar) {
6789        final String[] strs = split(str, separatorChar);
6790        ArrayUtils.reverse(strs);
6791        return join(strs, separatorChar);
6792    }
6793
6794    /**
6795     * Gets the rightmost {@code len} characters of a String.
6796     *
6797     * <p>
6798     * If {@code len} characters are not available, or the String is {@code null}, the String will be returned without an an exception. An empty String is
6799     * returned if len is negative.
6800     * </p>
6801     *
6802     * <pre>
6803     * StringUtils.right(null, *)    = null
6804     * StringUtils.right(*, -ve)     = ""
6805     * StringUtils.right("", *)      = ""
6806     * StringUtils.right("abc", 0)   = ""
6807     * StringUtils.right("abc", 2)   = "bc"
6808     * StringUtils.right("abc", 4)   = "abc"
6809     * </pre>
6810     *
6811     * @param str the String to get the rightmost characters from, may be null.
6812     * @param len the length of the required String.
6813     * @return the rightmost characters, {@code null} if null String input.
6814     */
6815    public static String right(final String str, final int len) {
6816        if (str == null) {
6817            return null;
6818        }
6819        if (len < 0) {
6820            return EMPTY;
6821        }
6822        if (str.length() <= len) {
6823            return str;
6824        }
6825        return str.substring(str.length() - len);
6826    }
6827
6828    /**
6829     * Right pad a String with spaces (' ').
6830     *
6831     * <p>
6832     * The String is padded to the size of {@code size}.
6833     * </p>
6834     *
6835     * <pre>
6836     * StringUtils.rightPad(null, *)   = null
6837     * StringUtils.rightPad("", 3)     = "   "
6838     * StringUtils.rightPad("bat", 3)  = "bat"
6839     * StringUtils.rightPad("bat", 5)  = "bat  "
6840     * StringUtils.rightPad("bat", 1)  = "bat"
6841     * StringUtils.rightPad("bat", -1) = "bat"
6842     * </pre>
6843     *
6844     * @param str  the String to pad out, may be null.
6845     * @param size the size to pad to.
6846     * @return right padded String or original String if no padding is necessary, {@code null} if null String input.
6847     */
6848    public static String rightPad(final String str, final int size) {
6849        return rightPad(str, size, ' ');
6850    }
6851
6852    /**
6853     * Right pad a String with a specified character.
6854     *
6855     * <p>
6856     * The String is padded to the size of {@code size}.
6857     * </p>
6858     *
6859     * <pre>
6860     * StringUtils.rightPad(null, *, *)     = null
6861     * StringUtils.rightPad("", 3, 'z')     = "zzz"
6862     * StringUtils.rightPad("bat", 3, 'z')  = "bat"
6863     * StringUtils.rightPad("bat", 5, 'z')  = "batzz"
6864     * StringUtils.rightPad("bat", 1, 'z')  = "bat"
6865     * StringUtils.rightPad("bat", -1, 'z') = "bat"
6866     * </pre>
6867     *
6868     * @param str     the String to pad out, may be null.
6869     * @param size    the size to pad to.
6870     * @param padChar the character to pad with.
6871     * @return right padded String or original String if no padding is necessary, {@code null} if null String input.
6872     * @since 2.0
6873     */
6874    public static String rightPad(final String str, final int size, final char padChar) {
6875        if (str == null) {
6876            return null;
6877        }
6878        final int pads = size - str.length();
6879        if (pads <= 0) {
6880            return str; // returns original String when possible
6881        }
6882        if (pads > PAD_LIMIT) {
6883            return rightPad(str, size, String.valueOf(padChar));
6884        }
6885        return str.concat(repeat(padChar, pads));
6886    }
6887
6888    /**
6889     * Right pad a String with a specified String.
6890     *
6891     * <p>
6892     * The String is padded to the size of {@code size}.
6893     * </p>
6894     *
6895     * <pre>
6896     * StringUtils.rightPad(null, *, *)      = null
6897     * StringUtils.rightPad("", 3, "z")      = "zzz"
6898     * StringUtils.rightPad("bat", 3, "yz")  = "bat"
6899     * StringUtils.rightPad("bat", 5, "yz")  = "batyz"
6900     * StringUtils.rightPad("bat", 8, "yz")  = "batyzyzy"
6901     * StringUtils.rightPad("bat", 1, "yz")  = "bat"
6902     * StringUtils.rightPad("bat", -1, "yz") = "bat"
6903     * StringUtils.rightPad("bat", 5, null)  = "bat  "
6904     * StringUtils.rightPad("bat", 5, "")    = "bat  "
6905     * </pre>
6906     *
6907     * @param str    the String to pad out, may be null.
6908     * @param size   the size to pad to.
6909     * @param padStr the String to pad with, null or empty treated as single space.
6910     * @return right padded String or original String if no padding is necessary, {@code null} if null String input.
6911     */
6912    public static String rightPad(final String str, final int size, String padStr) {
6913        if (str == null) {
6914            return null;
6915        }
6916        if (isEmpty(padStr)) {
6917            padStr = SPACE;
6918        }
6919        final int padLen = padStr.length();
6920        final int strLen = str.length();
6921        final int pads = size - strLen;
6922        if (pads <= 0) {
6923            return str; // returns original String when possible
6924        }
6925        if (padLen == 1 && pads <= PAD_LIMIT) {
6926            return rightPad(str, size, padStr.charAt(0));
6927        }
6928        if (pads == padLen) {
6929            return str.concat(padStr);
6930        }
6931        if (pads < padLen) {
6932            return str.concat(padStr.substring(0, pads));
6933        }
6934        final char[] padding = new char[pads];
6935        final char[] padChars = padStr.toCharArray();
6936        for (int i = 0; i < pads; i++) {
6937            padding[i] = padChars[i % padLen];
6938        }
6939        return str.concat(new String(padding));
6940    }
6941
6942    /**
6943     * Rotate (circular shift) a String of {@code shift} characters.
6944     * <ul>
6945     * <li>If {@code shift > 0}, right circular shift (ex : ABCDEF =&gt; FABCDE)</li>
6946     * <li>If {@code shift < 0}, left circular shift (ex : ABCDEF =&gt; BCDEFA)</li>
6947     * </ul>
6948     *
6949     * <pre>
6950     * StringUtils.rotate(null, *)        = null
6951     * StringUtils.rotate("", *)          = ""
6952     * StringUtils.rotate("abcdefg", 0)   = "abcdefg"
6953     * StringUtils.rotate("abcdefg", 2)   = "fgabcde"
6954     * StringUtils.rotate("abcdefg", -2)  = "cdefgab"
6955     * StringUtils.rotate("abcdefg", 7)   = "abcdefg"
6956     * StringUtils.rotate("abcdefg", -7)  = "abcdefg"
6957     * StringUtils.rotate("abcdefg", 9)   = "fgabcde"
6958     * StringUtils.rotate("abcdefg", -9)  = "cdefgab"
6959     * </pre>
6960     *
6961     * @param str   the String to rotate, may be null.
6962     * @param shift number of time to shift (positive : right shift, negative : left shift).
6963     * @return the rotated String, or the original String if {@code shift == 0}, or {@code null} if null String input.
6964     * @since 3.5
6965     */
6966    public static String rotate(final String str, final int shift) {
6967        if (str == null) {
6968            return null;
6969        }
6970        final int strLen = str.length();
6971        if (shift == 0 || strLen == 0 || shift % strLen == 0) {
6972            return str;
6973        }
6974        final StringBuilder builder = new StringBuilder(strLen);
6975        final int offset = -(shift % strLen);
6976        builder.append(substring(str, offset));
6977        builder.append(substring(str, 0, offset));
6978        return builder.toString();
6979    }
6980
6981    /**
6982     * Splits the provided text into an array, using whitespace as the separator. Whitespace is defined by {@link Character#isWhitespace(char)}.
6983     *
6984     * <p>
6985     * The separator is not included in the returned String array. Adjacent separators are treated as one separator. For more control over the split use the
6986     * StrTokenizer class.
6987     * </p>
6988     *
6989     * <p>
6990     * A {@code null} input String returns {@code null}.
6991     * </p>
6992     *
6993     * <pre>
6994     * StringUtils.split(null)       = null
6995     * StringUtils.split("")         = []
6996     * StringUtils.split("abc def")  = ["abc", "def"]
6997     * StringUtils.split("abc  def") = ["abc", "def"]
6998     * StringUtils.split(" abc ")    = ["abc"]
6999     * </pre>
7000     *
7001     * @param str the String to parse, may be null.
7002     * @return an array of parsed Strings, {@code null} if null String input.
7003     */
7004    public static String[] split(final String str) {
7005        return split(str, null, -1);
7006    }
7007
7008    /**
7009     * Splits the provided text into an array, separator specified. This is an alternative to using StringTokenizer.
7010     *
7011     * <p>
7012     * The separator is not included in the returned String array. Adjacent separators are treated as one separator. For more control over the split use the
7013     * StrTokenizer class.
7014     * </p>
7015     *
7016     * <p>
7017     * A {@code null} input String returns {@code null}.
7018     * </p>
7019     *
7020     * <pre>
7021     * StringUtils.split(null, *)         = null
7022     * StringUtils.split("", *)           = []
7023     * StringUtils.split("a.b.c", '.')    = ["a", "b", "c"]
7024     * StringUtils.split("a..b.c", '.')   = ["a", "b", "c"]
7025     * StringUtils.split("a:b:c", '.')    = ["a:b:c"]
7026     * StringUtils.split("a b c", ' ')    = ["a", "b", "c"]
7027     * </pre>
7028     *
7029     * @param str           the String to parse, may be null.
7030     * @param separatorChar the character used as the delimiter.
7031     * @return an array of parsed Strings, {@code null} if null String input.
7032     * @since 2.0
7033     */
7034    public static String[] split(final String str, final char separatorChar) {
7035        return splitWorker(str, separatorChar, false);
7036    }
7037
7038    /**
7039     * Splits the provided text into an array, separators specified. This is an alternative to using StringTokenizer.
7040     *
7041     * <p>
7042     * The separator is not included in the returned String array. Adjacent separators are treated as one separator. For more control over the split use the
7043     * StrTokenizer class.
7044     * </p>
7045     *
7046     * <p>
7047     * A {@code null} input String returns {@code null}. A {@code null} separatorChars splits on whitespace.
7048     * </p>
7049     *
7050     * <pre>
7051     * StringUtils.split(null, *)         = null
7052     * StringUtils.split("", *)           = []
7053     * StringUtils.split("abc def", null) = ["abc", "def"]
7054     * StringUtils.split("abc def", " ")  = ["abc", "def"]
7055     * StringUtils.split("abc  def", " ") = ["abc", "def"]
7056     * StringUtils.split("ab:cd:ef", ":") = ["ab", "cd", "ef"]
7057     * </pre>
7058     *
7059     * @param str            the String to parse, may be null.
7060     * @param separatorChars the characters used as the delimiters, {@code null} splits on whitespace.
7061     * @return an array of parsed Strings, {@code null} if null String input.
7062     */
7063    public static String[] split(final String str, final String separatorChars) {
7064        return splitWorker(str, separatorChars, -1, false);
7065    }
7066
7067    /**
7068     * Splits the provided text into an array with a maximum length, separators specified.
7069     *
7070     * <p>
7071     * The separator is not included in the returned String array. Adjacent separators are treated as one separator.
7072     * </p>
7073     *
7074     * <p>
7075     * A {@code null} input String returns {@code null}. A {@code null} separatorChars splits on whitespace.
7076     * </p>
7077     *
7078     * <p>
7079     * If more than {@code max} delimited substrings are found, the last returned string includes all characters after the first {@code max - 1} returned
7080     * strings (including separator characters).
7081     * </p>
7082     *
7083     * <pre>
7084     * StringUtils.split(null, *, *)            = null
7085     * StringUtils.split("", *, *)              = []
7086     * StringUtils.split("ab cd ef", null, 0)   = ["ab", "cd", "ef"]
7087     * StringUtils.split("ab   cd ef", null, 0) = ["ab", "cd", "ef"]
7088     * StringUtils.split("ab:cd:ef", ":", 0)    = ["ab", "cd", "ef"]
7089     * StringUtils.split("ab:cd:ef", ":", 2)    = ["ab", "cd:ef"]
7090     * </pre>
7091     *
7092     * @param str            the String to parse, may be null.
7093     * @param separatorChars the characters used as the delimiters, {@code null} splits on whitespace.
7094     * @param max            the maximum number of elements to include in the array. A zero or negative value implies no limit.
7095     * @return an array of parsed Strings, {@code null} if null String input.
7096     */
7097    public static String[] split(final String str, final String separatorChars, final int max) {
7098        return splitWorker(str, separatorChars, max, false);
7099    }
7100
7101    /**
7102     * Splits a String by Character type as returned by {@code java.lang.Character.getType(char)}. Groups of contiguous characters of the same type are returned
7103     * as complete tokens.
7104     *
7105     * <pre>
7106     * StringUtils.splitByCharacterType(null)         = null
7107     * StringUtils.splitByCharacterType("")           = []
7108     * StringUtils.splitByCharacterType("ab de fg")   = ["ab", " ", "de", " ", "fg"]
7109     * StringUtils.splitByCharacterType("ab   de fg") = ["ab", "   ", "de", " ", "fg"]
7110     * StringUtils.splitByCharacterType("ab:cd:ef")   = ["ab", ":", "cd", ":", "ef"]
7111     * StringUtils.splitByCharacterType("number5")    = ["number", "5"]
7112     * StringUtils.splitByCharacterType("fooBar")     = ["foo", "B", "ar"]
7113     * StringUtils.splitByCharacterType("foo200Bar")  = ["foo", "200", "B", "ar"]
7114     * StringUtils.splitByCharacterType("ASFRules")   = ["ASFR", "ules"]
7115     * </pre>
7116     *
7117     * @param str the String to split, may be {@code null}.
7118     * @return an array of parsed Strings, {@code null} if null String input.
7119     * @since 2.4
7120     */
7121    public static String[] splitByCharacterType(final String str) {
7122        return splitByCharacterType(str, false);
7123    }
7124
7125    /**
7126     * Splits a String by Character type as returned by {@code java.lang.Character.getType(char)}. Groups of contiguous characters of the same type are returned
7127     * as complete tokens, with the following exception: if {@code camelCase} is {@code true}, the character of type {@code Character.UPPERCASE_LETTER}, if any,
7128     * immediately preceding a token of type {@code Character.LOWERCASE_LETTER} will belong to the following token rather than to the preceding, if any,
7129     * {@code Character.UPPERCASE_LETTER} token.
7130     *
7131     * @param str       the String to split, may be {@code null}.
7132     * @param camelCase whether to use so-called "camel-case" for letter types.
7133     * @return an array of parsed Strings, {@code null} if null String input.
7134     * @since 2.4
7135     */
7136    private static String[] splitByCharacterType(final String str, final boolean camelCase) {
7137        if (str == null) {
7138            return null;
7139        }
7140        if (str.isEmpty()) {
7141            return ArrayUtils.EMPTY_STRING_ARRAY;
7142        }
7143        final char[] c = str.toCharArray();
7144        final List<String> list = new ArrayList<>();
7145        int tokenStart = 0;
7146        int currentType = Character.getType(c[tokenStart]);
7147        for (int pos = tokenStart + 1; pos < c.length; pos++) {
7148            final int type = Character.getType(c[pos]);
7149            if (type == currentType) {
7150                continue;
7151            }
7152            if (camelCase && type == Character.LOWERCASE_LETTER && currentType == Character.UPPERCASE_LETTER) {
7153                final int newTokenStart = pos - 1;
7154                if (newTokenStart != tokenStart) {
7155                    list.add(new String(c, tokenStart, newTokenStart - tokenStart));
7156                    tokenStart = newTokenStart;
7157                }
7158            } else {
7159                list.add(new String(c, tokenStart, pos - tokenStart));
7160                tokenStart = pos;
7161            }
7162            currentType = type;
7163        }
7164        list.add(new String(c, tokenStart, c.length - tokenStart));
7165        return list.toArray(ArrayUtils.EMPTY_STRING_ARRAY);
7166    }
7167
7168    /**
7169     * Splits a String by Character type as returned by {@code java.lang.Character.getType(char)}. Groups of contiguous characters of the same type are returned
7170     * as complete tokens, with the following exception: the character of type {@code Character.UPPERCASE_LETTER}, if any, immediately preceding a token of type
7171     * {@code Character.LOWERCASE_LETTER} will belong to the following token rather than to the preceding, if any, {@code Character.UPPERCASE_LETTER} token.
7172     *
7173     * <pre>
7174     * StringUtils.splitByCharacterTypeCamelCase(null)         = null
7175     * StringUtils.splitByCharacterTypeCamelCase("")           = []
7176     * StringUtils.splitByCharacterTypeCamelCase("ab de fg")   = ["ab", " ", "de", " ", "fg"]
7177     * StringUtils.splitByCharacterTypeCamelCase("ab   de fg") = ["ab", "   ", "de", " ", "fg"]
7178     * StringUtils.splitByCharacterTypeCamelCase("ab:cd:ef")   = ["ab", ":", "cd", ":", "ef"]
7179     * StringUtils.splitByCharacterTypeCamelCase("number5")    = ["number", "5"]
7180     * StringUtils.splitByCharacterTypeCamelCase("fooBar")     = ["foo", "Bar"]
7181     * StringUtils.splitByCharacterTypeCamelCase("foo200Bar")  = ["foo", "200", "Bar"]
7182     * StringUtils.splitByCharacterTypeCamelCase("ASFRules")   = ["ASF", "Rules"]
7183     * </pre>
7184     *
7185     * @param str the String to split, may be {@code null}.
7186     * @return an array of parsed Strings, {@code null} if null String input.
7187     * @since 2.4
7188     */
7189    public static String[] splitByCharacterTypeCamelCase(final String str) {
7190        return splitByCharacterType(str, true);
7191    }
7192
7193    /**
7194     * Splits the provided text into an array, separator string specified.
7195     *
7196     * <p>
7197     * The separator(s) will not be included in the returned String array. Adjacent separators are treated as one separator.
7198     * </p>
7199     *
7200     * <p>
7201     * A {@code null} input String returns {@code null}. A {@code null} separator splits on whitespace.
7202     * </p>
7203     *
7204     * <pre>
7205     * StringUtils.splitByWholeSeparator(null, *)               = null
7206     * StringUtils.splitByWholeSeparator("", *)                 = []
7207     * StringUtils.splitByWholeSeparator("ab de fg", null)      = ["ab", "de", "fg"]
7208     * StringUtils.splitByWholeSeparator("ab   de fg", null)    = ["ab", "de", "fg"]
7209     * StringUtils.splitByWholeSeparator("ab:cd:ef", ":")       = ["ab", "cd", "ef"]
7210     * StringUtils.splitByWholeSeparator("ab-!-cd-!-ef", "-!-") = ["ab", "cd", "ef"]
7211     * </pre>
7212     *
7213     * @param str       the String to parse, may be null.
7214     * @param separator String containing the String to be used as a delimiter, {@code null} splits on whitespace.
7215     * @return an array of parsed Strings, {@code null} if null String was input.
7216     */
7217    public static String[] splitByWholeSeparator(final String str, final String separator) {
7218        return splitByWholeSeparatorWorker(str, separator, -1, false);
7219    }
7220
7221    /**
7222     * Splits the provided text into an array, separator string specified. Returns a maximum of {@code max} substrings.
7223     *
7224     * <p>
7225     * The separator(s) will not be included in the returned String array. Adjacent separators are treated as one separator.
7226     * </p>
7227     *
7228     * <p>
7229     * A {@code null} input String returns {@code null}. A {@code null} separator splits on whitespace.
7230     * </p>
7231     *
7232     * <pre>
7233     * StringUtils.splitByWholeSeparator(null, *, *)               = null
7234     * StringUtils.splitByWholeSeparator("", *, *)                 = []
7235     * StringUtils.splitByWholeSeparator("ab de fg", null, 0)      = ["ab", "de", "fg"]
7236     * StringUtils.splitByWholeSeparator("ab   de fg", null, 0)    = ["ab", "de", "fg"]
7237     * StringUtils.splitByWholeSeparator("ab:cd:ef", ":", 2)       = ["ab", "cd:ef"]
7238     * StringUtils.splitByWholeSeparator("ab-!-cd-!-ef", "-!-", 5) = ["ab", "cd", "ef"]
7239     * StringUtils.splitByWholeSeparator("ab-!-cd-!-ef", "-!-", 2) = ["ab", "cd-!-ef"]
7240     * </pre>
7241     *
7242     * @param str       the String to parse, may be null.
7243     * @param separator String containing the String to be used as a delimiter, {@code null} splits on whitespace.
7244     * @param max       the maximum number of elements to include in the returned array. A zero or negative value implies no limit.
7245     * @return an array of parsed Strings, {@code null} if null String was input.
7246     */
7247    public static String[] splitByWholeSeparator(final String str, final String separator, final int max) {
7248        return splitByWholeSeparatorWorker(str, separator, max, false);
7249    }
7250
7251    /**
7252     * Splits the provided text into an array, separator string specified.
7253     *
7254     * <p>
7255     * The separator is not included in the returned String array. Adjacent separators are treated as separators for empty tokens. For more control over the
7256     * split use the StrTokenizer class.
7257     * </p>
7258     *
7259     * <p>
7260     * A {@code null} input String returns {@code null}. A {@code null} separator splits on whitespace.
7261     * </p>
7262     *
7263     * <pre>
7264     * StringUtils.splitByWholeSeparatorPreserveAllTokens(null, *)               = null
7265     * StringUtils.splitByWholeSeparatorPreserveAllTokens("", *)                 = []
7266     * StringUtils.splitByWholeSeparatorPreserveAllTokens("ab de fg", null)      = ["ab", "de", "fg"]
7267     * StringUtils.splitByWholeSeparatorPreserveAllTokens("ab   de fg", null)    = ["ab", "", "", "de", "fg"]
7268     * StringUtils.splitByWholeSeparatorPreserveAllTokens("ab:cd:ef", ":")       = ["ab", "cd", "ef"]
7269     * StringUtils.splitByWholeSeparatorPreserveAllTokens("ab-!-cd-!-ef", "-!-") = ["ab", "cd", "ef"]
7270     * </pre>
7271     *
7272     * @param str       the String to parse, may be null.
7273     * @param separator String containing the String to be used as a delimiter, {@code null} splits on whitespace.
7274     * @return an array of parsed Strings, {@code null} if null String was input.
7275     * @since 2.4
7276     */
7277    public static String[] splitByWholeSeparatorPreserveAllTokens(final String str, final String separator) {
7278        return splitByWholeSeparatorWorker(str, separator, -1, true);
7279    }
7280
7281    /**
7282     * Splits the provided text into an array, separator string specified. Returns a maximum of {@code max} substrings.
7283     *
7284     * <p>
7285     * The separator is not included in the returned String array. Adjacent separators are treated as separators for empty tokens. For more control over the
7286     * split use the StrTokenizer class.
7287     * </p>
7288     *
7289     * <p>
7290     * A {@code null} input String returns {@code null}. A {@code null} separator splits on whitespace.
7291     * </p>
7292     *
7293     * <pre>
7294     * StringUtils.splitByWholeSeparatorPreserveAllTokens(null, *, *)               = null
7295     * StringUtils.splitByWholeSeparatorPreserveAllTokens("", *, *)                 = []
7296     * StringUtils.splitByWholeSeparatorPreserveAllTokens("ab de fg", null, 0)      = ["ab", "de", "fg"]
7297     * StringUtils.splitByWholeSeparatorPreserveAllTokens("ab   de fg", null, 0)    = ["ab", "", "", "de", "fg"]
7298     * StringUtils.splitByWholeSeparatorPreserveAllTokens("ab:cd:ef", ":", 2)       = ["ab", "cd:ef"]
7299     * StringUtils.splitByWholeSeparatorPreserveAllTokens("ab-!-cd-!-ef", "-!-", 5) = ["ab", "cd", "ef"]
7300     * StringUtils.splitByWholeSeparatorPreserveAllTokens("ab-!-cd-!-ef", "-!-", 2) = ["ab", "cd-!-ef"]
7301     * </pre>
7302     *
7303     * @param str       the String to parse, may be null.
7304     * @param separator String containing the String to be used as a delimiter, {@code null} splits on whitespace.
7305     * @param max       the maximum number of elements to include in the returned array. A zero or negative value implies no limit.
7306     * @return an array of parsed Strings, {@code null} if null String was input.
7307     * @since 2.4
7308     */
7309    public static String[] splitByWholeSeparatorPreserveAllTokens(final String str, final String separator, final int max) {
7310        return splitByWholeSeparatorWorker(str, separator, max, true);
7311    }
7312
7313    /**
7314     * Performs the logic for the {@code splitByWholeSeparatorPreserveAllTokens} methods.
7315     *
7316     * @param str               the String to parse, may be {@code null}.
7317     * @param separator         String containing the String to be used as a delimiter, {@code null} splits on whitespace.
7318     * @param max               the maximum number of elements to include in the returned array. A zero or negative value implies no limit.
7319     * @param preserveAllTokens if {@code true}, adjacent separators are treated as empty token separators; if {@code false}, adjacent separators are treated as
7320     *                          one separator.
7321     * @return an array of parsed Strings, {@code null} if null String input.
7322     * @since 2.4
7323     */
7324    private static String[] splitByWholeSeparatorWorker(final String str, final String separator, final int max, final boolean preserveAllTokens) {
7325        if (str == null) {
7326            return null;
7327        }
7328        final int len = str.length();
7329        if (len == 0) {
7330            return ArrayUtils.EMPTY_STRING_ARRAY;
7331        }
7332        if (separator == null || EMPTY.equals(separator)) {
7333            // Split on whitespace.
7334            return splitWorker(str, null, max, preserveAllTokens);
7335        }
7336        final int separatorLength = separator.length();
7337        final ArrayList<String> substrings = new ArrayList<>();
7338        int numberOfSubstrings = 0;
7339        int beg = 0;
7340        int end = 0;
7341        while (end < len) {
7342            end = str.indexOf(separator, beg);
7343            if (end > -1) {
7344                if (end > beg) {
7345                    numberOfSubstrings += 1;
7346                    if (numberOfSubstrings == max) {
7347                        end = len;
7348                        substrings.add(str.substring(beg));
7349                    } else {
7350                        // The following is OK, because String.substring( beg, end ) excludes
7351                        // the character at the position 'end'.
7352                        substrings.add(str.substring(beg, end));
7353                        // Set the starting point for the next search.
7354                        // The following is equivalent to beg = end + (separatorLength - 1) + 1,
7355                        // which is the right calculation:
7356                        beg = end + separatorLength;
7357                    }
7358                } else {
7359                    // We found a consecutive occurrence of the separator, so skip it.
7360                    if (preserveAllTokens) {
7361                        numberOfSubstrings += 1;
7362                        if (numberOfSubstrings == max) {
7363                            end = len;
7364                            substrings.add(str.substring(beg));
7365                        } else {
7366                            substrings.add(EMPTY);
7367                        }
7368                    }
7369                    beg = end + separatorLength;
7370                }
7371            } else {
7372                // String.substring( beg ) goes from 'beg' to the end of the String.
7373                substrings.add(str.substring(beg));
7374                end = len;
7375            }
7376        }
7377        return substrings.toArray(ArrayUtils.EMPTY_STRING_ARRAY);
7378    }
7379
7380    /**
7381     * Splits the provided text into an array, using whitespace as the separator, preserving all tokens, including empty tokens created by adjacent separators.
7382     * This is an alternative to using StringTokenizer. Whitespace is defined by {@link Character#isWhitespace(char)}.
7383     *
7384     * <p>
7385     * The separator is not included in the returned String array. Adjacent separators are treated as separators for empty tokens. For more control over the
7386     * split use the StrTokenizer class.
7387     * </p>
7388     *
7389     * <p>
7390     * A {@code null} input String returns {@code null}.
7391     * </p>
7392     *
7393     * <pre>
7394     * StringUtils.splitPreserveAllTokens(null)       = null
7395     * StringUtils.splitPreserveAllTokens("")         = []
7396     * StringUtils.splitPreserveAllTokens("abc def")  = ["abc", "def"]
7397     * StringUtils.splitPreserveAllTokens("abc  def") = ["abc", "", "def"]
7398     * StringUtils.splitPreserveAllTokens(" abc ")    = ["", "abc", ""]
7399     * </pre>
7400     *
7401     * @param str the String to parse, may be {@code null}.
7402     * @return an array of parsed Strings, {@code null} if null String input.
7403     * @since 2.1
7404     */
7405    public static String[] splitPreserveAllTokens(final String str) {
7406        return splitWorker(str, null, -1, true);
7407    }
7408
7409    /**
7410     * Splits the provided text into an array, separator specified, preserving all tokens, including empty tokens created by adjacent separators. This is an
7411     * alternative to using StringTokenizer.
7412     *
7413     * <p>
7414     * The separator is not included in the returned String array. Adjacent separators are treated as separators for empty tokens. For more control over the
7415     * split use the StrTokenizer class.
7416     * </p>
7417     *
7418     * <p>
7419     * A {@code null} input String returns {@code null}.
7420     * </p>
7421     *
7422     * <pre>
7423     * StringUtils.splitPreserveAllTokens(null, *)         = null
7424     * StringUtils.splitPreserveAllTokens("", *)           = []
7425     * StringUtils.splitPreserveAllTokens("a.b.c", '.')    = ["a", "b", "c"]
7426     * StringUtils.splitPreserveAllTokens("a..b.c", '.')   = ["a", "", "b", "c"]
7427     * StringUtils.splitPreserveAllTokens("a:b:c", '.')    = ["a:b:c"]
7428     * StringUtils.splitPreserveAllTokens("a\tb\nc", null) = ["a", "b", "c"]
7429     * StringUtils.splitPreserveAllTokens("a b c", ' ')    = ["a", "b", "c"]
7430     * StringUtils.splitPreserveAllTokens("a b c ", ' ')   = ["a", "b", "c", ""]
7431     * StringUtils.splitPreserveAllTokens("a b c  ", ' ')  = ["a", "b", "c", "", ""]
7432     * StringUtils.splitPreserveAllTokens(" a b c", ' ')   = ["", "a", "b", "c"]
7433     * StringUtils.splitPreserveAllTokens("  a b c", ' ')  = ["", "", "a", "b", "c"]
7434     * StringUtils.splitPreserveAllTokens(" a b c ", ' ')  = ["", "a", "b", "c", ""]
7435     * </pre>
7436     *
7437     * @param str           the String to parse, may be {@code null}.
7438     * @param separatorChar the character used as the delimiter, {@code null} splits on whitespace.
7439     * @return an array of parsed Strings, {@code null} if null String input.
7440     * @since 2.1
7441     */
7442    public static String[] splitPreserveAllTokens(final String str, final char separatorChar) {
7443        return splitWorker(str, separatorChar, true);
7444    }
7445
7446    /**
7447     * Splits the provided text into an array, separators specified, preserving all tokens, including empty tokens created by adjacent separators. This is an
7448     * alternative to using StringTokenizer.
7449     *
7450     * <p>
7451     * The separator is not included in the returned String array. Adjacent separators are treated as separators for empty tokens. For more control over the
7452     * split use the StrTokenizer class.
7453     * </p>
7454     *
7455     * <p>
7456     * A {@code null} input String returns {@code null}. A {@code null} separatorChars splits on whitespace.
7457     * </p>
7458     *
7459     * <pre>
7460     * StringUtils.splitPreserveAllTokens(null, *)           = null
7461     * StringUtils.splitPreserveAllTokens("", *)             = []
7462     * StringUtils.splitPreserveAllTokens("abc def", null)   = ["abc", "def"]
7463     * StringUtils.splitPreserveAllTokens("abc def", " ")    = ["abc", "def"]
7464     * StringUtils.splitPreserveAllTokens("abc  def", " ")   = ["abc", "", "def"]
7465     * StringUtils.splitPreserveAllTokens("ab:cd:ef", ":")   = ["ab", "cd", "ef"]
7466     * StringUtils.splitPreserveAllTokens("ab:cd:ef:", ":")  = ["ab", "cd", "ef", ""]
7467     * StringUtils.splitPreserveAllTokens("ab:cd:ef::", ":") = ["ab", "cd", "ef", "", ""]
7468     * StringUtils.splitPreserveAllTokens("ab::cd:ef", ":")  = ["ab", "", "cd", "ef"]
7469     * StringUtils.splitPreserveAllTokens(":cd:ef", ":")     = ["", "cd", "ef"]
7470     * StringUtils.splitPreserveAllTokens("::cd:ef", ":")    = ["", "", "cd", "ef"]
7471     * StringUtils.splitPreserveAllTokens(":cd:ef:", ":")    = ["", "cd", "ef", ""]
7472     * </pre>
7473     *
7474     * @param str            the String to parse, may be {@code null}.
7475     * @param separatorChars the characters used as the delimiters, {@code null} splits on whitespace.
7476     * @return an array of parsed Strings, {@code null} if null String input.
7477     * @since 2.1
7478     */
7479    public static String[] splitPreserveAllTokens(final String str, final String separatorChars) {
7480        return splitWorker(str, separatorChars, -1, true);
7481    }
7482
7483    /**
7484     * Splits the provided text into an array with a maximum length, separators specified, preserving all tokens, including empty tokens created by adjacent
7485     * separators.
7486     *
7487     * <p>
7488     * The separator is not included in the returned String array. Adjacent separators are treated as separators for empty tokens. Adjacent separators are
7489     * treated as one separator.
7490     * </p>
7491     *
7492     * <p>
7493     * A {@code null} input String returns {@code null}. A {@code null} separatorChars splits on whitespace.
7494     * </p>
7495     *
7496     * <p>
7497     * If more than {@code max} delimited substrings are found, the last returned string includes all characters after the first {@code max - 1} returned
7498     * strings (including separator characters).
7499     * </p>
7500     *
7501     * <pre>
7502     * StringUtils.splitPreserveAllTokens(null, *, *)            = null
7503     * StringUtils.splitPreserveAllTokens("", *, *)              = []
7504     * StringUtils.splitPreserveAllTokens("ab de fg", null, 0)   = ["ab", "de", "fg"]
7505     * StringUtils.splitPreserveAllTokens("ab   de fg", null, 0) = ["ab", "", "", "de", "fg"]
7506     * StringUtils.splitPreserveAllTokens("ab:cd:ef", ":", 0)    = ["ab", "cd", "ef"]
7507     * StringUtils.splitPreserveAllTokens("ab:cd:ef", ":", 2)    = ["ab", "cd:ef"]
7508     * StringUtils.splitPreserveAllTokens("ab   de fg", null, 2) = ["ab", "  de fg"]
7509     * StringUtils.splitPreserveAllTokens("ab   de fg", null, 3) = ["ab", "", " de fg"]
7510     * StringUtils.splitPreserveAllTokens("ab   de fg", null, 4) = ["ab", "", "", "de fg"]
7511     * </pre>
7512     *
7513     * @param str            the String to parse, may be {@code null}.
7514     * @param separatorChars the characters used as the delimiters, {@code null} splits on whitespace.
7515     * @param max            the maximum number of elements to include in the array. A zero or negative value implies no limit.
7516     * @return an array of parsed Strings, {@code null} if null String input.
7517     * @since 2.1
7518     */
7519    public static String[] splitPreserveAllTokens(final String str, final String separatorChars, final int max) {
7520        return splitWorker(str, separatorChars, max, true);
7521    }
7522
7523    /**
7524     * Performs the logic for the {@code split} and {@code splitPreserveAllTokens} methods that do not return a maximum array length.
7525     *
7526     * @param str               the String to parse, may be {@code null}.
7527     * @param separatorChar     the separate character.
7528     * @param preserveAllTokens if {@code true}, adjacent separators are treated as empty token separators; if {@code false}, adjacent separators are treated as
7529     *                          one separator.
7530     * @return an array of parsed Strings, {@code null} if null String input.
7531     */
7532    private static String[] splitWorker(final String str, final char separatorChar, final boolean preserveAllTokens) {
7533        // Performance tuned for 2.0 (JDK1.4)
7534        if (str == null) {
7535            return null;
7536        }
7537        final int len = str.length();
7538        if (len == 0) {
7539            return ArrayUtils.EMPTY_STRING_ARRAY;
7540        }
7541        final List<String> list = new ArrayList<>();
7542        int i = 0;
7543        int start = 0;
7544        boolean match = false;
7545        boolean lastMatch = false;
7546        while (i < len) {
7547            if (str.charAt(i) == separatorChar) {
7548                if (match || preserveAllTokens) {
7549                    list.add(str.substring(start, i));
7550                    match = false;
7551                    lastMatch = true;
7552                }
7553                start = ++i;
7554                continue;
7555            }
7556            lastMatch = false;
7557            match = true;
7558            i++;
7559        }
7560        if (match || preserveAllTokens && lastMatch) {
7561            list.add(str.substring(start, i));
7562        }
7563        return list.toArray(ArrayUtils.EMPTY_STRING_ARRAY);
7564    }
7565
7566    /**
7567     * Performs the logic for the {@code split} and {@code splitPreserveAllTokens} methods that return a maximum array length.
7568     *
7569     * @param str               the String to parse, may be {@code null}.
7570     * @param separatorChars    the separate character.
7571     * @param max               the maximum number of elements to include in the array. A zero or negative value implies no limit.
7572     * @param preserveAllTokens if {@code true}, adjacent separators are treated as empty token separators; if {@code false}, adjacent separators are treated as
7573     *                          one separator.
7574     * @return an array of parsed Strings, {@code null} if null String input.
7575     */
7576    private static String[] splitWorker(final String str, final String separatorChars, final int max, final boolean preserveAllTokens) {
7577        // Performance tuned for 2.0 (JDK1.4)
7578        // Direct code is quicker than StringTokenizer.
7579        // Also, StringTokenizer uses isSpace() not isWhitespace()
7580        if (str == null) {
7581            return null;
7582        }
7583        final int len = str.length();
7584        if (len == 0) {
7585            return ArrayUtils.EMPTY_STRING_ARRAY;
7586        }
7587        final List<String> list = new ArrayList<>();
7588        int sizePlus1 = 1;
7589        int i = 0;
7590        int start = 0;
7591        boolean match = false;
7592        boolean lastMatch = false;
7593        if (separatorChars == null) {
7594            // Null separator means use whitespace
7595            while (i < len) {
7596                if (Character.isWhitespace(str.charAt(i))) {
7597                    if (match || preserveAllTokens) {
7598                        lastMatch = true;
7599                        if (sizePlus1++ == max) {
7600                            i = len;
7601                            lastMatch = false;
7602                        }
7603                        list.add(str.substring(start, i));
7604                        match = false;
7605                    }
7606                    start = ++i;
7607                    continue;
7608                }
7609                lastMatch = false;
7610                match = true;
7611                i++;
7612            }
7613        } else if (separatorChars.length() == 1) {
7614            // Optimize 1 character case
7615            final char sep = separatorChars.charAt(0);
7616            while (i < len) {
7617                if (str.charAt(i) == sep) {
7618                    if (match || preserveAllTokens) {
7619                        lastMatch = true;
7620                        if (sizePlus1++ == max) {
7621                            i = len;
7622                            lastMatch = false;
7623                        }
7624                        list.add(str.substring(start, i));
7625                        match = false;
7626                    }
7627                    start = ++i;
7628                    continue;
7629                }
7630                lastMatch = false;
7631                match = true;
7632                i++;
7633            }
7634        } else {
7635            // standard case
7636            while (i < len) {
7637                if (separatorChars.indexOf(str.charAt(i)) >= 0) {
7638                    if (match || preserveAllTokens) {
7639                        lastMatch = true;
7640                        if (sizePlus1++ == max) {
7641                            i = len;
7642                            lastMatch = false;
7643                        }
7644                        list.add(str.substring(start, i));
7645                        match = false;
7646                    }
7647                    start = ++i;
7648                    continue;
7649                }
7650                lastMatch = false;
7651                match = true;
7652                i++;
7653            }
7654        }
7655        if (match || preserveAllTokens && lastMatch) {
7656            list.add(str.substring(start, i));
7657        }
7658        return list.toArray(ArrayUtils.EMPTY_STRING_ARRAY);
7659    }
7660
7661    /**
7662     * Tests if a CharSequence starts with a specified prefix.
7663     *
7664     * <p>
7665     * {@code null}s are handled without exceptions. Two {@code null} references are considered to be equal. The comparison is case-sensitive.
7666     * </p>
7667     *
7668     * <pre>
7669     * StringUtils.startsWith(null, null)      = true
7670     * StringUtils.startsWith(null, "abc")     = false
7671     * StringUtils.startsWith("abcdef", null)  = false
7672     * StringUtils.startsWith("abcdef", "abc") = true
7673     * StringUtils.startsWith("ABCDEF", "abc") = false
7674     * </pre>
7675     *
7676     * @param str    the CharSequence to check, may be null.
7677     * @param prefix the prefix to find, may be null.
7678     * @return {@code true} if the CharSequence starts with the prefix, case-sensitive, or both {@code null}.
7679     * @see String#startsWith(String)
7680     * @since 2.4
7681     * @since 3.0 Changed signature from startsWith(String, String) to startsWith(CharSequence, CharSequence)
7682     * @deprecated Use {@link Strings#startsWith(CharSequence, CharSequence) Strings.CS.startsWith(CharSequence, CharSequence)}
7683     */
7684    @Deprecated
7685    public static boolean startsWith(final CharSequence str, final CharSequence prefix) {
7686        return Strings.CS.startsWith(str, prefix);
7687    }
7688
7689    /**
7690     * Tests if a CharSequence starts with any of the provided case-sensitive prefixes.
7691     *
7692     * <pre>
7693     * StringUtils.startsWithAny(null, null)      = false
7694     * StringUtils.startsWithAny(null, new String[] {"abc"})  = false
7695     * StringUtils.startsWithAny("abcxyz", null)     = false
7696     * StringUtils.startsWithAny("abcxyz", new String[] {""}) = true
7697     * StringUtils.startsWithAny("abcxyz", new String[] {"abc"}) = true
7698     * StringUtils.startsWithAny("abcxyz", new String[] {null, "xyz", "abc"}) = true
7699     * StringUtils.startsWithAny("abcxyz", null, "xyz", "ABCX") = false
7700     * StringUtils.startsWithAny("ABCXYZ", null, "xyz", "abc") = false
7701     * </pre>
7702     *
7703     * @param sequence      the CharSequence to check, may be null.
7704     * @param searchStrings the case-sensitive CharSequence prefixes, may be empty or contain {@code null}.
7705     * @return {@code true} if the input {@code sequence} is {@code null} AND no {@code searchStrings} are provided, or the input {@code sequence} begins with
7706     *         any of the provided case-sensitive {@code searchStrings}.
7707     * @see StringUtils#startsWith(CharSequence, CharSequence)
7708     * @since 2.5
7709     * @since 3.0 Changed signature from startsWithAny(String, String[]) to startsWithAny(CharSequence, CharSequence...)
7710     * @deprecated Use {@link Strings#startsWithAny(CharSequence, CharSequence...) Strings.CS.startsWithAny(CharSequence, CharSequence...)}
7711     */
7712    @Deprecated
7713    public static boolean startsWithAny(final CharSequence sequence, final CharSequence... searchStrings) {
7714        return Strings.CS.startsWithAny(sequence, searchStrings);
7715    }
7716
7717    /**
7718     * Case-insensitive check if a CharSequence starts with a specified prefix.
7719     *
7720     * <p>
7721     * {@code null}s are handled without exceptions. Two {@code null} references are considered to be equal. The comparison is case insensitive.
7722     * </p>
7723     *
7724     * <pre>
7725     * StringUtils.startsWithIgnoreCase(null, null)      = true
7726     * StringUtils.startsWithIgnoreCase(null, "abc")     = false
7727     * StringUtils.startsWithIgnoreCase("abcdef", null)  = false
7728     * StringUtils.startsWithIgnoreCase("abcdef", "abc") = true
7729     * StringUtils.startsWithIgnoreCase("ABCDEF", "abc") = true
7730     * </pre>
7731     *
7732     * @param str    the CharSequence to check, may be null.
7733     * @param prefix the prefix to find, may be null.
7734     * @return {@code true} if the CharSequence starts with the prefix, case-insensitive, or both {@code null}.
7735     * @see String#startsWith(String)
7736     * @since 2.4
7737     * @since 3.0 Changed signature from startsWithIgnoreCase(String, String) to startsWithIgnoreCase(CharSequence, CharSequence)
7738     * @deprecated Use {@link Strings#startsWith(CharSequence, CharSequence) Strings.CI.startsWith(CharSequence, CharSequence)}
7739     */
7740    @Deprecated
7741    public static boolean startsWithIgnoreCase(final CharSequence str, final CharSequence prefix) {
7742        return Strings.CI.startsWith(str, prefix);
7743    }
7744
7745    /**
7746     * Strips whitespace from the start and end of a String.
7747     *
7748     * <p>
7749     * This is similar to {@link #trim(String)} but removes whitespace. Whitespace is defined by {@link Character#isWhitespace(char)}.
7750     * </p>
7751     *
7752     * <p>
7753     * A {@code null} input String returns {@code null}.
7754     * </p>
7755     *
7756     * <pre>
7757     * StringUtils.strip(null)     = null
7758     * StringUtils.strip("")       = ""
7759     * StringUtils.strip("   ")    = ""
7760     * StringUtils.strip("abc")    = "abc"
7761     * StringUtils.strip("  abc")  = "abc"
7762     * StringUtils.strip("abc  ")  = "abc"
7763     * StringUtils.strip(" abc ")  = "abc"
7764     * StringUtils.strip(" ab c ") = "ab c"
7765     * </pre>
7766     *
7767     * @param str the String to remove whitespace from, may be null.
7768     * @return the stripped String, {@code null} if null String input.
7769     */
7770    public static String strip(final String str) {
7771        return strip(str, null);
7772    }
7773
7774    /**
7775     * Strips any of a set of characters from the start and end of a String. This is similar to {@link String#trim()} but allows the characters to be stripped
7776     * to be controlled.
7777     *
7778     * <p>
7779     * A {@code null} input String returns {@code null}. An empty string ("") input returns the empty string.
7780     * </p>
7781     *
7782     * <p>
7783     * If the stripChars String is {@code null}, whitespace is stripped as defined by {@link Character#isWhitespace(char)}. Alternatively use
7784     * {@link #strip(String)}.
7785     * </p>
7786     *
7787     * <pre>
7788     * StringUtils.strip(null, *)          = null
7789     * StringUtils.strip("", *)            = ""
7790     * StringUtils.strip("abc", null)      = "abc"
7791     * StringUtils.strip("  abc", null)    = "abc"
7792     * StringUtils.strip("abc  ", null)    = "abc"
7793     * StringUtils.strip(" abc ", null)    = "abc"
7794     * StringUtils.strip("  abcyx", "xyz") = "  abc"
7795     * </pre>
7796     *
7797     * @param str        the String to remove characters from, may be null.
7798     * @param stripChars the characters to remove, null treated as whitespace.
7799     * @return the stripped String, {@code null} if null String input.
7800     */
7801    public static String strip(String str, final String stripChars) {
7802        str = stripStart(str, stripChars);
7803        return stripEnd(str, stripChars);
7804    }
7805
7806    /**
7807     * Removes diacritics (~= accents) from a string. The case will not be altered.
7808     * <p>
7809     * For instance, '&agrave;' will be replaced by 'a'.
7810     * </p>
7811     * <p>
7812     * Decomposes ligatures and digraphs per the KD column in the <a href = "https://www.unicode.org/charts/normalization/">Unicode Normalization Chart.</a>
7813     * </p>
7814     *
7815     * <pre>
7816     * StringUtils.stripAccents(null)         = null
7817     * StringUtils.stripAccents("")           = ""
7818     * StringUtils.stripAccents("control")    = "control"
7819     * StringUtils.stripAccents("&eacute;clair")     = "eclair"
7820     * StringUtils.stripAccents("\u1d43\u1d47\u1d9c\u00b9\u00b2\u00b3")     = "abc123"
7821     * StringUtils.stripAccents("\u00BC \u00BD \u00BE")      = "1⁄4 1⁄2 3⁄4"
7822     * </pre>
7823     * <p>
7824     * See also <a href="http://www.unicode.org/unicode/reports/tr15/tr15-23.html">Unicode Standard Annex #15 Unicode Normalization Forms</a>.
7825     * </p>
7826     *
7827     * @param input String to be stripped.
7828     * @return input text with diacritics removed.
7829     * @since 3.0
7830     */
7831    // See also Lucene's ASCIIFoldingFilter (Lucene 2.9) that replaces accented characters by their unaccented equivalent (and uncommitted bug fix:
7832    // https://issues.apache.org/jira/browse/LUCENE-1343?focusedCommentId=12858907&page=com.atlassian.jira.plugin.system.issuetabpanels%3Acomment-tabpanel#action_12858907).
7833    public static String stripAccents(final String input) {
7834        if (isEmpty(input)) {
7835            return input;
7836        }
7837        final StringBuilder decomposed = new StringBuilder(Normalizer.normalize(input, Normalizer.Form.NFKD));
7838        convertRemainingAccentCharacters(decomposed);
7839        return STRIP_ACCENTS_PATTERN.matcher(decomposed).replaceAll(EMPTY);
7840    }
7841
7842    /**
7843     * Strips whitespace from the start and end of every String in an array. Whitespace is defined by {@link Character#isWhitespace(char)}.
7844     *
7845     * <p>
7846     * A new array is returned each time, except for length zero. A {@code null} array will return {@code null}. An empty array will return itself. A
7847     * {@code null} array entry will be ignored.
7848     * </p>
7849     *
7850     * <pre>
7851     * StringUtils.stripAll(null)             = null
7852     * StringUtils.stripAll([])               = []
7853     * StringUtils.stripAll(["abc", "  abc"]) = ["abc", "abc"]
7854     * StringUtils.stripAll(["abc  ", null])  = ["abc", null]
7855     * </pre>
7856     *
7857     * @param strs the array to remove whitespace from, may be null.
7858     * @return the stripped Strings, {@code null} if null array input.
7859     */
7860    public static String[] stripAll(final String... strs) {
7861        return stripAll(strs, null);
7862    }
7863
7864    /**
7865     * Strips any of a set of characters from the start and end of every String in an array.
7866     * <p>
7867     * Whitespace is defined by {@link Character#isWhitespace(char)}.
7868     * </p>
7869     *
7870     * <p>
7871     * A new array is returned each time, except for length zero. A {@code null} array will return {@code null}. An empty array will return itself. A
7872     * {@code null} array entry will be ignored. A {@code null} stripChars will strip whitespace as defined by {@link Character#isWhitespace(char)}.
7873     * </p>
7874     *
7875     * <pre>
7876     * StringUtils.stripAll(null, *)                = null
7877     * StringUtils.stripAll([], *)                  = []
7878     * StringUtils.stripAll(["abc", "  abc"], null) = ["abc", "abc"]
7879     * StringUtils.stripAll(["abc  ", null], null)  = ["abc", null]
7880     * StringUtils.stripAll(["abc  ", null], "yz")  = ["abc  ", null]
7881     * StringUtils.stripAll(["yabcz", null], "yz")  = ["abc", null]
7882     * </pre>
7883     *
7884     * @param strs       the array to remove characters from, may be null.
7885     * @param stripChars the characters to remove, null treated as whitespace.
7886     * @return the stripped Strings, {@code null} if null array input.
7887     */
7888    public static String[] stripAll(final String[] strs, final String stripChars) {
7889        final int strsLen = ArrayUtils.getLength(strs);
7890        if (strsLen == 0) {
7891            return strs;
7892        }
7893        final String[] newArr = new String[strsLen];
7894        Arrays.setAll(newArr, i -> strip(strs[i], stripChars));
7895        return newArr;
7896    }
7897
7898    /**
7899     * Strips any of a set of characters from the end of a String.
7900     *
7901     * <p>
7902     * A {@code null} input String returns {@code null}. An empty string ("") input returns the empty string.
7903     * </p>
7904     *
7905     * <p>
7906     * If the stripChars String is {@code null}, whitespace is stripped as defined by {@link Character#isWhitespace(char)}.
7907     * </p>
7908     *
7909     * <pre>
7910     * StringUtils.stripEnd(null, *)          = null
7911     * StringUtils.stripEnd("", *)            = ""
7912     * StringUtils.stripEnd("abc", "")        = "abc"
7913     * StringUtils.stripEnd("abc", null)      = "abc"
7914     * StringUtils.stripEnd("  abc", null)    = "  abc"
7915     * StringUtils.stripEnd("abc  ", null)    = "abc"
7916     * StringUtils.stripEnd(" abc ", null)    = " abc"
7917     * StringUtils.stripEnd("  abcyx", "xyz") = "  abc"
7918     * StringUtils.stripEnd("120.00", ".0")   = "12"
7919     * </pre>
7920     *
7921     * @param str        the String to remove characters from, may be null.
7922     * @param stripChars the set of characters to remove, null treated as whitespace.
7923     * @return the stripped String, {@code null} if null String input.
7924     */
7925    public static String stripEnd(final String str, final String stripChars) {
7926        int end = length(str);
7927        if (end == 0) {
7928            return str;
7929        }
7930        if (stripChars == null) {
7931            while (end != 0 && Character.isWhitespace(str.charAt(end - 1))) {
7932                end--;
7933            }
7934        } else if (stripChars.isEmpty()) {
7935            return str;
7936        } else {
7937            while (end != 0 && stripChars.indexOf(str.charAt(end - 1)) != INDEX_NOT_FOUND) {
7938                end--;
7939            }
7940        }
7941        return str.substring(0, end);
7942    }
7943
7944    /**
7945     * Strips any of a set of characters from the start of a String.
7946     *
7947     * <p>
7948     * A {@code null} input String returns {@code null}. An empty string ("") input returns the empty string.
7949     * </p>
7950     *
7951     * <p>
7952     * If the stripChars String is {@code null}, whitespace is stripped as defined by {@link Character#isWhitespace(char)}.
7953     * </p>
7954     *
7955     * <pre>
7956     * StringUtils.stripStart(null, *)          = null
7957     * StringUtils.stripStart("", *)            = ""
7958     * StringUtils.stripStart("abc", "")        = "abc"
7959     * StringUtils.stripStart("abc", null)      = "abc"
7960     * StringUtils.stripStart("  abc", null)    = "abc"
7961     * StringUtils.stripStart("abc  ", null)    = "abc  "
7962     * StringUtils.stripStart(" abc ", null)    = "abc "
7963     * StringUtils.stripStart("yxabc  ", "xyz") = "abc  "
7964     * </pre>
7965     *
7966     * @param str        the String to remove characters from, may be null.
7967     * @param stripChars the characters to remove, null treated as whitespace.
7968     * @return the stripped String, {@code null} if null String input.
7969     */
7970    public static String stripStart(final String str, final String stripChars) {
7971        final int strLen = length(str);
7972        if (strLen == 0) {
7973            return str;
7974        }
7975        int start = 0;
7976        if (stripChars == null) {
7977            while (start != strLen && Character.isWhitespace(str.charAt(start))) {
7978                start++;
7979            }
7980        } else if (stripChars.isEmpty()) {
7981            return str;
7982        } else {
7983            while (start != strLen && stripChars.indexOf(str.charAt(start)) != INDEX_NOT_FOUND) {
7984                start++;
7985            }
7986        }
7987        return str.substring(start);
7988    }
7989
7990    /**
7991     * Strips whitespace from the start and end of a String returning an empty String if {@code null} input.
7992     *
7993     * <p>
7994     * This is similar to {@link #trimToEmpty(String)} but removes whitespace. Whitespace is defined by {@link Character#isWhitespace(char)}.
7995     * </p>
7996     *
7997     * <pre>
7998     * StringUtils.stripToEmpty(null)     = ""
7999     * StringUtils.stripToEmpty("")       = ""
8000     * StringUtils.stripToEmpty("   ")    = ""
8001     * StringUtils.stripToEmpty("abc")    = "abc"
8002     * StringUtils.stripToEmpty("  abc")  = "abc"
8003     * StringUtils.stripToEmpty("abc  ")  = "abc"
8004     * StringUtils.stripToEmpty(" abc ")  = "abc"
8005     * StringUtils.stripToEmpty(" ab c ") = "ab c"
8006     * </pre>
8007     *
8008     * @param str the String to be stripped, may be null.
8009     * @return the trimmed String, or an empty String if {@code null} input.
8010     * @since 2.0
8011     */
8012    public static String stripToEmpty(final String str) {
8013        return str == null ? EMPTY : strip(str, null);
8014    }
8015
8016    /**
8017     * Strips whitespace from the start and end of a String returning {@code null} if the String is empty ("") after the strip.
8018     *
8019     * <p>
8020     * This is similar to {@link #trimToNull(String)} but removes whitespace. Whitespace is defined by {@link Character#isWhitespace(char)}.
8021     * </p>
8022     *
8023     * <pre>
8024     * StringUtils.stripToNull(null)     = null
8025     * StringUtils.stripToNull("")       = null
8026     * StringUtils.stripToNull("   ")    = null
8027     * StringUtils.stripToNull("abc")    = "abc"
8028     * StringUtils.stripToNull("  abc")  = "abc"
8029     * StringUtils.stripToNull("abc  ")  = "abc"
8030     * StringUtils.stripToNull(" abc ")  = "abc"
8031     * StringUtils.stripToNull(" ab c ") = "ab c"
8032     * </pre>
8033     *
8034     * @param str the String to be stripped, may be null.
8035     * @return the stripped String, {@code null} if whitespace, empty or null String input.
8036     * @since 2.0
8037     */
8038    public static String stripToNull(String str) {
8039        if (str == null) {
8040            return null;
8041        }
8042        str = strip(str, null);
8043        return str.isEmpty() ? null : str; // NOSONARLINT str cannot be null here
8044    }
8045
8046    /**
8047     * Gets a substring from the specified String avoiding exceptions.
8048     *
8049     * <p>
8050     * A negative start position can be used to start {@code n} characters from the end of the String.
8051     * </p>
8052     *
8053     * <p>
8054     * A {@code null} String will return {@code null}. An empty ("") String will return "".
8055     * </p>
8056     *
8057     * <pre>
8058     * StringUtils.substring(null, *)   = null
8059     * StringUtils.substring("", *)     = ""
8060     * StringUtils.substring("abc", 0)  = "abc"
8061     * StringUtils.substring("abc", 2)  = "c"
8062     * StringUtils.substring("abc", 4)  = ""
8063     * StringUtils.substring("abc", -2) = "bc"
8064     * StringUtils.substring("abc", -4) = "abc"
8065     * </pre>
8066     *
8067     * @param str   the String to get the substring from, may be null.
8068     * @param start the position to start from, negative means count back from the end of the String by this many characters.
8069     * @return substring from start position, {@code null} if null String input.
8070     */
8071    public static String substring(final String str, int start) {
8072        if (str == null) {
8073            return null;
8074        }
8075        // handle negatives, which means last n characters
8076        if (start < 0) {
8077            start = str.length() + start; // remember start is negative
8078        }
8079        if (start < 0) {
8080            start = 0;
8081        }
8082        if (start > str.length()) {
8083            return EMPTY;
8084        }
8085        return str.substring(start);
8086    }
8087
8088    /**
8089     * Gets a substring from the specified String avoiding exceptions.
8090     *
8091     * <p>
8092     * A negative start position can be used to start/end {@code n} characters from the end of the String.
8093     * </p>
8094     *
8095     * <p>
8096     * The returned substring starts with the character in the {@code start} position and ends before the {@code end} position. All position counting is
8097     * zero-based -- i.e., to start at the beginning of the string use {@code start = 0}. Negative start and end positions can be used to specify offsets
8098     * relative to the end of the String.
8099     * </p>
8100     *
8101     * <p>
8102     * If {@code start} is not strictly to the left of {@code end}, "" is returned.
8103     * </p>
8104     *
8105     * <pre>
8106     * StringUtils.substring(null, *, *)    = null
8107     * StringUtils.substring("", * ,  *)    = "";
8108     * StringUtils.substring("abc", 0, 2)   = "ab"
8109     * StringUtils.substring("abc", 2, 0)   = ""
8110     * StringUtils.substring("abc", 2, 4)   = "c"
8111     * StringUtils.substring("abc", 4, 6)   = ""
8112     * StringUtils.substring("abc", 2, 2)   = ""
8113     * StringUtils.substring("abc", -2, -1) = "b"
8114     * StringUtils.substring("abc", -4, 2)  = "ab"
8115     * </pre>
8116     *
8117     * @param str   the String to get the substring from, may be null.
8118     * @param start the position to start from, negative means count back from the end of the String by this many characters.
8119     * @param end   the position to end at (exclusive), negative means count back from the end of the String by this many characters.
8120     * @return substring from start position to end position, {@code null} if null String input.
8121     */
8122    public static String substring(final String str, int start, int end) {
8123        if (str == null) {
8124            return null;
8125        }
8126        // handle negatives
8127        if (end < 0) {
8128            end = str.length() + end; // remember end is negative
8129        }
8130        if (start < 0) {
8131            start = str.length() + start; // remember start is negative
8132        }
8133        // check length next
8134        if (end > str.length()) {
8135            end = str.length();
8136        }
8137        // if start is greater than end, return ""
8138        if (start > end) {
8139            return EMPTY;
8140        }
8141        if (start < 0) {
8142            start = 0;
8143        }
8144        if (end < 0) {
8145            end = 0;
8146        }
8147        return str.substring(start, end);
8148    }
8149
8150    /**
8151     * Gets the substring after the first occurrence of a separator. The separator is not returned.
8152     *
8153     * <p>
8154     * A {@code null} string input will return {@code null}. An empty ("") string input will return the empty string.
8155     *
8156     * <p>
8157     * If nothing is found, the empty string is returned.
8158     * </p>
8159     *
8160     * <pre>
8161     * StringUtils.substringAfter(null, *)      = null
8162     * StringUtils.substringAfter("", *)        = ""
8163     * StringUtils.substringAfter("abc", 'a')   = "bc"
8164     * StringUtils.substringAfter("abcba", 'b') = "cba"
8165     * StringUtils.substringAfter("abc", 'c')   = ""
8166     * StringUtils.substringAfter("abc", 'd')   = ""
8167     * StringUtils.substringAfter(" abc", 32)   = "abc"
8168     * </pre>
8169     *
8170     * @param str       the String to get a substring from, may be null.
8171     * @param separator the character (Unicode code point) to search.
8172     * @return the substring after the first occurrence of the separator, {@code null} if null String input.
8173     * @since 3.11
8174     */
8175    public static String substringAfter(final String str, final int separator) {
8176        if (isEmpty(str)) {
8177            return str;
8178        }
8179        final int pos = str.indexOf(separator);
8180        if (pos == INDEX_NOT_FOUND) {
8181            return EMPTY;
8182        }
8183        return str.substring(pos + 1);
8184    }
8185
8186    /**
8187     * Gets the substring after the first occurrence of a separator. The separator is not returned.
8188     *
8189     * <p>
8190     * A {@code null} string input will return {@code null}. An empty ("") string input will return the empty string. A {@code null} separator will return the
8191     * empty string if the input string is not {@code null}.
8192     * </p>
8193     *
8194     * <p>
8195     * If nothing is found, the empty string is returned.
8196     * </p>
8197     *
8198     * <pre>
8199     * StringUtils.substringAfter(null, *)      = null
8200     * StringUtils.substringAfter("", *)        = ""
8201     * StringUtils.substringAfter(*, null)      = ""
8202     * StringUtils.substringAfter("abc", "a")   = "bc"
8203     * StringUtils.substringAfter("abcba", "b") = "cba"
8204     * StringUtils.substringAfter("abc", "c")   = ""
8205     * StringUtils.substringAfter("abc", "d")   = ""
8206     * StringUtils.substringAfter("abc", "")    = "abc"
8207     * </pre>
8208     *
8209     * @param str       the String to get a substring from, may be null.
8210     * @param separator the String to search for, may be null.
8211     * @return the substring after the first occurrence of the separator, {@code null} if null String input.
8212     * @since 2.0
8213     */
8214    public static String substringAfter(final String str, final String separator) {
8215        if (isEmpty(str)) {
8216            return str;
8217        }
8218        if (separator == null) {
8219            return EMPTY;
8220        }
8221        final int pos = str.indexOf(separator);
8222        if (pos == INDEX_NOT_FOUND) {
8223            return EMPTY;
8224        }
8225        return str.substring(pos + separator.length());
8226    }
8227
8228    /**
8229     * Gets the substring after the last occurrence of a separator. The separator is not returned.
8230     *
8231     * <p>
8232     * A {@code null} string input will return {@code null}. An empty ("") string input will return the empty string.
8233     *
8234     * <p>
8235     * If nothing is found, the empty string is returned.
8236     * </p>
8237     *
8238     * <pre>
8239     * StringUtils.substringAfterLast(null, *)      = null
8240     * StringUtils.substringAfterLast("", *)        = ""
8241     * StringUtils.substringAfterLast("abc", 'a')   = "bc"
8242     * StringUtils.substringAfterLast(" bc", 32)    = "bc"
8243     * StringUtils.substringAfterLast("abcba", 'b') = "a"
8244     * StringUtils.substringAfterLast("abc", 'c')   = ""
8245     * StringUtils.substringAfterLast("a", 'a')     = ""
8246     * StringUtils.substringAfterLast("a", 'z')     = ""
8247     * </pre>
8248     *
8249     * @param str       the String to get a substring from, may be null.
8250     * @param separator the character (Unicode code point) to search.
8251     * @return the substring after the last occurrence of the separator, {@code null} if null String input.
8252     * @since 3.11
8253     */
8254    public static String substringAfterLast(final String str, final int separator) {
8255        if (isEmpty(str)) {
8256            return str;
8257        }
8258        final int pos = str.lastIndexOf(separator);
8259        if (pos == INDEX_NOT_FOUND || pos == str.length() - 1) {
8260            return EMPTY;
8261        }
8262        return str.substring(pos + 1);
8263    }
8264
8265    /**
8266     * Gets the substring after the last occurrence of a separator. The separator is not returned.
8267     *
8268     * <p>
8269     * A {@code null} string input will return {@code null}. An empty ("") string input will return the empty string. An empty or {@code null} separator will
8270     * return the empty string if the input string is not {@code null}.
8271     * </p>
8272     *
8273     * <p>
8274     * If nothing is found, the empty string is returned.
8275     * </p>
8276     *
8277     * <pre>
8278     * StringUtils.substringAfterLast(null, *)      = null
8279     * StringUtils.substringAfterLast("", *)        = ""
8280     * StringUtils.substringAfterLast(*, "")        = ""
8281     * StringUtils.substringAfterLast(*, null)      = ""
8282     * StringUtils.substringAfterLast("abc", "a")   = "bc"
8283     * StringUtils.substringAfterLast("abcba", "b") = "a"
8284     * StringUtils.substringAfterLast("abc", "c")   = ""
8285     * StringUtils.substringAfterLast("a", "a")     = ""
8286     * StringUtils.substringAfterLast("a", "z")     = ""
8287     * </pre>
8288     *
8289     * @param str       the String to get a substring from, may be null.
8290     * @param separator the String to search for, may be null.
8291     * @return the substring after the last occurrence of the separator, {@code null} if null String input.
8292     * @since 2.0
8293     */
8294    public static String substringAfterLast(final String str, final String separator) {
8295        if (isEmpty(str)) {
8296            return str;
8297        }
8298        if (isEmpty(separator)) {
8299            return EMPTY;
8300        }
8301        final int pos = str.lastIndexOf(separator);
8302        if (pos == INDEX_NOT_FOUND || pos == str.length() - separator.length()) {
8303            return EMPTY;
8304        }
8305        return str.substring(pos + separator.length());
8306    }
8307
8308    /**
8309     * Gets the substring before the first occurrence of a separator. The separator is not returned.
8310     *
8311     * <p>
8312     * A {@code null} string input will return {@code null}. An empty ("") string input will return the empty string.
8313     * </p>
8314     *
8315     * <p>
8316     * If nothing is found, the string input is returned.
8317     * </p>
8318     *
8319     * <pre>
8320     * StringUtils.substringBefore(null, *)      = null
8321     * StringUtils.substringBefore("", *)        = ""
8322     * StringUtils.substringBefore("abc", 'a')   = ""
8323     * StringUtils.substringBefore("abcba", 'b') = "a"
8324     * StringUtils.substringBefore("abc", 'c')   = "ab"
8325     * StringUtils.substringBefore("abc", 'd')   = "abc"
8326     * </pre>
8327     *
8328     * @param str       the String to get a substring from, may be null.
8329     * @param separator the character (Unicode code point) to search.
8330     * @return the substring before the first occurrence of the separator, {@code null} if null String input.
8331     * @since 3.12.0
8332     */
8333    public static String substringBefore(final String str, final int separator) {
8334        if (isEmpty(str)) {
8335            return str;
8336        }
8337        final int pos = str.indexOf(separator);
8338        if (pos == INDEX_NOT_FOUND) {
8339            return str;
8340        }
8341        return str.substring(0, pos);
8342    }
8343
8344    /**
8345     * Gets the substring before the first occurrence of a separator. The separator is not returned.
8346     *
8347     * <p>
8348     * A {@code null} string input will return {@code null}. An empty ("") string input will return the empty string. A {@code null} separator will return the
8349     * input string.
8350     * </p>
8351     *
8352     * <p>
8353     * If nothing is found, the string input is returned.
8354     * </p>
8355     *
8356     * <pre>
8357     * StringUtils.substringBefore(null, *)      = null
8358     * StringUtils.substringBefore("", *)        = ""
8359     * StringUtils.substringBefore("abc", "a")   = ""
8360     * StringUtils.substringBefore("abcba", "b") = "a"
8361     * StringUtils.substringBefore("abc", "c")   = "ab"
8362     * StringUtils.substringBefore("abc", "d")   = "abc"
8363     * StringUtils.substringBefore("abc", "")    = ""
8364     * StringUtils.substringBefore("abc", null)  = "abc"
8365     * </pre>
8366     *
8367     * @param str       the String to get a substring from, may be null.
8368     * @param separator the String to search for, may be null.
8369     * @return the substring before the first occurrence of the separator, {@code null} if null String input.
8370     * @since 2.0
8371     */
8372    public static String substringBefore(final String str, final String separator) {
8373        if (isEmpty(str) || separator == null) {
8374            return str;
8375        }
8376        if (separator.isEmpty()) {
8377            return EMPTY;
8378        }
8379        final int pos = str.indexOf(separator);
8380        if (pos == INDEX_NOT_FOUND) {
8381            return str;
8382        }
8383        return str.substring(0, pos);
8384    }
8385
8386    /**
8387     * Gets the substring before the last occurrence of a separator. The separator is not returned.
8388     *
8389     * <p>
8390     * A {@code null} string input will return {@code null}. An empty ("") string input will return the empty string. An empty or {@code null} separator will
8391     * return the input string.
8392     * </p>
8393     *
8394     * <p>
8395     * If nothing is found, the string input is returned.
8396     * </p>
8397     *
8398     * <pre>
8399     * StringUtils.substringBeforeLast(null, *)      = null
8400     * StringUtils.substringBeforeLast("", *)        = ""
8401     * StringUtils.substringBeforeLast("abcba", "b") = "abc"
8402     * StringUtils.substringBeforeLast("abc", "c")   = "ab"
8403     * StringUtils.substringBeforeLast("a", "a")     = ""
8404     * StringUtils.substringBeforeLast("a", "z")     = "a"
8405     * StringUtils.substringBeforeLast("a", null)    = "a"
8406     * StringUtils.substringBeforeLast("a", "")      = "a"
8407     * </pre>
8408     *
8409     * @param str       the String to get a substring from, may be null.
8410     * @param separator the String to search for, may be null.
8411     * @return the substring before the last occurrence of the separator, {@code null} if null String input.
8412     * @since 2.0
8413     */
8414    public static String substringBeforeLast(final String str, final String separator) {
8415        if (isEmpty(str) || isEmpty(separator)) {
8416            return str;
8417        }
8418        final int pos = str.lastIndexOf(separator);
8419        if (pos == INDEX_NOT_FOUND) {
8420            return str;
8421        }
8422        return str.substring(0, pos);
8423    }
8424
8425    /**
8426     * Gets the String that is nested in between two instances of the same String.
8427     *
8428     * <p>
8429     * A {@code null} input String returns {@code null}. A {@code null} tag returns {@code null}.
8430     * </p>
8431     *
8432     * <pre>
8433     * StringUtils.substringBetween(null, *)            = null
8434     * StringUtils.substringBetween("", "")             = ""
8435     * StringUtils.substringBetween("", "tag")          = null
8436     * StringUtils.substringBetween("tagabctag", null)  = null
8437     * StringUtils.substringBetween("tagabctag", "")    = ""
8438     * StringUtils.substringBetween("tagabctag", "tag") = "abc"
8439     * </pre>
8440     *
8441     * @param str the String containing the substring, may be null.
8442     * @param tag the String before and after the substring, may be null.
8443     * @return the substring, {@code null} if no match.
8444     * @since 2.0
8445     */
8446    public static String substringBetween(final String str, final String tag) {
8447        return substringBetween(str, tag, tag);
8448    }
8449
8450    /**
8451     * Gets the String that is nested in between two Strings. Only the first match is returned.
8452     *
8453     * <p>
8454     * A {@code null} input String returns {@code null}. A {@code null} open/close returns {@code null} (no match). An empty ("") open and close returns an
8455     * empty string.
8456     * </p>
8457     *
8458     * <pre>
8459     * StringUtils.substringBetween("wx[b]yz", "[", "]") = "b"
8460     * StringUtils.substringBetween(null, *, *)          = null
8461     * StringUtils.substringBetween(*, null, *)          = null
8462     * StringUtils.substringBetween(*, *, null)          = null
8463     * StringUtils.substringBetween("", "", "")          = ""
8464     * StringUtils.substringBetween("", "", "]")         = null
8465     * StringUtils.substringBetween("", "[", "]")        = null
8466     * StringUtils.substringBetween("yabcz", "", "")     = ""
8467     * StringUtils.substringBetween("yabcz", "y", "z")   = "abc"
8468     * StringUtils.substringBetween("yabczyabcz", "y", "z")   = "abc"
8469     * </pre>
8470     *
8471     * @param str   the String containing the substring, may be null.
8472     * @param open  the String before the substring, may be null.
8473     * @param close the String after the substring, may be null.
8474     * @return the substring, {@code null} if no match.
8475     * @since 2.0
8476     */
8477    public static String substringBetween(final String str, final String open, final String close) {
8478        if (!ObjectUtils.allNotNull(str, open, close)) {
8479            return null;
8480        }
8481        final int start = str.indexOf(open);
8482        if (start != INDEX_NOT_FOUND) {
8483            final int end = str.indexOf(close, start + open.length());
8484            if (end != INDEX_NOT_FOUND) {
8485                return str.substring(start + open.length(), end);
8486            }
8487        }
8488        return null;
8489    }
8490
8491    /**
8492     * Searches a String for substrings delimited by a start and end tag, returning all matching substrings in an array.
8493     *
8494     * <p>
8495     * A {@code null} input String returns {@code null}. A {@code null} open/close returns {@code null} (no match). An empty ("") open/close returns
8496     * {@code null} (no match).
8497     * </p>
8498     *
8499     * <pre>
8500     * StringUtils.substringsBetween("[a][b][c]", "[", "]") = ["a","b","c"]
8501     * StringUtils.substringsBetween(null, *, *)            = null
8502     * StringUtils.substringsBetween(*, null, *)            = null
8503     * StringUtils.substringsBetween(*, *, null)            = null
8504     * StringUtils.substringsBetween("", "[", "]")          = []
8505     * </pre>
8506     *
8507     * @param str   the String containing the substrings, null returns null, empty returns empty.
8508     * @param open  the String identifying the start of the substring, empty returns null.
8509     * @param close the String identifying the end of the substring, empty returns null.
8510     * @return a String Array of substrings, or {@code null} if no match.
8511     * @since 2.3
8512     */
8513    public static String[] substringsBetween(final String str, final String open, final String close) {
8514        if (str == null || isEmpty(open) || isEmpty(close)) {
8515            return null;
8516        }
8517        final int strLen = str.length();
8518        if (strLen == 0) {
8519            return ArrayUtils.EMPTY_STRING_ARRAY;
8520        }
8521        final int closeLen = close.length();
8522        final int openLen = open.length();
8523        final List<String> list = new ArrayList<>();
8524        int pos = 0;
8525        while (pos < strLen - closeLen) {
8526            int start = str.indexOf(open, pos);
8527            if (start < 0) {
8528                break;
8529            }
8530            start += openLen;
8531            final int end = str.indexOf(close, start);
8532            if (end < 0) {
8533                break;
8534            }
8535            list.add(str.substring(start, end));
8536            pos = end + closeLen;
8537        }
8538        if (list.isEmpty()) {
8539            return null;
8540        }
8541        return list.toArray(ArrayUtils.EMPTY_STRING_ARRAY);
8542    }
8543
8544    /**
8545     * Swaps the case of a String changing upper and title case to lower case, and lower case to upper case.
8546     *
8547     * <ul>
8548     * <li>Upper case character converts to Lower case</li>
8549     * <li>Title case character converts to Lower case</li>
8550     * <li>Lower case character converts to Upper case</li>
8551     * </ul>
8552     *
8553     * <p>
8554     * For a word based algorithm, see {@link org.apache.commons.text.WordUtils#swapCase(String)}. A {@code null} input String returns {@code null}.
8555     * </p>
8556     *
8557     * <pre>
8558     * StringUtils.swapCase(null)                 = null
8559     * StringUtils.swapCase("")                   = ""
8560     * StringUtils.swapCase("The dog has a BONE") = "tHE DOG HAS A bone"
8561     * </pre>
8562     *
8563     * <p>
8564     * NOTE: This method changed in Lang version 2.0. It no longer performs a word based algorithm. If you only use ASCII, you will notice no change. That
8565     * functionality is available in org.apache.commons.lang3.text.WordUtils.
8566     * </p>
8567     *
8568     * @param str the String to swap case, may be null.
8569     * @return the changed String, {@code null} if null String input.
8570     */
8571    public static String swapCase(final String str) {
8572        if (isEmpty(str)) {
8573            return str;
8574        }
8575        final int strLen = str.length();
8576        final int[] newCodePoints = new int[strLen]; // cannot be longer than the char array
8577        int outOffset = 0;
8578        for (int i = 0; i < strLen;) {
8579            final int oldCodepoint = str.codePointAt(i);
8580            final int newCodePoint;
8581            if (Character.isUpperCase(oldCodepoint) || Character.isTitleCase(oldCodepoint)) {
8582                newCodePoint = Character.toLowerCase(oldCodepoint);
8583            } else if (Character.isLowerCase(oldCodepoint)) {
8584                newCodePoint = Character.toUpperCase(oldCodepoint);
8585            } else {
8586                newCodePoint = oldCodepoint;
8587            }
8588            newCodePoints[outOffset++] = newCodePoint;
8589            i += Character.charCount(newCodePoint);
8590        }
8591        return new String(newCodePoints, 0, outOffset);
8592    }
8593
8594    /**
8595     * Converts a {@link CharSequence} into an array of code points.
8596     *
8597     * <p>
8598     * Valid pairs of surrogate code units will be converted into a single supplementary code point. Isolated surrogate code units (i.e. a high surrogate not
8599     * followed by a low surrogate or a low surrogate not preceded by a high surrogate) will be returned as-is.
8600     * </p>
8601     *
8602     * <pre>
8603     * StringUtils.toCodePoints(null)   =  null
8604     * StringUtils.toCodePoints("")     =  []  // empty array
8605     * </pre>
8606     *
8607     * @param cs the character sequence to convert.
8608     * @return an array of code points.
8609     * @since 3.6
8610     */
8611    public static int[] toCodePoints(final CharSequence cs) {
8612        if (cs == null) {
8613            return null;
8614        }
8615        if (cs.length() == 0) {
8616            return ArrayUtils.EMPTY_INT_ARRAY;
8617        }
8618        return cs.toString().codePoints().toArray();
8619    }
8620
8621    /**
8622     * Converts a {@code byte[]} to a String using the specified character encoding.
8623     *
8624     * @param bytes   the byte array to read from.
8625     * @param charset the encoding to use, if null then use the platform default.
8626     * @return a new String.
8627     * @throws NullPointerException if {@code bytes} is null
8628     * @since 3.2
8629     * @since 3.3 No longer throws {@link UnsupportedEncodingException}.
8630     */
8631    public static String toEncodedString(final byte[] bytes, final Charset charset) {
8632        return new String(bytes, Charsets.toCharset(charset));
8633    }
8634
8635    /**
8636     * Converts the given source String as a lower-case using the {@link Locale#ROOT} locale in a null-safe manner.
8637     *
8638     * @param source A source String or null.
8639     * @return the given source String as a lower-case using the {@link Locale#ROOT} locale or null.
8640     * @since 3.10
8641     */
8642    public static String toRootLowerCase(final String source) {
8643        return source == null ? null : source.toLowerCase(Locale.ROOT);
8644    }
8645
8646    /**
8647     * Converts the given source String as an upper-case using the {@link Locale#ROOT} locale in a null-safe manner.
8648     *
8649     * @param source A source String or null.
8650     * @return the given source String as an upper-case using the {@link Locale#ROOT} locale or null.
8651     * @since 3.10
8652     */
8653    public static String toRootUpperCase(final String source) {
8654        return source == null ? null : source.toUpperCase(Locale.ROOT);
8655    }
8656
8657    /**
8658     * Converts a {@code byte[]} to a String using the specified character encoding.
8659     *
8660     * @param bytes       the byte array to read from.
8661     * @param charsetName the encoding to use, if null then use the platform default.
8662     * @return a new String.
8663     * @throws NullPointerException if the input is null.
8664     * @deprecated use {@link StringUtils#toEncodedString(byte[], Charset)} instead of String constants in your code
8665     * @since 3.1
8666     */
8667    @Deprecated
8668    public static String toString(final byte[] bytes, final String charsetName) {
8669        return new String(bytes, Charsets.toCharset(charsetName));
8670    }
8671
8672    /**
8673     * Removes control characters (char &lt;= 32) from both ends of this String, handling {@code null} by returning {@code null}.
8674     *
8675     * <p>
8676     * The String is trimmed using {@link String#trim()}. Trim removes start and end characters &lt;= 32. To strip whitespace use {@link #strip(String)}.
8677     * </p>
8678     *
8679     * <p>
8680     * To trim your choice of characters, use the {@link #strip(String, String)} methods.
8681     * </p>
8682     *
8683     * <pre>
8684     * StringUtils.trim(null)          = null
8685     * StringUtils.trim("")            = ""
8686     * StringUtils.trim("     ")       = ""
8687     * StringUtils.trim("abc")         = "abc"
8688     * StringUtils.trim("    abc    ") = "abc"
8689     * </pre>
8690     *
8691     * @param str the String to be trimmed, may be null.
8692     * @return the trimmed string, {@code null} if null String input.
8693     */
8694    public static String trim(final String str) {
8695        return str == null ? null : str.trim();
8696    }
8697
8698    /**
8699     * Removes control characters (char &lt;= 32) from both ends of this String returning an empty String ("") if the String is empty ("") after the trim or if
8700     * it is {@code null}.
8701     *
8702     * <p>
8703     * The String is trimmed using {@link String#trim()}. Trim removes start and end characters &lt;= 32. To strip whitespace use {@link #stripToEmpty(String)}.
8704     *
8705     * <pre>
8706     * StringUtils.trimToEmpty(null)          = ""
8707     * StringUtils.trimToEmpty("")            = ""
8708     * StringUtils.trimToEmpty("     ")       = ""
8709     * StringUtils.trimToEmpty("abc")         = "abc"
8710     * StringUtils.trimToEmpty("    abc    ") = "abc"
8711     * </pre>
8712     *
8713     * @param str the String to be trimmed, may be null.
8714     * @return the trimmed String, or an empty String if {@code null} input.
8715     * @since 2.0
8716     */
8717    public static String trimToEmpty(final String str) {
8718        return str == null ? EMPTY : str.trim();
8719    }
8720
8721    /**
8722     * Removes control characters (char &lt;= 32) from both ends of this String returning {@code null} if the String is empty ("") after the trim or if it is
8723     * {@code null}.
8724     *
8725     * <p>
8726     * The String is trimmed using {@link String#trim()}. Trim removes start and end characters &lt;= 32. To strip whitespace use {@link #stripToNull(String)}.
8727     *
8728     * <pre>
8729     * StringUtils.trimToNull(null)          = null
8730     * StringUtils.trimToNull("")            = null
8731     * StringUtils.trimToNull("     ")       = null
8732     * StringUtils.trimToNull("abc")         = "abc"
8733     * StringUtils.trimToNull("    abc    ") = "abc"
8734     * </pre>
8735     *
8736     * @param str the String to be trimmed, may be null.
8737     * @return the trimmed String, {@code null} if only chars &lt;= 32, empty or null String input.
8738     * @since 2.0
8739     */
8740    public static String trimToNull(final String str) {
8741        final String ts = trim(str);
8742        return isEmpty(ts) ? null : ts;
8743    }
8744
8745    /**
8746     * Truncates a String. This will turn "Now is the time for all good men" into "Now is the time for".
8747     *
8748     * <p>
8749     * Specifically:
8750     * </p>
8751     * <ul>
8752     * <li>If {@code str} is less than {@code maxWidth} characters long, return it.</li>
8753     * <li>Else truncate it to {@code substring(str, 0, maxWidth)}.</li>
8754     * <li>If {@code maxWidth} is less than {@code 0}, throw an {@link IllegalArgumentException}.</li>
8755     * <li>In no case will it return a String of length greater than {@code maxWidth}.</li>
8756     * </ul>
8757     *
8758     * <pre>
8759     * StringUtils.truncate(null, 0)       = null
8760     * StringUtils.truncate(null, 2)       = null
8761     * StringUtils.truncate("", 4)         = ""
8762     * StringUtils.truncate("abcdefg", 4)  = "abcd"
8763     * StringUtils.truncate("abcdefg", 6)  = "abcdef"
8764     * StringUtils.truncate("abcdefg", 7)  = "abcdefg"
8765     * StringUtils.truncate("abcdefg", 8)  = "abcdefg"
8766     * StringUtils.truncate("abcdefg", -1) = throws an IllegalArgumentException
8767     * </pre>
8768     *
8769     * @param str      the String to truncate, may be null.
8770     * @param maxWidth maximum length of result String, must be positive.
8771     * @return truncated String, {@code null} if null String input.
8772     * @throws IllegalArgumentException If {@code maxWidth} is less than {@code 0}.
8773     * @since 3.5
8774     */
8775    public static String truncate(final String str, final int maxWidth) {
8776        return truncate(str, 0, maxWidth);
8777    }
8778
8779    /**
8780     * Truncates a String. This will turn "Now is the time for all good men" into "is the time for all".
8781     *
8782     * <p>
8783     * Works like {@code truncate(String, int)}, but allows you to specify a "left edge" offset.
8784     *
8785     * <p>
8786     * Specifically:
8787     * </p>
8788     * <ul>
8789     * <li>If {@code str} is less than {@code maxWidth} characters long, return it.</li>
8790     * <li>Else truncate it to {@code substring(str, offset, maxWidth)}.</li>
8791     * <li>If {@code maxWidth} is less than {@code 0}, throw an {@link IllegalArgumentException}.</li>
8792     * <li>If {@code offset} is less than {@code 0}, throw an {@link IllegalArgumentException}.</li>
8793     * <li>In no case will it return a String of length greater than {@code maxWidth}.</li>
8794     * </ul>
8795     *
8796     * <pre>
8797     * StringUtils.truncate(null, 0, 0) = null
8798     * StringUtils.truncate(null, 2, 4) = null
8799     * StringUtils.truncate("", 0, 10) = ""
8800     * StringUtils.truncate("", 2, 10) = ""
8801     * StringUtils.truncate("abcdefghij", 0, 3) = "abc"
8802     * StringUtils.truncate("abcdefghij", 5, 6) = "fghij"
8803     * StringUtils.truncate("raspberry peach", 10, 15) = "peach"
8804     * StringUtils.truncate("abcdefghijklmno", 0, 10) = "abcdefghij"
8805     * StringUtils.truncate("abcdefghijklmno", -1, 10) = throws an IllegalArgumentException
8806     * StringUtils.truncate("abcdefghijklmno", Integer.MIN_VALUE, 10) = throws an IllegalArgumentException
8807     * StringUtils.truncate("abcdefghijklmno", Integer.MIN_VALUE, Integer.MAX_VALUE) = throws an IllegalArgumentException
8808     * StringUtils.truncate("abcdefghijklmno", 0, Integer.MAX_VALUE) = "abcdefghijklmno"
8809     * StringUtils.truncate("abcdefghijklmno", 1, 10) = "bcdefghijk"
8810     * StringUtils.truncate("abcdefghijklmno", 2, 10) = "cdefghijkl"
8811     * StringUtils.truncate("abcdefghijklmno", 3, 10) = "defghijklm"
8812     * StringUtils.truncate("abcdefghijklmno", 4, 10) = "efghijklmn"
8813     * StringUtils.truncate("abcdefghijklmno", 5, 10) = "fghijklmno"
8814     * StringUtils.truncate("abcdefghijklmno", 5, 5) = "fghij"
8815     * StringUtils.truncate("abcdefghijklmno", 5, 3) = "fgh"
8816     * StringUtils.truncate("abcdefghijklmno", 10, 3) = "klm"
8817     * StringUtils.truncate("abcdefghijklmno", 10, Integer.MAX_VALUE) = "klmno"
8818     * StringUtils.truncate("abcdefghijklmno", 13, 1) = "n"
8819     * StringUtils.truncate("abcdefghijklmno", 13, Integer.MAX_VALUE) = "no"
8820     * StringUtils.truncate("abcdefghijklmno", 14, 1) = "o"
8821     * StringUtils.truncate("abcdefghijklmno", 14, Integer.MAX_VALUE) = "o"
8822     * StringUtils.truncate("abcdefghijklmno", 15, 1) = ""
8823     * StringUtils.truncate("abcdefghijklmno", 15, Integer.MAX_VALUE) = ""
8824     * StringUtils.truncate("abcdefghijklmno", Integer.MAX_VALUE, Integer.MAX_VALUE) = ""
8825     * StringUtils.truncate("abcdefghij", 3, -1) = throws an IllegalArgumentException
8826     * StringUtils.truncate("abcdefghij", -2, 4) = throws an IllegalArgumentException
8827     * </pre>
8828     *
8829     * @param str      the String to truncate, may be null.
8830     * @param offset   left edge of source String.
8831     * @param maxWidth maximum length of result String, must be positive.
8832     * @return truncated String, {@code null} if null String input.
8833     * @throws IllegalArgumentException If {@code offset} or {@code maxWidth} is less than {@code 0}.
8834     * @since 3.5
8835     */
8836    public static String truncate(final String str, final int offset, final int maxWidth) {
8837        if (offset < 0) {
8838            throw new IllegalArgumentException("offset cannot be negative");
8839        }
8840        if (maxWidth < 0) {
8841            throw new IllegalArgumentException("maxWith cannot be negative");
8842        }
8843        if (str == null) {
8844            return null;
8845        }
8846        if (offset > str.length()) {
8847            return EMPTY;
8848        }
8849        if (str.length() > maxWidth) {
8850            final int ix = Math.min(offset + maxWidth, str.length());
8851            return str.substring(offset, ix);
8852        }
8853        return str.substring(offset);
8854    }
8855
8856    /**
8857     * Uncapitalizes a String, changing the first character to lower case as per {@link Character#toLowerCase(int)}. No other characters are changed.
8858     *
8859     * <p>
8860     * For a word based algorithm, see {@link org.apache.commons.text.WordUtils#uncapitalize(String)}. A {@code null} input String returns {@code null}.
8861     * </p>
8862     *
8863     * <pre>
8864     * StringUtils.uncapitalize(null)  = null
8865     * StringUtils.uncapitalize("")    = ""
8866     * StringUtils.uncapitalize("cat") = "cat"
8867     * StringUtils.uncapitalize("Cat") = "cat"
8868     * StringUtils.uncapitalize("CAT") = "cAT"
8869     * </pre>
8870     *
8871     * @param str the String to uncapitalize, may be null.
8872     * @return the uncapitalized String, {@code null} if null String input.
8873     * @see org.apache.commons.text.WordUtils#uncapitalize(String)
8874     * @see #capitalize(String)
8875     * @since 2.0
8876     */
8877    public static String uncapitalize(final String str) {
8878        final int strLen = length(str);
8879        if (strLen == 0) {
8880            return str;
8881        }
8882        final int firstCodePoint = str.codePointAt(0);
8883        final int newCodePoint = Character.toLowerCase(firstCodePoint);
8884        if (firstCodePoint == newCodePoint) {
8885            // already uncapitalized
8886            return str;
8887        }
8888        final int[] newCodePoints = str.codePoints().toArray();
8889        newCodePoints[0] = newCodePoint; // copy the first code point
8890        return new String(newCodePoints, 0, newCodePoints.length);
8891    }
8892
8893    /**
8894     * Unwraps a given string from a character.
8895     *
8896     * <pre>
8897     * StringUtils.unwrap(null, null)         = null
8898     * StringUtils.unwrap(null, '\0')         = null
8899     * StringUtils.unwrap(null, '1')          = null
8900     * StringUtils.unwrap("a", 'a')           = "a"
8901     * StringUtils.unwrap("aa", 'a')           = ""
8902     * StringUtils.unwrap("\'abc\'", '\'')    = "abc"
8903     * StringUtils.unwrap("AABabcBAA", 'A')   = "ABabcBA"
8904     * StringUtils.unwrap("A", '#')           = "A"
8905     * StringUtils.unwrap("#A", '#')          = "#A"
8906     * StringUtils.unwrap("A#", '#')          = "A#"
8907     * </pre>
8908     *
8909     * @param str      the String to be unwrapped, can be null.
8910     * @param wrapChar the character used to unwrap.
8911     * @return unwrapped String or the original string if it is not quoted properly with the wrapChar.
8912     * @since 3.6
8913     */
8914    public static String unwrap(final String str, final char wrapChar) {
8915        if (isEmpty(str) || wrapChar == CharUtils.NUL || str.length() == 1) {
8916            return str;
8917        }
8918        if (str.charAt(0) == wrapChar && str.charAt(str.length() - 1) == wrapChar) {
8919            final int startIndex = 0;
8920            final int endIndex = str.length() - 1;
8921            return str.substring(startIndex + 1, endIndex);
8922        }
8923        return str;
8924    }
8925
8926    /**
8927     * Unwraps a given string from another string.
8928     *
8929     * <pre>
8930     * StringUtils.unwrap(null, null)         = null
8931     * StringUtils.unwrap(null, "")           = null
8932     * StringUtils.unwrap(null, "1")          = null
8933     * StringUtils.unwrap("a", "a")           = "a"
8934     * StringUtils.unwrap("aa", "a")          = ""
8935     * StringUtils.unwrap("\'abc\'", "\'")    = "abc"
8936     * StringUtils.unwrap("\"abc\"", "\"")    = "abc"
8937     * StringUtils.unwrap("AABabcBAA", "AA")  = "BabcB"
8938     * StringUtils.unwrap("A", "#")           = "A"
8939     * StringUtils.unwrap("#A", "#")          = "#A"
8940     * StringUtils.unwrap("A#", "#")          = "A#"
8941     * </pre>
8942     *
8943     * @param str       the String to be unwrapped, can be null.
8944     * @param wrapToken the String used to unwrap.
8945     * @return unwrapped String or the original string if it is not quoted properly with the wrapToken.
8946     * @since 3.6
8947     */
8948    public static String unwrap(final String str, final String wrapToken) {
8949        if (isEmpty(str) || isEmpty(wrapToken) || str.length() < 2 * wrapToken.length()) {
8950            return str;
8951        }
8952        if (Strings.CS.startsWith(str, wrapToken) && Strings.CS.endsWith(str, wrapToken)) {
8953            return str.substring(wrapToken.length(), str.lastIndexOf(wrapToken));
8954        }
8955        return str;
8956    }
8957
8958    /**
8959     * Converts a String to upper case as per {@link String#toUpperCase()}.
8960     *
8961     * <p>
8962     * A {@code null} input String returns {@code null}.
8963     * </p>
8964     *
8965     * <pre>
8966     * StringUtils.upperCase(null)  = null
8967     * StringUtils.upperCase("")    = ""
8968     * StringUtils.upperCase("aBc") = "ABC"
8969     * </pre>
8970     *
8971     * <p>
8972     * <strong>Note:</strong> As described in the documentation for {@link String#toUpperCase()}, the result of this method is affected by the current locale.
8973     * For platform-independent case transformations, the method {@link #upperCase(String, Locale)} should be used with a specific locale (e.g.
8974     * {@link Locale#ENGLISH}).
8975     * </p>
8976     *
8977     * @param str the String to upper case, may be null.
8978     * @return the upper-cased String, {@code null} if null String input.
8979     */
8980    public static String upperCase(final String str) {
8981        if (str == null) {
8982            return null;
8983        }
8984        return str.toUpperCase();
8985    }
8986
8987    /**
8988     * Converts a String to upper case as per {@link String#toUpperCase(Locale)}.
8989     *
8990     * <p>
8991     * A {@code null} input String returns {@code null}.
8992     * </p>
8993     *
8994     * <pre>
8995     * StringUtils.upperCase(null, Locale.ENGLISH)  = null
8996     * StringUtils.upperCase("", Locale.ENGLISH)    = ""
8997     * StringUtils.upperCase("aBc", Locale.ENGLISH) = "ABC"
8998     * </pre>
8999     *
9000     * @param str    the String to upper case, may be null.
9001     * @param locale the locale that defines the case transformation rules, must not be null.
9002     * @return the upper-cased String, {@code null} if null String input.
9003     * @since 2.5
9004     */
9005    public static String upperCase(final String str, final Locale locale) {
9006        if (str == null) {
9007            return null;
9008        }
9009        return str.toUpperCase(LocaleUtils.toLocale(locale));
9010    }
9011
9012    /**
9013     * Returns the string representation of the {@code char} array or null.
9014     *
9015     * @param value the character array.
9016     * @return a String or null.
9017     * @see String#valueOf(char[])
9018     * @since 3.9
9019     */
9020    public static String valueOf(final char[] value) {
9021        return value == null ? null : String.valueOf(value);
9022    }
9023
9024    /**
9025     * Wraps a string with a char.
9026     *
9027     * <pre>
9028     * StringUtils.wrap(null, *)        = null
9029     * StringUtils.wrap("", *)          = ""
9030     * StringUtils.wrap("ab", '\0')     = "ab"
9031     * StringUtils.wrap("ab", 'x')      = "xabx"
9032     * StringUtils.wrap("ab", '\'')     = "'ab'"
9033     * StringUtils.wrap("\"ab\"", '\"') = "\"\"ab\"\""
9034     * </pre>
9035     *
9036     * @param str      the string to be wrapped, may be {@code null}.
9037     * @param wrapWith the char that will wrap {@code str}.
9038     * @return the wrapped string, or {@code null} if {@code str == null}.
9039     * @since 3.4
9040     */
9041    public static String wrap(final String str, final char wrapWith) {
9042        if (isEmpty(str) || wrapWith == CharUtils.NUL) {
9043            return str;
9044        }
9045        return wrapWith + str + wrapWith;
9046    }
9047
9048    /**
9049     * Wraps a String with another String.
9050     *
9051     * <p>
9052     * A {@code null} input String returns {@code null}.
9053     * </p>
9054     *
9055     * <pre>
9056     * StringUtils.wrap(null, *)         = null
9057     * StringUtils.wrap("", *)           = ""
9058     * StringUtils.wrap("ab", null)      = "ab"
9059     * StringUtils.wrap("ab", "x")       = "xabx"
9060     * StringUtils.wrap("ab", "\"")      = "\"ab\""
9061     * StringUtils.wrap("\"ab\"", "\"")  = "\"\"ab\"\""
9062     * StringUtils.wrap("ab", "'")       = "'ab'"
9063     * StringUtils.wrap("'abcd'", "'")   = "''abcd''"
9064     * StringUtils.wrap("\"abcd\"", "'") = "'\"abcd\"'"
9065     * StringUtils.wrap("'abcd'", "\"")  = "\"'abcd'\""
9066     * </pre>
9067     *
9068     * @param str      the String to be wrapper, may be null.
9069     * @param wrapWith the String that will wrap str.
9070     * @return wrapped String, {@code null} if null String input.
9071     * @since 3.4
9072     */
9073    public static String wrap(final String str, final String wrapWith) {
9074        if (isEmpty(str) || isEmpty(wrapWith)) {
9075            return str;
9076        }
9077        return wrapWith.concat(str).concat(wrapWith);
9078    }
9079
9080    /**
9081     * Wraps a string with a char if that char is missing from the start or end of the given string.
9082     *
9083     * <p>
9084     * A new {@link String} will not be created if {@code str} is already wrapped.
9085     * </p>
9086     *
9087     * <pre>
9088     * StringUtils.wrapIfMissing(null, *)        = null
9089     * StringUtils.wrapIfMissing("", *)          = ""
9090     * StringUtils.wrapIfMissing("ab", '\0')     = "ab"
9091     * StringUtils.wrapIfMissing("ab", 'x')      = "xabx"
9092     * StringUtils.wrapIfMissing("ab", '\'')     = "'ab'"
9093     * StringUtils.wrapIfMissing("\"ab\"", '\"') = "\"ab\""
9094     * StringUtils.wrapIfMissing("/", '/')  = "/"
9095     * StringUtils.wrapIfMissing("a/b/c", '/')  = "/a/b/c/"
9096     * StringUtils.wrapIfMissing("/a/b/c", '/')  = "/a/b/c/"
9097     * StringUtils.wrapIfMissing("a/b/c/", '/')  = "/a/b/c/"
9098     * </pre>
9099     *
9100     * @param str      the string to be wrapped, may be {@code null}.
9101     * @param wrapWith the char that will wrap {@code str}.
9102     * @return the wrapped string, or {@code null} if {@code str == null}.
9103     * @since 3.5
9104     */
9105    public static String wrapIfMissing(final String str, final char wrapWith) {
9106        if (isEmpty(str) || wrapWith == CharUtils.NUL) {
9107            return str;
9108        }
9109        final boolean wrapStart = str.charAt(0) != wrapWith;
9110        final boolean wrapEnd = str.charAt(str.length() - 1) != wrapWith;
9111        if (!wrapStart && !wrapEnd) {
9112            return str;
9113        }
9114        final StringBuilder builder = new StringBuilder(str.length() + 2);
9115        if (wrapStart) {
9116            builder.append(wrapWith);
9117        }
9118        builder.append(str);
9119        if (wrapEnd) {
9120            builder.append(wrapWith);
9121        }
9122        return builder.toString();
9123    }
9124
9125    /**
9126     * Wraps a string with a string if that string is missing from the start or end of the given string.
9127     *
9128     * <p>
9129     * A new {@link String} will not be created if {@code str} is already wrapped.
9130     * </p>
9131     *
9132     * <pre>
9133     * StringUtils.wrapIfMissing(null, *)         = null
9134     * StringUtils.wrapIfMissing("", *)           = ""
9135     * StringUtils.wrapIfMissing("ab", null)      = "ab"
9136     * StringUtils.wrapIfMissing("ab", "x")       = "xabx"
9137     * StringUtils.wrapIfMissing("ab", "\"")      = "\"ab\""
9138     * StringUtils.wrapIfMissing("\"ab\"", "\"")  = "\"ab\""
9139     * StringUtils.wrapIfMissing("ab", "'")       = "'ab'"
9140     * StringUtils.wrapIfMissing("'abcd'", "'")   = "'abcd'"
9141     * StringUtils.wrapIfMissing("\"abcd\"", "'") = "'\"abcd\"'"
9142     * StringUtils.wrapIfMissing("'abcd'", "\"")  = "\"'abcd'\""
9143     * StringUtils.wrapIfMissing("/", "/")  = "/"
9144     * StringUtils.wrapIfMissing("a/b/c", "/")  = "/a/b/c/"
9145     * StringUtils.wrapIfMissing("/a/b/c", "/")  = "/a/b/c/"
9146     * StringUtils.wrapIfMissing("a/b/c/", "/")  = "/a/b/c/"
9147     * </pre>
9148     *
9149     * @param str      the string to be wrapped, may be {@code null}.
9150     * @param wrapWith the string that will wrap {@code str}.
9151     * @return the wrapped string, or {@code null} if {@code str == null}.
9152     * @since 3.5
9153     */
9154    public static String wrapIfMissing(final String str, final String wrapWith) {
9155        if (isEmpty(str) || isEmpty(wrapWith)) {
9156            return str;
9157        }
9158        final boolean wrapStart = !str.startsWith(wrapWith);
9159        final boolean wrapEnd = !str.endsWith(wrapWith);
9160        if (!wrapStart && !wrapEnd) {
9161            return str;
9162        }
9163        final StringBuilder builder = new StringBuilder(str.length() + wrapWith.length() + wrapWith.length());
9164        if (wrapStart) {
9165            builder.append(wrapWith);
9166        }
9167        builder.append(str);
9168        if (wrapEnd) {
9169            builder.append(wrapWith);
9170        }
9171        return builder.toString();
9172    }
9173
9174    /**
9175     * {@link StringUtils} instances should NOT be constructed in standard programming. Instead, the class should be used as {@code StringUtils.trim(" foo ");}.
9176     *
9177     * <p>
9178     * This constructor is public to permit tools that require a JavaBean instance to operate.
9179     * </p>
9180     *
9181     * @deprecated TODO Make private in 4.0.
9182     */
9183    @Deprecated
9184    public StringUtils() {
9185        // empty
9186    }
9187
9188}