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</li>
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>
098 * The {@link StringUtils} class defines certain words related to
099 * String handling.
100 * </p>
101 *
102 * <ul>
103 *  <li>null - {@code null}</li>
104 *  <li>empty - a zero-length string ({@code ""})</li>
105 *  <li>space - the space character ({@code ' '}, char 32)</li>
106 *  <li>whitespace - the characters defined by {@link Character#isWhitespace(char)}</li>
107 *  <li>trim - the characters &lt;= 32 as in {@link String#trim()}</li>
108 * </ul>
109 *
110 * <p>
111 * {@link StringUtils} handles {@code null} input Strings quietly.
112 * That is to say that a {@code null} input will return {@code null}.
113 * Where a {@code boolean} or {@code int} is being returned
114 * details vary by method.
115 * </p>
116 *
117 * <p>
118 * A side effect of the {@code null} handling is that a
119 * {@link NullPointerException} should be considered a bug in
120 * {@link StringUtils}.
121 * </p>
122 *
123 * <p>
124 * Methods in this class include sample code in their Javadoc comments to explain their operation.
125 * The symbol {@code *} is used to indicate any input including {@code null}.
126 * </p>
127 *
128 * <p>
129 * #ThreadSafe#
130 * </p>
131 *
132 * @see String
133 * @since 1.0
134 */
135//@Immutable
136public class StringUtils {
137
138    // Performance testing notes (JDK 1.4, Jul03, scolebourne)
139    // Whitespace:
140    // Character.isWhitespace() is faster than WHITESPACE.indexOf()
141    // where WHITESPACE is a string of all whitespace characters
142    //
143    // Character access:
144    // String.charAt(n) versus toCharArray(), then array[n]
145    // String.charAt(n) is about 15% worse for a 10K string
146    // They are about equal for a length 50 string
147    // String.charAt(n) is about 4 times better for a length 3 string
148    // String.charAt(n) is best bet overall
149    //
150    // Append:
151    // String.concat about twice as fast as StringBuffer.append
152    // (not sure who tested this)
153
154    /**
155     * This is a 3 character version of an ellipsis. There is a Unicode character for a HORIZONTAL ELLIPSIS, U+2026 '…', this isn't it.
156     */
157    private static final String ELLIPSIS3 = "...";
158
159    /**
160     * A String for a space character.
161     *
162     * @since 3.2
163     */
164    public static final String SPACE = " ";
165
166    /**
167     * The empty String {@code ""}.
168     *
169     * @since 2.0
170     */
171    public static final String EMPTY = "";
172
173    /**
174     * The null String {@code null}. Package-private only.
175     */
176    static final String NULL = null;
177
178    /**
179     * A String for linefeed LF ("\n").
180     *
181     * @see <a href="https://docs.oracle.com/javase/specs/jls/se8/html/jls-3.html#jls-3.10.6">JLF: Escape Sequences
182     *      for Character and String Literals</a>
183     * @since 3.2
184     */
185    public static final String LF = "\n";
186
187    /**
188     * A String for carriage return CR ("\r").
189     *
190     * @see <a href="https://docs.oracle.com/javase/specs/jls/se8/html/jls-3.html#jls-3.10.6">JLF: Escape Sequences
191     *      for Character and String Literals</a>
192     * @since 3.2
193     */
194    public static final String CR = "\r";
195
196    /**
197     * Represents a failed index search.
198     *
199     * @since 2.1
200     */
201    public static final int INDEX_NOT_FOUND = -1;
202
203    /**
204     * The maximum size to which the padding constant(s) can expand.
205     */
206    private static final int PAD_LIMIT = 8192;
207
208    /**
209     * The default maximum depth at which recursive replacement will continue until no further search replacements are possible.
210     */
211    private static final int DEFAULT_TTL = 5;
212
213    /**
214     * Pattern used in {@link #stripAccents(String)}.
215     */
216    private static final Pattern STRIP_ACCENTS_PATTERN = Pattern.compile("\\p{InCombiningDiacriticalMarks}+"); //$NON-NLS-1$
217
218    /**
219     * Abbreviates a String using ellipses. This will convert "Now is the time for all good men" into "Now is the time for..."
220     *
221     * <p>
222     * Specifically:
223     * </p>
224     * <ul>
225     * <li>If the number of characters in {@code str} is less than or equal to {@code maxWidth}, return {@code str}.</li>
226     * <li>Else abbreviate it to {@code (substring(str, 0, max - 3) + "...")}.</li>
227     * <li>If {@code maxWidth} is less than {@code 4}, throw an {@link IllegalArgumentException}.</li>
228     * <li>In no case will it return a String of length greater than {@code maxWidth}.</li>
229     * </ul>
230     *
231     * <pre>
232     * StringUtils.abbreviate(null, *)      = null
233     * StringUtils.abbreviate("", 4)        = ""
234     * StringUtils.abbreviate("abcdefg", 6) = "abc..."
235     * StringUtils.abbreviate("abcdefg", 7) = "abcdefg"
236     * StringUtils.abbreviate("abcdefg", 8) = "abcdefg"
237     * StringUtils.abbreviate("abcdefg", 4) = "a..."
238     * StringUtils.abbreviate("abcdefg", 3) = Throws {@link IllegalArgumentException}.
239     * </pre>
240     *
241     * @param str      The String to check, may be null.
242     * @param maxWidth maximum length of result String, must be at least 4.
243     * @return abbreviated String, {@code null} if null String input.
244     * @throws IllegalArgumentException Thrown if the width is too small.
245     * @since 2.0
246     */
247    public static String abbreviate(final String str, final int maxWidth) {
248        return abbreviate(str, ELLIPSIS3, 0, maxWidth);
249    }
250
251    /**
252     * Abbreviates a String using ellipses. This will convert "Now is the time for all good men" into "...is the time for...".
253     *
254     * <p>
255     * 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
256     * leftmost character in the result, or the first character following the ellipses, but it will appear somewhere in the result.
257     * </p>
258     * <p>
259     * In no case will it return a String of length greater than {@code maxWidth}.
260     * </p>
261     *
262     * <pre>
263     * StringUtils.abbreviate(null, *, *)                = null
264     * StringUtils.abbreviate("", 0, 4)                  = ""
265     * StringUtils.abbreviate("abcdefghijklmno", -1, 10) = "abcdefg..."
266     * StringUtils.abbreviate("abcdefghijklmno", 0, 10)  = "abcdefg..."
267     * StringUtils.abbreviate("abcdefghijklmno", 1, 10)  = "abcdefg..."
268     * StringUtils.abbreviate("abcdefghijklmno", 4, 10)  = "abcdefg..."
269     * StringUtils.abbreviate("abcdefghijklmno", 5, 10)  = "...fghi..."
270     * StringUtils.abbreviate("abcdefghijklmno", 6, 10)  = "...ghij..."
271     * StringUtils.abbreviate("abcdefghijklmno", 8, 10)  = "...ijklmno"
272     * StringUtils.abbreviate("abcdefghijklmno", 10, 10) = "...ijklmno"
273     * StringUtils.abbreviate("abcdefghijklmno", 12, 10) = "...ijklmno"
274     * StringUtils.abbreviate("abcdefghij", 0, 3)        = Throws {@link IllegalArgumentException}.
275     * StringUtils.abbreviate("abcdefghij", 5, 6)        = Throws {@link IllegalArgumentException}.
276     * </pre>
277     *
278     * @param str      The String to check, may be null.
279     * @param offset   left edge of source String.
280     * @param maxWidth maximum length of result String, must be at least 4.
281     * @return abbreviated String, {@code null} if null String input.
282     * @throws IllegalArgumentException Thrown if the width is too small.
283     * @since 2.0
284     */
285    public static String abbreviate(final String str, final int offset, final int maxWidth) {
286        return abbreviate(str, ELLIPSIS3, offset, maxWidth);
287    }
288
289    /**
290     * Abbreviates a String using another given String as replacement marker. This will convert "Now is the time for all good men" into "Now is the time for..."
291     * when "..." is the replacement marker.
292     *
293     * <p>
294     * Specifically:
295     * </p>
296     * <ul>
297     * <li>If the number of characters in {@code str} is less than or equal to {@code maxWidth}, return {@code str}.</li>
298     * <li>Else abbreviate it to {@code (substring(str, 0, max - abbrevMarker.length) + abbrevMarker)}.</li>
299     * <li>If {@code maxWidth} is less than {@code abbrevMarker.length + 1}, throw an {@link IllegalArgumentException}.</li>
300     * <li>In no case will it return a String of length greater than {@code maxWidth}.</li>
301     * </ul>
302     *
303     * <pre>
304     * StringUtils.abbreviate(null, "...", *)      = null
305     * StringUtils.abbreviate("abcdefg", null, *)  = "abcdefg"
306     * StringUtils.abbreviate("", "...", 4)        = ""
307     * StringUtils.abbreviate("abcdefg", ".", 5)   = "abcd."
308     * StringUtils.abbreviate("abcdefg", ".", 7)   = "abcdefg"
309     * StringUtils.abbreviate("abcdefg", ".", 8)   = "abcdefg"
310     * StringUtils.abbreviate("abcdefg", "..", 4)  = "ab.."
311     * StringUtils.abbreviate("abcdefg", "..", 3)  = "a.."
312     * StringUtils.abbreviate("abcdefg", "..", 2)  = Throws {@link IllegalArgumentException}.
313     * StringUtils.abbreviate("abcdefg", "...", 3) = Throws {@link IllegalArgumentException}.
314     * </pre>
315     *
316     * @param str          The String to check, may be null.
317     * @param abbrevMarker The String used as replacement marker.
318     * @param maxWidth     maximum length of result String, must be at least {@code abbrevMarker.length + 1}.
319     * @return abbreviated String, {@code null} if null String input.
320     * @throws IllegalArgumentException Thrown if the width is too small.
321     * @since 3.6
322     */
323    public static String abbreviate(final String str, final String abbrevMarker, final int maxWidth) {
324        return abbreviate(str, abbrevMarker, 0, maxWidth);
325    }
326
327    /**
328     * Abbreviates a String using a given replacement marker. This will convert "Now is the time for all good men" into "...is the time for..." when "..." is
329     * the replacement marker.
330     * <p>
331     * 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
332     * be the leftmost character in the result, or the first character following the replacement marker, but it will appear somewhere in the result.
333     * </p>
334     * <p>
335     * In no case will it return a String of length greater than {@code maxWidth}.
336     * </p>
337     *
338     * <pre>
339     * StringUtils.abbreviate(null, null, *, *)                 = null
340     * StringUtils.abbreviate("abcdefghijklmno", null, *, *)    = "abcdefghijklmno"
341     * StringUtils.abbreviate("", "...", 0, 4)                  = ""
342     * StringUtils.abbreviate("abcdefghijklmno", "---", -1, 10) = "abcdefg---"
343     * StringUtils.abbreviate("abcdefghijklmno", ",", 0, 10)    = "abcdefghi,"
344     * StringUtils.abbreviate("abcdefghijklmno", ",", 1, 10)    = "abcdefghi,"
345     * StringUtils.abbreviate("abcdefghijklmno", ",", 2, 10)    = "abcdefghi,"
346     * StringUtils.abbreviate("abcdefghijklmno", "::", 4, 10)   = "::efghij::"
347     * StringUtils.abbreviate("abcdefghijklmno", "...", 6, 10)  = "...ghij..."
348     * StringUtils.abbreviate("abcdefghijklmno", "…", 6, 10)    = "…ghijklmno"
349     * StringUtils.abbreviate("abcdefghijklmno", "*", 9, 10)    = "*ghijklmno"
350     * StringUtils.abbreviate("abcdefghijklmno", "'", 10, 10)   = "'ghijklmno"
351     * StringUtils.abbreviate("abcdefghijklmno", "!", 12, 10)   = "!ghijklmno"
352     * StringUtils.abbreviate("abcdefghij", "abra", 0, 4)       = Throws {@link IllegalArgumentException}.
353     * StringUtils.abbreviate("abcdefghij", "...", 5, 6)        = Throws {@link IllegalArgumentException}.
354     * </pre>
355     *
356     * @param str          The String to check, may be null.
357     * @param abbrevMarker The String used as replacement marker, for example "...", or Unicode HORIZONTAL ELLIPSIS, U+2026 '…'.
358     * @param offset       left edge of source String.
359     * @param maxWidth     maximum length of result String, must be at least 4.
360     * @return abbreviated String, {@code null} if null String input.
361     * @throws IllegalArgumentException Thrown if the width is too small.
362     * @since 3.6
363     */
364    public static String abbreviate(final String str, String abbrevMarker, final int offset, final int maxWidth) {
365        if (isEmpty(str)) {
366            return str;
367        }
368        if (abbrevMarker == null) {
369            abbrevMarker = EMPTY;
370        }
371        final int abbrevMarkerLength = abbrevMarker.length();
372        final int minAbbrevWidth = abbrevMarkerLength + 1;
373        final int minAbbrevWidthOffset = abbrevMarkerLength + abbrevMarkerLength + 1;
374
375        if (maxWidth < minAbbrevWidth) {
376            throw new IllegalArgumentException(String.format("Minimum abbreviation width is %d", minAbbrevWidth));
377        }
378        final int strLen = str.length();
379        if (strLen <= maxWidth) {
380            return str;
381        }
382        if (strLen - offset <= maxWidth - abbrevMarkerLength) {
383            int tailStart = strLen - (maxWidth - abbrevMarkerLength);
384            if (splitsSurrogatePair(str, tailStart)) {
385                tailStart++;
386            }
387            return abbrevMarker + str.substring(tailStart);
388        }
389        if (offset <= abbrevMarkerLength + 1) {
390            int headEnd = maxWidth - abbrevMarkerLength;
391            if (splitsSurrogatePair(str, headEnd)) {
392                headEnd--;
393            }
394            return str.substring(0, headEnd) + abbrevMarker;
395        }
396        if (maxWidth < minAbbrevWidthOffset) {
397            throw new IllegalArgumentException(String.format("Minimum abbreviation width with offset is %d", minAbbrevWidthOffset));
398        }
399        int from = offset;
400        if (splitsSurrogatePair(str, from)) {
401            from++;
402        }
403        return abbrevMarker + abbreviate(str.substring(from), abbrevMarker, maxWidth - abbrevMarkerLength);
404    }
405
406    /**
407     * Abbreviates a String to the length passed, replacing the middle characters with the supplied replacement String.
408     *
409     * <p>
410     * This abbreviation only occurs if the following criteria is met:
411     * </p>
412     * <ul>
413     * <li>Neither the String for abbreviation nor the replacement String are null or empty</li>
414     * <li>The length to truncate to is less than the length of the supplied String</li>
415     * <li>The length to truncate to is greater than 0</li>
416     * <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
417     * abbreviation</li>
418     * </ul>
419     * <p>
420     * Otherwise, the returned String will be the same as the supplied String for abbreviation.
421     * </p>
422     *
423     * <pre>
424     * StringUtils.abbreviateMiddle(null, null, 0)    = null
425     * StringUtils.abbreviateMiddle("abc", null, 0)   = "abc"
426     * StringUtils.abbreviateMiddle("abc", ".", 0)    = "abc"
427     * StringUtils.abbreviateMiddle("abc", ".", 3)    = "abc"
428     * StringUtils.abbreviateMiddle("abcdef", ".", 4) = "ab.f"
429     * </pre>
430     *
431     * @param str    The String to abbreviate, may be null.
432     * @param middle The String to replace the middle characters with, may be null.
433     * @param length The length to abbreviate {@code str} to.
434     * @return The abbreviated String if the above criteria is met, or the original String supplied for abbreviation.
435     * @since 2.5
436     */
437    public static String abbreviateMiddle(final String str, final String middle, final int length) {
438        if (isAnyEmpty(str, middle) || length >= str.length() || length < middle.length() + 2) {
439            return str;
440        }
441        final int targetString = length - middle.length();
442        int startOffset = targetString / 2 + targetString % 2;
443        int endOffset = str.length() - targetString / 2;
444        // keep both cuts off the middle of a surrogate pair so the result is never left holding a lone surrogate
445        if (splitsSurrogatePair(str, startOffset)) {
446            startOffset--;
447        }
448        if (splitsSurrogatePair(str, endOffset)) {
449            endOffset++;
450        }
451        return str.substring(0, startOffset) + middle + str.substring(endOffset);
452    }
453
454    /**
455     * Appends the suffix to the end of the string if the string does not already end with any of the suffixes.
456     *
457     * <pre>
458     * StringUtils.appendIfMissing(null, null)      = null
459     * StringUtils.appendIfMissing("abc", null)     = "abc"
460     * StringUtils.appendIfMissing("", "xyz")       = "xyz"
461     * StringUtils.appendIfMissing("abc", "xyz")    = "abcxyz"
462     * StringUtils.appendIfMissing("abcxyz", "xyz") = "abcxyz"
463     * StringUtils.appendIfMissing("abcXYZ", "xyz") = "abcXYZxyz"
464     * </pre>
465     * <p>
466     * With additional suffixes,
467     * </p>
468     *
469     * <pre>
470     * StringUtils.appendIfMissing(null, null, null)       = null
471     * StringUtils.appendIfMissing("abc", null, null)      = "abc"
472     * StringUtils.appendIfMissing("", "xyz", null)        = "xyz"
473     * StringUtils.appendIfMissing("abc", "xyz", new CharSequence[]{null}) = "abcxyz"
474     * StringUtils.appendIfMissing("abc", "xyz", "")       = "abc"
475     * StringUtils.appendIfMissing("abc", "xyz", "mno")    = "abcxyz"
476     * StringUtils.appendIfMissing("abcxyz", "xyz", "mno") = "abcxyz"
477     * StringUtils.appendIfMissing("abcmno", "xyz", "mno") = "abcmno"
478     * StringUtils.appendIfMissing("abcXYZ", "xyz", "mno") = "abcXYZxyz"
479     * StringUtils.appendIfMissing("abcMNO", "xyz", "mno") = "abcMNOxyz"
480     * </pre>
481     *
482     * @param str      The string.
483     * @param suffix   The suffix to append to the end of the string.
484     * @param suffixes Additional suffixes that are valid terminators.
485     * @return A new String if suffix was appended, the same string otherwise.
486     * @since 3.2
487     * @deprecated Use {@link Strings#appendIfMissing(String, CharSequence, CharSequence...) Strings.CS.appendIfMissing(String, CharSequence, CharSequence...)}.
488     */
489    @Deprecated
490    public static String appendIfMissing(final String str, final CharSequence suffix, final CharSequence... suffixes) {
491        return Strings.CS.appendIfMissing(str, suffix, suffixes);
492    }
493
494    /**
495     * Appends the suffix to the end of the string if the string does not
496     * already end, case-insensitive, with any of the suffixes.
497     *
498     * <pre>
499     * StringUtils.appendIfMissingIgnoreCase(null, null)      = null
500     * StringUtils.appendIfMissingIgnoreCase("abc", null)     = "abc"
501     * StringUtils.appendIfMissingIgnoreCase("", "xyz")       = "xyz"
502     * StringUtils.appendIfMissingIgnoreCase("abc", "xyz")    = "abcxyz"
503     * StringUtils.appendIfMissingIgnoreCase("abcxyz", "xyz") = "abcxyz"
504     * StringUtils.appendIfMissingIgnoreCase("abcXYZ", "xyz") = "abcXYZ"
505     * </pre>
506     * <p>
507     * With additional suffixes,
508     * </p>
509     * <pre>
510     * StringUtils.appendIfMissingIgnoreCase(null, null, null)       = null
511     * StringUtils.appendIfMissingIgnoreCase("abc", null, null)      = "abc"
512     * StringUtils.appendIfMissingIgnoreCase("", "xyz", null)        = "xyz"
513     * StringUtils.appendIfMissingIgnoreCase("abc", "xyz", new CharSequence[]{null}) = "abcxyz"
514     * StringUtils.appendIfMissingIgnoreCase("abc", "xyz", "")       = "abc"
515     * StringUtils.appendIfMissingIgnoreCase("abc", "xyz", "mno")    = "abcxyz"
516     * StringUtils.appendIfMissingIgnoreCase("abcxyz", "xyz", "mno") = "abcxyz"
517     * StringUtils.appendIfMissingIgnoreCase("abcmno", "xyz", "mno") = "abcmno"
518     * StringUtils.appendIfMissingIgnoreCase("abcXYZ", "xyz", "mno") = "abcXYZ"
519     * StringUtils.appendIfMissingIgnoreCase("abcMNO", "xyz", "mno") = "abcMNO"
520     * </pre>
521     *
522     * @param str The string.
523     * @param suffix The suffix to append to the end of the string.
524     * @param suffixes Additional suffixes that are valid terminators.
525     * @return A new String if suffix was appended, the same string otherwise.
526     * @since 3.2
527     * @deprecated Use {@link Strings#appendIfMissing(String, CharSequence, CharSequence...) Strings.CI.appendIfMissing(String, CharSequence, CharSequence...)}.
528     */
529    @Deprecated
530    public static String appendIfMissingIgnoreCase(final String str, final CharSequence suffix, final CharSequence... suffixes) {
531        return Strings.CI.appendIfMissing(str, suffix, suffixes);
532    }
533
534    /**
535     * Computes the capacity required for a StringBuilder to hold {@code items} of {@code maxElementChars} characters plus the separators between them. The
536     * separator is assumed to be 1 character.
537     *
538     * @param count           The number of items.
539     * @param maxElementChars The maximum number of characters per item.
540     * @return A StringBuilder with the appropriate capacity.
541     */
542    private static StringBuilder capacity(final int count, final byte maxElementChars) {
543        return new StringBuilder(count * maxElementChars + count - 1);
544    }
545
546    /**
547     * Capitalizes a String changing the first character to title case as per {@link Character#toTitleCase(int)}. No other characters are changed.
548     *
549     * <p>
550     * For a word based algorithm, see {@link org.apache.commons.text.WordUtils#capitalize(String)}. A {@code null} input String returns {@code null}.
551     * </p>
552     *
553     * <pre>
554     * StringUtils.capitalize(null)    = null
555     * StringUtils.capitalize("")      = ""
556     * StringUtils.capitalize("cat")   = "Cat"
557     * StringUtils.capitalize("cAt")   = "CAt"
558     * StringUtils.capitalize("'cat'") = "'cat'"
559     * </pre>
560     *
561     * @param str The String to capitalize, may be null.
562     * @return The capitalized String, {@code null} if null String input.
563     * @see org.apache.commons.text.WordUtils#capitalize(String)
564     * @see #uncapitalize(String)
565     * @since 2.0
566     */
567    public static String capitalize(final String str) {
568        if (isEmpty(str)) {
569            return str;
570        }
571        final int firstCodepoint = str.codePointAt(0);
572        final int newCodePoint = Character.toTitleCase(firstCodepoint);
573        if (firstCodepoint == newCodePoint) {
574            // already capitalized
575            return str;
576        }
577        final int[] newCodePoints = str.codePoints().toArray();
578        newCodePoints[0] = newCodePoint; // copy the first code point
579        return new String(newCodePoints, 0, newCodePoints.length);
580    }
581
582    /**
583     * Centers a String in a larger String of size {@code size} using the space character (' ').
584     *
585     * <p>
586     * 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
587     * zero.
588     * </p>
589     *
590     * <p>
591     * Equivalent to {@code center(str, size, " ")}.
592     * </p>
593     *
594     * <pre>
595     * StringUtils.center(null, *)   = null
596     * StringUtils.center("", 4)     = "    "
597     * StringUtils.center("ab", -1)  = "ab"
598     * StringUtils.center("ab", 4)   = " ab "
599     * StringUtils.center("abcd", 2) = "abcd"
600     * StringUtils.center("a", 4)    = " a  "
601     * </pre>
602     *
603     * @param str  The String to center, may be null.
604     * @param size The int size of new String, negative treated as zero.
605     * @return centered String, {@code null} if null String input.
606     */
607    public static String center(final String str, final int size) {
608        return center(str, size, ' ');
609    }
610
611    /**
612     * Centers a String in a larger String of size {@code size}. Uses a supplied character as the value to pad the String with.
613     *
614     * <p>
615     * 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.
616     * </p>
617     *
618     * <pre>
619     * StringUtils.center(null, *, *)     = null
620     * StringUtils.center("", 4, ' ')     = "    "
621     * StringUtils.center("ab", -1, ' ')  = "ab"
622     * StringUtils.center("ab", 4, ' ')   = " ab "
623     * StringUtils.center("abcd", 2, ' ') = "abcd"
624     * StringUtils.center("a", 4, ' ')    = " a  "
625     * StringUtils.center("a", 4, 'y')    = "yayy"
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 padChar The character to pad the new String with.
631     * @return centered String, {@code null} if null String input.
632     * @since 2.0
633     */
634    public static String center(String str, final int size, final char padChar) {
635        if (str == null || size <= 0) {
636            return str;
637        }
638        final int strLen = str.length();
639        final int pads = size - strLen;
640        if (pads <= 0) {
641            return str;
642        }
643        str = leftPad(str, strLen + pads / 2, padChar);
644        return rightPad(str, size, padChar);
645    }
646
647    /**
648     * Centers a String in a larger String of size {@code size}. Uses a supplied String as the value to pad the String with.
649     *
650     * <p>
651     * 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.
652     * </p>
653     *
654     * <pre>
655     * StringUtils.center(null, *, *)     = null
656     * StringUtils.center("", 4, " ")     = "    "
657     * StringUtils.center("ab", -1, " ")  = "ab"
658     * StringUtils.center("ab", 4, " ")   = " ab "
659     * StringUtils.center("abcd", 2, " ") = "abcd"
660     * StringUtils.center("a", 4, " ")    = " a  "
661     * StringUtils.center("a", 4, "yz")   = "yayz"
662     * StringUtils.center("abc", 7, null) = "  abc  "
663     * StringUtils.center("abc", 7, "")   = "  abc  "
664     * </pre>
665     *
666     * @param str    The String to center, may be null.
667     * @param size   The int size of new String, negative treated as zero.
668     * @param padStr The String to pad the new String with, must not be null or empty.
669     * @return centered String, {@code null} if null String input.
670     * @throws IllegalArgumentException Thrown if padStr is {@code null} or empty.
671     */
672    public static String center(String str, final int size, String padStr) {
673        if (str == null || size <= 0) {
674            return str;
675        }
676        if (isEmpty(padStr)) {
677            padStr = SPACE;
678        }
679        final int strLen = str.length();
680        final int pads = size - strLen;
681        if (pads <= 0) {
682            return str;
683        }
684        str = leftPad(str, strLen + pads / 2, padStr);
685        return rightPad(str, size, padStr);
686    }
687
688    private static void checkFromToIndex(final int startIndex, final int endIndex, final int length) {
689        if (startIndex < 0) {
690            throw new ArrayIndexOutOfBoundsException(startIndex);
691        }
692        if (endIndex > length) {
693            throw new ArrayIndexOutOfBoundsException(endIndex);
694        }
695    }
696
697    /**
698     * 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
699     * &quot;{@code \r\n}&quot;.
700     *
701     * <p>
702     * NOTE: This method changed in 2.0. It now more closely matches Perl chomp.
703     * </p>
704     *
705     * <pre>
706     * StringUtils.chomp(null)          = null
707     * StringUtils.chomp("")            = ""
708     * StringUtils.chomp("abc \r")      = "abc "
709     * StringUtils.chomp("abc\n")       = "abc"
710     * StringUtils.chomp("abc\r\n")     = "abc"
711     * StringUtils.chomp("abc\r\n\r\n") = "abc\r\n"
712     * StringUtils.chomp("abc\n\r")     = "abc\n"
713     * StringUtils.chomp("abc\n\rabc")  = "abc\n\rabc"
714     * StringUtils.chomp("\r")          = ""
715     * StringUtils.chomp("\n")          = ""
716     * StringUtils.chomp("\r\n")        = ""
717     * </pre>
718     *
719     * @param str The String to chomp a newline from, may be null.
720     * @return String without newline, {@code null} if null String input.
721     */
722    public static String chomp(final String str) {
723        if (isEmpty(str)) {
724            return str;
725        }
726        if (str.length() == 1) {
727            final char ch = str.charAt(0);
728            if (ch == CharUtils.CR || ch == CharUtils.LF) {
729                return EMPTY;
730            }
731            return str;
732        }
733        int lastIdx = str.length() - 1;
734        final char last = str.charAt(lastIdx);
735        if (last == CharUtils.LF) {
736            if (str.charAt(lastIdx - 1) == CharUtils.CR) {
737                lastIdx--;
738            }
739        } else if (last != CharUtils.CR) {
740            lastIdx++;
741        }
742        return str.substring(0, lastIdx);
743    }
744
745    /**
746     * Removes {@code separator} from the end of {@code str} if it's there, otherwise leave it alone.
747     *
748     * <p>
749     * NOTE: This method changed in version 2.0. It now more closely matches Perl chomp. For the previous behavior, use
750     * {@link #substringBeforeLast(String, String)}. This method uses {@link String#endsWith(String)}.
751     * </p>
752     *
753     * <pre>
754     * StringUtils.chomp(null, *)         = null
755     * StringUtils.chomp("", *)           = ""
756     * StringUtils.chomp("foobar", "bar") = "foo"
757     * StringUtils.chomp("foobar", "baz") = "foobar"
758     * StringUtils.chomp("foo", "foo")    = ""
759     * StringUtils.chomp("foo ", "foo")   = "foo "
760     * StringUtils.chomp(" foo", "foo")   = " "
761     * StringUtils.chomp("foo", "foooo")  = "foo"
762     * StringUtils.chomp("foo", "")       = "foo"
763     * StringUtils.chomp("foo", null)     = "foo"
764     * </pre>
765     *
766     * @param str       The String to chomp from, may be null.
767     * @param separator separator String, may be null.
768     * @return String without trailing separator, {@code null} if null String input.
769     * @deprecated This feature will be removed in Lang 4, use {@link StringUtils#removeEnd(String, String)} instead.
770     */
771    @Deprecated
772    public static String chomp(final String str, final String separator) {
773        return Strings.CS.removeEnd(str, separator);
774    }
775
776    /**
777     * Removes the last character from a String.
778     *
779     * <p>
780     * If the String ends in {@code \r\n}, then remove both of them.
781     * </p>
782     *
783     * <pre>
784     * StringUtils.chop(null)          = null
785     * StringUtils.chop("")            = ""
786     * StringUtils.chop("abc \r")      = "abc "
787     * StringUtils.chop("abc\n")       = "abc"
788     * StringUtils.chop("abc\r\n")     = "abc"
789     * StringUtils.chop("abc")         = "ab"
790     * StringUtils.chop("abc\nabc")    = "abc\nab"
791     * StringUtils.chop("a")           = ""
792     * StringUtils.chop("\r")          = ""
793     * StringUtils.chop("\n")          = ""
794     * StringUtils.chop("\r\n")        = ""
795     * </pre>
796     *
797     * @param str The String to chop last character from, may be null.
798     * @return String without last character, {@code null} if null String input.
799     */
800    public static String chop(final String str) {
801        if (str == null) {
802            return null;
803        }
804        final int strLen = str.length();
805        if (strLen < 2) {
806            return EMPTY;
807        }
808        final int lastIdx = strLen - 1;
809        // keep the cut off the middle of a surrogate pair so the result is never left holding a lone surrogate
810        if (splitsSurrogatePair(str, lastIdx)) {
811            return str.substring(0, lastIdx - 1);
812        }
813        final String ret = str.substring(0, lastIdx);
814        final char last = str.charAt(lastIdx);
815        if (last == CharUtils.LF && ret.charAt(lastIdx - 1) == CharUtils.CR) {
816            return ret.substring(0, lastIdx - 1);
817        }
818        return ret;
819    }
820
821    /**
822     * Compares two Strings lexicographically, as per {@link String#compareTo(String)}, returning :
823     * <ul>
824     * <li>{@code int = 0}, if {@code str1} is equal to {@code str2} (or both {@code null})</li>
825     * <li>{@code int < 0}, if {@code str1} is less than {@code str2}</li>
826     * <li>{@code int > 0}, if {@code str1} is greater than {@code str2}</li>
827     * </ul>
828     *
829     * <p>
830     * This is a {@code null} safe version of:
831     * </p>
832     *
833     * <pre>
834     * str1.compareTo(str2)
835     * </pre>
836     *
837     * <p>
838     * {@code null} value is considered less than non-{@code null} value. Two {@code null} references are considered equal.
839     * </p>
840     *
841     * <pre>{@code
842     * StringUtils.compare(null, null)   = 0
843     * StringUtils.compare(null , "a")   < 0
844     * StringUtils.compare("a", null)   > 0
845     * StringUtils.compare("abc", "abc") = 0
846     * StringUtils.compare("a", "b")     < 0
847     * StringUtils.compare("b", "a")     > 0
848     * StringUtils.compare("a", "B")     > 0
849     * StringUtils.compare("ab", "abc")  < 0
850     * }</pre>
851     *
852     * @param str1 The String to compare from.
853     * @param str2 The String to compare to.
854     * @return &lt; 0, 0, &gt; 0, if {@code str1} is respectively less, equal or greater than {@code str2}.
855     * @see #compare(String, String, boolean)
856     * @see String#compareTo(String)
857     * @since 3.5
858     * @deprecated Use {@link Strings#compare(String, String) Strings.CS.compare(String, String)}.
859     */
860    @Deprecated
861    public static int compare(final String str1, final String str2) {
862        return Strings.CS.compare(str1, str2);
863    }
864
865    /**
866     * Compares two Strings lexicographically, as per {@link String#compareTo(String)}, returning :
867     * <ul>
868     * <li>{@code int = 0}, if {@code str1} is equal to {@code str2} (or both {@code null})</li>
869     * <li>{@code int < 0}, if {@code str1} is less than {@code str2}</li>
870     * <li>{@code int > 0}, if {@code str1} is greater than {@code str2}</li>
871     * </ul>
872     *
873     * <p>
874     * This is a {@code null} safe version of :
875     * </p>
876     *
877     * <pre>
878     * str1.compareTo(str2)
879     * </pre>
880     *
881     * <p>
882     * {@code null} inputs are handled according to the {@code nullIsLess} parameter. Two {@code null} references are considered equal.
883     * </p>
884     *
885     * <pre>{@code
886     * StringUtils.compare(null, null, *)     = 0
887     * StringUtils.compare(null , "a", true)  < 0
888     * StringUtils.compare(null , "a", false) > 0
889     * StringUtils.compare("a", null, true)   > 0
890     * StringUtils.compare("a", null, false)  < 0
891     * StringUtils.compare("abc", "abc", *)   = 0
892     * StringUtils.compare("a", "b", *)       < 0
893     * StringUtils.compare("b", "a", *)       > 0
894     * StringUtils.compare("a", "B", *)       > 0
895     * StringUtils.compare("ab", "abc", *)    < 0
896     * }</pre>
897     *
898     * @param str1       The String to compare from.
899     * @param str2       The String to compare to.
900     * @param nullIsLess whether consider {@code null} value less than non-{@code null} value.
901     * @return &lt; 0, 0, &gt; 0, if {@code str1} is respectively less, equal ou greater than {@code str2}.
902     * @see String#compareTo(String)
903     * @since 3.5
904     */
905    public static int compare(final String str1, final String str2, final boolean nullIsLess) {
906        if (str1 == str2) { // NOSONARLINT this intentionally uses == to allow for both null
907            return 0;
908        }
909        if (str1 == null) {
910            return nullIsLess ? -1 : 1;
911        }
912        if (str2 == null) {
913            return nullIsLess ? 1 : -1;
914        }
915        return str1.compareTo(str2);
916    }
917
918    /**
919     * Compares two Strings lexicographically, ignoring case differences, as per {@link String#compareToIgnoreCase(String)}, returning :
920     * <ul>
921     * <li>{@code int = 0}, if {@code str1} is equal to {@code str2} (or both {@code null})</li>
922     * <li>{@code int < 0}, if {@code str1} is less than {@code str2}</li>
923     * <li>{@code int > 0}, if {@code str1} is greater than {@code str2}</li>
924     * </ul>
925     *
926     * <p>
927     * This is a {@code null} safe version of:
928     * </p>
929     *
930     * <pre>
931     * str1.compareToIgnoreCase(str2)
932     * </pre>
933     *
934     * <p>
935     * {@code null} value is considered less than non-{@code null} value. Two {@code null} references are considered equal. Comparison is case insensitive.
936     * </p>
937     *
938     * <pre>{@code
939     * StringUtils.compareIgnoreCase(null, null)   = 0
940     * StringUtils.compareIgnoreCase(null , "a")   < 0
941     * StringUtils.compareIgnoreCase("a", null)    > 0
942     * StringUtils.compareIgnoreCase("abc", "abc") = 0
943     * StringUtils.compareIgnoreCase("abc", "ABC") = 0
944     * StringUtils.compareIgnoreCase("a", "b")     < 0
945     * StringUtils.compareIgnoreCase("b", "a")     > 0
946     * StringUtils.compareIgnoreCase("a", "B")     < 0
947     * StringUtils.compareIgnoreCase("A", "b")     < 0
948     * StringUtils.compareIgnoreCase("ab", "ABC")  < 0
949     * }</pre>
950     *
951     * @param str1 The String to compare from.
952     * @param str2 The String to compare to.
953     * @return &lt; 0, 0, &gt; 0, if {@code str1} is respectively less, equal ou greater than {@code str2}, ignoring case differences.
954     * @see #compareIgnoreCase(String, String, boolean)
955     * @see String#compareToIgnoreCase(String)
956     * @since 3.5
957     * @deprecated Use {@link Strings#compare(String, String) Strings.CI.compare(String, String)}.
958     */
959    @Deprecated
960    public static int compareIgnoreCase(final String str1, final String str2) {
961        return Strings.CI.compare(str1, str2);
962    }
963
964    /**
965     * Compares two Strings lexicographically, ignoring case differences, as per {@link String#compareToIgnoreCase(String)}, returning :
966     * <ul>
967     * <li>{@code int = 0}, if {@code str1} is equal to {@code str2} (or both {@code null})</li>
968     * <li>{@code int < 0}, if {@code str1} is less than {@code str2}</li>
969     * <li>{@code int > 0}, if {@code str1} is greater than {@code str2}</li>
970     * </ul>
971     *
972     * <p>
973     * This is a {@code null} safe version of :
974     * </p>
975     * <pre>
976     * str1.compareToIgnoreCase(str2)
977     * </pre>
978     *
979     * <p>
980     * {@code null} inputs are handled according to the {@code nullIsLess} parameter. Two {@code null} references are considered equal. Comparison is case
981     * insensitive.
982     * </p>
983     *
984     * <pre>{@code
985     * StringUtils.compareIgnoreCase(null, null, *)     = 0
986     * StringUtils.compareIgnoreCase(null , "a", true)  < 0
987     * StringUtils.compareIgnoreCase(null , "a", false) > 0
988     * StringUtils.compareIgnoreCase("a", null, true)   > 0
989     * StringUtils.compareIgnoreCase("a", null, false)  < 0
990     * StringUtils.compareIgnoreCase("abc", "abc", *)   = 0
991     * StringUtils.compareIgnoreCase("abc", "ABC", *)   = 0
992     * StringUtils.compareIgnoreCase("a", "b", *)       < 0
993     * StringUtils.compareIgnoreCase("b", "a", *)       > 0
994     * StringUtils.compareIgnoreCase("a", "B", *)       < 0
995     * StringUtils.compareIgnoreCase("A", "b", *)       < 0
996     * StringUtils.compareIgnoreCase("ab", "abc", *)    < 0
997     * }</pre>
998     *
999     * @param str1       The String to compare from.
1000     * @param str2       The String to compare to.
1001     * @param nullIsLess whether consider {@code null} value less than non-{@code null} value.
1002     * @return &lt; 0, 0, &gt; 0, if {@code str1} is respectively less, equal ou greater than {@code str2}, ignoring case differences.
1003     * @see String#compareToIgnoreCase(String)
1004     * @since 3.5
1005     */
1006    public static int compareIgnoreCase(final String str1, final String str2, final boolean nullIsLess) {
1007        if (str1 == str2) { // NOSONARLINT this intentionally uses == to allow for both null
1008            return 0;
1009        }
1010        if (str1 == null) {
1011            return nullIsLess ? -1 : 1;
1012        }
1013        if (str2 == null) {
1014            return nullIsLess ? 1 : -1;
1015        }
1016        return str1.compareToIgnoreCase(str2);
1017    }
1018
1019    /**
1020     * Tests if CharSequence contains a search CharSequence, handling {@code null}.
1021     * This method uses {@link String#indexOf(String)} if possible.
1022     *
1023     * <p>
1024     * A {@code null} CharSequence will return {@code false}.
1025     * </p>
1026     *
1027     * <pre>
1028     * StringUtils.contains(null, *)     = false
1029     * StringUtils.contains(*, null)     = false
1030     * StringUtils.contains("", "")      = true
1031     * StringUtils.contains("abc", "")   = true
1032     * StringUtils.contains("abc", "a")  = true
1033     * StringUtils.contains("abc", "z")  = false
1034     * </pre>
1035     *
1036     * @param seq  The CharSequence to check, may be null
1037     * @param searchSeq  The CharSequence to find, may be null
1038     * @return true if the CharSequence contains the search CharSequence,
1039     *  false if not or {@code null} string input
1040     * @since 2.0
1041     * @since 3.0 Changed signature from contains(String, String) to contains(CharSequence, CharSequence)
1042     * @deprecated Use {@link Strings#contains(CharSequence, CharSequence) Strings.CS.contains(CharSequence, CharSequence)}.
1043     */
1044    @Deprecated
1045    public static boolean contains(final CharSequence seq, final CharSequence searchSeq) {
1046        return Strings.CS.contains(seq, searchSeq);
1047    }
1048
1049    /**
1050     * Tests if CharSequence contains a search character, handling {@code null}. This method uses {@link String#indexOf(int)} if possible.
1051     *
1052     * <p>
1053     * A {@code null} or empty ("") CharSequence will return {@code false}.
1054     * </p>
1055     *
1056     * <pre>
1057     * StringUtils.contains(null, *)    = false
1058     * StringUtils.contains("", *)      = false
1059     * StringUtils.contains("abc", 'a') = true
1060     * StringUtils.contains("abc", 'z') = false
1061     * </pre>
1062     *
1063     * @param seq        The CharSequence to check, may be null
1064     * @param searchChar The character to find
1065     * @return true if the CharSequence contains the search character, false if not or {@code null} string input
1066     * @since 2.0
1067     * @since 3.0 Changed signature from contains(String, int) to contains(CharSequence, int)
1068     */
1069    public static boolean contains(final CharSequence seq, final int searchChar) {
1070        if (isEmpty(seq)) {
1071            return false;
1072        }
1073        return CharSequenceUtils.indexOf(seq, searchChar, 0) >= 0;
1074    }
1075
1076    /**
1077     * Tests if the CharSequence contains any character in the given set of characters.
1078     *
1079     * <p>
1080     * A {@code null} CharSequence will return {@code false}. A {@code null} or zero length search array will return {@code false}.
1081     * </p>
1082     *
1083     * <pre>
1084     * StringUtils.containsAny(null, *)                  = false
1085     * StringUtils.containsAny("", *)                    = false
1086     * StringUtils.containsAny(*, null)                  = false
1087     * StringUtils.containsAny(*, [])                    = false
1088     * StringUtils.containsAny("zzabyycdxx", 'z', 'a')   = true
1089     * StringUtils.containsAny("zzabyycdxx", 'b', 'y')   = true
1090     * StringUtils.containsAny("zzabyycdxx", 'z', 'y')   = true
1091     * StringUtils.containsAny("aba", 'z])               = false
1092     * </pre>
1093     *
1094     * @param cs          The CharSequence to check, may be null.
1095     * @param searchChars The chars to search for, may be null.
1096     * @return The {@code true} if any of the chars are found, {@code false} if no match or null input.
1097     * @since 2.4
1098     * @since 3.0 Changed signature from containsAny(String, char[]) to containsAny(CharSequence, char...)
1099     */
1100    public static boolean containsAny(final CharSequence cs, final char... searchChars) {
1101        if (isEmpty(cs) || ArrayUtils.isEmpty(searchChars)) {
1102            return false;
1103        }
1104        final int csLength = cs.length();
1105        final int searchLength = searchChars.length;
1106        final int csLast = csLength - 1;
1107        final int searchLast = searchLength - 1;
1108        for (int i = 0; i < csLength; i++) {
1109            final char ch = cs.charAt(i);
1110            for (int j = 0; j < searchLength; j++) {
1111                if (searchChars[j] == ch) {
1112                    if (Character.isHighSurrogate(ch)
1113                            ? j == searchLast || i < csLast && searchChars[j + 1] == cs.charAt(i + 1)
1114                            : j == 0 || !Character.isLowSurrogate(ch) || !Character.isHighSurrogate(searchChars[j - 1]) || i > 0 && searchChars[j - 1] == cs.charAt(i - 1)) {
1115                        return true;
1116                    }
1117                }
1118            }
1119        }
1120        return false;
1121    }
1122
1123    /**
1124     * Tests if the CharSequence contains any character in the given set of characters.
1125     *
1126     * <p>
1127     * A {@code null} CharSequence will return {@code false}. A {@code null} search CharSequence will return {@code false}.
1128     * </p>
1129     *
1130     * <pre>
1131     * StringUtils.containsAny(null, *)               = false
1132     * StringUtils.containsAny("", *)                 = false
1133     * StringUtils.containsAny(*, null)               = false
1134     * StringUtils.containsAny(*, "")                 = false
1135     * StringUtils.containsAny("zzabyycdxx", "za")    = true
1136     * StringUtils.containsAny("zzabyycdxx", "by")    = true
1137     * StringUtils.containsAny("zzabyycdxx", "zy")    = true
1138     * StringUtils.containsAny("zzabyycdxx", "\tx")   = true
1139     * StringUtils.containsAny("zzabyycdxx", "$.#yF") = true
1140     * StringUtils.containsAny("aba", "z")            = false
1141     * </pre>
1142     *
1143     * @param cs          The CharSequence to check, may be null.
1144     * @param searchChars The chars to search for, may be null.
1145     * @return The {@code true} if any of the chars are found, {@code false} if no match or null input.
1146     * @since 2.4
1147     * @since 3.0 Changed signature from containsAny(String, String) to containsAny(CharSequence, CharSequence)
1148     */
1149    public static boolean containsAny(final CharSequence cs, final CharSequence searchChars) {
1150        if (searchChars == null) {
1151            return false;
1152        }
1153        return containsAny(cs, CharSequenceUtils.toCharArray(searchChars));
1154    }
1155
1156    /**
1157     * Tests if the CharSequence contains any of the CharSequences in the given array.
1158     *
1159     * <p>
1160     * A {@code null} {@code cs} CharSequence will return {@code false}. A {@code null} or zero length search array will
1161     * return {@code false}.
1162     * </p>
1163     *
1164     * <pre>
1165     * StringUtils.containsAny(null, *)            = false
1166     * StringUtils.containsAny("", *)              = false
1167     * StringUtils.containsAny(*, null)            = false
1168     * StringUtils.containsAny(*, [])              = false
1169     * StringUtils.containsAny("abcd", "ab", null) = true
1170     * StringUtils.containsAny("abcd", "ab", "cd") = true
1171     * StringUtils.containsAny("abc", "d", "abc")  = true
1172     * </pre>
1173     *
1174     * @param cs The CharSequence to check, may be null.
1175     * @param searchCharSequences The array of CharSequences to search for, may be null. Individual CharSequences may be
1176     *        null as well.
1177     * @return {@code true} if any of the search CharSequences are found, {@code false} otherwise.
1178     * @since 3.4
1179     * @deprecated Use {@link Strings#containsAny(CharSequence, CharSequence...) Strings.CS.containsAny(CharSequence, CharSequence...)}.
1180     */
1181    @Deprecated
1182    public static boolean containsAny(final CharSequence cs, final CharSequence... searchCharSequences) {
1183        return Strings.CS.containsAny(cs, searchCharSequences);
1184    }
1185
1186    /**
1187     * Tests if the CharSequence contains any of the CharSequences in the given array, ignoring case.
1188     *
1189     * <p>
1190     * A {@code null} {@code cs} CharSequence will return {@code false}. A {@code null} or zero length search array will
1191     * return {@code false}.
1192     * </p>
1193     *
1194     * <pre>
1195     * StringUtils.containsAny(null, *)            = false
1196     * StringUtils.containsAny("", *)              = false
1197     * StringUtils.containsAny(*, null)            = false
1198     * StringUtils.containsAny(*, [])              = false
1199     * StringUtils.containsAny("abcd", "ab", null) = true
1200     * StringUtils.containsAny("abcd", "ab", "cd") = true
1201     * StringUtils.containsAny("abc", "d", "abc")  = true
1202     * StringUtils.containsAny("abc", "D", "ABC")  = true
1203     * StringUtils.containsAny("ABC", "d", "abc")  = true
1204     * </pre>
1205     *
1206     * @param cs The CharSequence to check, may be null.
1207     * @param searchCharSequences The array of CharSequences to search for, may be null. Individual CharSequences may be
1208     *        null as well.
1209     * @return {@code true} if any of the search CharSequences are found, {@code false} otherwise
1210     * @since 3.12.0
1211     * @deprecated Use {@link Strings#containsAny(CharSequence, CharSequence...) Strings.CI.containsAny(CharSequence, CharSequence...)}.
1212     */
1213    @Deprecated
1214    public static boolean containsAnyIgnoreCase(final CharSequence cs, final CharSequence... searchCharSequences) {
1215        return Strings.CI.containsAny(cs, searchCharSequences);
1216    }
1217
1218    /**
1219     * Tests if CharSequence contains a search CharSequence irrespective of case, handling {@code null}. Case-insensitivity is defined as by
1220     * {@link String#equalsIgnoreCase(String)}.
1221     *
1222     * <p>
1223     * A {@code null} CharSequence will return {@code false}.
1224     * </p>
1225     *
1226     * <pre>
1227     * StringUtils.containsIgnoreCase(null, *)    = false
1228     * StringUtils.containsIgnoreCase(*, null)    = false
1229     * StringUtils.containsIgnoreCase("", "")     = true
1230     * StringUtils.containsIgnoreCase("abc", "")  = true
1231     * StringUtils.containsIgnoreCase("abc", "a") = true
1232     * StringUtils.containsIgnoreCase("abc", "z") = false
1233     * StringUtils.containsIgnoreCase("abc", "A") = true
1234     * StringUtils.containsIgnoreCase("abc", "Z") = false
1235     * </pre>
1236     *
1237     * @param str       The CharSequence to check, may be null.
1238     * @param searchStr The CharSequence to find, may be null.
1239     * @return true if the CharSequence contains the search CharSequence irrespective of case or false if not or {@code null} string input.
1240     * @since 3.0 Changed signature from containsIgnoreCase(String, String) to containsIgnoreCase(CharSequence, CharSequence).
1241     * @deprecated Use {@link Strings#contains(CharSequence, CharSequence) Strings.CI.contains(CharSequence, CharSequence)}.
1242     */
1243    @Deprecated
1244    public static boolean containsIgnoreCase(final CharSequence str, final CharSequence searchStr) {
1245        return Strings.CI.contains(str, searchStr);
1246    }
1247
1248    /**
1249     * Tests that the CharSequence does not contain certain characters.
1250     *
1251     * <p>
1252     * A {@code null} CharSequence will return {@code true}. A {@code null} invalid character array will return {@code true}. An empty CharSequence (length()=0)
1253     * always returns true.
1254     * </p>
1255     *
1256     * <pre>
1257     * StringUtils.containsNone(null, *)               = true
1258     * StringUtils.containsNone(*, null)               = true
1259     * StringUtils.containsNone("", *)                 = true
1260     * StringUtils.containsNone("ab", '')              = true
1261     * StringUtils.containsNone("abab", 'x', 'y', 'z') = true
1262     * StringUtils.containsNone("ab1", 'x', 'y', 'z')  = true
1263     * StringUtils.containsNone("abz", 'x', 'y', 'z')  = false
1264     * </pre>
1265     *
1266     * @param cs          The CharSequence to check, may be null.
1267     * @param searchChars An array of invalid chars, may be null.
1268     * @return true if it contains none of the invalid chars, or is null.
1269     * @since 2.0
1270     * @since 3.0 Changed signature from containsNone(String, char[]) to containsNone(CharSequence, char...)
1271     */
1272    public static boolean containsNone(final CharSequence cs, final char... searchChars) {
1273        if (cs == null || searchChars == null) {
1274            return true;
1275        }
1276        final int csLen = cs.length();
1277        final int csLast = csLen - 1;
1278        final int searchLen = searchChars.length;
1279        final int searchLast = searchLen - 1;
1280        for (int i = 0; i < csLen; i++) {
1281            final char ch = cs.charAt(i);
1282            for (int j = 0; j < searchLen; j++) {
1283                if (searchChars[j] == ch) {
1284                    if (Character.isHighSurrogate(ch)
1285                            ? j == searchLast || i < csLast && searchChars[j + 1] == cs.charAt(i + 1)
1286                            : j == 0 || !Character.isLowSurrogate(ch) || !Character.isHighSurrogate(searchChars[j - 1]) || i > 0 && searchChars[j - 1] == cs.charAt(i - 1)) {
1287                        return false;
1288                    }
1289                }
1290            }
1291        }
1292        return true;
1293    }
1294
1295    /**
1296     * Tests that the CharSequence does not contain certain characters.
1297     *
1298     * <p>
1299     * A {@code null} CharSequence will return {@code true}. A {@code null} invalid character array will return {@code true}. An empty String ("") always
1300     * returns true.
1301     * </p>
1302     *
1303     * <pre>
1304     * StringUtils.containsNone(null, *)       = true
1305     * StringUtils.containsNone(*, null)       = true
1306     * StringUtils.containsNone("", *)         = true
1307     * StringUtils.containsNone("ab", "")      = true
1308     * StringUtils.containsNone("abab", "xyz") = true
1309     * StringUtils.containsNone("ab1", "xyz")  = true
1310     * StringUtils.containsNone("abz", "xyz")  = false
1311     * </pre>
1312     *
1313     * @param cs           The CharSequence to check, may be null.
1314     * @param invalidChars A String of invalid chars, may be null.
1315     * @return true if it contains none of the invalid chars, or is null.
1316     * @since 2.0
1317     * @since 3.0 Changed signature from containsNone(String, String) to containsNone(CharSequence, String)
1318     */
1319    public static boolean containsNone(final CharSequence cs, final String invalidChars) {
1320        if (invalidChars == null) {
1321            return true;
1322        }
1323        return containsNone(cs, invalidChars.toCharArray());
1324    }
1325
1326    /**
1327     * Tests if the CharSequence contains only certain characters.
1328     *
1329     * <p>
1330     * A {@code null} CharSequence will return {@code false}. A {@code null} valid character array will return {@code false}. An empty CharSequence (length()=0)
1331     * always returns {@code true}.
1332     * </p>
1333     *
1334     * <pre>
1335     * StringUtils.containsOnly(null, *)               = false
1336     * StringUtils.containsOnly(*, null)               = false
1337     * StringUtils.containsOnly("", *)                 = true
1338     * StringUtils.containsOnly("ab", '')              = false
1339     * StringUtils.containsOnly("abab", 'a', 'b', 'c') = true
1340     * StringUtils.containsOnly("ab1", 'a', 'b', 'c')  = false
1341     * StringUtils.containsOnly("abz", 'a', 'b', 'c')  = false
1342     * </pre>
1343     *
1344     * @param cs    The String to check, may be null.
1345     * @param valid An array of valid chars, may be null.
1346     * @return true if it only contains valid chars and is non-null.
1347     * @since 3.0 Changed signature from containsOnly(String, char[]) to containsOnly(CharSequence, char...)
1348     */
1349    public static boolean containsOnly(final CharSequence cs, final char... valid) {
1350        // All these pre-checks are to maintain API with an older version
1351        if (valid == null || cs == null) {
1352            return false;
1353        }
1354        if (isEmpty(cs)) {
1355            return true;
1356        }
1357        if (valid.length == 0) {
1358            return false;
1359        }
1360        return indexOfAnyBut(cs, valid) == INDEX_NOT_FOUND;
1361    }
1362
1363    /**
1364     * Tests if the CharSequence contains only certain characters.
1365     *
1366     * <p>
1367     * A {@code null} CharSequence will return {@code false}. A {@code null} valid character String will return {@code false}. An empty String (length()=0)
1368     * always returns {@code true}.
1369     * </p>
1370     *
1371     * <pre>
1372     * StringUtils.containsOnly(null, *)       = false
1373     * StringUtils.containsOnly(*, null)       = false
1374     * StringUtils.containsOnly("", *)         = true
1375     * StringUtils.containsOnly("ab", "")      = false
1376     * StringUtils.containsOnly("abab", "abc") = true
1377     * StringUtils.containsOnly("ab1", "abc")  = false
1378     * StringUtils.containsOnly("abz", "abc")  = false
1379     * </pre>
1380     *
1381     * @param cs         The CharSequence to check, may be null.
1382     * @param validChars A String of valid chars, may be null.
1383     * @return true if it only contains valid chars and is non-null.
1384     * @since 2.0
1385     * @since 3.0 Changed signature from containsOnly(String, String) to containsOnly(CharSequence, String)
1386     */
1387    public static boolean containsOnly(final CharSequence cs, final String validChars) {
1388        if (cs == null || validChars == null) {
1389            return false;
1390        }
1391        return containsOnly(cs, validChars.toCharArray());
1392    }
1393
1394    /**
1395     * Tests whether the given CharSequence contains any whitespace characters.
1396     *
1397     * <p>
1398     * Whitespace is defined by {@link Character#isWhitespace(char)}.
1399     * </p>
1400     *
1401     * <pre>
1402     * StringUtils.containsWhitespace(null)       = false
1403     * StringUtils.containsWhitespace("")         = false
1404     * StringUtils.containsWhitespace("ab")       = false
1405     * StringUtils.containsWhitespace(" ab")      = true
1406     * StringUtils.containsWhitespace("a b")      = true
1407     * StringUtils.containsWhitespace("ab ")      = true
1408     * </pre>
1409     *
1410     * @param seq The CharSequence to check (may be {@code null}).
1411     * @return {@code true} if the CharSequence is not empty and contains at least 1 (breaking) whitespace character.
1412     * @since 3.0
1413     */
1414    public static boolean containsWhitespace(final CharSequence seq) {
1415        if (isEmpty(seq)) {
1416            return false;
1417        }
1418        final int strLen = seq.length();
1419        for (int i = 0; i < strLen; i++) {
1420            if (Character.isWhitespace(seq.charAt(i))) {
1421                return true;
1422            }
1423        }
1424        return false;
1425    }
1426
1427    private static void convertRemainingAccentCharacters(final StringBuilder decomposed) {
1428        for (int i = 0; i < decomposed.length(); i++) {
1429            final char charAt = decomposed.charAt(i);
1430            switch (charAt) {
1431            case '\u0141':
1432                decomposed.setCharAt(i, 'L');
1433                break;
1434            case '\u0142':
1435                decomposed.setCharAt(i, 'l');
1436                break;
1437            // D with stroke
1438            case '\u0110':
1439                // LATIN CAPITAL LETTER D WITH STROKE
1440                decomposed.setCharAt(i, 'D');
1441                break;
1442            case '\u0111':
1443                // LATIN SMALL LETTER D WITH STROKE
1444                decomposed.setCharAt(i, 'd');
1445                break;
1446            // I with bar
1447            case '\u0197':
1448                decomposed.setCharAt(i, 'I');
1449                break;
1450            case '\u0268':
1451                decomposed.setCharAt(i, 'i');
1452                break;
1453            case '\u1D7B':
1454                decomposed.setCharAt(i, 'I');
1455                break;
1456            case '\u1DA4':
1457                decomposed.setCharAt(i, 'i');
1458                break;
1459            case '\u1DA7':
1460                decomposed.setCharAt(i, 'I');
1461                break;
1462            // U with bar
1463            case '\u0244':
1464                // LATIN CAPITAL LETTER U BAR
1465                decomposed.setCharAt(i, 'U');
1466                break;
1467            case '\u0289':
1468                // LATIN SMALL LETTER U BAR
1469                decomposed.setCharAt(i, 'u');
1470                break;
1471            case '\u1D7E':
1472                // LATIN SMALL CAPITAL LETTER U WITH STROKE
1473                decomposed.setCharAt(i, 'U');
1474                break;
1475            case '\u1DB6':
1476                // MODIFIER LETTER SMALL U BAR
1477                decomposed.setCharAt(i, 'u');
1478                break;
1479            // T with stroke
1480            case '\u0166':
1481                // LATIN CAPITAL LETTER T WITH STROKE
1482                decomposed.setCharAt(i, 'T');
1483                break;
1484            case '\u0167':
1485                // LATIN SMALL LETTER T WITH STROKE
1486                decomposed.setCharAt(i, 't');
1487                break;
1488            default:
1489                break;
1490            }
1491        }
1492    }
1493
1494    /**
1495     * Counts how many times the char appears in the given string.
1496     *
1497     * <p>
1498     * A {@code null} or empty ("") String input returns {@code 0}.
1499     * </p>
1500     *
1501     * <pre>
1502     * StringUtils.countMatches(null, *)     = 0
1503     * StringUtils.countMatches("", *)       = 0
1504     * StringUtils.countMatches("abba", 0)   = 0
1505     * StringUtils.countMatches("abba", 'a') = 2
1506     * StringUtils.countMatches("abba", 'b') = 2
1507     * StringUtils.countMatches("abba", 'x') = 0
1508     * </pre>
1509     *
1510     * @param str The CharSequence to check, may be null.
1511     * @param ch  The char to count.
1512     * @return The number of occurrences, 0 if the CharSequence is {@code null}.
1513     * @since 3.4
1514     */
1515    public static int countMatches(final CharSequence str, final char ch) {
1516        if (isEmpty(str)) {
1517            return 0;
1518        }
1519        int count = 0;
1520        // We could also call str.toCharArray() for faster lookups but that would generate more garbage.
1521        for (int i = 0; i < str.length(); i++) {
1522            if (ch == str.charAt(i)) {
1523                count++;
1524            }
1525        }
1526        return count;
1527    }
1528
1529    /**
1530     * Counts how many times the substring appears in the larger string. Note that the code only counts non-overlapping matches.
1531     *
1532     * <p>
1533     * A {@code null} or empty ("") String input returns {@code 0}.
1534     * </p>
1535     *
1536     * <pre>
1537     * StringUtils.countMatches(null, *)        = 0
1538     * StringUtils.countMatches("", *)          = 0
1539     * StringUtils.countMatches("abba", null)   = 0
1540     * StringUtils.countMatches("abba", "")     = 0
1541     * StringUtils.countMatches("abba", "a")    = 2
1542     * StringUtils.countMatches("abba", "ab")   = 1
1543     * StringUtils.countMatches("abba", "xxx")  = 0
1544     * StringUtils.countMatches("ababa", "aba") = 1
1545     * </pre>
1546     *
1547     * @param str The CharSequence to check, may be null.
1548     * @param sub The substring to count, may be null.
1549     * @return The number of occurrences, 0 if either CharSequence is {@code null}.
1550     * @since 3.0 Changed signature from countMatches(String, String) to countMatches(CharSequence, CharSequence)
1551     */
1552    public static int countMatches(final CharSequence str, final CharSequence sub) {
1553        if (isEmpty(str) || isEmpty(sub)) {
1554            return 0;
1555        }
1556        int count = 0;
1557        int idx = 0;
1558        while ((idx = CharSequenceUtils.indexOf(str, sub, idx)) != INDEX_NOT_FOUND) {
1559            count++;
1560            idx += sub.length();
1561        }
1562        return count;
1563    }
1564
1565    /**
1566     * Returns either the passed in CharSequence, or if the CharSequence is {@link #isBlank(CharSequence) blank} (whitespaces, empty ({@code ""}), or
1567     * {@code null}), the value of {@code defaultStr}.
1568     *
1569     * <p>
1570     * Whitespace is defined by {@link Character#isWhitespace(char)}.
1571     * </p>
1572     *
1573     * <pre>
1574     * StringUtils.defaultIfBlank(null, "NULL")  = "NULL"
1575     * StringUtils.defaultIfBlank("", "NULL")    = "NULL"
1576     * StringUtils.defaultIfBlank(" ", "NULL")   = "NULL"
1577     * StringUtils.defaultIfBlank("bat", "NULL") = "bat"
1578     * StringUtils.defaultIfBlank("", null)      = null
1579     * </pre>
1580     *
1581     * @param <T>        the specific kind of CharSequence.
1582     * @param str        The CharSequence to check, may be null.
1583     * @param defaultStr The default CharSequence to return if {@code str} is {@link #isBlank(CharSequence) blank} (whitespaces, empty ({@code ""}), or
1584     *                   {@code null}); may be null.
1585     * @return The passed in CharSequence, or the default.
1586     * @see StringUtils#defaultString(String, String)
1587     * @see #isBlank(CharSequence)
1588     */
1589    public static <T extends CharSequence> T defaultIfBlank(final T str, final T defaultStr) {
1590        return isBlank(str) ? defaultStr : str;
1591    }
1592
1593    /**
1594     * Returns either the passed in CharSequence, or if the CharSequence is empty or {@code null}, the value of {@code defaultStr}.
1595     *
1596     * <pre>
1597     * StringUtils.defaultIfEmpty(null, "NULL")  = "NULL"
1598     * StringUtils.defaultIfEmpty("", "NULL")    = "NULL"
1599     * StringUtils.defaultIfEmpty(" ", "NULL")   = " "
1600     * StringUtils.defaultIfEmpty("bat", "NULL") = "bat"
1601     * StringUtils.defaultIfEmpty("", null)      = null
1602     * </pre>
1603     *
1604     * @param <T>        the specific kind of CharSequence.
1605     * @param str        The CharSequence to check, may be null.
1606     * @param defaultStr The default CharSequence to return if the input is empty ("") or {@code null}, may be null.
1607     * @return The passed in CharSequence, or the default.
1608     * @see StringUtils#defaultString(String, String)
1609     */
1610    public static <T extends CharSequence> T defaultIfEmpty(final T str, final T defaultStr) {
1611        return isEmpty(str) ? defaultStr : str;
1612    }
1613
1614    /**
1615     * Returns either the passed in String, or if the String is {@code null}, an empty String ("").
1616     *
1617     * <pre>
1618     * StringUtils.defaultString(null)  = ""
1619     * StringUtils.defaultString("")    = ""
1620     * StringUtils.defaultString("bat") = "bat"
1621     * </pre>
1622     *
1623     * @param str The String to check, may be null.
1624     * @return The passed in String, or the empty String if it was {@code null}.
1625     * @see Objects#toString(Object, String)
1626     * @see String#valueOf(Object)
1627     */
1628    public static String defaultString(final String str) {
1629        return Objects.toString(str, EMPTY);
1630    }
1631
1632    /**
1633     * Returns either the given String, or if the String is {@code null}, {@code nullDefault}.
1634     *
1635     * <pre>
1636     * StringUtils.defaultString(null, "NULL")  = "NULL"
1637     * StringUtils.defaultString("", "NULL")    = ""
1638     * StringUtils.defaultString("bat", "NULL") = "bat"
1639     * </pre>
1640     * <p>
1641     * Since this is now provided by Java, instead call {@link Objects#toString(Object, String)}:
1642     * </p>
1643     *
1644     * <pre>
1645     * Objects.toString(null, "NULL")  = "NULL"
1646     * Objects.toString("", "NULL")    = ""
1647     * Objects.toString("bat", "NULL") = "bat"
1648     * </pre>
1649     *
1650     * @param str         The String to check, may be null.
1651     * @param nullDefault The default String to return if the input is {@code null}, may be null.
1652     * @return The passed in String, or the default if it was {@code null}.
1653     * @see Objects#toString(Object, String)
1654     * @see String#valueOf(Object)
1655     * @deprecated Use {@link Objects#toString(Object, String)}.
1656     */
1657    @Deprecated
1658    public static String defaultString(final String str, final String nullDefault) {
1659        return Objects.toString(str, nullDefault);
1660    }
1661
1662    /**
1663     * Deletes all whitespaces from a String as defined by {@link Character#isWhitespace(char)}.
1664     *
1665     * <pre>
1666     * StringUtils.deleteWhitespace(null)         = null
1667     * StringUtils.deleteWhitespace("")           = ""
1668     * StringUtils.deleteWhitespace("abc")        = "abc"
1669     * StringUtils.deleteWhitespace("   ab  c  ") = "abc"
1670     * </pre>
1671     *
1672     * @param str The String to delete whitespace from, may be null.
1673     * @return The String without whitespaces, {@code null} if null String input.
1674     */
1675    public static String deleteWhitespace(final String str) {
1676        if (isEmpty(str)) {
1677            return str;
1678        }
1679        final int sz = str.length();
1680        final char[] chs = new char[sz];
1681        int count = 0;
1682        for (int i = 0; i < sz; i++) {
1683            if (!Character.isWhitespace(str.charAt(i))) {
1684                chs[count++] = str.charAt(i);
1685            }
1686        }
1687        if (count == sz) {
1688            return str;
1689        }
1690        if (count == 0) {
1691            return EMPTY;
1692        }
1693        return new String(chs, 0, count);
1694    }
1695
1696    /**
1697     * Compares two Strings, and returns the portion where they differ. More precisely, return the remainder of the second String, starting from where it's
1698     * different from the first. This means that the difference between "abc" and "ab" is the empty String and not "c".
1699     *
1700     * <p>
1701     * For example, {@code difference("i am a machine", "i am a robot") -> "robot"}.
1702     * </p>
1703     *
1704     * <pre>
1705     * StringUtils.difference(null, null)       = null
1706     * StringUtils.difference("", "")           = ""
1707     * StringUtils.difference("", "abc")        = "abc"
1708     * StringUtils.difference("abc", "")        = ""
1709     * StringUtils.difference("abc", "abc")     = ""
1710     * StringUtils.difference("abc", "ab")      = ""
1711     * StringUtils.difference("ab", "abxyz")    = "xyz"
1712     * StringUtils.difference("abcde", "abxyz") = "xyz"
1713     * StringUtils.difference("abcde", "xyz")   = "xyz"
1714     * </pre>
1715     *
1716     * @param str1 The first String, may be null.
1717     * @param str2 The second String, may be null.
1718     * @return The portion of str2 where it differs from str1; returns the empty String if they are equal.
1719     * @see #indexOfDifference(CharSequence,CharSequence)
1720     * @since 2.0
1721     */
1722    public static String difference(final String str1, final String str2) {
1723        if (str1 == null) {
1724            return str2;
1725        }
1726        if (str2 == null) {
1727            return str1;
1728        }
1729        final int at = indexOfDifference(str1, str2);
1730        if (at == INDEX_NOT_FOUND) {
1731            return EMPTY;
1732        }
1733        return str2.substring(at);
1734    }
1735
1736    /**
1737     * Tests if a CharSequence ends with a specified suffix.
1738     *
1739     * <p>
1740     * {@code null}s are handled without exceptions. Two {@code null} references are considered to be equal. The comparison is case-sensitive.
1741     * </p>
1742     *
1743     * <pre>
1744     * StringUtils.endsWith(null, null)      = true
1745     * StringUtils.endsWith(null, "def")     = false
1746     * StringUtils.endsWith("abcdef", null)  = false
1747     * StringUtils.endsWith("abcdef", "def") = true
1748     * StringUtils.endsWith("ABCDEF", "def") = false
1749     * StringUtils.endsWith("ABCDEF", "cde") = false
1750     * StringUtils.endsWith("ABCDEF", "")    = true
1751     * </pre>
1752     *
1753     * @param str    The CharSequence to check, may be null.
1754     * @param suffix The suffix to find, may be null.
1755     * @return {@code true} if the CharSequence ends with the suffix, case-sensitive, or both {@code null}.
1756     * @see String#endsWith(String)
1757     * @since 2.4
1758     * @since 3.0 Changed signature from endsWith(String, String) to endsWith(CharSequence, CharSequence)
1759     * @deprecated Use {@link Strings#endsWith(CharSequence, CharSequence) Strings.CS.endsWith(CharSequence, CharSequence)}.
1760     */
1761    @Deprecated
1762    public static boolean endsWith(final CharSequence str, final CharSequence suffix) {
1763        return Strings.CS.endsWith(str, suffix);
1764    }
1765
1766    /**
1767     * Tests if a CharSequence ends with any of the provided case-sensitive suffixes.
1768     *
1769     * <pre>
1770     * StringUtils.endsWithAny(null, null)                  = false
1771     * StringUtils.endsWithAny(null, new String[] {"abc"})  = false
1772     * StringUtils.endsWithAny("abcxyz", null)              = false
1773     * StringUtils.endsWithAny("abcxyz", new String[] {""}) = true
1774     * StringUtils.endsWithAny("abcxyz", new String[] {"xyz"}) = true
1775     * StringUtils.endsWithAny("abcxyz", new String[] {null, "xyz", "abc"}) = true
1776     * StringUtils.endsWithAny("abcXYZ", "def", "XYZ")      = true
1777     * StringUtils.endsWithAny("abcXYZ", "def", "xyz")      = false
1778     * </pre>
1779     *
1780     * @param sequence      The CharSequence to check, may be null.
1781     * @param searchStrings The case-sensitive CharSequences to find, may be empty or contain {@code null}.
1782     * @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
1783     *         of the provided case-sensitive {@code searchStrings}.
1784     * @see StringUtils#endsWith(CharSequence, CharSequence)
1785     * @since 3.0
1786     * @deprecated Use {@link Strings#endsWithAny(CharSequence, CharSequence...) Strings.CS.endsWithAny(CharSequence, CharSequence...)}.
1787     */
1788    @Deprecated
1789    public static boolean endsWithAny(final CharSequence sequence, final CharSequence... searchStrings) {
1790        return Strings.CS.endsWithAny(sequence, searchStrings);
1791    }
1792
1793    /**
1794     * Case-insensitive check if a CharSequence ends with a specified suffix.
1795     *
1796     * <p>
1797     * {@code null}s are handled without exceptions. Two {@code null} references are considered to be equal. The comparison is case insensitive.
1798     * </p>
1799     *
1800     * <pre>
1801     * StringUtils.endsWithIgnoreCase(null, null)      = true
1802     * StringUtils.endsWithIgnoreCase(null, "def")     = false
1803     * StringUtils.endsWithIgnoreCase("abcdef", null)  = false
1804     * StringUtils.endsWithIgnoreCase("abcdef", "def") = true
1805     * StringUtils.endsWithIgnoreCase("ABCDEF", "def") = true
1806     * StringUtils.endsWithIgnoreCase("ABCDEF", "cde") = false
1807     * </pre>
1808     *
1809     * @param str    The CharSequence to check, may be null
1810     * @param suffix The suffix to find, may be null
1811     * @return {@code true} if the CharSequence ends with the suffix, case-insensitive, or both {@code null}
1812     * @see String#endsWith(String)
1813     * @since 2.4
1814     * @since 3.0 Changed signature from endsWithIgnoreCase(String, String) to endsWithIgnoreCase(CharSequence, CharSequence)
1815     * @deprecated Use {@link Strings#endsWith(CharSequence, CharSequence) Strings.CI.endsWith(CharSequence, CharSequence)}.
1816     */
1817    @Deprecated
1818    public static boolean endsWithIgnoreCase(final CharSequence str, final CharSequence suffix) {
1819        return Strings.CI.endsWith(str, suffix);
1820    }
1821
1822    /**
1823     * Compares two CharSequences, returning {@code true} if they represent equal sequences of characters.
1824     *
1825     * <p>
1826     * {@code null}s are handled without exceptions. Two {@code null} references are considered to be equal. The comparison is <strong>case-sensitive</strong>.
1827     * </p>
1828     *
1829     * <pre>
1830     * StringUtils.equals(null, null)   = true
1831     * StringUtils.equals(null, "abc")  = false
1832     * StringUtils.equals("abc", null)  = false
1833     * StringUtils.equals("abc", "abc") = true
1834     * StringUtils.equals("abc", "ABC") = false
1835     * </pre>
1836     *
1837     * @param cs1 The first CharSequence, may be {@code null}.
1838     * @param cs2 The second CharSequence, may be {@code null}.
1839     * @return {@code true} if the CharSequences are equal (case-sensitive), or both {@code null}.
1840     * @since 3.0 Changed signature from equals(String, String) to equals(CharSequence, CharSequence)
1841     * @see Object#equals(Object)
1842     * @see #equalsIgnoreCase(CharSequence, CharSequence)
1843     * @deprecated Use {@link Strings#equals(CharSequence, CharSequence) Strings.CS.equals(CharSequence, CharSequence)}.
1844     */
1845    @Deprecated
1846    public static boolean equals(final CharSequence cs1, final CharSequence cs2) {
1847        return Strings.CS.equals(cs1, cs2);
1848    }
1849
1850    /**
1851     * Compares given {@code string} to a CharSequences vararg of {@code searchStrings}, returning {@code true} if the {@code string} is equal to any of the
1852     * {@code searchStrings}.
1853     *
1854     * <pre>
1855     * StringUtils.equalsAny(null, (CharSequence[]) null) = false
1856     * StringUtils.equalsAny(null, null, null)    = true
1857     * StringUtils.equalsAny(null, "abc", "def")  = false
1858     * StringUtils.equalsAny("abc", null, "def")  = false
1859     * StringUtils.equalsAny("abc", "abc", "def") = true
1860     * StringUtils.equalsAny("abc", "ABC", "DEF") = false
1861     * </pre>
1862     *
1863     * @param string        to compare, may be {@code null}.
1864     * @param searchStrings A vararg of strings, may be {@code null}.
1865     * @return {@code true} if the string is equal (case-sensitive) to any other element of {@code searchStrings}; {@code false} if {@code searchStrings} is
1866     *         null or contains no matches.
1867     * @since 3.5
1868     * @deprecated Use {@link Strings#equalsAny(CharSequence, CharSequence...) Strings.CS.equalsAny(CharSequence, CharSequence...)}.
1869     */
1870    @Deprecated
1871    public static boolean equalsAny(final CharSequence string, final CharSequence... searchStrings) {
1872        return Strings.CS.equalsAny(string, searchStrings);
1873    }
1874
1875    /**
1876     * Compares given {@code string} to a CharSequences vararg of {@code searchStrings},
1877     * returning {@code true} if the {@code string} is equal to any of the {@code searchStrings}, ignoring case.
1878     *
1879     * <pre>
1880     * StringUtils.equalsAnyIgnoreCase(null, (CharSequence[]) null) = false
1881     * StringUtils.equalsAnyIgnoreCase(null, null, null)    = true
1882     * StringUtils.equalsAnyIgnoreCase(null, "abc", "def")  = false
1883     * StringUtils.equalsAnyIgnoreCase("abc", null, "def")  = false
1884     * StringUtils.equalsAnyIgnoreCase("abc", "abc", "def") = true
1885     * StringUtils.equalsAnyIgnoreCase("abc", "ABC", "DEF") = true
1886     * </pre>
1887     *
1888     * @param string to compare, may be {@code null}.
1889     * @param searchStrings A vararg of strings, may be {@code null}.
1890     * @return {@code true} if the string is equal (case-insensitive) to any other element of {@code searchStrings};
1891     * {@code false} if {@code searchStrings} is null or contains no matches.
1892     * @since 3.5
1893     * @deprecated Use {@link Strings#equalsAny(CharSequence, CharSequence...) Strings.CI.equalsAny(CharSequence, CharSequence...)}.
1894     */
1895    @Deprecated
1896    public static boolean equalsAnyIgnoreCase(final CharSequence string, final CharSequence... searchStrings) {
1897        return Strings.CI.equalsAny(string, searchStrings);
1898    }
1899
1900    /**
1901     * Compares two CharSequences, returning {@code true} if they represent equal sequences of characters, ignoring case.
1902     *
1903     * <p>
1904     * {@code null}s are handled without exceptions. Two {@code null} references are considered equal. The comparison is <strong>case insensitive</strong>.
1905     * </p>
1906     *
1907     * <pre>
1908     * StringUtils.equalsIgnoreCase(null, null)   = true
1909     * StringUtils.equalsIgnoreCase(null, "abc")  = false
1910     * StringUtils.equalsIgnoreCase("abc", null)  = false
1911     * StringUtils.equalsIgnoreCase("abc", "abc") = true
1912     * StringUtils.equalsIgnoreCase("abc", "ABC") = true
1913     * </pre>
1914     *
1915     * @param cs1 The first CharSequence, may be {@code null}.
1916     * @param cs2 The second CharSequence, may be {@code null}.
1917     * @return {@code true} if the CharSequences are equal (case-insensitive), or both {@code null}.
1918     * @since 3.0 Changed signature from equalsIgnoreCase(String, String) to equalsIgnoreCase(CharSequence, CharSequence)
1919     * @see #equals(CharSequence, CharSequence)
1920     * @deprecated Use {@link Strings#equals(CharSequence, CharSequence) Strings.CI.equals(CharSequence, CharSequence)}.
1921     */
1922    @Deprecated
1923    public static boolean equalsIgnoreCase(final CharSequence cs1, final CharSequence cs2) {
1924        return Strings.CI.equals(cs1, cs2);
1925    }
1926
1927    /**
1928     * Returns the first value in the array which is not empty (""), {@code null} or whitespace only.
1929     *
1930     * <p>
1931     * Whitespace is defined by {@link Character#isWhitespace(char)}.
1932     * </p>
1933     *
1934     * <p>
1935     * If all values are blank or the array is {@code null} or empty then {@code null} is returned.
1936     * </p>
1937     *
1938     * <pre>
1939     * StringUtils.firstNonBlank(null, null, null)     = null
1940     * StringUtils.firstNonBlank(null, "", " ")        = null
1941     * StringUtils.firstNonBlank("abc")                = "abc"
1942     * StringUtils.firstNonBlank(null, "xyz")          = "xyz"
1943     * StringUtils.firstNonBlank(null, "", " ", "xyz") = "xyz"
1944     * StringUtils.firstNonBlank(null, "xyz", "abc")   = "xyz"
1945     * StringUtils.firstNonBlank()                     = null
1946     * </pre>
1947     *
1948     * @param <T>    the specific kind of CharSequence.
1949     * @param values The values to test, may be {@code null} or empty.
1950     * @return The first value from {@code values} which is not blank, or {@code null} if there are no non-blank values.
1951     * @since 3.8
1952     */
1953    @SafeVarargs
1954    public static <T extends CharSequence> T firstNonBlank(final T... values) {
1955        if (values != null) {
1956            for (final T val : values) {
1957                if (isNotBlank(val)) {
1958                    return val;
1959                }
1960            }
1961        }
1962        return null;
1963    }
1964
1965    /**
1966     * Returns the first value in the array which is not empty.
1967     *
1968     * <p>
1969     * If all values are empty or the array is {@code null} or empty then {@code null} is returned.
1970     * </p>
1971     *
1972     * <pre>
1973     * StringUtils.firstNonEmpty(null, null, null)   = null
1974     * StringUtils.firstNonEmpty(null, null, "")     = null
1975     * StringUtils.firstNonEmpty(null, "", " ")      = " "
1976     * StringUtils.firstNonEmpty("abc")              = "abc"
1977     * StringUtils.firstNonEmpty(null, "xyz")        = "xyz"
1978     * StringUtils.firstNonEmpty("", "xyz")          = "xyz"
1979     * StringUtils.firstNonEmpty(null, "xyz", "abc") = "xyz"
1980     * StringUtils.firstNonEmpty()                   = null
1981     * </pre>
1982     *
1983     * @param <T>    the specific kind of CharSequence.
1984     * @param values The values to test, may be {@code null} or empty.
1985     * @return The first value from {@code values} which is not empty, or {@code null} if there are no non-empty values.
1986     * @since 3.8
1987     */
1988    @SafeVarargs
1989    public static <T extends CharSequence> T firstNonEmpty(final T... values) {
1990        if (values != null) {
1991            for (final T val : values) {
1992                if (isNotEmpty(val)) {
1993                    return val;
1994                }
1995            }
1996        }
1997        return null;
1998    }
1999
2000    /**
2001     * Gets the bytes of the string using {@link String#getBytes(Charset)}, handling {@code null} safely.
2002     *
2003     * @param string input string.
2004     * @param charset The {@link Charset} to encode the {@link String}. If null, then use the default Charset.
2005     * @return The empty byte[] if {@code string} is null, the result of {@link String#getBytes(Charset)} otherwise.
2006     * @see String#getBytes(Charset)
2007     * @since 3.10
2008     */
2009    public static byte[] getBytes(final String string, final Charset charset) {
2010        return string == null ? ArrayUtils.EMPTY_BYTE_ARRAY : string.getBytes(Charsets.toCharset(charset));
2011    }
2012
2013    /**
2014     * Gets the bytes of the string using {@link String#getBytes(String)}, handling {@code null} safely.
2015     *
2016     * @param string input string.
2017     * @param charset The {@link Charset} name to encode the {@link String}. If null, then use the default Charset.
2018     * @return The empty byte[] if {@code string} is null, the result of {@link String#getBytes(String)} otherwise.
2019     * @throws UnsupportedEncodingException Thrown when the named charset is not supported.
2020     * @see String#getBytes(String)
2021     * @since 3.10
2022     */
2023    public static byte[] getBytes(final String string, final String charset) throws UnsupportedEncodingException {
2024        return string == null ? ArrayUtils.EMPTY_BYTE_ARRAY : string.getBytes(Charsets.toCharsetName(charset));
2025    }
2026
2027    /**
2028     * Gets the initial sequence of characters common to all strings in the array.
2029     *
2030     * <p>
2031     * For example, {@code getCommonPrefix("i am a machine", "i am a robot") -&gt; "i am a "}
2032     * </p>
2033     *
2034     * <pre>
2035     * StringUtils.getCommonPrefix(null)                             = ""
2036     * StringUtils.getCommonPrefix(new String[] {})                  = ""
2037     * StringUtils.getCommonPrefix(new String[] {"abc"})             = "abc"
2038     * StringUtils.getCommonPrefix(new String[] {null, null})        = ""
2039     * StringUtils.getCommonPrefix(new String[] {"", ""})            = ""
2040     * StringUtils.getCommonPrefix(new String[] {"", null})          = ""
2041     * StringUtils.getCommonPrefix(new String[] {"abc", null, null}) = ""
2042     * StringUtils.getCommonPrefix(new String[] {null, null, "abc"}) = ""
2043     * StringUtils.getCommonPrefix(new String[] {"", "abc"})         = ""
2044     * StringUtils.getCommonPrefix(new String[] {"abc", ""})         = ""
2045     * StringUtils.getCommonPrefix(new String[] {"abc", "abc"})      = "abc"
2046     * StringUtils.getCommonPrefix(new String[] {"abc", "a"})        = "a"
2047     * StringUtils.getCommonPrefix(new String[] {"ab", "abxyz"})     = "ab"
2048     * StringUtils.getCommonPrefix(new String[] {"abcde", "abxyz"})  = "ab"
2049     * StringUtils.getCommonPrefix(new String[] {"abcde", "xyz"})    = ""
2050     * StringUtils.getCommonPrefix(new String[] {"xyz", "abcde"})    = ""
2051     * StringUtils.getCommonPrefix(new String[] {"i am a machine", "i am a robot"}) = "i am a "
2052     * </pre>
2053     *
2054     * @param strs array of String objects, entries may be null.
2055     * @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
2056     *         if there is no common prefix.
2057     * @since 2.4
2058     */
2059    public static String getCommonPrefix(final String... strs) {
2060        if (ArrayUtils.isEmpty(strs)) {
2061            return EMPTY;
2062        }
2063        final int smallestIndexOfDiff = indexOfDifference(strs);
2064        if (smallestIndexOfDiff == INDEX_NOT_FOUND) {
2065            // all strings were identical
2066            if (strs[0] == null) {
2067                return EMPTY;
2068            }
2069            return strs[0];
2070        }
2071        if (smallestIndexOfDiff == 0) {
2072            // there were no common initial characters
2073            return EMPTY;
2074        }
2075        // we found a common initial character sequence
2076        return strs[0].substring(0, smallestIndexOfDiff);
2077    }
2078
2079    /**
2080     * Gets the Unicode digits in {@code str}, concatenated in their original order.
2081     *
2082     * <p>
2083     * An empty ("") String will be returned if no digits are found in {@code str}.
2084     * </p>
2085     *
2086     * <pre>
2087     * StringUtils.getDigits(null)                 = null
2088     * StringUtils.getDigits("")                   = ""
2089     * StringUtils.getDigits("abc")                = ""
2090     * StringUtils.getDigits("1000$")              = "1000"
2091     * StringUtils.getDigits("1123~45")            = "112345"
2092     * StringUtils.getDigits("(541) 754-3010")     = "5417543010"
2093     * StringUtils.getDigits("\u0967\u0968\u0969") = "\u0967\u0968\u0969"
2094     * </pre>
2095     *
2096     * @param str The String to extract digits from, may be null.
2097     * @return String with only digits, or an empty ("") String if no digits are found, or {@code null} String if {@code str} is null.
2098     * @since 3.6
2099     */
2100    public static String getDigits(final String str) {
2101        if (isEmpty(str)) {
2102            return str;
2103        }
2104        final int len = str.length();
2105        final char[] buffer = new char[len];
2106        int count = 0;
2107
2108        for (int i = 0; i < len;) {
2109            final int codePoint = str.codePointAt(i);
2110            if (Character.isDigit(codePoint)) {
2111                count += Character.toChars(codePoint, buffer, count);
2112            }
2113            i += Character.charCount(codePoint);
2114        }
2115        return new String(buffer, 0, count);
2116    }
2117
2118    /**
2119     * Gets the Fuzzy Distance which indicates the similarity score between two Strings.
2120     *
2121     * <p>
2122     * 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
2123     * matched character. Subsequent matches yield two bonus points. A higher score indicates a higher similarity.
2124     * </p>
2125     *
2126     * <pre>
2127     * StringUtils.getFuzzyDistance(null, null, null)                                    = Throws {@link IllegalArgumentException}
2128     * StringUtils.getFuzzyDistance("", "", Locale.ENGLISH)                              = 0
2129     * StringUtils.getFuzzyDistance("Workshop", "b", Locale.ENGLISH)                     = 0
2130     * StringUtils.getFuzzyDistance("Room", "o", Locale.ENGLISH)                         = 1
2131     * StringUtils.getFuzzyDistance("Workshop", "w", Locale.ENGLISH)                     = 1
2132     * StringUtils.getFuzzyDistance("Workshop", "ws", Locale.ENGLISH)                    = 2
2133     * StringUtils.getFuzzyDistance("Workshop", "wo", Locale.ENGLISH)                    = 4
2134     * StringUtils.getFuzzyDistance("Apache Software Foundation", "asf", Locale.ENGLISH) = 3
2135     * </pre>
2136     *
2137     * @param term   A full term that should be matched against, must not be null.
2138     * @param query  The query that will be matched against a term, must not be null.
2139     * @param locale This string matching logic is case-insensitive. A locale is necessary to normalize both Strings to lower case.
2140     * @return result score.
2141     * @throws IllegalArgumentException Thrown if either String input {@code null} or Locale input {@code null}.
2142     * @since 3.4
2143     * @deprecated As of 3.6, use Apache Commons Text
2144     *             <a href="https://commons.apache.org/proper/commons-text/javadocs/api-release/org/apache/commons/text/similarity/FuzzyScore.html">
2145     *             FuzzyScore</a> instead.
2146     */
2147    @Deprecated
2148    public static int getFuzzyDistance(final CharSequence term, final CharSequence query, final Locale locale) {
2149        if (term == null || query == null) {
2150            throw new IllegalArgumentException("Strings must not be null");
2151        }
2152        if (locale == null) {
2153            throw new IllegalArgumentException("Locale must not be null");
2154        }
2155        // fuzzy logic is case-insensitive. We normalize the Strings to lower
2156        // case right from the start. Turning characters to lower case
2157        // via Character.toLowerCase(char) is unfortunately insufficient
2158        // as it does not accept a locale.
2159        final String termLowerCase = term.toString().toLowerCase(locale);
2160        final String queryLowerCase = query.toString().toLowerCase(locale);
2161        // the resulting score
2162        int score = 0;
2163        // the position in the term which will be scanned next for potential
2164        // query character matches
2165        int termIndex = 0;
2166        // index of the previously matched character in the term
2167        int previousMatchingCharacterIndex = Integer.MIN_VALUE;
2168        for (int queryIndex = 0; queryIndex < queryLowerCase.length(); queryIndex++) {
2169            final char queryChar = queryLowerCase.charAt(queryIndex);
2170            boolean termCharacterMatchFound = false;
2171            for (; termIndex < termLowerCase.length() && !termCharacterMatchFound; termIndex++) {
2172                final char termChar = termLowerCase.charAt(termIndex);
2173                if (queryChar == termChar) {
2174                    // simple character matches result in one point
2175                    score++;
2176                    // subsequent character matches further improve
2177                    // the score.
2178                    if (previousMatchingCharacterIndex + 1 == termIndex) {
2179                        score += 2;
2180                    }
2181                    previousMatchingCharacterIndex = termIndex;
2182                    // we can leave the nested loop. Every character in the
2183                    // query can match at most one character in the term.
2184                    termCharacterMatchFound = true;
2185                }
2186            }
2187        }
2188        return score;
2189    }
2190
2191    /**
2192     * Gets either the passed in CharSequence, or if the CharSequence is {@link #isBlank(CharSequence) blank} (whitespaces, empty ({@code ""}), or
2193     * {@code null}), the value supplied by {@code defaultStrSupplier}.
2194     *
2195     * <p>
2196     * Whitespace is defined by {@link Character#isWhitespace(char)}.
2197     * </p>
2198     *
2199     * <p>
2200     * The caller is responsible for thread safety and exception handling for the default value supplier.
2201     * </p>
2202     *
2203     * <pre>
2204     * {@code
2205     * StringUtils.getIfBlank(null, () -> "NULL")   = "NULL"
2206     * StringUtils.getIfBlank("", () -> "NULL")     = "NULL"
2207     * StringUtils.getIfBlank(" ", () -> "NULL")    = "NULL"
2208     * StringUtils.getIfBlank("bat", () -> "NULL")  = "bat"
2209     * StringUtils.getIfBlank("", () -> null)       = null
2210     * StringUtils.getIfBlank("", null)             = null
2211     * }</pre>
2212     *
2213     * @param <T>             the specific kind of CharSequence.
2214     * @param str             The CharSequence to check, may be null.
2215     * @param defaultSupplier The supplier of default CharSequence to return if the input is {@link #isBlank(CharSequence) blank} (whitespaces, empty
2216     *                        ({@code ""}), or {@code null}); may be null.
2217     * @return The passed in CharSequence, or the default
2218     * @see StringUtils#defaultString(String, String)
2219     * @see #isBlank(CharSequence)
2220     * @since 3.10
2221     */
2222    public static <T extends CharSequence> T getIfBlank(final T str, final Supplier<T> defaultSupplier) {
2223        return isBlank(str) ? Suppliers.get(defaultSupplier) : str;
2224    }
2225
2226    /**
2227     * Gets either the passed in CharSequence, or if the CharSequence is empty or {@code null}, the value supplied by {@code defaultStrSupplier}.
2228     *
2229     * <p>
2230     * The caller is responsible for thread safety and exception handling for the default value supplier.
2231     * </p>
2232     *
2233     * <pre>
2234     * {@code
2235     * StringUtils.getIfEmpty(null, () -> "NULL")    = "NULL"
2236     * StringUtils.getIfEmpty("", () -> "NULL")      = "NULL"
2237     * StringUtils.getIfEmpty(" ", () -> "NULL")     = " "
2238     * StringUtils.getIfEmpty("bat", () -> "NULL")   = "bat"
2239     * StringUtils.getIfEmpty("", () -> null)        = null
2240     * StringUtils.getIfEmpty("", null)              = null
2241     * }
2242     * </pre>
2243     *
2244     * @param <T>             the specific kind of CharSequence.
2245     * @param str             The CharSequence to check, may be null.
2246     * @param defaultSupplier The supplier of default CharSequence to return if the input is empty ("") or {@code null}, may be null.
2247     * @return The passed in CharSequence, or the default.
2248     * @see StringUtils#defaultString(String, String)
2249     * @since 3.10
2250     */
2251    public static <T extends CharSequence> T getIfEmpty(final T str, final Supplier<T> defaultSupplier) {
2252        return isEmpty(str) ? Suppliers.get(defaultSupplier) : str;
2253    }
2254
2255    /**
2256     * Gets the Jaro Winkler Distance which indicates the similarity score between two Strings.
2257     *
2258     * <p>
2259     * The Jaro measure is the weighted sum of percentage of matched characters from each file and transposed characters. Winkler increased this measure for
2260     * matching initial characters.
2261     * </p>
2262     *
2263     * <p>
2264     * This implementation is based on the Jaro Winkler similarity algorithm from
2265     * <a href="https://en.wikipedia.org/wiki/Jaro%E2%80%93Winkler_distance">https://en.wikipedia.org/wiki/Jaro%E2%80%93Winkler_distance</a>.
2266     * </p>
2267     *
2268     * <pre>
2269     * StringUtils.getJaroWinklerDistance(null, null)          = Throws {@link IllegalArgumentException}
2270     * StringUtils.getJaroWinklerDistance("", "")              = 0.0
2271     * StringUtils.getJaroWinklerDistance("", "a")             = 0.0
2272     * StringUtils.getJaroWinklerDistance("aaapppp", "")       = 0.0
2273     * StringUtils.getJaroWinklerDistance("frog", "fog")       = 0.93
2274     * StringUtils.getJaroWinklerDistance("fly", "ant")        = 0.0
2275     * StringUtils.getJaroWinklerDistance("elephant", "hippo") = 0.44
2276     * StringUtils.getJaroWinklerDistance("hippo", "elephant") = 0.44
2277     * StringUtils.getJaroWinklerDistance("hippo", "zzzzzzzz") = 0.0
2278     * StringUtils.getJaroWinklerDistance("hello", "hallo")    = 0.88
2279     * StringUtils.getJaroWinklerDistance("ABC Corporation", "ABC Corp") = 0.93
2280     * StringUtils.getJaroWinklerDistance("D N H Enterprises Inc", "D &amp; H Enterprises, Inc.") = 0.95
2281     * StringUtils.getJaroWinklerDistance("My Gym Children's Fitness Center", "My Gym. Childrens Fitness") = 0.92
2282     * StringUtils.getJaroWinklerDistance("PENNSYLVANIA", "PENNCISYLVNIA") = 0.88
2283     * </pre>
2284     *
2285     * @param first  The first String, must not be null.
2286     * @param second The second String, must not be null.
2287     * @return result distance.
2288     * @throws IllegalArgumentException Thrown if either String input {@code null}.
2289     * @since 3.3
2290     * @deprecated As of 3.6, use Apache Commons Text
2291     *             <a href="https://commons.apache.org/proper/commons-text/javadocs/api-release/org/apache/commons/text/similarity/JaroWinklerDistance.html">
2292     *             JaroWinklerDistance</a> instead.
2293     */
2294    @Deprecated
2295    public static double getJaroWinklerDistance(final CharSequence first, final CharSequence second) {
2296        final double DEFAULT_SCALING_FACTOR = 0.1;
2297
2298        if (first == null || second == null) {
2299            throw new IllegalArgumentException("Strings must not be null");
2300        }
2301
2302        final int[] mtp = matches(first, second);
2303        final double m = mtp[0];
2304        if (m == 0) {
2305            return 0D;
2306        }
2307        final double j = (m / first.length() + m / second.length() + (m - mtp[1]) / m) / 3;
2308        final double jw = j < 0.7D ? j : j + Math.min(DEFAULT_SCALING_FACTOR, 1D / mtp[3]) * mtp[2] * (1D - j);
2309        return Math.round(jw * 100.0D) / 100.0D;
2310    }
2311
2312    /**
2313     * Gets the Levenshtein distance between two Strings.
2314     *
2315     * <p>
2316     * This is the number of changes needed to change one String into another, where each change is a single character modification (deletion, insertion or
2317     * substitution).
2318     * </p>
2319     *
2320     * <p>
2321     * The implementation uses a single-dimensional array of length s.length() + 1. See
2322     * <a href="https://blog.softwx.net/2014/12/optimizing-levenshtein-algorithm-in-c.html">
2323     * https://blog.softwx.net/2014/12/optimizing-levenshtein-algorithm-in-c.html</a> for details.
2324     * </p>
2325     *
2326     * <pre>
2327     * StringUtils.getLevenshteinDistance(null, *)             = Throws {@link IllegalArgumentException}
2328     * StringUtils.getLevenshteinDistance(*, null)             = Throws {@link IllegalArgumentException}
2329     * StringUtils.getLevenshteinDistance("", "")              = 0
2330     * StringUtils.getLevenshteinDistance("", "a")             = 1
2331     * StringUtils.getLevenshteinDistance("aaapppp", "")       = 7
2332     * StringUtils.getLevenshteinDistance("frog", "fog")       = 1
2333     * StringUtils.getLevenshteinDistance("fly", "ant")        = 3
2334     * StringUtils.getLevenshteinDistance("elephant", "hippo") = 7
2335     * StringUtils.getLevenshteinDistance("hippo", "elephant") = 7
2336     * StringUtils.getLevenshteinDistance("hippo", "zzzzzzzz") = 8
2337     * StringUtils.getLevenshteinDistance("hello", "hallo")    = 1
2338     * </pre>
2339     *
2340     * @param s The first String, must not be null.
2341     * @param t The second String, must not be null.
2342     * @return result distance.
2343     * @throws IllegalArgumentException Thrown if either String input {@code null}.
2344     * @since 3.0 Changed signature from getLevenshteinDistance(String, String) to getLevenshteinDistance(CharSequence, CharSequence)
2345     * @deprecated As of 3.6, use Apache Commons Text
2346     *             <a href="https://commons.apache.org/proper/commons-text/javadocs/api-release/org/apache/commons/text/similarity/LevenshteinDistance.html">
2347     *             LevenshteinDistance</a> instead.
2348     */
2349    @Deprecated
2350    public static int getLevenshteinDistance(CharSequence s, CharSequence t) {
2351        if (s == null || t == null) {
2352            throw new IllegalArgumentException("Strings must not be null");
2353        }
2354
2355        int n = s.length();
2356        int m = t.length();
2357
2358        if (n == 0) {
2359            return m;
2360        }
2361        if (m == 0) {
2362            return n;
2363        }
2364
2365        if (n > m) {
2366            // swap the input strings to consume less memory
2367            final CharSequence tmp = s;
2368            s = t;
2369            t = tmp;
2370            n = m;
2371            m = t.length();
2372        }
2373
2374        final int[] p = new int[n + 1];
2375        // indexes into strings s and t
2376        int i; // iterates through s
2377        int j; // iterates through t
2378        int upperleft;
2379        int upper;
2380
2381        char jOfT; // jth character of t
2382        int cost;
2383
2384        for (i = 0; i <= n; i++) {
2385            p[i] = i;
2386        }
2387
2388        for (j = 1; j <= m; j++) {
2389            upperleft = p[0];
2390            jOfT = t.charAt(j - 1);
2391            p[0] = j;
2392
2393            for (i = 1; i <= n; i++) {
2394                upper = p[i];
2395                cost = s.charAt(i - 1) == jOfT ? 0 : 1;
2396                // minimum of cell to the left+1, to the top+1, diagonally left and up +cost
2397                p[i] = Math.min(Math.min(p[i - 1] + 1, p[i] + 1), upperleft + cost);
2398                upperleft = upper;
2399            }
2400        }
2401
2402        return p[n];
2403    }
2404
2405    /**
2406     * Gets the Levenshtein distance between two Strings if it's less than or equal to a given threshold.
2407     *
2408     * <p>
2409     * This is the number of changes needed to change one String into another, where each change is a single character modification (deletion, insertion or
2410     * substitution).
2411     * </p>
2412     *
2413     * <p>
2414     * This implementation follows from Algorithms on Strings, Trees and Sequences by Dan Gusfield and Chas Emerick's implementation of the Levenshtein distance
2415     * algorithm.
2416     * </p>
2417     *
2418     * <pre>
2419     * StringUtils.getLevenshteinDistance(null, *, *)             = Throws {@link IllegalArgumentException}
2420     * StringUtils.getLevenshteinDistance(*, null, *)             = Throws {@link IllegalArgumentException}
2421     * StringUtils.getLevenshteinDistance(*, *, -1)               = Throws {@link IllegalArgumentException}
2422     * StringUtils.getLevenshteinDistance("", "", 0)              = 0
2423     * StringUtils.getLevenshteinDistance("aaapppp", "", 8)       = 7
2424     * StringUtils.getLevenshteinDistance("aaapppp", "", 7)       = 7
2425     * StringUtils.getLevenshteinDistance("aaapppp", "", 6))      = -1
2426     * StringUtils.getLevenshteinDistance("elephant", "hippo", 7) = 7
2427     * StringUtils.getLevenshteinDistance("elephant", "hippo", 6) = -1
2428     * StringUtils.getLevenshteinDistance("hippo", "elephant", 7) = 7
2429     * StringUtils.getLevenshteinDistance("hippo", "elephant", 6) = -1
2430     * </pre>
2431     *
2432     * @param s         The first String, must not be null.
2433     * @param t         The second String, must not be null.
2434     * @param threshold The target threshold, must not be negative.
2435     * @return result distance, or {@code -1} if the distance would be greater than the threshold.
2436     * @throws IllegalArgumentException Thrown if either String input {@code null} or negative threshold.
2437     * @deprecated As of 3.6, use Apache Commons Text
2438     *             <a href="https://commons.apache.org/proper/commons-text/javadocs/api-release/org/apache/commons/text/similarity/LevenshteinDistance.html">
2439     *             LevenshteinDistance</a> instead.
2440     */
2441    @Deprecated
2442    public static int getLevenshteinDistance(CharSequence s, CharSequence t, final int threshold) {
2443        if (s == null || t == null) {
2444            throw new IllegalArgumentException("Strings must not be null");
2445        }
2446        if (threshold < 0) {
2447            throw new IllegalArgumentException("Threshold must not be negative");
2448        }
2449
2450        /*
2451        This implementation only computes the distance if it's less than or equal to the
2452        threshold value, returning -1 if it's greater.  The advantage is performance: unbounded
2453        distance is O(nm), but a bound of k allows us to reduce it to O(km) time by only
2454        computing a diagonal stripe of width 2k + 1 of the cost table.
2455        It is also possible to use this to compute the unbounded Levenshtein distance by starting
2456        the threshold at 1 and doubling each time until the distance is found; this is O(dm), where
2457        d is the distance.
2458
2459        One subtlety comes from needing to ignore entries on the border of our stripe
2460        for example,
2461        p[] = |#|#|#|*
2462        d[] =  *|#|#|#|
2463        We must ignore the entry to the left of the leftmost member
2464        We must ignore the entry above the rightmost member
2465
2466        Another subtlety comes from our stripe running off the matrix if the strings aren't
2467        of the same size.  Since string s is always swapped to be the shorter of the two,
2468        the stripe will always run off to the upper right instead of the lower left of the matrix.
2469
2470        As a concrete example, suppose s is of length 5, t is of length 7, and our threshold is 1.
2471        In this case we're going to walk a stripe of length 3.  The matrix would look like so:
2472
2473           1 2 3 4 5
2474        1 |#|#| | | |
2475        2 |#|#|#| | |
2476        3 | |#|#|#| |
2477        4 | | |#|#|#|
2478        5 | | | |#|#|
2479        6 | | | | |#|
2480        7 | | | | | |
2481
2482        Note how the stripe leads off the table as there is no possible way to turn a string of length 5
2483        into one of length 7 in edit distance of 1.
2484
2485        Additionally, this implementation decreases memory usage by using two
2486        single-dimensional arrays and swapping them back and forth instead of allocating
2487        an entire n by m matrix.  This requires a few minor changes, such as immediately returning
2488        when it's detected that the stripe has run off the matrix and initially filling the arrays with
2489        large values so that entries we don't compute are ignored.
2490
2491        See Algorithms on Strings, Trees and Sequences by Dan Gusfield for some discussion.
2492         */
2493
2494        int n = s.length(); // length of s
2495        int m = t.length(); // length of t
2496
2497        // if one string is empty, the edit distance is necessarily the length of the other
2498        if (n == 0) {
2499            return m <= threshold ? m : -1;
2500        }
2501        if (m == 0) {
2502            return n <= threshold ? n : -1;
2503        }
2504        if (Math.abs(n - m) > threshold) {
2505            // no need to calculate the distance if the length difference is greater than the threshold
2506            return -1;
2507        }
2508
2509        if (n > m) {
2510            // swap the two strings to consume less memory
2511            final CharSequence tmp = s;
2512            s = t;
2513            t = tmp;
2514            n = m;
2515            m = t.length();
2516        }
2517
2518        int[] p = new int[n + 1]; // 'previous' cost array, horizontally
2519        int[] d = new int[n + 1]; // cost array, horizontally
2520        int[] tmp; // placeholder to assist in swapping p and d
2521
2522        // fill in starting table values
2523        final int boundary = Math.min(n, threshold) + 1;
2524        for (int i = 0; i < boundary; i++) {
2525            p[i] = i;
2526        }
2527        // these fills ensure that the value above the rightmost entry of our
2528        // stripe will be ignored in following loop iterations
2529        Arrays.fill(p, boundary, p.length, Integer.MAX_VALUE);
2530        Arrays.fill(d, Integer.MAX_VALUE);
2531
2532        // iterates through t
2533        for (int j = 1; j <= m; j++) {
2534            final char jOfT = t.charAt(j - 1); // jth character of t
2535            d[0] = j;
2536
2537            // compute stripe indices, constrain to array size
2538            final int min = Math.max(1, j - threshold);
2539            final int max = j > Integer.MAX_VALUE - threshold ? n : Math.min(n, j + threshold);
2540
2541            // the stripe may lead off of the table if s and t are of different sizes
2542            if (min > max) {
2543                return -1;
2544            }
2545
2546            // ignore entry left of leftmost
2547            if (min > 1) {
2548                d[min - 1] = Integer.MAX_VALUE;
2549            }
2550
2551            // iterates through [min, max] in s
2552            for (int i = min; i <= max; i++) {
2553                if (s.charAt(i - 1) == jOfT) {
2554                    // diagonally left and up
2555                    d[i] = p[i - 1];
2556                } else {
2557                    // 1 + minimum of cell to the left, to the top, diagonally left and up
2558                    d[i] = 1 + Math.min(Math.min(d[i - 1], p[i]), p[i - 1]);
2559                }
2560            }
2561
2562            // copy current distance counts to 'previous row' distance counts
2563            tmp = p;
2564            p = d;
2565            d = tmp;
2566        }
2567
2568        // if p[n] is greater than the threshold, there's no guarantee on it being the correct
2569        // distance
2570        if (p[n] <= threshold) {
2571            return p[n];
2572        }
2573        return -1;
2574    }
2575
2576    /**
2577     * Finds the first index within a CharSequence, handling {@code null}. This method uses {@link String#indexOf(String, int)} if possible.
2578     *
2579     * <p>
2580     * A {@code null} CharSequence will return {@code -1}.
2581     * </p>
2582     *
2583     * <pre>
2584     * StringUtils.indexOf(null, *)          = -1
2585     * StringUtils.indexOf(*, null)          = -1
2586     * StringUtils.indexOf("", "")           = 0
2587     * StringUtils.indexOf("", *)            = -1 (except when * = "")
2588     * StringUtils.indexOf("aabaabaa", "a")  = 0
2589     * StringUtils.indexOf("aabaabaa", "b")  = 2
2590     * StringUtils.indexOf("aabaabaa", "ab") = 1
2591     * StringUtils.indexOf("aabaabaa", "")   = 0
2592     * </pre>
2593     *
2594     * @param seq       The CharSequence to check, may be null.
2595     * @param searchSeq The CharSequence to find, may be null.
2596     * @return The first index of the search CharSequence, -1 if no match or {@code null} string input.
2597     * @since 2.0
2598     * @since 3.0 Changed signature from indexOf(String, String) to indexOf(CharSequence, CharSequence)
2599     * @deprecated Use {@link Strings#indexOf(CharSequence, CharSequence) Strings.CS.indexOf(CharSequence, CharSequence)}.
2600     */
2601    @Deprecated
2602    public static int indexOf(final CharSequence seq, final CharSequence searchSeq) {
2603        return Strings.CS.indexOf(seq, searchSeq);
2604    }
2605
2606    /**
2607     * Finds the first index within a CharSequence, handling {@code null}. This method uses {@link String#indexOf(String, int)} if possible.
2608     *
2609     * <p>
2610     * A {@code null} CharSequence will return {@code -1}. A negative start position is treated as zero. An empty ("") search CharSequence always matches. A
2611     * start position greater than the string length only matches an empty search CharSequence.
2612     * </p>
2613     *
2614     * <pre>
2615     * StringUtils.indexOf(null, *, *)          = -1
2616     * StringUtils.indexOf(*, null, *)          = -1
2617     * StringUtils.indexOf("", "", 0)           = 0
2618     * StringUtils.indexOf("", *, 0)            = -1 (except when * = "")
2619     * StringUtils.indexOf("aabaabaa", "a", 0)  = 0
2620     * StringUtils.indexOf("aabaabaa", "b", 0)  = 2
2621     * StringUtils.indexOf("aabaabaa", "ab", 0) = 1
2622     * StringUtils.indexOf("aabaabaa", "b", 3)  = 5
2623     * StringUtils.indexOf("aabaabaa", "b", 9)  = -1
2624     * StringUtils.indexOf("aabaabaa", "b", -1) = 2
2625     * StringUtils.indexOf("aabaabaa", "", 2)   = 2
2626     * StringUtils.indexOf("abc", "", 9)        = 3
2627     * </pre>
2628     *
2629     * @param seq       The CharSequence to check, may be null.
2630     * @param searchSeq The CharSequence to find, may be null.
2631     * @param startPos  The start position, negative treated as zero.
2632     * @return The first index of the search CharSequence (always &ge; startPos), -1 if no match or {@code null} string input.
2633     * @since 2.0
2634     * @since 3.0 Changed signature from indexOf(String, String, int) to indexOf(CharSequence, CharSequence, int)
2635     * @deprecated Use {@link Strings#indexOf(CharSequence, CharSequence, int) Strings.CS.indexOf(CharSequence, CharSequence, int)}.
2636     */
2637    @Deprecated
2638    public static int indexOf(final CharSequence seq, final CharSequence searchSeq, final int startPos) {
2639        return Strings.CS.indexOf(seq, searchSeq, startPos);
2640    }
2641
2642    /**
2643     * Returns the index within {@code seq} of the first occurrence of the specified character. If a character with value {@code searchChar} occurs in the
2644     * character sequence represented by {@code seq} {@link CharSequence} object, then the index (in Unicode code units) of the first such occurrence is
2645     * returned. For values of {@code searchChar} in the range from 0 to 0xFFFF (inclusive), this is the smallest value <em>k</em> such that:
2646     *
2647     * <pre>
2648     * this.charAt(<em>k</em>) == searchChar
2649     * </pre>
2650     *
2651     * <p>
2652     * is true. For other values of {@code searchChar}, it is the smallest value <em>k</em> such that:
2653     * </p>
2654     *
2655     * <pre>
2656     * this.codePointAt(<em>k</em>) == searchChar
2657     * </pre>
2658     *
2659     * <p>
2660     * is true. In either case, if no such character occurs in {@code seq}, then {@code INDEX_NOT_FOUND (-1)} is returned.
2661     * </p>
2662     *
2663     * <p>
2664     * Furthermore, a {@code null} or empty ("") CharSequence will return {@code INDEX_NOT_FOUND (-1)}.
2665     * </p>
2666     *
2667     * <pre>
2668     * StringUtils.indexOf(null, *)         = -1
2669     * StringUtils.indexOf("", *)           = -1
2670     * StringUtils.indexOf("aabaabaa", 'a') = 0
2671     * StringUtils.indexOf("aabaabaa", 'b') = 2
2672     * StringUtils.indexOf("aaaaaaaa", 'Z') = -1
2673     * </pre>
2674     *
2675     * @param seq        The CharSequence to check, may be null.
2676     * @param searchChar The character to find.
2677     * @return The first index of the search character, -1 if no match or {@code null} string input.
2678     * @since 2.0
2679     * @since 3.0 Changed signature from indexOf(String, int) to indexOf(CharSequence, int)
2680     * @since 3.6 Updated {@link CharSequenceUtils} call to behave more like {@link String}
2681     */
2682    public static int indexOf(final CharSequence seq, final int searchChar) {
2683        if (isEmpty(seq)) {
2684            return INDEX_NOT_FOUND;
2685        }
2686        return CharSequenceUtils.indexOf(seq, searchChar, 0);
2687    }
2688
2689    /**
2690     * Returns the index within {@code seq} of the first occurrence of the specified character, starting the search at the specified index.
2691     * <p>
2692     * If a character with value {@code searchChar} occurs in the character sequence represented by the {@code seq} {@link CharSequence} object at an index no
2693     * 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
2694     * (inclusive), this is the smallest value <em>k</em> such that:
2695     * </p>
2696     *
2697     * <pre>
2698     * (this.charAt(<em>k</em>) == searchChar) &amp;&amp; (<em>k</em> &gt;= startPos)
2699     * </pre>
2700     *
2701     * <p>
2702     * is true. For other values of {@code searchChar}, it is the smallest value <em>k</em> such that:
2703     * </p>
2704     *
2705     * <pre>
2706     * (this.codePointAt(<em>k</em>) == searchChar) &amp;&amp; (<em>k</em> &gt;= startPos)
2707     * </pre>
2708     *
2709     * <p>
2710     * is true. In either case, if no such character occurs in {@code seq} at or after position {@code startPos}, then {@code -1} is returned.
2711     * </p>
2712     *
2713     * <p>
2714     * 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
2715     * 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:
2716     * {@code (INDEX_NOT_FOUND) -1} is returned. Furthermore, a {@code null} or empty ("") CharSequence will return {@code (INDEX_NOT_FOUND) -1}.
2717     * </p>
2718     * <p>
2719     * All indices are specified in {@code char} values (Unicode code units).
2720     * </p>
2721     *
2722     * <pre>
2723     * StringUtils.indexOf(null, *, *)          = -1
2724     * StringUtils.indexOf("", *, *)            = -1
2725     * StringUtils.indexOf("aabaabaa", 'b', 0)  = 2
2726     * StringUtils.indexOf("aabaabaa", 'b', 3)  = 5
2727     * StringUtils.indexOf("aabaabaa", 'b', 9)  = -1
2728     * StringUtils.indexOf("aabaabaa", 'b', -1) = 2
2729     * </pre>
2730     *
2731     * @param seq        The CharSequence to check, may be null.
2732     * @param searchChar The character to find.
2733     * @param startPos   The start position, negative treated as zero.
2734     * @return The first index of the search character (always &ge; startPos), -1 if no match or {@code null} string input.
2735     * @since 2.0
2736     * @since 3.0 Changed signature from indexOf(String, int, int) to indexOf(CharSequence, int, int)
2737     * @since 3.6 Updated {@link CharSequenceUtils} call to behave more like {@link String}
2738     */
2739    public static int indexOf(final CharSequence seq, final int searchChar, final int startPos) {
2740        if (isEmpty(seq)) {
2741            return INDEX_NOT_FOUND;
2742        }
2743        return CharSequenceUtils.indexOf(seq, searchChar, startPos);
2744    }
2745
2746    /**
2747     * Search a CharSequence to find the first index of any character in the given set of characters.
2748     *
2749     * <p>
2750     * A {@code null} String will return {@code -1}. A {@code null} or zero length search array will return {@code -1}.
2751     * </p>
2752     *
2753     * <pre>
2754     * StringUtils.indexOfAny(null, *)                  = -1
2755     * StringUtils.indexOfAny("", *)                    = -1
2756     * StringUtils.indexOfAny(*, null)                  = -1
2757     * StringUtils.indexOfAny(*, [])                    = -1
2758     * StringUtils.indexOfAny("zzabyycdxx", 'z', 'a')   = 0
2759     * StringUtils.indexOfAny("zzabyycdxx", 'b', 'y')   = 3
2760     * StringUtils.indexOfAny("aba", 'z')               = -1
2761     * </pre>
2762     *
2763     * @param cs          The CharSequence to check, may be null.
2764     * @param searchChars The chars to search for, may be null.
2765     * @return The index of any of the chars, -1 if no match or null input.
2766     * @since 2.0
2767     * @since 3.0 Changed signature from indexOfAny(String, char[]) to indexOfAny(CharSequence, char...)
2768     */
2769    public static int indexOfAny(final CharSequence cs, final char... searchChars) {
2770        return indexOfAny(cs, 0, searchChars);
2771    }
2772
2773    /**
2774     * Find the first index of any of a set of potential substrings.
2775     *
2776     * <p>
2777     * 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
2778     * 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
2779     * possible.
2780     * </p>
2781     *
2782     * <pre>
2783     * StringUtils.indexOfAny(null, *)                    = -1
2784     * StringUtils.indexOfAny(*, null)                    = -1
2785     * StringUtils.indexOfAny(*, [])                      = -1
2786     * StringUtils.indexOfAny("zzabyycdxx", "ab", "cd")   = 2
2787     * StringUtils.indexOfAny("zzabyycdxx", "cd", "ab")   = 2
2788     * StringUtils.indexOfAny("zzabyycdxx", "mn", "op")   = -1
2789     * StringUtils.indexOfAny("zzabyycdxx", "zab", "aby") = 1
2790     * StringUtils.indexOfAny("zzabyycdxx", "")           = 0
2791     * StringUtils.indexOfAny("", "")                     = 0
2792     * StringUtils.indexOfAny("", "a")                    = -1
2793     * </pre>
2794     *
2795     * @param str        The CharSequence to check, may be null.
2796     * @param searchStrs The CharSequences to search for, may be null.
2797     * @return The first index of any of the searchStrs in str, -1 if no match.
2798     * @since 3.0 Changed signature from indexOfAny(String, String[]) to indexOfAny(CharSequence, CharSequence...)
2799     */
2800    public static int indexOfAny(final CharSequence str, final CharSequence... searchStrs) {
2801        if (str == null || searchStrs == null) {
2802            return INDEX_NOT_FOUND;
2803        }
2804        // String's can't have a MAX_VALUEth index.
2805        int ret = Integer.MAX_VALUE;
2806        int tmp;
2807        for (final CharSequence search : searchStrs) {
2808            if (search == null) {
2809                continue;
2810            }
2811            tmp = CharSequenceUtils.indexOf(str, search, 0);
2812            if (tmp == INDEX_NOT_FOUND) {
2813                continue;
2814            }
2815            if (tmp < ret) {
2816                ret = tmp;
2817            }
2818        }
2819        return ret == Integer.MAX_VALUE ? INDEX_NOT_FOUND : ret;
2820    }
2821
2822    /**
2823     * Search a CharSequence to find the first index of any character in the given set of characters.
2824     *
2825     * <p>
2826     * A {@code null} String will return {@code -1}. A {@code null} or zero length search array will return {@code -1}.
2827     * </p>
2828     * <p>
2829     * The following is the same as {@code indexOfAny(cs, 0, searchChars)}.
2830     * </p>
2831     * <pre>
2832     * StringUtils.indexOfAny(null, 0, *)                  = -1
2833     * StringUtils.indexOfAny("", 0, *)                    = -1
2834     * StringUtils.indexOfAny(*, 0, null)                  = -1
2835     * StringUtils.indexOfAny(*, 0, [])                    = -1
2836     * StringUtils.indexOfAny("zzabyycdxx", 0, ['z', 'a']) = 0
2837     * StringUtils.indexOfAny("zzabyycdxx", 0, ['b', 'y']) = 3
2838     * StringUtils.indexOfAny("aba", 0, ['z'])             = -1
2839     * </pre>
2840     *
2841     * @param cs          The CharSequence to check, may be null.
2842     * @param csStart Start searching the input {@code cs} at this index.
2843     * @param searchChars The chars to search for, may be null.
2844     * @return The index of any of the chars, -1 if no match or null input.
2845     * @since 2.0
2846     * @since 3.0 Changed signature from indexOfAny(String, char[]) to indexOfAny(CharSequence, char...)
2847     */
2848    public static int indexOfAny(final CharSequence cs, final int csStart, final char... searchChars) {
2849        if (isEmpty(cs) || ArrayUtils.isEmpty(searchChars)) {
2850            return INDEX_NOT_FOUND;
2851        }
2852        final int csLen = cs.length();
2853        final int csLast = csLen - 1;
2854        final int searchLen = searchChars.length;
2855        final int searchLast = searchLen - 1;
2856        for (int i = Math.max(csStart, 0); i < csLen; i++) {
2857            final char ch = cs.charAt(i);
2858            for (int j = 0; j < searchLen; j++) {
2859                if (searchChars[j] == ch) {
2860                    if (Character.isHighSurrogate(ch)
2861                            ? j == searchLast || i < csLast && searchChars[j + 1] == cs.charAt(i + 1)
2862                            : j == 0 || !Character.isLowSurrogate(ch) || !Character.isHighSurrogate(searchChars[j - 1]) || i > 0 && searchChars[j - 1] == cs.charAt(i - 1)) {
2863                        return i;
2864                    }
2865                }
2866            }
2867        }
2868        return INDEX_NOT_FOUND;
2869    }
2870
2871    /**
2872     * Search a CharSequence to find the first index of any character in the given set of characters.
2873     *
2874     * <p>
2875     * A {@code null} String will return {@code -1}. A {@code null} search string will return {@code -1}.
2876     * </p>
2877     *
2878     * <pre>
2879     * StringUtils.indexOfAny(null, *)            = -1
2880     * StringUtils.indexOfAny("", *)              = -1
2881     * StringUtils.indexOfAny(*, null)            = -1
2882     * StringUtils.indexOfAny(*, "")              = -1
2883     * StringUtils.indexOfAny("zzabyycdxx", "za") = 0
2884     * StringUtils.indexOfAny("zzabyycdxx", "by") = 3
2885     * StringUtils.indexOfAny("aba", "z")         = -1
2886     * </pre>
2887     *
2888     * @param cs          The CharSequence to check, may be null.
2889     * @param searchChars The chars to search for, may be null.
2890     * @return The index of any of the chars, -1 if no match or null input.
2891     * @since 2.0
2892     * @since 3.0 Changed signature from indexOfAny(String, String) to indexOfAny(CharSequence, String)
2893     */
2894    public static int indexOfAny(final CharSequence cs, final String searchChars) {
2895        if (isEmpty(cs) || isEmpty(searchChars)) {
2896            return INDEX_NOT_FOUND;
2897        }
2898        return indexOfAny(cs, searchChars.toCharArray());
2899    }
2900
2901    /**
2902     * 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
2903     * (cs.codePointAt(i) ∉ { x ∈ codepoints(searchChars) })
2904     *
2905     * <p>
2906     * A {@code null} CharSequence will return {@code -1}. A {@code null} or zero length search array will return {@code -1}.
2907     * </p>
2908     *
2909     * <pre>
2910     * StringUtils.indexOfAnyBut(null, *)                              = -1
2911     * StringUtils.indexOfAnyBut("", *)                                = -1
2912     * StringUtils.indexOfAnyBut(*, null)                              = -1
2913     * StringUtils.indexOfAnyBut(*, [])                                = -1
2914     * StringUtils.indexOfAnyBut("zzabyycdxx", new char[] {'z', 'a'} ) = 3
2915     * StringUtils.indexOfAnyBut("aba", new char[] {'z'} )             = 0
2916     * StringUtils.indexOfAnyBut("aba", new char[] {'a', 'b'} )        = -1
2917     * </pre>
2918     *
2919     * @param cs          The CharSequence to check, may be null.
2920     * @param searchChars The chars to search for, may be null.
2921     * @return The index of any of the chars, -1 if no match or null input.
2922     * @since 2.0
2923     * @since 3.0 Changed signature from indexOfAnyBut(String, char[]) to indexOfAnyBut(CharSequence, char...)
2924     */
2925    public static int indexOfAnyBut(final CharSequence cs, final char... searchChars) {
2926        if (isEmpty(cs) || ArrayUtils.isEmpty(searchChars)) {
2927            return INDEX_NOT_FOUND;
2928        }
2929        return indexOfAnyBut(cs, CharBuffer.wrap(searchChars));
2930    }
2931
2932    /**
2933     * 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
2934     * (seq.codePointAt(i) ∉ { x ∈ codepoints(searchChars) })
2935     *
2936     * <p>
2937     * A {@code null} CharSequence will return {@code -1}. A {@code null} or empty search string will return {@code -1}.
2938     * </p>
2939     *
2940     * <pre>
2941     * StringUtils.indexOfAnyBut(null, *)            = -1
2942     * StringUtils.indexOfAnyBut("", *)              = -1
2943     * StringUtils.indexOfAnyBut(*, null)            = -1
2944     * StringUtils.indexOfAnyBut(*, "")              = -1
2945     * StringUtils.indexOfAnyBut("zzabyycdxx", "za") = 3
2946     * StringUtils.indexOfAnyBut("zzabyycdxx", "")   = -1
2947     * StringUtils.indexOfAnyBut("aba", "ab")        = -1
2948     * </pre>
2949     *
2950     * @param seq         The CharSequence to check, may be null.
2951     * @param searchChars The chars to search for, may be null.
2952     * @return The index of any of the chars, -1 if no match or null input.
2953     * @since 2.0
2954     * @since 3.0 Changed signature from indexOfAnyBut(String, String) to indexOfAnyBut(CharSequence, CharSequence)
2955     */
2956    public static int indexOfAnyBut(final CharSequence seq, final CharSequence searchChars) {
2957        if (isEmpty(seq) || isEmpty(searchChars)) {
2958            return INDEX_NOT_FOUND;
2959        }
2960        final Set<Integer> searchSetCodePoints = searchChars.codePoints()
2961                .boxed().collect(Collectors.toSet());
2962        // advance character index from one interpreted codepoint to the next
2963        for (int curSeqCharIdx = 0; curSeqCharIdx < seq.length();) {
2964            final int curSeqCodePoint = Character.codePointAt(seq, curSeqCharIdx);
2965            if (!searchSetCodePoints.contains(curSeqCodePoint)) {
2966                return curSeqCharIdx;
2967            }
2968            curSeqCharIdx += Character.charCount(curSeqCodePoint); // skip indices to paired low-surrogates
2969        }
2970        return INDEX_NOT_FOUND;
2971    }
2972
2973    /**
2974     * Compares all CharSequences in an array and returns the index at which the CharSequences begin to differ.
2975     *
2976     * <p>
2977     * For example, {@code indexOfDifference(new String[] {"i am a machine", "i am a robot"}) -> 7}
2978     * </p>
2979     *
2980     * <pre>
2981     * StringUtils.indexOfDifference(null)                             = -1
2982     * StringUtils.indexOfDifference(new String[] {})                  = -1
2983     * StringUtils.indexOfDifference(new String[] {"abc"})             = -1
2984     * StringUtils.indexOfDifference(new String[] {null, null})        = -1
2985     * StringUtils.indexOfDifference(new String[] {"", ""})            = -1
2986     * StringUtils.indexOfDifference(new String[] {"", null})          = 0
2987     * StringUtils.indexOfDifference(new String[] {"abc", null, null}) = 0
2988     * StringUtils.indexOfDifference(new String[] {null, null, "abc"}) = 0
2989     * StringUtils.indexOfDifference(new String[] {"", "abc"})         = 0
2990     * StringUtils.indexOfDifference(new String[] {"abc", ""})         = 0
2991     * StringUtils.indexOfDifference(new String[] {"abc", "abc"})      = -1
2992     * StringUtils.indexOfDifference(new String[] {"abc", "a"})        = 1
2993     * StringUtils.indexOfDifference(new String[] {"ab", "abxyz"})     = 2
2994     * StringUtils.indexOfDifference(new String[] {"abcde", "abxyz"})  = 2
2995     * StringUtils.indexOfDifference(new String[] {"abcde", "xyz"})    = 0
2996     * StringUtils.indexOfDifference(new String[] {"xyz", "abcde"})    = 0
2997     * StringUtils.indexOfDifference(new String[] {"i am a machine", "i am a robot"}) = 7
2998     * </pre>
2999     *
3000     * @param css array of CharSequences, entries may be null.
3001     * @return The index where the strings begin to differ; -1 if they are all equal.
3002     * @since 2.4
3003     * @since 3.0 Changed signature from indexOfDifference(String...) to indexOfDifference(CharSequence...)
3004     */
3005    public static int indexOfDifference(final CharSequence... css) {
3006        if (ArrayUtils.getLength(css) <= 1) {
3007            return INDEX_NOT_FOUND;
3008        }
3009        boolean anyStringNull = false;
3010        boolean allStringsNull = true;
3011        final int arrayLen = css.length;
3012        int shortestStrLen = Integer.MAX_VALUE;
3013        int longestStrLen = 0;
3014        // find the min and max string lengths; this avoids checking to make
3015        // sure we are not exceeding the length of the string each time through
3016        // the bottom loop.
3017        for (final CharSequence cs : css) {
3018            if (cs == null) {
3019                anyStringNull = true;
3020                shortestStrLen = 0;
3021            } else {
3022                allStringsNull = false;
3023                shortestStrLen = Math.min(cs.length(), shortestStrLen);
3024                longestStrLen = Math.max(cs.length(), longestStrLen);
3025            }
3026        }
3027        // handle lists containing all nulls or all empty strings
3028        if (allStringsNull || longestStrLen == 0 && !anyStringNull) {
3029            return INDEX_NOT_FOUND;
3030        }
3031        // handle lists containing some nulls or some empty strings
3032        if (shortestStrLen == 0) {
3033            return 0;
3034        }
3035        // find the position with the first difference across all strings
3036        int firstDiff = -1;
3037        for (int stringPos = 0; stringPos < shortestStrLen; stringPos++) {
3038            final char comparisonChar = css[0].charAt(stringPos);
3039            for (int arrayPos = 1; arrayPos < arrayLen; arrayPos++) {
3040                if (css[arrayPos].charAt(stringPos) != comparisonChar) {
3041                    firstDiff = stringPos;
3042                    break;
3043                }
3044            }
3045            if (firstDiff != -1) {
3046                break;
3047            }
3048        }
3049        if (firstDiff > 0 && Character.isLowSurrogate(css[0].charAt(firstDiff))
3050                && Character.isHighSurrogate(css[0].charAt(firstDiff - 1))) {
3051            // the difference splits a surrogate pair whose high half is common; report the start of the
3052            // pair so getCommonPrefix never slices it in half and leaves a stray high surrogate.
3053            firstDiff--;
3054        }
3055        if (firstDiff == -1 && shortestStrLen != longestStrLen) {
3056            // we compared all of the characters up to the length of the
3057            // shortest string and didn't find a match, but the string lengths
3058            // vary, so return the length of the shortest string.
3059            return shortestStrLen;
3060        }
3061        return firstDiff;
3062    }
3063
3064    /**
3065     * Compares two CharSequences, and returns the index at which the CharSequences begin to differ.
3066     *
3067     * <p>
3068     * For example, {@code indexOfDifference("i am a machine", "i am a robot") -> 7}
3069     * </p>
3070     *
3071     * <pre>
3072     * StringUtils.indexOfDifference(null, null)       = -1
3073     * StringUtils.indexOfDifference("", "")           = -1
3074     * StringUtils.indexOfDifference("", "abc")        = 0
3075     * StringUtils.indexOfDifference("abc", "")        = 0
3076     * StringUtils.indexOfDifference("abc", "abc")     = -1
3077     * StringUtils.indexOfDifference("ab", "abxyz")    = 2
3078     * StringUtils.indexOfDifference("abcde", "abxyz") = 2
3079     * StringUtils.indexOfDifference("abcde", "xyz")   = 0
3080     * </pre>
3081     *
3082     * @param cs1 The first CharSequence, may be null.
3083     * @param cs2 The second CharSequence, may be null.
3084     * @return The index where cs1 and cs2 begin to differ; -1 if they are equal.
3085     * @since 2.0
3086     * @since 3.0 Changed signature from indexOfDifference(String, String) to indexOfDifference(CharSequence, CharSequence)
3087     */
3088    public static int indexOfDifference(final CharSequence cs1, final CharSequence cs2) {
3089        if (cs1 == cs2) {
3090            return INDEX_NOT_FOUND;
3091        }
3092        if (cs1 == null || cs2 == null) {
3093            return 0;
3094        }
3095        int i;
3096        for (i = 0; i < cs1.length() && i < cs2.length(); ++i) {
3097            if (cs1.charAt(i) != cs2.charAt(i)) {
3098                break;
3099            }
3100        }
3101        if (i > 0 && i < cs1.length() && i < cs2.length() && Character.isHighSurrogate(cs1.charAt(i - 1))
3102                && (Character.isLowSurrogate(cs1.charAt(i)) || Character.isLowSurrogate(cs2.charAt(i)))) {
3103            // the difference splits a surrogate pair whose high half is common; report the start of the
3104            // pair so difference does not return a string that begins with a stray low surrogate.
3105            i--;
3106        }
3107        if (i < cs2.length() || i < cs1.length()) {
3108            return i;
3109        }
3110        return INDEX_NOT_FOUND;
3111    }
3112
3113    /**
3114     * Case insensitive find of the first index within a CharSequence.
3115     *
3116     * <p>
3117     * A {@code null} CharSequence will return {@code -1}. A negative start position is treated as zero. An empty ("") search CharSequence always matches. A
3118     * start position greater than the string length only matches an empty search CharSequence.
3119     * </p>
3120     *
3121     * <pre>
3122     * StringUtils.indexOfIgnoreCase(null, *)          = -1
3123     * StringUtils.indexOfIgnoreCase(*, null)          = -1
3124     * StringUtils.indexOfIgnoreCase("", "")           = 0
3125     * StringUtils.indexOfIgnoreCase(" ", " ")         = 0
3126     * StringUtils.indexOfIgnoreCase("aabaabaa", "a")  = 0
3127     * StringUtils.indexOfIgnoreCase("aabaabaa", "b")  = 2
3128     * StringUtils.indexOfIgnoreCase("aabaabaa", "ab") = 1
3129     * </pre>
3130     *
3131     * @param str       The CharSequence to check, may be null.
3132     * @param searchStr The CharSequence to find, may be null.
3133     * @return The first index of the search CharSequence, -1 if no match or {@code null} string input.
3134     * @since 2.5
3135     * @since 3.0 Changed signature from indexOfIgnoreCase(String, String) to indexOfIgnoreCase(CharSequence, CharSequence)
3136     * @deprecated Use {@link Strings#indexOf(CharSequence, CharSequence) Strings.CI.indexOf(CharSequence, CharSequence)}.
3137     */
3138    @Deprecated
3139    public static int indexOfIgnoreCase(final CharSequence str, final CharSequence searchStr) {
3140        return Strings.CI.indexOf(str, searchStr);
3141    }
3142
3143    /**
3144     * Case insensitive find of the first index within a CharSequence from the specified position.
3145     *
3146     * <p>
3147     * A {@code null} CharSequence will return {@code -1}. A negative start position is treated as zero. An empty ("") search CharSequence always matches. A
3148     * start position greater than the string length only matches an empty search CharSequence.
3149     * </p>
3150     *
3151     * <pre>
3152     * StringUtils.indexOfIgnoreCase(null, *, *)          = -1
3153     * StringUtils.indexOfIgnoreCase(*, null, *)          = -1
3154     * StringUtils.indexOfIgnoreCase("", "", 0)           = 0
3155     * StringUtils.indexOfIgnoreCase("aabaabaa", "A", 0)  = 0
3156     * StringUtils.indexOfIgnoreCase("aabaabaa", "B", 0)  = 2
3157     * StringUtils.indexOfIgnoreCase("aabaabaa", "AB", 0) = 1
3158     * StringUtils.indexOfIgnoreCase("aabaabaa", "B", 3)  = 5
3159     * StringUtils.indexOfIgnoreCase("aabaabaa", "B", 9)  = -1
3160     * StringUtils.indexOfIgnoreCase("aabaabaa", "B", -1) = 2
3161     * StringUtils.indexOfIgnoreCase("aabaabaa", "", 2)   = 2
3162     * StringUtils.indexOfIgnoreCase("abc", "", 9)        = -1
3163     * </pre>
3164     *
3165     * @param str       The CharSequence to check, may be null.
3166     * @param searchStr The CharSequence to find, may be null.
3167     * @param startPos  The start position, negative treated as zero.
3168     * @return The first index of the search CharSequence (always &ge; startPos), -1 if no match or {@code null} string input.
3169     * @since 2.5
3170     * @since 3.0 Changed signature from indexOfIgnoreCase(String, String, int) to indexOfIgnoreCase(CharSequence, CharSequence, int)
3171     * @deprecated Use {@link Strings#indexOf(CharSequence, CharSequence, int) Strings.CI.indexOf(CharSequence, CharSequence, int)}.
3172     */
3173    @Deprecated
3174    public static int indexOfIgnoreCase(final CharSequence str, final CharSequence searchStr, final int startPos) {
3175        return Strings.CI.indexOf(str, searchStr, startPos);
3176    }
3177
3178    /**
3179     * Tests if all of the CharSequences are empty (""), null or whitespace only.
3180     *
3181     * <p>
3182     * Whitespace is defined by {@link Character#isWhitespace(char)}.
3183     * </p>
3184     *
3185     * <pre>
3186     * StringUtils.isAllBlank(null)             = true
3187     * StringUtils.isAllBlank(null, "foo")      = false
3188     * StringUtils.isAllBlank(null, null)       = true
3189     * StringUtils.isAllBlank("", "bar")        = false
3190     * StringUtils.isAllBlank("bob", "")        = false
3191     * StringUtils.isAllBlank("  bob  ", null)  = false
3192     * StringUtils.isAllBlank(" ", "bar")       = false
3193     * StringUtils.isAllBlank("foo", "bar")     = false
3194     * StringUtils.isAllBlank(new String[] {})  = true
3195     * </pre>
3196     *
3197     * @param css The CharSequences to check, may be null or empty.
3198     * @return {@code true} if all of the CharSequences are empty or null or whitespace only.
3199     * @since 3.6
3200     */
3201    public static boolean isAllBlank(final CharSequence... css) {
3202        if (ArrayUtils.isEmpty(css)) {
3203            return true;
3204        }
3205        for (final CharSequence cs : css) {
3206            if (isNotBlank(cs)) {
3207                return false;
3208            }
3209        }
3210        return true;
3211    }
3212
3213    /**
3214     * Tests if all of the CharSequences are empty ("") or null.
3215     *
3216     * <pre>
3217     * StringUtils.isAllEmpty(null)             = true
3218     * StringUtils.isAllEmpty(null, "")         = true
3219     * StringUtils.isAllEmpty(new String[] {})  = true
3220     * StringUtils.isAllEmpty(null, "foo")      = false
3221     * StringUtils.isAllEmpty("", "bar")        = false
3222     * StringUtils.isAllEmpty("bob", "")        = false
3223     * StringUtils.isAllEmpty("  bob  ", null)  = false
3224     * StringUtils.isAllEmpty(" ", "bar")       = false
3225     * StringUtils.isAllEmpty("foo", "bar")     = false
3226     * </pre>
3227     *
3228     * @param css The CharSequences to check, may be null or empty.
3229     * @return {@code true} if all of the CharSequences are empty or null.
3230     * @since 3.6
3231     */
3232    public static boolean isAllEmpty(final CharSequence... css) {
3233        if (ArrayUtils.isEmpty(css)) {
3234            return true;
3235        }
3236        for (final CharSequence cs : css) {
3237            if (isNotEmpty(cs)) {
3238                return false;
3239            }
3240        }
3241        return true;
3242    }
3243
3244    /**
3245     * Tests if the CharSequence contains only lowercase characters.
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.isAllLowerCase(null)   = false
3253     * StringUtils.isAllLowerCase("")     = false
3254     * StringUtils.isAllLowerCase("  ")   = false
3255     * StringUtils.isAllLowerCase("abc")  = true
3256     * StringUtils.isAllLowerCase("abC")  = false
3257     * StringUtils.isAllLowerCase("ab c") = false
3258     * StringUtils.isAllLowerCase("ab1c") = false
3259     * StringUtils.isAllLowerCase("ab/c") = false
3260     * </pre>
3261     *
3262     * @param cs The CharSequence to check, may be null.
3263     * @return {@code true} if only contains lowercase characters, and is non-null.
3264     * @since 2.5
3265     * @since 3.0 Changed signature from isAllLowerCase(String) to isAllLowerCase(CharSequence)
3266     */
3267    public static boolean isAllLowerCase(final CharSequence cs) {
3268        if (isEmpty(cs)) {
3269            return false;
3270        }
3271        final int sz = cs.length();
3272        for (int i = 0; i < sz;) {
3273            final int codePoint = Character.codePointAt(cs, i);
3274            if (!Character.isLowerCase(codePoint)) {
3275                return false;
3276            }
3277            i += Character.charCount(codePoint);
3278        }
3279        return true;
3280    }
3281
3282    /**
3283     * Tests if the CharSequence contains only uppercase characters.
3284     *
3285     * <p>
3286     * {@code null} will return {@code false}.
3287     * An empty String (length()=0) will return {@code false}.
3288     * </p>
3289     *
3290     * <pre>
3291     * StringUtils.isAllUpperCase(null)   = false
3292     * StringUtils.isAllUpperCase("")     = false
3293     * StringUtils.isAllUpperCase("  ")   = false
3294     * StringUtils.isAllUpperCase("ABC")  = true
3295     * StringUtils.isAllUpperCase("aBC")  = false
3296     * StringUtils.isAllUpperCase("A C")  = false
3297     * StringUtils.isAllUpperCase("A1C")  = false
3298     * StringUtils.isAllUpperCase("A/C")  = false
3299     * </pre>
3300     *
3301     * @param cs The CharSequence to check, may be null.
3302     * @return {@code true} if only contains uppercase characters, and is non-null.
3303     * @since 2.5
3304     * @since 3.0 Changed signature from isAllUpperCase(String) to isAllUpperCase(CharSequence)
3305     */
3306    public static boolean isAllUpperCase(final CharSequence cs) {
3307        if (isEmpty(cs)) {
3308            return false;
3309        }
3310        final int sz = cs.length();
3311        for (int i = 0; i < sz;) {
3312            final int codePoint = Character.codePointAt(cs, i);
3313            if (!Character.isUpperCase(codePoint)) {
3314                return false;
3315            }
3316            i += Character.charCount(codePoint);
3317        }
3318        return true;
3319    }
3320
3321    /**
3322     * Tests if the CharSequence contains only Unicode letters.
3323     *
3324     * <p>
3325     * {@code null} will return {@code false}. An empty CharSequence (length()=0) will return {@code false}.
3326     * </p>
3327     *
3328     * <pre>
3329     * StringUtils.isAlpha(null)   = false
3330     * StringUtils.isAlpha("")     = false
3331     * StringUtils.isAlpha("  ")   = false
3332     * StringUtils.isAlpha("abc")  = true
3333     * StringUtils.isAlpha("ab2c") = false
3334     * StringUtils.isAlpha("ab-c") = false
3335     * </pre>
3336     *
3337     * @param cs The CharSequence to check, may be null.
3338     * @return {@code true} if only contains letters, and is non-null.
3339     * @since 3.0 Changed signature from isAlpha(String) to isAlpha(CharSequence)
3340     * @since 3.0 Changed "" to return false and not true
3341     */
3342    public static boolean isAlpha(final CharSequence cs) {
3343        if (isEmpty(cs)) {
3344            return false;
3345        }
3346        final int sz = cs.length();
3347        for (int i = 0; i < sz;) {
3348            final int codePoint = Character.codePointAt(cs, i);
3349            if (!Character.isLetter(codePoint)) {
3350                return false;
3351            }
3352            i += Character.charCount(codePoint);
3353        }
3354        return true;
3355    }
3356
3357    /**
3358     * Tests if the CharSequence contains only Unicode letters or digits.
3359     *
3360     * <p>
3361     * {@code null} will return {@code false}. An empty CharSequence (length()=0) will return {@code false}.
3362     * </p>
3363     *
3364     * <pre>
3365     * StringUtils.isAlphanumeric(null)   = false
3366     * StringUtils.isAlphanumeric("")     = false
3367     * StringUtils.isAlphanumeric("  ")   = false
3368     * StringUtils.isAlphanumeric("abc")  = true
3369     * StringUtils.isAlphanumeric("ab c") = false
3370     * StringUtils.isAlphanumeric("ab2c") = true
3371     * StringUtils.isAlphanumeric("ab-c") = false
3372     * </pre>
3373     *
3374     * @param cs The CharSequence to check, may be null.
3375     * @return {@code true} if only contains letters or digits, and is non-null.
3376     * @since 3.0 Changed signature from isAlphanumeric(String) to isAlphanumeric(CharSequence)
3377     * @since 3.0 Changed "" to return false and not true
3378     */
3379    public static boolean isAlphanumeric(final CharSequence cs) {
3380        if (isEmpty(cs)) {
3381            return false;
3382        }
3383        final int sz = cs.length();
3384        for (int i = 0; i < sz;) {
3385            final int codePoint = Character.codePointAt(cs, i);
3386            if (!Character.isLetterOrDigit(codePoint)) {
3387                return false;
3388            }
3389            i += Character.charCount(codePoint);
3390        }
3391        return true;
3392    }
3393
3394    /**
3395     * Tests if the CharSequence contains only Unicode letters, digits or space ({@code ' '}).
3396     *
3397     * <p>
3398     * {@code null} will return {@code false}. An empty CharSequence (length()=0) will return {@code true}.
3399     * </p>
3400     *
3401     * <pre>
3402     * StringUtils.isAlphanumericSpace(null)   = false
3403     * StringUtils.isAlphanumericSpace("")     = true
3404     * StringUtils.isAlphanumericSpace("  ")   = true
3405     * StringUtils.isAlphanumericSpace("abc")  = true
3406     * StringUtils.isAlphanumericSpace("ab c") = true
3407     * StringUtils.isAlphanumericSpace("ab2c") = true
3408     * StringUtils.isAlphanumericSpace("ab-c") = false
3409     * </pre>
3410     *
3411     * @param cs The CharSequence to check, may be null.
3412     * @return {@code true} if only contains letters, digits or space, and is non-null.
3413     * @since 3.0 Changed signature from isAlphanumericSpace(String) to isAlphanumericSpace(CharSequence)
3414     */
3415    public static boolean isAlphanumericSpace(final CharSequence cs) {
3416        if (cs == null) {
3417            return false;
3418        }
3419        final int sz = cs.length();
3420        for (int i = 0; i < sz;) {
3421            final int codePoint = Character.codePointAt(cs, i);
3422            if (codePoint != ' ' && !Character.isLetterOrDigit(codePoint)) {
3423                return false;
3424            }
3425            i += Character.charCount(codePoint);
3426        }
3427        return true;
3428    }
3429
3430    /**
3431     * Tests if the CharSequence contains only Unicode letters and space (' ').
3432     *
3433     * <p>
3434     * {@code null} will return {@code false} An empty CharSequence (length()=0) will return {@code true}.
3435     * </p>
3436     *
3437     * <pre>
3438     * StringUtils.isAlphaSpace(null)   = false
3439     * StringUtils.isAlphaSpace("")     = true
3440     * StringUtils.isAlphaSpace("  ")   = true
3441     * StringUtils.isAlphaSpace("abc")  = true
3442     * StringUtils.isAlphaSpace("ab c") = true
3443     * StringUtils.isAlphaSpace("ab2c") = false
3444     * StringUtils.isAlphaSpace("ab-c") = false
3445     * </pre>
3446     *
3447     * @param cs The CharSequence to check, may be null.
3448     * @return {@code true} if only contains letters and space, and is non-null.
3449     * @since 3.0 Changed signature from isAlphaSpace(String) to isAlphaSpace(CharSequence)
3450     */
3451    public static boolean isAlphaSpace(final CharSequence cs) {
3452        if (cs == null) {
3453            return false;
3454        }
3455        final int sz = cs.length();
3456        for (int i = 0; i < sz;) {
3457            final int codePoint = Character.codePointAt(cs, i);
3458            if (codePoint != ' ' && !Character.isLetter(codePoint)) {
3459                return false;
3460            }
3461            i += Character.charCount(codePoint);
3462        }
3463        return true;
3464    }
3465
3466    /**
3467     * Tests if any of the CharSequences are {@link #isBlank(CharSequence) blank} (whitespaces, empty ({@code ""}), or {@code null}).
3468     *
3469     * <p>
3470     * Whitespace is defined by {@link Character#isWhitespace(char)}.
3471     * </p>
3472     *
3473     * <pre>
3474     * StringUtils.isAnyBlank((String) null)    = true
3475     * StringUtils.isAnyBlank((String[]) null)  = false
3476     * StringUtils.isAnyBlank(null, "foo")      = true
3477     * StringUtils.isAnyBlank(null, null)       = true
3478     * StringUtils.isAnyBlank("", "bar")        = true
3479     * StringUtils.isAnyBlank("bob", "")        = true
3480     * StringUtils.isAnyBlank("  bob  ", null)  = true
3481     * StringUtils.isAnyBlank(" ", "bar")       = true
3482     * StringUtils.isAnyBlank(new String[] {})  = false
3483     * StringUtils.isAnyBlank(new String[]{""}) = true
3484     * StringUtils.isAnyBlank("foo", "bar")     = false
3485     * </pre>
3486     *
3487     * @param css The CharSequences to check, may be null or empty.
3488     * @return {@code true} if any of the CharSequences are {@link #isBlank(CharSequence) blank} (whitespaces, empty ({@code ""}), or {@code null}).
3489     * @see #isBlank(CharSequence)
3490     * @since 3.2
3491     */
3492    public static boolean isAnyBlank(final CharSequence... css) {
3493        if (ArrayUtils.isEmpty(css)) {
3494            return false;
3495        }
3496        for (final CharSequence cs : css) {
3497            if (isBlank(cs)) {
3498                return true;
3499            }
3500        }
3501        return false;
3502    }
3503
3504    /**
3505     * Tests if any of the CharSequences are empty ("") or null.
3506     *
3507     * <pre>
3508     * StringUtils.isAnyEmpty((String) null)    = true
3509     * StringUtils.isAnyEmpty((String[]) null)  = false
3510     * StringUtils.isAnyEmpty(null, "foo")      = true
3511     * StringUtils.isAnyEmpty("", "bar")        = true
3512     * StringUtils.isAnyEmpty("bob", "")        = true
3513     * StringUtils.isAnyEmpty("  bob  ", null)  = true
3514     * StringUtils.isAnyEmpty(" ", "bar")       = false
3515     * StringUtils.isAnyEmpty("foo", "bar")     = false
3516     * StringUtils.isAnyEmpty(new String[]{})   = false
3517     * StringUtils.isAnyEmpty(new String[]{""}) = true
3518     * </pre>
3519     *
3520     * @param css  The CharSequences to check, may be null or empty.
3521     * @return {@code true} if any of the CharSequences are empty or null.
3522     * @since 3.2
3523     */
3524    public static boolean isAnyEmpty(final CharSequence... css) {
3525        if (ArrayUtils.isEmpty(css)) {
3526            return false;
3527        }
3528        for (final CharSequence cs : css) {
3529            if (isEmpty(cs)) {
3530                return true;
3531            }
3532        }
3533        return false;
3534    }
3535
3536    /**
3537     * Tests if the CharSequence contains only ASCII printable characters.
3538     *
3539     * <p>
3540     * {@code null} will return {@code false}. An empty CharSequence (length()=0) will return {@code true}.
3541     * </p>
3542     *
3543     * <pre>
3544     * StringUtils.isAsciiPrintable(null)     = false
3545     * StringUtils.isAsciiPrintable("")       = true
3546     * StringUtils.isAsciiPrintable(" ")      = true
3547     * StringUtils.isAsciiPrintable("Ceki")   = true
3548     * StringUtils.isAsciiPrintable("ab2c")   = true
3549     * StringUtils.isAsciiPrintable("!ab-c~") = true
3550     * StringUtils.isAsciiPrintable("\u0020") = true
3551     * StringUtils.isAsciiPrintable("\u0021") = true
3552     * StringUtils.isAsciiPrintable("\u007e") = true
3553     * StringUtils.isAsciiPrintable("\u007f") = false
3554     * StringUtils.isAsciiPrintable("Ceki G\u00fclc\u00fc") = false
3555     * </pre>
3556     *
3557     * @param cs The CharSequence to check, may be null.
3558     * @return {@code true} if every character is in the range 32 through 126.
3559     * @since 2.1
3560     * @since 3.0 Changed signature from isAsciiPrintable(String) to isAsciiPrintable(CharSequence)
3561     */
3562    public static boolean isAsciiPrintable(final CharSequence cs) {
3563        if (cs == null) {
3564            return false;
3565        }
3566        final int sz = cs.length();
3567        for (int i = 0; i < sz; i++) {
3568            if (!CharUtils.isAsciiPrintable(cs.charAt(i))) {
3569                return false;
3570            }
3571        }
3572        return true;
3573    }
3574
3575    /**
3576     * Tests if a CharSequence is empty ({@code "")}, null, or contains only whitespace as defined by {@link Character#isWhitespace(char)}.
3577     *
3578     * <pre>
3579     * StringUtils.isBlank(null)      = true
3580     * StringUtils.isBlank("")        = true
3581     * StringUtils.isBlank(" ")       = true
3582     * StringUtils.isBlank("bob")     = false
3583     * StringUtils.isBlank("  bob  ") = false
3584     * </pre>
3585     *
3586     * @param cs The CharSequence to check, may be null.
3587     * @return {@code true} if the CharSequence is null, empty or whitespace only.
3588     * @since 2.0
3589     * @since 3.0 Changed signature from isBlank(String) to isBlank(CharSequence)
3590     */
3591    public static boolean isBlank(final CharSequence cs) {
3592        final int strLen = length(cs);
3593        for (int i = 0; i < strLen; i++) {
3594            if (!Character.isWhitespace(cs.charAt(i))) {
3595                return false;
3596            }
3597        }
3598        return true;
3599    }
3600
3601    /**
3602     * Tests if a CharSequence is empty ("") or null.
3603     *
3604     * <pre>
3605     * StringUtils.isEmpty(null)      = true
3606     * StringUtils.isEmpty("")        = true
3607     * StringUtils.isEmpty(" ")       = false
3608     * StringUtils.isEmpty("bob")     = false
3609     * StringUtils.isEmpty("  bob  ") = false
3610     * </pre>
3611     *
3612     * <p>
3613     * NOTE: This method changed in Lang version 2.0. It no longer trims the CharSequence. That functionality is available in isBlank().
3614     * </p>
3615     *
3616     * @param cs The CharSequence to check, may be null.
3617     * @return {@code true} if the CharSequence is empty or null.
3618     * @since 3.0 Changed signature from isEmpty(String) to isEmpty(CharSequence)
3619     */
3620    public static boolean isEmpty(final CharSequence cs) {
3621        return cs == null || cs.length() == 0;
3622    }
3623
3624    /**
3625     * Tests if the CharSequence contains mixed casing of both uppercase and lowercase characters.
3626     *
3627     * <p>
3628     * {@code null} will return {@code false}. An empty CharSequence ({@code length()=0}) will return {@code false}.
3629     * </p>
3630     *
3631     * <pre>
3632     * StringUtils.isMixedCase(null)    = false
3633     * StringUtils.isMixedCase("")      = false
3634     * StringUtils.isMixedCase(" ")     = false
3635     * StringUtils.isMixedCase("ABC")   = false
3636     * StringUtils.isMixedCase("abc")   = false
3637     * StringUtils.isMixedCase("aBc")   = true
3638     * StringUtils.isMixedCase("A c")   = true
3639     * StringUtils.isMixedCase("A1c")   = true
3640     * StringUtils.isMixedCase("a/C")   = true
3641     * StringUtils.isMixedCase("aC\t")  = true
3642     * </pre>
3643     *
3644     * @param cs The CharSequence to check, may be null.
3645     * @return {@code true} if the CharSequence contains both uppercase and lowercase characters.
3646     * @since 3.5
3647     */
3648    public static boolean isMixedCase(final CharSequence cs) {
3649        if (isEmpty(cs) || cs.length() == 1) {
3650            return false;
3651        }
3652        boolean containsUppercase = false;
3653        boolean containsLowercase = false;
3654        final int sz = cs.length();
3655        for (int i = 0; i < sz;) {
3656            final int codePoint = Character.codePointAt(cs, i);
3657            if (Character.isUpperCase(codePoint)) {
3658                containsUppercase = true;
3659            } else if (Character.isLowerCase(codePoint)) {
3660                containsLowercase = true;
3661            }
3662            if (containsUppercase && containsLowercase) {
3663                return true;
3664            }
3665            i += Character.charCount(codePoint);
3666        }
3667        return false;
3668    }
3669
3670    /**
3671     * Tests if none of the CharSequences are empty (""), null or whitespace only.
3672     *
3673     * <p>
3674     * Whitespace is defined by {@link Character#isWhitespace(char)}.
3675     * </p>
3676     *
3677     * <pre>
3678     * StringUtils.isNoneBlank((String) null)    = false
3679     * StringUtils.isNoneBlank((String[]) null)  = true
3680     * StringUtils.isNoneBlank(null, "foo")      = false
3681     * StringUtils.isNoneBlank(null, null)       = false
3682     * StringUtils.isNoneBlank("", "bar")        = false
3683     * StringUtils.isNoneBlank("bob", "")        = false
3684     * StringUtils.isNoneBlank("  bob  ", null)  = false
3685     * StringUtils.isNoneBlank(" ", "bar")       = false
3686     * StringUtils.isNoneBlank(new String[] {})  = true
3687     * StringUtils.isNoneBlank(new String[]{""}) = false
3688     * StringUtils.isNoneBlank("foo", "bar")     = true
3689     * </pre>
3690     *
3691     * @param css The CharSequences to check, may be null or empty.
3692     * @return {@code true} if none of the CharSequences are empty or null or whitespace only.
3693     * @since 3.2
3694     */
3695    public static boolean isNoneBlank(final CharSequence... css) {
3696        return !isAnyBlank(css);
3697    }
3698
3699    /**
3700     * Tests if none of the CharSequences are empty ("") or null.
3701     *
3702     * <pre>
3703     * StringUtils.isNoneEmpty((String) null)    = false
3704     * StringUtils.isNoneEmpty((String[]) null)  = true
3705     * StringUtils.isNoneEmpty(null, "foo")      = false
3706     * StringUtils.isNoneEmpty("", "bar")        = false
3707     * StringUtils.isNoneEmpty("bob", "")        = false
3708     * StringUtils.isNoneEmpty("  bob  ", null)  = false
3709     * StringUtils.isNoneEmpty(new String[] {})  = true
3710     * StringUtils.isNoneEmpty(new String[]{""}) = false
3711     * StringUtils.isNoneEmpty(" ", "bar")       = true
3712     * StringUtils.isNoneEmpty("foo", "bar")     = true
3713     * </pre>
3714     *
3715     * @param css  The CharSequences to check, may be null or empty.
3716     * @return {@code true} if none of the CharSequences are empty or null.
3717     * @since 3.2
3718     */
3719    public static boolean isNoneEmpty(final CharSequence... css) {
3720        return !isAnyEmpty(css);
3721    }
3722
3723    /**
3724     * Tests if a CharSequence is not {@link #isBlank(CharSequence) blank} (whitespaces, empty ({@code ""}), or {@code null}).
3725     *
3726     * <p>
3727     * Whitespace is defined by {@link Character#isWhitespace(char)}.
3728     * </p>
3729     *
3730     * <pre>
3731     * StringUtils.isNotBlank(null)      = false
3732     * StringUtils.isNotBlank("")        = false
3733     * StringUtils.isNotBlank(" ")       = false
3734     * StringUtils.isNotBlank("bob")     = true
3735     * StringUtils.isNotBlank("  bob  ") = true
3736     * </pre>
3737     *
3738     * @param cs The CharSequence to check, may be null.
3739     * @return {@code true} if the CharSequence is not {@link #isBlank(CharSequence) blank} (whitespaces, empty ({@code ""}), or {@code null}).
3740     * @see #isBlank(CharSequence)
3741     * @since 2.0
3742     * @since 3.0 Changed signature from isNotBlank(String) to isNotBlank(CharSequence)
3743     */
3744    public static boolean isNotBlank(final CharSequence cs) {
3745        return !isBlank(cs);
3746    }
3747
3748    /**
3749     * Tests if a CharSequence is not empty ("") and not null.
3750     *
3751     * <pre>
3752     * StringUtils.isNotEmpty(null)      = false
3753     * StringUtils.isNotEmpty("")        = false
3754     * StringUtils.isNotEmpty(" ")       = true
3755     * StringUtils.isNotEmpty("bob")     = true
3756     * StringUtils.isNotEmpty("  bob  ") = true
3757     * </pre>
3758     *
3759     * @param cs  The CharSequence to check, may be null.
3760     * @return {@code true} if the CharSequence is not empty and not null.
3761     * @since 3.0 Changed signature from isNotEmpty(String) to isNotEmpty(CharSequence)
3762     */
3763    public static boolean isNotEmpty(final CharSequence cs) {
3764        return !isEmpty(cs);
3765    }
3766
3767    /**
3768     * Tests if the CharSequence contains only Unicode digits. A decimal point is not a Unicode digit and returns false.
3769     *
3770     * <p>
3771     * {@code null} will return {@code false}. An empty CharSequence (length()=0) will return {@code false}.
3772     * </p>
3773     *
3774     * <p>
3775     * 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
3776     * NumberFormatException when parsed by Integer.parseInt or Long.parseLong, e.g. if the value is outside the range for int or long respectively.
3777     * </p>
3778     *
3779     * <pre>
3780     * StringUtils.isNumeric(null)   = false
3781     * StringUtils.isNumeric("")     = false
3782     * StringUtils.isNumeric("  ")   = false
3783     * StringUtils.isNumeric("123")  = true
3784     * StringUtils.isNumeric("\u0967\u0968\u0969")  = true
3785     * StringUtils.isNumeric("12 3") = false
3786     * StringUtils.isNumeric("ab2c") = false
3787     * StringUtils.isNumeric("12-3") = false
3788     * StringUtils.isNumeric("12.3") = false
3789     * StringUtils.isNumeric("-123") = false
3790     * StringUtils.isNumeric("+123") = false
3791     * </pre>
3792     *
3793     * @param cs The CharSequence to check, may be null.
3794     * @return {@code true} if only contains digits, and is non-null.
3795     * @since 3.0 Changed signature from isNumeric(String) to isNumeric(CharSequence)
3796     * @since 3.0 Changed "" to return false and not true
3797     */
3798    public static boolean isNumeric(final CharSequence cs) {
3799        if (isEmpty(cs)) {
3800            return false;
3801        }
3802        final int sz = cs.length();
3803        for (int i = 0; i < sz;) {
3804            final int codePoint = Character.codePointAt(cs, i);
3805            if (!Character.isDigit(codePoint)) {
3806                return false;
3807            }
3808            i += Character.charCount(codePoint);
3809        }
3810        return true;
3811    }
3812
3813    /**
3814     * Tests if the CharSequence contains only Unicode digits or space ({@code ' '}). A decimal point is not a Unicode digit and returns false.
3815     *
3816     * <p>
3817     * {@code null} will return {@code false}. An empty CharSequence (length()=0) will return {@code true}.
3818     * </p>
3819     *
3820     * <pre>
3821     * StringUtils.isNumericSpace(null)   = false
3822     * StringUtils.isNumericSpace("")     = true
3823     * StringUtils.isNumericSpace("  ")   = true
3824     * StringUtils.isNumericSpace("123")  = true
3825     * StringUtils.isNumericSpace("12 3") = true
3826     * StringUtils.isNumericSpace("\u0967\u0968\u0969")   = true
3827     * StringUtils.isNumericSpace("\u0967\u0968 \u0969")  = true
3828     * StringUtils.isNumericSpace("ab2c") = false
3829     * StringUtils.isNumericSpace("12-3") = false
3830     * StringUtils.isNumericSpace("12.3") = false
3831     * </pre>
3832     *
3833     * @param cs The CharSequence to check, may be null.
3834     * @return {@code true} if only contains digits or space, and is non-null.
3835     * @since 3.0 Changed signature from isNumericSpace(String) to isNumericSpace(CharSequence)
3836     */
3837    public static boolean isNumericSpace(final CharSequence cs) {
3838        if (cs == null) {
3839            return false;
3840        }
3841        final int sz = cs.length();
3842        for (int i = 0; i < sz;) {
3843            final int codePoint = Character.codePointAt(cs, i);
3844            if (codePoint != ' ' && !Character.isDigit(codePoint)) {
3845                return false;
3846            }
3847            i += Character.charCount(codePoint);
3848        }
3849        return true;
3850    }
3851
3852    /**
3853     * Tests if the CharSequence contains only whitespace.
3854     *
3855     * <p>
3856     * Whitespace is defined by {@link Character#isWhitespace(char)}.
3857     * </p>
3858     *
3859     * <p>
3860     * {@code null} will return {@code false}. An empty CharSequence (length()=0) will return {@code true}.
3861     * </p>
3862     *
3863     * <pre>
3864     * StringUtils.isWhitespace(null)   = false
3865     * StringUtils.isWhitespace("")     = true
3866     * StringUtils.isWhitespace("  ")   = true
3867     * StringUtils.isWhitespace("abc")  = false
3868     * StringUtils.isWhitespace("ab2c") = false
3869     * StringUtils.isWhitespace("ab-c") = false
3870     * </pre>
3871     *
3872     * @param cs The CharSequence to check, may be null.
3873     * @return {@code true} if only contains whitespace, and is non-null.
3874     * @since 2.0
3875     * @since 3.0 Changed signature from isWhitespace(String) to isWhitespace(CharSequence)
3876     */
3877    public static boolean isWhitespace(final CharSequence cs) {
3878        if (cs == null) {
3879            return false;
3880        }
3881        final int sz = cs.length();
3882        for (int i = 0; i < sz; i++) {
3883            if (!Character.isWhitespace(cs.charAt(i))) {
3884                return false;
3885            }
3886        }
3887        return true;
3888    }
3889
3890    /**
3891     * Joins the elements of the provided array into a single String containing the provided list of elements.
3892     *
3893     * <p>
3894     * No delimiter is added before or after the list. Null objects or empty strings within the array are represented by empty strings.
3895     * </p>
3896     *
3897     * <pre>
3898     * StringUtils.join(null, *)             = null
3899     * StringUtils.join([], *)               = ""
3900     * StringUtils.join([null], *)           = ""
3901     * StringUtils.join([false, false], ';') = "false;false"
3902     * </pre>
3903     *
3904     * @param array     The array of values to join together, may be null.
3905     * @param delimiter The separator character to use.
3906     * @return The joined String, {@code null} if null array input.
3907     * @since 3.12.0
3908     */
3909    public static String join(final boolean[] array, final char delimiter) {
3910        if (array == null) {
3911            return null;
3912        }
3913        return join(array, delimiter, 0, array.length);
3914    }
3915
3916    /**
3917     * Joins the elements of the provided array into a single String containing the provided list of elements.
3918     *
3919     * <p>
3920     * No delimiter is added before or after the list. Null objects or empty strings within the array are represented
3921     * by empty strings.
3922     * </p>
3923     *
3924     * <pre>
3925     * StringUtils.join(null, *)                  = null
3926     * StringUtils.join([], *)                    = ""
3927     * StringUtils.join([null], *)                = ""
3928     * StringUtils.join([true, false, true], ';') = "true;false;true"
3929     * </pre>
3930     *
3931     * @param array
3932     *            the array of values to join together, may be null.
3933     * @param delimiter
3934     *            the separator character to use.
3935     * @param startIndex
3936     *            the first index to start joining from. It is an error to pass in a start index past the end of the
3937     *            array.
3938     * @param endIndex
3939     *            the index to stop joining from (exclusive). It is an error to pass in an end index past the end of
3940     *            the array.
3941     * @return The joined String, {@code null} if null array input.
3942     * @since 3.12.0
3943     */
3944    public static String join(final boolean[] array, final char delimiter, final int startIndex, final int endIndex) {
3945        // See StringUtilsJoinBenchmark
3946        if (array == null) {
3947            return null;
3948        }
3949        checkFromToIndex(startIndex, endIndex, array.length);
3950        final int count = endIndex - startIndex;
3951        if (count <= 0) {
3952            return EMPTY;
3953        }
3954        final byte maxElementChars = 5; // "false"
3955        final StringBuilder stringBuilder = capacity(count, maxElementChars);
3956        stringBuilder.append(array[startIndex]);
3957        for (int i = startIndex + 1; i < endIndex; i++) {
3958            stringBuilder.append(delimiter).append(array[i]);
3959        }
3960        return stringBuilder.toString();
3961    }
3962
3963    /**
3964     * Joins the elements of the provided array into a single String containing the provided list of elements.
3965     *
3966     * <p>
3967     * No delimiter is added before or after the list. Null objects or empty strings within the array are represented
3968     * by empty strings.
3969     * </p>
3970     *
3971     * <pre>
3972     * StringUtils.join(null, *)         = null
3973     * StringUtils.join([], *)           = ""
3974     * StringUtils.join([null], *)       = ""
3975     * StringUtils.join([1, 2, 3], ';')  = "1;2;3"
3976     * StringUtils.join([1, 2, 3], null) = "123"
3977     * </pre>
3978     *
3979     * @param array
3980     *            the array of values to join together, may be null.
3981     * @param delimiter
3982     *            the separator character to use.
3983     * @return The joined String, {@code null} if null array input.
3984     * @since 3.2
3985     */
3986    public static String join(final byte[] array, final char delimiter) {
3987        if (array == null) {
3988            return null;
3989        }
3990        return join(array, delimiter, 0, array.length);
3991    }
3992
3993    /**
3994     * Joins the elements of the provided array into a single String containing the provided list of elements.
3995     *
3996     * <p>
3997     * No delimiter is added before or after the list. Null objects or empty strings within the array are represented
3998     * by empty strings.
3999     * </p>
4000     *
4001     * <pre>
4002     * StringUtils.join(null, *)         = null
4003     * StringUtils.join([], *)           = ""
4004     * StringUtils.join([null], *)       = ""
4005     * StringUtils.join([1, 2, 3], ';')  = "1;2;3"
4006     * StringUtils.join([1, 2, 3], null) = "123"
4007     * </pre>
4008     *
4009     * @param array
4010     *            the array of values to join together, may be null.
4011     * @param delimiter
4012     *            the separator character to use.
4013     * @param startIndex
4014     *            the first index to start joining from. It is an error to pass in a start index past the end of the
4015     *            array.
4016     * @param endIndex
4017     *            the index to stop joining from (exclusive). It is an error to pass in an end index past the end of
4018     *            the array.
4019     * @return The joined String, {@code null} if null array input.
4020     * @since 3.2
4021     */
4022    public static String join(final byte[] array, final char delimiter, final int startIndex, final int endIndex) {
4023        // See StringUtilsJoinBenchmark
4024        if (array == null) {
4025            return null;
4026        }
4027        checkFromToIndex(startIndex, endIndex, array.length);
4028        final int count = endIndex - startIndex;
4029        if (count <= 0) {
4030            return EMPTY;
4031        }
4032        final byte maxElementChars = 4; // "-128"
4033        final StringBuilder stringBuilder = capacity(count, maxElementChars);
4034        stringBuilder.append(array[startIndex]);
4035        for (int i = startIndex + 1; i < endIndex; i++) {
4036            stringBuilder.append(delimiter).append(array[i]);
4037        }
4038        return stringBuilder.toString();
4039    }
4040
4041    /**
4042     * Joins the elements of the provided array into a single String containing the provided list of elements.
4043     *
4044     * <p>
4045     * No delimiter is added before or after the list. Null objects or empty strings within the array are represented
4046     * by empty strings.
4047     * </p>
4048     *
4049     * <pre>
4050     * StringUtils.join(null, *)         = null
4051     * StringUtils.join([], *)           = ""
4052     * StringUtils.join([null], *)       = ""
4053     * StringUtils.join([1, 2, 3], ';')  = "1;2;3"
4054     * StringUtils.join([1, 2, 3], null) = "123"
4055     * </pre>
4056     *
4057     * @param array
4058     *            the array of values to join together, may be null.
4059     * @param delimiter
4060     *            the separator character to use.
4061     * @return The joined String, {@code null} if null array input.
4062     * @since 3.2
4063     */
4064    public static String join(final char[] array, final char delimiter) {
4065        if (array == null) {
4066            return null;
4067        }
4068        return join(array, delimiter, 0, array.length);
4069    }
4070
4071    /**
4072     * Joins the elements of the provided array into a single String containing the provided list of elements.
4073     *
4074     * <p>
4075     * No delimiter is added before or after the list. Null objects or empty strings within the array are represented
4076     * by empty strings.
4077     * </p>
4078     *
4079     * <pre>
4080     * StringUtils.join(null, *)         = null
4081     * StringUtils.join([], *)           = ""
4082     * StringUtils.join([null], *)       = ""
4083     * StringUtils.join([1, 2, 3], ';')  = "1;2;3"
4084     * StringUtils.join([1, 2, 3], null) = "123"
4085     * </pre>
4086     *
4087     * @param array
4088     *            the array of values to join together, may be null.
4089     * @param delimiter
4090     *            the separator character to use.
4091     * @param startIndex
4092     *            the first index to start joining from. It is an error to pass in a start index past the end of the
4093     *            array.
4094     * @param endIndex
4095     *            the index to stop joining from (exclusive). It is an error to pass in an end index past the end of
4096     *            the array.
4097     * @return The joined String, {@code null} if null array input.
4098     * @since 3.2
4099     */
4100    public static String join(final char[] array, final char delimiter, final int startIndex, final int endIndex) {
4101        // See StringUtilsJoinBenchmark
4102        if (array == null) {
4103            return null;
4104        }
4105        checkFromToIndex(startIndex, endIndex, array.length);
4106        final int count = endIndex - startIndex;
4107        if (count <= 0) {
4108            return EMPTY;
4109        }
4110        final byte maxElementChars = 1;
4111        final StringBuilder stringBuilder = capacity(count, maxElementChars);
4112        stringBuilder.append(array[startIndex]);
4113        for (int i = startIndex + 1; i < endIndex; i++) {
4114            stringBuilder.append(delimiter).append(array[i]);
4115        }
4116        return stringBuilder.toString();
4117    }
4118
4119    /**
4120     * Joins the elements of the provided array into a single String containing the provided list of elements.
4121     *
4122     * <p>
4123     * No delimiter is added before or after the list. Null objects or empty strings within the array are represented
4124     * by empty strings.
4125     * </p>
4126     *
4127     * <pre>
4128     * StringUtils.join(null, *)          = null
4129     * StringUtils.join([], *)            = ""
4130     * StringUtils.join([null], *)        = ""
4131     * StringUtils.join([1, 2, 3], ';')   = "1;2;3"
4132     * StringUtils.join([1, 2, 3], null)  = "123"
4133     * </pre>
4134     *
4135     * @param array
4136     *            the array of values to join together, may be null.
4137     * @param delimiter
4138     *            the separator character to use.
4139     * @return The joined String, {@code null} if null array input.
4140     * @since 3.2
4141     */
4142    public static String join(final double[] array, final char delimiter) {
4143        if (array == null) {
4144            return null;
4145        }
4146        return join(array, delimiter, 0, array.length);
4147    }
4148
4149    /**
4150     * Joins the elements of the provided array into a single String containing the provided list of elements.
4151     *
4152     * <p>
4153     * No delimiter is added before or after the list. Null objects or empty strings within the array are represented
4154     * by empty strings.
4155     * </p>
4156     *
4157     * <pre>
4158     * StringUtils.join(null, *)          = null
4159     * StringUtils.join([], *)            = ""
4160     * StringUtils.join([null], *)        = ""
4161     * StringUtils.join([1, 2, 3], ';')   = "1;2;3"
4162     * StringUtils.join([1, 2, 3], null)  = "123"
4163     * </pre>
4164     *
4165     * @param array
4166     *            the array of values to join together, may be null.
4167     * @param delimiter
4168     *            the separator character to use.
4169     * @param startIndex
4170     *            the first index to start joining from. It is an error to pass in a start index past the end of the
4171     *            array.
4172     * @param endIndex
4173     *            the index to stop joining from (exclusive). It is an error to pass in an end index past the end of
4174     *            the array.
4175     * @return The joined String, {@code null} if null array input.
4176     * @since 3.2
4177     */
4178    public static String join(final double[] array, final char delimiter, final int startIndex, final int endIndex) {
4179        // See StringUtilsJoinBenchmark
4180        if (array == null) {
4181            return null;
4182        }
4183        checkFromToIndex(startIndex, endIndex, array.length);
4184        final int count = endIndex - startIndex;
4185        if (count <= 0) {
4186            return EMPTY;
4187        }
4188        final byte maxElementChars = 22; // "1.7976931348623157E308"
4189        final StringBuilder stringBuilder = capacity(count, maxElementChars);
4190        stringBuilder.append(array[startIndex]);
4191        for (int i = startIndex + 1; i < endIndex; i++) {
4192            stringBuilder.append(delimiter).append(array[i]);
4193        }
4194        return stringBuilder.toString();
4195    }
4196
4197    /**
4198     * Joins the elements of the provided array into a single String containing the provided list of elements.
4199     *
4200     * <p>
4201     * No delimiter is added before or after the list. Null objects or empty strings within the array are represented
4202     * by empty strings.
4203     * </p>
4204     *
4205     * <pre>
4206     * StringUtils.join(null, *)          = null
4207     * StringUtils.join([], *)            = ""
4208     * StringUtils.join([null], *)        = ""
4209     * StringUtils.join([1, 2, 3], ';')   = "1;2;3"
4210     * StringUtils.join([1, 2, 3], null)  = "123"
4211     * </pre>
4212     *
4213     * @param array
4214     *            the array of values to join together, may be null.
4215     * @param delimiter
4216     *            the separator character to use.
4217     * @return The joined String, {@code null} if null array input
4218     * @since 3.2
4219     */
4220    public static String join(final float[] array, final char delimiter) {
4221        if (array == null) {
4222            return null;
4223        }
4224        return join(array, delimiter, 0, array.length);
4225    }
4226
4227    /**
4228     * Joins the elements of the provided array into a single String containing the provided list of elements.
4229     *
4230     * <p>
4231     * No delimiter is added before or after the list. Null objects or empty strings within the array are represented
4232     * by empty strings.
4233     * </p>
4234     *
4235     * <pre>
4236     * StringUtils.join(null, *)          = null
4237     * StringUtils.join([], *)            = ""
4238     * StringUtils.join([null], *)        = ""
4239     * StringUtils.join([1, 2, 3], ';')   = "1;2;3"
4240     * StringUtils.join([1, 2, 3], null)  = "123"
4241     * </pre>
4242     *
4243     * @param array
4244     *            the array of values to join together, may be null.
4245     * @param delimiter
4246     *            the separator character to use.
4247     * @param startIndex
4248     *            the first index to start joining from. It is an error to pass in a start index past the end of the
4249     *            array.
4250     * @param endIndex
4251     *            the index to stop joining from (exclusive). It is an error to pass in an end index past the end of
4252     *            the array.
4253     * @return The joined String, {@code null} if null array input.
4254     * @since 3.2
4255     */
4256    public static String join(final float[] array, final char delimiter, final int startIndex, final int endIndex) {
4257        // See StringUtilsJoinBenchmark
4258        if (array == null) {
4259            return null;
4260        }
4261        checkFromToIndex(startIndex, endIndex, array.length);
4262        final int count = endIndex - startIndex;
4263        if (count <= 0) {
4264            return EMPTY;
4265        }
4266        final byte maxElementChars = 12; // "3.4028235E38"
4267        final StringBuilder stringBuilder = capacity(count, maxElementChars);
4268        stringBuilder.append(array[startIndex]);
4269        for (int i = startIndex + 1; i < endIndex; i++) {
4270            stringBuilder.append(delimiter).append(array[i]);
4271        }
4272        return stringBuilder.toString();
4273    }
4274
4275    /**
4276     * Joins the elements of the provided array into a single String containing the provided list of elements.
4277     *
4278     * <p>
4279     * No delimiter is added before or after the list. Null objects or empty strings within the array are represented
4280     * by empty strings.
4281     * </p>
4282     *
4283     * <pre>
4284     * StringUtils.join(null, *)          = null
4285     * StringUtils.join([], *)            = ""
4286     * StringUtils.join([null], *)        = ""
4287     * StringUtils.join([1, 2, 3], ';')   = "1;2;3"
4288     * StringUtils.join([1, 2, 3], null)  = "123"
4289     * </pre>
4290     *
4291     * @param array
4292     *            the array of values to join together, may be null.
4293     * @param separator
4294     *            the separator character to use.
4295     * @return The joined String, {@code null} if null array input.
4296     * @since 3.2
4297     */
4298    public static String join(final int[] array, final char separator) {
4299        if (array == null) {
4300            return null;
4301        }
4302        return join(array, separator, 0, array.length);
4303    }
4304
4305    /**
4306     * Joins the elements of the provided array into a single String containing the provided list of elements.
4307     *
4308     * <p>
4309     * No delimiter is added before or after the list. Null objects or empty strings within the array are represented
4310     * by empty strings.
4311     * </p>
4312     *
4313     * <pre>
4314     * StringUtils.join(null, *)          = null
4315     * StringUtils.join([], *)            = ""
4316     * StringUtils.join([null], *)        = ""
4317     * StringUtils.join([1, 2, 3], ';')   = "1;2;3"
4318     * StringUtils.join([1, 2, 3], null)  = "123"
4319     * </pre>
4320     *
4321     * @param array
4322     *            the array of values to join together, may be null.
4323     * @param delimiter
4324     *            the separator character to use.
4325     * @param startIndex
4326     *            the first index to start joining from. It is an error to pass in a start index past the end of the
4327     *            array.
4328     * @param endIndex
4329     *            the index to stop joining from (exclusive). It is an error to pass in an end index past the end of
4330     *            the array.
4331     * @return The joined String, {@code null} if null array input.
4332     * @since 3.2
4333     */
4334    public static String join(final int[] array, final char delimiter, final int startIndex, final int endIndex) {
4335        // See StringUtilsJoinBenchmark
4336        if (array == null) {
4337            return null;
4338        }
4339        checkFromToIndex(startIndex, endIndex, array.length);
4340        final int count = endIndex - startIndex;
4341        if (count <= 0) {
4342            return EMPTY;
4343        }
4344        final byte maxElementChars = 11; // "-2147483648"
4345        final StringBuilder stringBuilder = capacity(count, maxElementChars);
4346        stringBuilder.append(array[startIndex]);
4347        for (int i = startIndex + 1; i < endIndex; i++) {
4348            stringBuilder.append(delimiter).append(array[i]);
4349        }
4350        return stringBuilder.toString();
4351    }
4352
4353    /**
4354     * Joins the elements of the provided {@link Iterable} into a single String containing the provided elements.
4355     *
4356     * <p>
4357     * No delimiter is added before or after the list. Null objects or empty strings within the iteration are represented by empty strings.
4358     * </p>
4359     *
4360     * <p>
4361     * See the examples here: {@link #join(Object[],char)}.
4362     * </p>
4363     *
4364     * @param iterable  The {@link Iterable} providing the values to join together, may be null.
4365     * @param separator The separator character to use.
4366     * @return The joined String, {@code null} if null iterator input.
4367     * @since 2.3
4368     */
4369    public static String join(final Iterable<?> iterable, final char separator) {
4370        return iterable != null ? join(iterable.iterator(), separator) : null;
4371    }
4372
4373    /**
4374     * Joins the elements of the provided {@link Iterable} into a single String containing the provided elements.
4375     *
4376     * <p>
4377     * No delimiter is added before or after the list. A {@code null} separator is the same as an empty String ("").
4378     * </p>
4379     *
4380     * <p>
4381     * See the examples here: {@link #join(Object[],String)}.
4382     * </p>
4383     *
4384     * @param iterable  The {@link Iterable} providing the values to join together, may be null.
4385     * @param separator The separator character to use, null treated as "".
4386     * @return The joined String, {@code null} if null iterator input.
4387     * @since 2.3
4388     */
4389    public static String join(final Iterable<?> iterable, final String separator) {
4390        return iterable != null ? join(iterable.iterator(), separator) : null;
4391    }
4392
4393    /**
4394     * Joins the elements of the provided {@link Iterator} into a single String containing the provided elements.
4395     *
4396     * <p>
4397     * No delimiter is added before or after the list. Null objects or empty strings within the iteration are represented by empty strings.
4398     * </p>
4399     *
4400     * <p>
4401     * See the examples here: {@link #join(Object[],char)}.
4402     * </p>
4403     *
4404     * @param iterator  The {@link Iterator} of values to join together, may be null.
4405     * @param separator The separator character to use.
4406     * @return The joined String, {@code null} if null iterator input.
4407     * @since 2.0
4408     */
4409    public static String join(final Iterator<?> iterator, final char separator) {
4410        // handle null, zero and one elements before building a buffer
4411        if (iterator == null) {
4412            return null;
4413        }
4414        if (!iterator.hasNext()) {
4415            return EMPTY;
4416        }
4417        return Streams.of(iterator).collect(LangCollectors.joining(ObjectUtils.toString(String.valueOf(separator)), EMPTY, EMPTY, ObjectUtils::toString));
4418    }
4419
4420    /**
4421     * Joins the elements of the provided {@link Iterator} into a single String containing the provided elements.
4422     *
4423     * <p>
4424     * No delimiter is added before or after the list. A {@code null} separator is the same as an empty String ("").
4425     * </p>
4426     *
4427     * <p>
4428     * See the examples here: {@link #join(Object[],String)}.
4429     * </p>
4430     *
4431     * @param iterator  The {@link Iterator} of values to join together, may be null.
4432     * @param separator The separator character to use, null treated as "".
4433     * @return The joined String, {@code null} if null iterator input.
4434     */
4435    public static String join(final Iterator<?> iterator, final String separator) {
4436        // handle null, zero and one elements before building a buffer
4437        if (iterator == null) {
4438            return null;
4439        }
4440        if (!iterator.hasNext()) {
4441            return EMPTY;
4442        }
4443        return Streams.of(iterator).collect(LangCollectors.joining(ObjectUtils.toString(separator), EMPTY, EMPTY, ObjectUtils::toString));
4444    }
4445
4446    /**
4447     * Joins the elements of the provided {@link List} into a single String containing the provided list of elements.
4448     *
4449     * <p>
4450     * No delimiter is added before or after the list. Null objects or empty strings within the array are represented by empty strings.
4451     * </p>
4452     *
4453     * <pre>
4454     * StringUtils.join(null, *)               = null
4455     * StringUtils.join([], *)                 = ""
4456     * StringUtils.join([null], *)             = ""
4457     * StringUtils.join(["a", "b", "c"], ';')  = "a;b;c"
4458     * StringUtils.join(["a", "b", "c"], null) = "abc"
4459     * StringUtils.join([null, "", "a"], ';')  = ";;a"
4460     * </pre>
4461     *
4462     * @param list       The {@link List} of values to join together, may be null.
4463     * @param separator  The separator character to use.
4464     * @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.
4465     * @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.
4466     * @return The joined String, {@code null} if null list input.
4467     * @since 3.8
4468     */
4469    public static String join(final List<?> list, final char separator, final int startIndex, final int endIndex) {
4470        if (list == null) {
4471            return null;
4472        }
4473        final int noOfItems = endIndex - startIndex;
4474        if (noOfItems <= 0) {
4475            return EMPTY;
4476        }
4477        final List<?> subList = list.subList(startIndex, endIndex);
4478        return join(subList.iterator(), separator);
4479    }
4480
4481    /**
4482     * Joins the elements of the provided {@link List} into a single String containing the provided list of elements.
4483     *
4484     * <p>
4485     * No delimiter is added before or after the list. Null objects or empty strings within the array are represented by empty strings.
4486     * </p>
4487     *
4488     * <pre>
4489     * StringUtils.join(null, *)               = null
4490     * StringUtils.join([], *)                 = ""
4491     * StringUtils.join([null], *)             = ""
4492     * StringUtils.join(["a", "b", "c"], ';')  = "a;b;c"
4493     * StringUtils.join(["a", "b", "c"], null) = "abc"
4494     * StringUtils.join([null, "", "a"], ';')  = ";;a"
4495     * </pre>
4496     *
4497     * @param list       The {@link List} of values to join together, may be null.
4498     * @param separator  The separator character to use.
4499     * @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.
4500     * @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.
4501     * @return The joined String, {@code null} if null list input.
4502     * @since 3.8
4503     */
4504    public static String join(final List<?> list, final String separator, final int startIndex, final int endIndex) {
4505        if (list == null) {
4506            return null;
4507        }
4508        final int noOfItems = endIndex - startIndex;
4509        if (noOfItems <= 0) {
4510            return EMPTY;
4511        }
4512        final List<?> subList = list.subList(startIndex, endIndex);
4513        return join(subList.iterator(), separator);
4514    }
4515
4516    /**
4517     * Joins the elements of the provided array into a single String containing the provided list of elements.
4518     *
4519     * <p>
4520     * No delimiter is added before or after the list. Null objects or empty strings within the array are represented
4521     * by empty strings.
4522     * </p>
4523     *
4524     * <pre>
4525     * StringUtils.join(null, *)               = null
4526     * StringUtils.join([], *)                 = ""
4527     * StringUtils.join([null], *)             = ""
4528     * StringUtils.join([1, 2, 3], ';')  = "1;2;3"
4529     * StringUtils.join([1, 2, 3], null) = "123"
4530     * </pre>
4531     *
4532     * @param array
4533     *            the array of values to join together, may be null.
4534     * @param separator
4535     *            the separator character to use.
4536     * @return The joined String, {@code null} if null array input.
4537     * @since 3.2
4538     */
4539    public static String join(final long[] array, final char separator) {
4540        if (array == null) {
4541            return null;
4542        }
4543        return join(array, separator, 0, array.length);
4544    }
4545
4546    /**
4547     * Joins the elements of the provided array into a single String containing the provided list of elements.
4548     *
4549     * <p>
4550     * No delimiter is added before or after the list. Null objects or empty strings within the array are represented
4551     * by empty strings.
4552     * </p>
4553     *
4554     * <pre>
4555     * StringUtils.join(null, *)               = null
4556     * StringUtils.join([], *)                 = ""
4557     * StringUtils.join([null], *)             = ""
4558     * StringUtils.join([1, 2, 3], ';')  = "1;2;3"
4559     * StringUtils.join([1, 2, 3], null) = "123"
4560     * </pre>
4561     *
4562     * @param array
4563     *            the array of values to join together, may be null.
4564     * @param delimiter
4565     *            the separator character to use.
4566     * @param startIndex
4567     *            the first index to start joining from. It is an error to pass in a start index past the end of the
4568     *            array.
4569     * @param endIndex
4570     *            the index to stop joining from (exclusive). It is an error to pass in an end index past the end of
4571     *            the array.
4572     * @return The joined String, {@code null} if null array input.
4573     * @since 3.2
4574     */
4575    public static String join(final long[] array, final char delimiter, final int startIndex, final int endIndex) {
4576        // See StringUtilsJoinBenchmark
4577        if (array == null) {
4578            return null;
4579        }
4580        checkFromToIndex(startIndex, endIndex, array.length);
4581        final int count = endIndex - startIndex;
4582        if (count <= 0) {
4583            return EMPTY;
4584        }
4585        final byte maxElementChars = 20; // "-9223372036854775808"
4586        final StringBuilder stringBuilder = capacity(count, maxElementChars);
4587        stringBuilder.append(array[startIndex]);
4588        for (int i = startIndex + 1; i < endIndex; i++) {
4589            stringBuilder.append(delimiter).append(array[i]);
4590        }
4591        return stringBuilder.toString();
4592    }
4593
4594    /**
4595     * Joins the elements of the provided array into a single String containing the provided list of elements.
4596     *
4597     * <p>
4598     * No delimiter is added before or after the list. Null objects or empty strings within the array are represented by empty strings.
4599     * </p>
4600     *
4601     * <pre>
4602     * StringUtils.join(null, *)               = null
4603     * StringUtils.join([], *)                 = ""
4604     * StringUtils.join([null], *)             = ""
4605     * StringUtils.join(["a", "b", "c"], ';')  = "a;b;c"
4606     * StringUtils.join(["a", "b", "c"], null) = "abc"
4607     * StringUtils.join([null, "", "a"], ';')  = ";;a"
4608     * </pre>
4609     *
4610     * @param array     The array of values to join together, may be null.
4611     * @param delimiter The separator character to use.
4612     * @return The joined String, {@code null} if null array input.
4613     * @since 2.0
4614     */
4615    public static String join(final Object[] array, final char delimiter) {
4616        if (array == null) {
4617            return null;
4618        }
4619        return join(array, delimiter, 0, array.length);
4620    }
4621
4622    /**
4623     * Joins the elements of the provided array into a single String containing the provided list of elements.
4624     *
4625     * <p>
4626     * No delimiter is added before or after the list. Null objects or empty strings within the array are represented by empty strings.
4627     * </p>
4628     *
4629     * <pre>
4630     * StringUtils.join(null, *)               = null
4631     * StringUtils.join([], *)                 = ""
4632     * StringUtils.join([null], *)             = ""
4633     * StringUtils.join(["a", "b", "c"], ';')  = "a;b;c"
4634     * StringUtils.join(["a", "b", "c"], null) = "abc"
4635     * StringUtils.join([null, "", "a"], ';')  = ";;a"
4636     * </pre>
4637     *
4638     * @param array      The array of values to join together, may be null.
4639     * @param delimiter  The separator character to use.
4640     * @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.
4641     * @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.
4642     * @return The joined String, {@code null} if null array input.
4643     * @since 2.0
4644     */
4645    public static String join(final Object[] array, final char delimiter, final int startIndex, final int endIndex) {
4646        return join(array, String.valueOf(delimiter), startIndex, endIndex);
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 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
4654     * array are represented by empty strings.
4655     * </p>
4656     *
4657     * <pre>
4658     * StringUtils.join(null, *)                = null
4659     * StringUtils.join([], *)                  = ""
4660     * StringUtils.join([null], *)              = ""
4661     * StringUtils.join(["a", "b", "c"], "--")  = "a--b--c"
4662     * StringUtils.join(["a", "b", "c"], null)  = "abc"
4663     * StringUtils.join(["a", "b", "c"], "")    = "abc"
4664     * StringUtils.join([null, "", "a"], ',')   = ",,a"
4665     * </pre>
4666     *
4667     * @param array     The array of values to join together, may be null.
4668     * @param delimiter The separator character to use, null treated as "".
4669     * @return The joined String, {@code null} if null array input.
4670     */
4671    public static String join(final Object[] array, final String delimiter) {
4672        return array != null ? join(array, ObjectUtils.toString(delimiter), 0, array.length) : null;
4673    }
4674
4675    /**
4676     * Joins the elements of the provided array into a single String containing the provided list of elements.
4677     *
4678     * <p>
4679     * No delimiter is added before or after the list. A {@code null} separator is the same as an empty String (""). Null objects or empty strings within the
4680     * array are represented by empty strings.
4681     * </p>
4682     *
4683     * <pre>
4684     * StringUtils.join(null, *, *, *)                = null
4685     * StringUtils.join([], *, *, *)                  = ""
4686     * StringUtils.join([null], *, *, *)              = ""
4687     * StringUtils.join(["a", "b", "c"], "--", 0, 3)  = "a--b--c"
4688     * StringUtils.join(["a", "b", "c"], "--", 1, 3)  = "b--c"
4689     * StringUtils.join(["a", "b", "c"], "--", 2, 3)  = "c"
4690     * StringUtils.join(["a", "b", "c"], "--", 2, 2)  = ""
4691     * StringUtils.join(["a", "b", "c"], null, 0, 3)  = "abc"
4692     * StringUtils.join(["a", "b", "c"], "", 0, 3)    = "abc"
4693     * StringUtils.join([null, "", "a"], ',', 0, 3)   = ",,a"
4694     * </pre>
4695     *
4696     * @param array      The array of values to join together, may be null.
4697     * @param delimiter  The separator character to use, null treated as "".
4698     * @param startIndex The first index to start joining from.
4699     * @param endIndex   The index to stop joining from (exclusive).
4700     * @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
4701     *         given by {@code endIndex - startIndex}.
4702     * @throws ArrayIndexOutOfBoundsException Thrown if<br> {@code startIndex < 0} or <br> {@code startIndex >= array.length()} or <br> {@code endIndex < 0} or
4703     *         <br> {@code endIndex > array.length()}.
4704     */
4705    public static String join(final Object[] array, final String delimiter, final int startIndex, final int endIndex) {
4706        return array != null ? Streams.of(array).skip(startIndex).limit(Math.max(0, endIndex - startIndex))
4707                .collect(LangCollectors.joining(delimiter, EMPTY, EMPTY, ObjectUtils::toString)) : null;
4708    }
4709
4710    /**
4711     * Joins the elements of the provided array into a single String containing the provided list of elements.
4712     *
4713     * <p>
4714     * No delimiter is added before or after the list. Null objects or empty strings within the array are represented
4715     * by empty strings.
4716     * </p>
4717     *
4718     * <pre>
4719     * StringUtils.join(null, *)          = null
4720     * StringUtils.join([], *)            = ""
4721     * StringUtils.join([null], *)        = ""
4722     * StringUtils.join([1, 2, 3], ';')   = "1;2;3"
4723     * StringUtils.join([1, 2, 3], null)  = "123"
4724     * </pre>
4725     *
4726     * @param array
4727     *            the array of values to join together, may be null.
4728     * @param delimiter
4729     *            the separator character to use.
4730     * @return The joined String, {@code null} if null array input.
4731     * @since 3.2
4732     */
4733    public static String join(final short[] array, final char delimiter) {
4734        if (array == null) {
4735            return null;
4736        }
4737        return join(array, delimiter, 0, array.length);
4738    }
4739
4740    /**
4741     * Joins the elements of the provided array into a single String containing the provided list of elements.
4742     *
4743     * <p>
4744     * No delimiter is added before or after the list. Null objects or empty strings within the array are represented
4745     * by empty strings.
4746     * </p>
4747     *
4748     * <pre>
4749     * StringUtils.join(null, *)          = null
4750     * StringUtils.join([], *)            = ""
4751     * StringUtils.join([null], *)        = ""
4752     * StringUtils.join([1, 2, 3], ';')   = "1;2;3"
4753     * StringUtils.join([1, 2, 3], null)  = "123"
4754     * </pre>
4755     *
4756     * @param array
4757     *            the array of values to join together, may be null.
4758     * @param delimiter
4759     *            the separator character to use.
4760     * @param startIndex
4761     *            the first index to start joining from. It is an error to pass in a start index past the end of the
4762     *            array.
4763     * @param endIndex
4764     *            the index to stop joining from (exclusive). It is an error to pass in an end index past the end of
4765     *            the array.
4766     * @return The joined String, {@code null} if null array input.
4767     * @since 3.2
4768     */
4769    public static String join(final short[] array, final char delimiter, final int startIndex, final int endIndex) {
4770        // See StringUtilsJoinBenchmark
4771        if (array == null) {
4772            return null;
4773        }
4774        checkFromToIndex(startIndex, endIndex, array.length);
4775        final int count = endIndex - startIndex;
4776        if (count <= 0) {
4777            return EMPTY;
4778        }
4779        final byte maxElementChars = 6; // "-32768"
4780        final StringBuilder stringBuilder = capacity(count, maxElementChars);
4781        stringBuilder.append(array[startIndex]);
4782        for (int i = startIndex + 1; i < endIndex; i++) {
4783            stringBuilder.append(delimiter).append(array[i]);
4784        }
4785        return stringBuilder.toString();
4786    }
4787
4788    /**
4789     * Joins the elements of the provided array into a single String containing the provided list of elements.
4790     *
4791     * <p>
4792     * No separator is added to the joined String. Null objects or empty strings within the array are represented by empty strings.
4793     * </p>
4794     *
4795     * <pre>
4796     * StringUtils.join(null)            = null
4797     * StringUtils.join([])              = ""
4798     * StringUtils.join([null])          = ""
4799     * StringUtils.join("a", "b", "c")   = "abc"
4800     * StringUtils.join(null, "", "a")   = "a"
4801     * </pre>
4802     *
4803     * @param <T>      the specific type of values to join together.
4804     * @param elements The values to join together, may be null.
4805     * @return The joined String, {@code null} if null array input.
4806     * @since 2.0
4807     * @since 3.0 Changed signature to use varargs
4808     */
4809    @SafeVarargs
4810    public static <T> String join(final T... elements) {
4811        return join(elements, null);
4812    }
4813
4814    /**
4815     * Joins the elements of the provided varargs into a single String containing the provided elements.
4816     *
4817     * <p>
4818     * No delimiter is added before or after the list. {@code null} elements and separator are treated as empty Strings ("").
4819     * </p>
4820     *
4821     * <pre>
4822     * StringUtils.joinWith(",", "a", "b")        = "a,b"
4823     * StringUtils.joinWith(",", "a", "b","")     = "a,b,"
4824     * StringUtils.joinWith(",", "a", null, "b")  = "a,,b"
4825     * StringUtils.joinWith(null, "a", "b")       = "ab"
4826     * </pre>
4827     *
4828     * @param delimiter The separator character to use, null treated as "".
4829     * @param array     The varargs providing the values to join together. {@code null} elements are treated as "".
4830     * @return The joined String.
4831     * @throws IllegalArgumentException Thrown if a null varargs is provided.
4832     * @since 3.5
4833     */
4834    public static String joinWith(final String delimiter, final Object... array) {
4835        if (array == null) {
4836            throw new IllegalArgumentException("Object varargs must not be null");
4837        }
4838        return join(array, delimiter);
4839    }
4840
4841    /**
4842     * Finds the last index within a CharSequence, handling {@code null}. This method uses {@link String#lastIndexOf(String)} if possible.
4843     *
4844     * <p>
4845     * A {@code null} CharSequence will return {@code -1}.
4846     * </p>
4847     *
4848     * <pre>
4849     * StringUtils.lastIndexOf(null, *)          = -1
4850     * StringUtils.lastIndexOf(*, null)          = -1
4851     * StringUtils.lastIndexOf("", "")           = 0
4852     * StringUtils.lastIndexOf("aabaabaa", "a")  = 7
4853     * StringUtils.lastIndexOf("aabaabaa", "b")  = 5
4854     * StringUtils.lastIndexOf("aabaabaa", "ab") = 4
4855     * StringUtils.lastIndexOf("aabaabaa", "")   = 8
4856     * </pre>
4857     *
4858     * @param seq       The CharSequence to check, may be null.
4859     * @param searchSeq The CharSequence to find, may be null.
4860     * @return The last index of the search String, -1 if no match or {@code null} string input.
4861     * @since 2.0
4862     * @since 3.0 Changed signature from lastIndexOf(String, String) to lastIndexOf(CharSequence, CharSequence)
4863     * @deprecated Use {@link Strings#lastIndexOf(CharSequence, CharSequence) Strings.CS.lastIndexOf(CharSequence, CharSequence)}.
4864     */
4865    @Deprecated
4866    public static int lastIndexOf(final CharSequence seq, final CharSequence searchSeq) {
4867        return Strings.CS.lastIndexOf(seq, searchSeq);
4868    }
4869
4870    /**
4871     * Finds the last index within a CharSequence, handling {@code null}. This method uses {@link String#lastIndexOf(String, int)} if possible.
4872     *
4873     * <p>
4874     * A {@code null} CharSequence will return {@code -1}. A negative start position returns {@code -1}. An empty ("") search CharSequence always matches unless
4875     * 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
4876     * backwards; matches starting after the start position are ignored.
4877     * </p>
4878     *
4879     * <pre>
4880     * StringUtils.lastIndexOf(null, *, *)          = -1
4881     * StringUtils.lastIndexOf(*, null, *)          = -1
4882     * StringUtils.lastIndexOf("aabaabaa", "a", 8)  = 7
4883     * StringUtils.lastIndexOf("aabaabaa", "b", 8)  = 5
4884     * StringUtils.lastIndexOf("aabaabaa", "ab", 8) = 4
4885     * StringUtils.lastIndexOf("aabaabaa", "b", 9)  = 5
4886     * StringUtils.lastIndexOf("aabaabaa", "b", -1) = -1
4887     * StringUtils.lastIndexOf("aabaabaa", "a", 0)  = 0
4888     * StringUtils.lastIndexOf("aabaabaa", "b", 0)  = -1
4889     * StringUtils.lastIndexOf("aabaabaa", "b", 1)  = -1
4890     * StringUtils.lastIndexOf("aabaabaa", "b", 2)  = 2
4891     * StringUtils.lastIndexOf("aabaabaa", "ba", 2)  = 2
4892     * </pre>
4893     *
4894     * @param seq       The CharSequence to check, may be null.
4895     * @param searchSeq The CharSequence to find, may be null.
4896     * @param startPos  The start position, negative treated as zero.
4897     * @return The last index of the search CharSequence (always &le; startPos), -1 if no match or {@code null} string input.
4898     * @since 2.0
4899     * @since 3.0 Changed signature from lastIndexOf(String, String, int) to lastIndexOf(CharSequence, CharSequence, int)
4900     * @deprecated Use {@link Strings#lastIndexOf(CharSequence, CharSequence, int) Strings.CS.lastIndexOf(CharSequence, CharSequence, int)}.
4901     */
4902    @Deprecated
4903    public static int lastIndexOf(final CharSequence seq, final CharSequence searchSeq, final int startPos) {
4904        return Strings.CS.lastIndexOf(seq, searchSeq, startPos);
4905    }
4906
4907    /**
4908     * 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
4909     * (inclusive), the index (in Unicode code units) returned is the largest value <em>k</em> such that:
4910     *
4911     * <pre>
4912     * this.charAt(<em>k</em>) == searchChar
4913     * </pre>
4914     *
4915     * <p>
4916     * is true. For other values of {@code searchChar}, it is the largest value <em>k</em> such that:
4917     * </p>
4918     *
4919     * <pre>
4920     * this.codePointAt(<em>k</em>) == searchChar
4921     * </pre>
4922     *
4923     * <p>
4924     * is true. In either case, if no such character occurs in this string, then {@code -1} is returned. Furthermore, a {@code null} or empty ("")
4925     * {@link CharSequence} will return {@code -1}. The {@code seq} {@link CharSequence} object is searched backwards starting at the last character.
4926     * </p>
4927     *
4928     * <pre>
4929     * StringUtils.lastIndexOf(null, *)         = -1
4930     * StringUtils.lastIndexOf("", *)           = -1
4931     * StringUtils.lastIndexOf("aabaabaa", 'a') = 7
4932     * StringUtils.lastIndexOf("aabaabaa", 'b') = 5
4933     * </pre>
4934     *
4935     * @param seq        The {@link CharSequence} to check, may be null.
4936     * @param searchChar The character to find.
4937     * @return The last index of the search character, -1 if no match or {@code null} string input.
4938     * @since 2.0
4939     * @since 3.0 Changed signature from lastIndexOf(String, int) to lastIndexOf(CharSequence, int)
4940     * @since 3.6 Updated {@link CharSequenceUtils} call to behave more like {@link String}
4941     */
4942    public static int lastIndexOf(final CharSequence seq, final int searchChar) {
4943        if (isEmpty(seq)) {
4944            return INDEX_NOT_FOUND;
4945        }
4946        return CharSequenceUtils.lastIndexOf(seq, searchChar, seq.length());
4947    }
4948
4949    /**
4950     * Returns the index within {@code seq} of the last occurrence of the specified character, searching backward starting at the specified index. For values of
4951     * {@code searchChar} in the range from 0 to 0xFFFF (inclusive), the index returned is the largest value <em>k</em> such that:
4952     *
4953     * <pre>
4954     * (this.charAt(<em>k</em>) == searchChar) &amp;&amp; (<em>k</em> &lt;= startPos)
4955     * </pre>
4956     *
4957     * <p>
4958     * is true. For other values of {@code searchChar}, it is the largest value <em>k</em> such that:
4959     * </p>
4960     *
4961     * <pre>
4962     * (this.codePointAt(<em>k</em>) == searchChar) &amp;&amp; (<em>k</em> &lt;= startPos)
4963     * </pre>
4964     *
4965     * <p>
4966     * 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
4967     * {@code null} or empty ("") {@link CharSequence} will return {@code -1}. A start position greater than the string length searches the whole string. The
4968     * search starts at the {@code startPos} and works backwards; matches starting after the start position are ignored.
4969     * </p>
4970     *
4971     * <p>
4972     * All indices are specified in {@code char} values (Unicode code units).
4973     * </p>
4974     *
4975     * <pre>
4976     * StringUtils.lastIndexOf(null, *, *)          = -1
4977     * StringUtils.lastIndexOf("", *,  *)           = -1
4978     * StringUtils.lastIndexOf("aabaabaa", 'b', 8)  = 5
4979     * StringUtils.lastIndexOf("aabaabaa", 'b', 4)  = 2
4980     * StringUtils.lastIndexOf("aabaabaa", 'b', 0)  = -1
4981     * StringUtils.lastIndexOf("aabaabaa", 'b', 9)  = 5
4982     * StringUtils.lastIndexOf("aabaabaa", 'b', -1) = -1
4983     * StringUtils.lastIndexOf("aabaabaa", 'a', 0)  = 0
4984     * </pre>
4985     *
4986     * @param seq        The CharSequence to check, may be null.
4987     * @param searchChar The character to find.
4988     * @param startPos   The start position.
4989     * @return The last index of the search character (always &le; startPos), -1 if no match or {@code null} string input.
4990     * @since 2.0
4991     * @since 3.0 Changed signature from lastIndexOf(String, int, int) to lastIndexOf(CharSequence, int, int)
4992     */
4993    public static int lastIndexOf(final CharSequence seq, final int searchChar, final int startPos) {
4994        if (isEmpty(seq)) {
4995            return INDEX_NOT_FOUND;
4996        }
4997        return CharSequenceUtils.lastIndexOf(seq, searchChar, startPos);
4998    }
4999
5000    /**
5001     * Finds the latest index of any substring in a set of potential substrings.
5002     *
5003     * <p>
5004     * 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
5005     * will be ignored, but a search array containing "" will return the length of {@code str} if {@code str} is not null. This method uses
5006     * {@link String#indexOf(String)} if possible
5007     * </p>
5008     *
5009     * <pre>
5010     * StringUtils.lastIndexOfAny(null, *)                    = -1
5011     * StringUtils.lastIndexOfAny(*, null)                    = -1
5012     * StringUtils.lastIndexOfAny(*, [])                      = -1
5013     * StringUtils.lastIndexOfAny(*, [null])                  = -1
5014     * StringUtils.lastIndexOfAny("zzabyycdxx", ["ab", "cd"]) = 6
5015     * StringUtils.lastIndexOfAny("zzabyycdxx", ["cd", "ab"]) = 6
5016     * StringUtils.lastIndexOfAny("zzabyycdxx", ["mn", "op"]) = -1
5017     * StringUtils.lastIndexOfAny("zzabyycdxx", ["mn", "op"]) = -1
5018     * StringUtils.lastIndexOfAny("zzabyycdxx", ["mn", ""])   = 10
5019     * </pre>
5020     *
5021     * @param str        The CharSequence to check, may be null.
5022     * @param searchStrs The CharSequences to search for, may be null.
5023     * @return The last index of any of the CharSequences, -1 if no match.
5024     * @since 3.0 Changed signature from lastIndexOfAny(String, String[]) to lastIndexOfAny(CharSequence, CharSequence)
5025     */
5026    public static int lastIndexOfAny(final CharSequence str, final CharSequence... searchStrs) {
5027        if (str == null || searchStrs == null) {
5028            return INDEX_NOT_FOUND;
5029        }
5030        int ret = INDEX_NOT_FOUND;
5031        int tmp;
5032        for (final CharSequence search : searchStrs) {
5033            if (search == null) {
5034                continue;
5035            }
5036            tmp = CharSequenceUtils.lastIndexOf(str, search, str.length());
5037            if (tmp > ret) {
5038                ret = tmp;
5039            }
5040        }
5041        return ret;
5042    }
5043
5044    /**
5045     * Case insensitive find of the last index within a CharSequence.
5046     *
5047     * <p>
5048     * A {@code null} CharSequence will return {@code -1}. A negative start position returns {@code -1}. An empty ("") search CharSequence always matches unless
5049     * the start position is negative. A start position greater than the string length searches the whole string.
5050     * </p>
5051     *
5052     * <pre>
5053     * StringUtils.lastIndexOfIgnoreCase(null, *)          = -1
5054     * StringUtils.lastIndexOfIgnoreCase(*, null)          = -1
5055     * StringUtils.lastIndexOfIgnoreCase("aabaabaa", "A")  = 7
5056     * StringUtils.lastIndexOfIgnoreCase("aabaabaa", "B")  = 5
5057     * StringUtils.lastIndexOfIgnoreCase("aabaabaa", "AB") = 4
5058     * </pre>
5059     *
5060     * @param str       The CharSequence to check, may be null.
5061     * @param searchStr The CharSequence to find, may be null.
5062     * @return The first index of the search CharSequence, -1 if no match or {@code null} string input.
5063     * @since 2.5
5064     * @since 3.0 Changed signature from lastIndexOfIgnoreCase(String, String) to lastIndexOfIgnoreCase(CharSequence, CharSequence)
5065     * @deprecated Use {@link Strings#lastIndexOf(CharSequence, CharSequence) Strings.CI.lastIndexOf(CharSequence, CharSequence)}.
5066     */
5067    @Deprecated
5068    public static int lastIndexOfIgnoreCase(final CharSequence str, final CharSequence searchStr) {
5069        return Strings.CI.lastIndexOf(str, searchStr);
5070    }
5071
5072    /**
5073     * Case insensitive find of the last index within a CharSequence from the specified position.
5074     *
5075     * <p>
5076     * A {@code null} CharSequence will return {@code -1}. A negative start position returns {@code -1}. An empty ("") search CharSequence always matches unless
5077     * 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
5078     * backwards; matches starting after the start position are ignored.
5079     * </p>
5080     *
5081     * <pre>
5082     * StringUtils.lastIndexOfIgnoreCase(null, *, *)          = -1
5083     * StringUtils.lastIndexOfIgnoreCase(*, null, *)          = -1
5084     * StringUtils.lastIndexOfIgnoreCase("aabaabaa", "A", 8)  = 7
5085     * StringUtils.lastIndexOfIgnoreCase("aabaabaa", "B", 8)  = 5
5086     * StringUtils.lastIndexOfIgnoreCase("aabaabaa", "AB", 8) = 4
5087     * StringUtils.lastIndexOfIgnoreCase("aabaabaa", "B", 9)  = 5
5088     * StringUtils.lastIndexOfIgnoreCase("aabaabaa", "B", -1) = -1
5089     * StringUtils.lastIndexOfIgnoreCase("aabaabaa", "A", 0)  = 0
5090     * StringUtils.lastIndexOfIgnoreCase("aabaabaa", "B", 0)  = -1
5091     * </pre>
5092     *
5093     * @param str       The CharSequence to check, may be null.
5094     * @param searchStr The CharSequence to find, may be null.
5095     * @param startPos  The start position.
5096     * @return The last index of the search CharSequence (always &le; startPos), -1 if no match or {@code null} input.
5097     * @since 2.5
5098     * @since 3.0 Changed signature from lastIndexOfIgnoreCase(String, String, int) to lastIndexOfIgnoreCase(CharSequence, CharSequence, int)
5099     * @deprecated Use {@link Strings#lastIndexOf(CharSequence, CharSequence, int) Strings.CI.lastIndexOf(CharSequence, CharSequence, int)}.
5100     */
5101    @Deprecated
5102    public static int lastIndexOfIgnoreCase(final CharSequence str, final CharSequence searchStr, final int startPos) {
5103        return Strings.CI.lastIndexOf(str, searchStr, startPos);
5104    }
5105
5106    /**
5107     * Finds the n-th last index within a String, handling {@code null}. This method uses {@link String#lastIndexOf(String)}.
5108     *
5109     * <p>
5110     * A {@code null} String will return {@code -1}.
5111     * </p>
5112     *
5113     * <pre>
5114     * StringUtils.lastOrdinalIndexOf(null, *, *)          = -1
5115     * StringUtils.lastOrdinalIndexOf(*, null, *)          = -1
5116     * StringUtils.lastOrdinalIndexOf("", "", *)           = 0
5117     * StringUtils.lastOrdinalIndexOf("aabaabaa", "a", 1)  = 7
5118     * StringUtils.lastOrdinalIndexOf("aabaabaa", "a", 2)  = 6
5119     * StringUtils.lastOrdinalIndexOf("aabaabaa", "b", 1)  = 5
5120     * StringUtils.lastOrdinalIndexOf("aabaabaa", "b", 2)  = 2
5121     * StringUtils.lastOrdinalIndexOf("aabaabaa", "ab", 1) = 4
5122     * StringUtils.lastOrdinalIndexOf("aabaabaa", "ab", 2) = 1
5123     * StringUtils.lastOrdinalIndexOf("aabaabaa", "", 1)   = 8
5124     * StringUtils.lastOrdinalIndexOf("aabaabaa", "", 2)   = 8
5125     * </pre>
5126     *
5127     * <p>
5128     * Note that 'tail(CharSequence str, int n)' may be implemented as:
5129     * </p>
5130     *
5131     * <pre>
5132     * str.substring(lastOrdinalIndexOf(str, "\n", n) + 1)
5133     * </pre>
5134     *
5135     * @param str       The CharSequence to check, may be null.
5136     * @param searchStr The CharSequence to find, may be null.
5137     * @param ordinal   The n-th last {@code searchStr} to find.
5138     * @return The n-th last index of the search CharSequence, {@code -1} ({@code INDEX_NOT_FOUND}) if no match or {@code null} string input.
5139     * @since 2.5
5140     * @since 3.0 Changed signature from lastOrdinalIndexOf(String, String, int) to lastOrdinalIndexOf(CharSequence, CharSequence, int)
5141     */
5142    public static int lastOrdinalIndexOf(final CharSequence str, final CharSequence searchStr, final int ordinal) {
5143        return ordinalIndexOf(str, searchStr, ordinal, true);
5144    }
5145
5146    /**
5147     * Gets the leftmost {@code len} characters of a String.
5148     *
5149     * <p>
5150     * 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
5151     * if len is negative.
5152     * </p>
5153     *
5154     * <pre>
5155     * StringUtils.left(null, *)    = null
5156     * StringUtils.left(*, -ve)     = ""
5157     * StringUtils.left("", *)      = ""
5158     * StringUtils.left("abc", 0)   = ""
5159     * StringUtils.left("abc", 2)   = "ab"
5160     * StringUtils.left("abc", 4)   = "abc"
5161     * </pre>
5162     *
5163     * @param str The String to get the leftmost characters from, may be null.
5164     * @param len The length of the required String.
5165     * @return The leftmost characters, {@code null} if null String input.
5166     */
5167    public static String left(final String str, final int len) {
5168        if (str == null) {
5169            return null;
5170        }
5171        if (len < 0) {
5172            return EMPTY;
5173        }
5174        if (str.length() <= len) {
5175            return str;
5176        }
5177        int cut = len;
5178        // keep the cut off the middle of a surrogate pair so the result is never left holding a lone surrogate
5179        if (splitsSurrogatePair(str, cut)) {
5180            cut--;
5181        }
5182        return str.substring(0, cut);
5183    }
5184
5185    /**
5186     * Left pad a String with spaces (' ').
5187     *
5188     * <p>
5189     * The String is padded to the size of {@code size}.
5190     * </p>
5191     *
5192     * <pre>
5193     * StringUtils.leftPad(null, *)   = null
5194     * StringUtils.leftPad("", 3)     = "   "
5195     * StringUtils.leftPad("bat", 3)  = "bat"
5196     * StringUtils.leftPad("bat", 5)  = "  bat"
5197     * StringUtils.leftPad("bat", 1)  = "bat"
5198     * StringUtils.leftPad("bat", -1) = "bat"
5199     * </pre>
5200     *
5201     * @param str  The String to pad out, may be null.
5202     * @param size The size to pad to.
5203     * @return left padded String or original String if no padding is necessary, {@code null} if null String input.
5204     */
5205    public static String leftPad(final String str, final int size) {
5206        return leftPad(str, size, ' ');
5207    }
5208
5209    /**
5210     * Left pad a String with a specified character.
5211     *
5212     * <p>
5213     * Pad to a size of {@code size}.
5214     * </p>
5215     *
5216     * <pre>
5217     * StringUtils.leftPad(null, *, *)     = null
5218     * StringUtils.leftPad("", 3, 'z')     = "zzz"
5219     * StringUtils.leftPad("bat", 3, 'z')  = "bat"
5220     * StringUtils.leftPad("bat", 5, 'z')  = "zzbat"
5221     * StringUtils.leftPad("bat", 1, 'z')  = "bat"
5222     * StringUtils.leftPad("bat", -1, 'z') = "bat"
5223     * </pre>
5224     *
5225     * @param str     The String to pad out, may be null.
5226     * @param size    The size to pad to.
5227     * @param padChar The character to pad with.
5228     * @return left padded String or original String if no padding is necessary, {@code null} if null String input.
5229     * @since 2.0
5230     */
5231    public static String leftPad(final String str, final int size, final char padChar) {
5232        if (str == null || size <= str.length()) {
5233            return str;
5234        }
5235        final int pads = size - str.length();
5236        if (pads <= 0) {
5237            return str; // returns original String when possible
5238        }
5239        if (pads > PAD_LIMIT) {
5240            return leftPad(str, size, String.valueOf(padChar));
5241        }
5242        return repeat(padChar, pads).concat(str);
5243    }
5244
5245    /**
5246     * Left pad a String with a specified String.
5247     *
5248     * <p>
5249     * Pad to a size of {@code size}.
5250     * </p>
5251     *
5252     * <pre>
5253     * StringUtils.leftPad(null, *, *)      = null
5254     * StringUtils.leftPad("", 3, "z")      = "zzz"
5255     * StringUtils.leftPad("bat", 3, "yz")  = "bat"
5256     * StringUtils.leftPad("bat", 5, "yz")  = "yzbat"
5257     * StringUtils.leftPad("bat", 8, "yz")  = "yzyzybat"
5258     * StringUtils.leftPad("bat", 1, "yz")  = "bat"
5259     * StringUtils.leftPad("bat", -1, "yz") = "bat"
5260     * StringUtils.leftPad("bat", 5, null)  = "  bat"
5261     * StringUtils.leftPad("bat", 5, "")    = "  bat"
5262     * </pre>
5263     *
5264     * @param str    The String to pad out, may be null.
5265     * @param size   The size to pad to.
5266     * @param padStr The String to pad with, null or empty treated as single space.
5267     * @return left padded String or original String if no padding is necessary, {@code null} if null String input.
5268     */
5269    public static String leftPad(final String str, final int size, String padStr) {
5270        if (str == null || size <= str.length()) {
5271            return str;
5272        }
5273        if (isEmpty(padStr)) {
5274            padStr = SPACE;
5275        }
5276        final int padLen = padStr.length();
5277        final int strLen = str.length();
5278        final int pads = size - strLen;
5279        if (pads <= 0) {
5280            return str; // returns original String when possible
5281        }
5282        if (padLen == 1 && pads <= PAD_LIMIT) {
5283            return leftPad(str, size, padStr.charAt(0));
5284        }
5285        if (pads == padLen) {
5286            return padStr.concat(str);
5287        }
5288        if (pads < padLen) {
5289            return padStr.substring(0, pads).concat(str);
5290        }
5291        final char[] padding = new char[pads];
5292        final char[] padChars = padStr.toCharArray();
5293        for (int i = 0; i < pads; i++) {
5294            padding[i] = padChars[i % padLen];
5295        }
5296        return new String(padding).concat(str);
5297    }
5298
5299    /**
5300     * Gets a CharSequence length or {@code 0} if the CharSequence is {@code null}.
5301     *
5302     * @param cs A CharSequence or {@code null}.
5303     * @return CharSequence length or {@code 0} if the CharSequence is {@code null}.
5304     * @since 2.4
5305     * @since 3.0 Changed signature from length(String) to length(CharSequence)
5306     */
5307    public static int length(final CharSequence cs) {
5308        return cs == null ? 0 : cs.length();
5309    }
5310
5311    /**
5312     * Converts a String to lower case as per {@link String#toLowerCase()}.
5313     *
5314     * <p>
5315     * A {@code null} input String returns {@code null}.
5316     * </p>
5317     *
5318     * <pre>
5319     * StringUtils.lowerCase(null)  = null
5320     * StringUtils.lowerCase("")    = ""
5321     * StringUtils.lowerCase("aBc") = "abc"
5322     * </pre>
5323     *
5324     * <p>
5325     * <strong>Note:</strong> As described in the documentation for {@link String#toLowerCase()}, the result of this method is affected by the current locale.
5326     * For platform-independent case transformations, the method {@link #lowerCase(String, Locale)} should be used with a specific locale (e.g.
5327     * {@link Locale#ENGLISH}).
5328     * </p>
5329     *
5330     * @param str The String to lower case, may be null.
5331     * @return The lower cased String, {@code null} if null String input.
5332     */
5333    public static String lowerCase(final String str) {
5334        if (str == null) {
5335            return null;
5336        }
5337        return str.toLowerCase();
5338    }
5339
5340    /**
5341     * Converts a String to lower case as per {@link String#toLowerCase(Locale)}.
5342     *
5343     * <p>
5344     * A {@code null} input String returns {@code null}.
5345     * </p>
5346     *
5347     * <pre>
5348     * StringUtils.lowerCase(null, Locale.ENGLISH)  = null
5349     * StringUtils.lowerCase("", Locale.ENGLISH)    = ""
5350     * StringUtils.lowerCase("aBc", Locale.ENGLISH) = "abc"
5351     * </pre>
5352     *
5353     * @param str    The String to lower case, may be null.
5354     * @param locale The locale that defines the case transformation rules, must not be null.
5355     * @return The lower cased String, {@code null} if null String input.
5356     * @since 2.5
5357     */
5358    public static String lowerCase(final String str, final Locale locale) {
5359        if (str == null) {
5360            return null;
5361        }
5362        return str.toLowerCase(LocaleUtils.toLocale(locale));
5363    }
5364
5365    private static int[] matches(final CharSequence first, final CharSequence second) {
5366        final CharSequence max;
5367        final CharSequence min;
5368        if (first.length() > second.length()) {
5369            max = first;
5370            min = second;
5371        } else {
5372            max = second;
5373            min = first;
5374        }
5375        final int range = Math.max(max.length() / 2 - 1, 0);
5376        final int[] matchIndexes = ArrayFill.fill(new int[min.length()], -1);
5377        final boolean[] matchFlags = new boolean[max.length()];
5378        int matches = 0;
5379        for (int mi = 0; mi < min.length(); mi++) {
5380            final char c1 = min.charAt(mi);
5381            for (int xi = Math.max(mi - range, 0), xn = Math.min(mi + range + 1, max.length()); xi < xn; xi++) {
5382                if (!matchFlags[xi] && c1 == max.charAt(xi)) {
5383                    matchIndexes[mi] = xi;
5384                    matchFlags[xi] = true;
5385                    matches++;
5386                    break;
5387                }
5388            }
5389        }
5390        final char[] ms1 = new char[matches];
5391        final char[] ms2 = new char[matches];
5392        for (int i = 0, si = 0; i < min.length(); i++) {
5393            if (matchIndexes[i] != -1) {
5394                ms1[si] = min.charAt(i);
5395                si++;
5396            }
5397        }
5398        for (int i = 0, si = 0; i < max.length(); i++) {
5399            if (matchFlags[i]) {
5400                ms2[si] = max.charAt(i);
5401                si++;
5402            }
5403        }
5404        int transpositions = 0;
5405        for (int mi = 0; mi < ms1.length; mi++) {
5406            if (ms1[mi] != ms2[mi]) {
5407                transpositions++;
5408            }
5409        }
5410        int prefix = 0;
5411        for (int mi = 0; mi < min.length(); mi++) {
5412            if (first.charAt(mi) != second.charAt(mi)) {
5413                break;
5414            }
5415            prefix++;
5416        }
5417        return new int[] { matches, transpositions / 2, prefix, max.length() };
5418    }
5419
5420    /**
5421     * Gets {@code len} characters from the middle of a String.
5422     *
5423     * <p>
5424     * If {@code len} characters are not available, the remainder of the String will be returned without an exception. If the String is {@code null},
5425     * {@code null} will be returned. An empty String is returned if len is negative or exceeds the length of {@code str}.
5426     * </p>
5427     *
5428     * <pre>
5429     * StringUtils.mid(null, *, *)    = null
5430     * StringUtils.mid(*, *, -ve)     = ""
5431     * StringUtils.mid("", 0, *)      = ""
5432     * StringUtils.mid("abc", 0, 2)   = "ab"
5433     * StringUtils.mid("abc", 0, 4)   = "abc"
5434     * StringUtils.mid("abc", 2, 4)   = "c"
5435     * StringUtils.mid("abc", 4, 2)   = ""
5436     * StringUtils.mid("abc", -2, 2)  = "ab"
5437     * </pre>
5438     *
5439     * @param str The String to get the characters from, may be null.
5440     * @param pos The position to start from, negative treated as zero.
5441     * @param len The length of the required String.
5442     * @return The middle characters, {@code null} if null String input.
5443     */
5444    public static String mid(final String str, int pos, final int len) {
5445        if (str == null) {
5446            return null;
5447        }
5448        if (len < 0 || pos > str.length()) {
5449            return EMPTY;
5450        }
5451        if (pos < 0) {
5452            pos = 0;
5453        }
5454        int start = pos;
5455        // keep the start off the middle of a surrogate pair so the result is never left holding a lone surrogate
5456        if (splitsSurrogatePair(str, start)) {
5457            start++;
5458        }
5459        if (str.length() - pos <= len) {
5460            return str.substring(start);
5461        }
5462        int end = pos + len;
5463        // keep both cuts off the middle of a surrogate pair so the result is never left holding a lone surrogate
5464        if (splitsSurrogatePair(str, end)) {
5465            end--;
5466        }
5467        return str.substring(start, Math.max(start, end));
5468    }
5469
5470    /**
5471     * Similar to <a href="https://www.w3.org/TR/xpath/#function-normalize-space">https://www.w3.org/TR/xpath/#function-normalize -space</a>
5472     *
5473     * <p>
5474     * This function returns the argument string with whitespace normalized by using {@code {@link #trim(String)}} to remove leading and trailing whitespace and
5475     * then replacing sequences of whitespace characters by a single space.
5476     * </p>
5477     * 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 |
5478     * #x9 | #xD | #xA)+
5479     * <p>
5480     * Java's regexp pattern \s defines whitespace as [ \t\n\x0B\f\r]
5481     * </p>
5482     * <p>
5483     * For reference:
5484     * </p>
5485     * <ul>
5486     * <li>\x0B = vertical tab</li>
5487     * <li>\f = #xC = form feed</li>
5488     * <li>#x20 = space</li>
5489     * <li>#x9 = \t</li>
5490     * <li>#xA = \n</li>
5491     * <li>#xD = \r</li>
5492     * </ul>
5493     *
5494     * <p>
5495     * The difference is that Java's whitespace includes vertical tab and form feed, which this function will also normalize. Additionally {@code {@link
5496     * #trim(String)}} removes control characters (char &lt;= 32) from both ends of this String.
5497     * </p>
5498     *
5499     * @param str The source String to normalize whitespaces from, may be null.
5500     * @return The modified string with whitespace normalized, {@code null} if null String input.
5501     * @see Pattern
5502     * @see #trim(String)
5503     * @see <a href="https://www.w3.org/TR/xpath/#function-normalize-space">https://www.w3.org/TR/xpath/#function-normalize-space</a>
5504     * @since 3.0
5505     */
5506    public static String normalizeSpace(final String str) {
5507        // LANG-1020: Improved performance significantly by normalizing manually instead of using regex
5508        // See https://github.com/librucha/commons-lang-normalizespaces-benchmark for performance test
5509        if (isEmpty(str)) {
5510            return str;
5511        }
5512        final int size = str.length();
5513        final char[] newChars = new char[size];
5514        int count = 0;
5515        int whitespacesCount = 0;
5516        boolean startWhitespaces = true;
5517        for (int i = 0; i < size; i++) {
5518            final char actualChar = str.charAt(i);
5519            final boolean isWhitespace = Character.isWhitespace(actualChar);
5520            if (isWhitespace) {
5521                if (whitespacesCount == 0 && !startWhitespaces) {
5522                    newChars[count++] = SPACE.charAt(0);
5523                }
5524                whitespacesCount++;
5525            } else {
5526                startWhitespaces = false;
5527                newChars[count++] = actualChar == 160 ? 32 : actualChar;
5528                whitespacesCount = 0;
5529            }
5530        }
5531        if (startWhitespaces) {
5532            return EMPTY;
5533        }
5534        return new String(newChars, 0, count - (whitespacesCount > 0 ? 1 : 0)).trim();
5535    }
5536
5537    /**
5538     * Finds the n-th index within a CharSequence, handling {@code null}. This method uses {@link String#indexOf(String)} if possible.
5539     * <p>
5540     * <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
5541     * (unless {@code searchStr} is an empty string, in which case the position is never incremented and {@code 0} is returned immediately). This means that
5542     * matches may overlap.
5543     * </p>
5544     * <p>
5545     * A {@code null} CharSequence will return {@code -1}.
5546     * </p>
5547     *
5548     * <pre>
5549     * StringUtils.ordinalIndexOf(null, *, *)          = -1
5550     * StringUtils.ordinalIndexOf(*, null, *)          = -1
5551     * StringUtils.ordinalIndexOf("", "", *)           = 0
5552     * StringUtils.ordinalIndexOf("aabaabaa", "a", 1)  = 0
5553     * StringUtils.ordinalIndexOf("aabaabaa", "a", 2)  = 1
5554     * StringUtils.ordinalIndexOf("aabaabaa", "b", 1)  = 2
5555     * StringUtils.ordinalIndexOf("aabaabaa", "b", 2)  = 5
5556     * StringUtils.ordinalIndexOf("aabaabaa", "ab", 1) = 1
5557     * StringUtils.ordinalIndexOf("aabaabaa", "ab", 2) = 4
5558     * StringUtils.ordinalIndexOf("aabaabaa", "", 1)   = 0
5559     * StringUtils.ordinalIndexOf("aabaabaa", "", 2)   = 0
5560     * </pre>
5561     *
5562     * <p>
5563     * Matches may overlap:
5564     * </p>
5565     *
5566     * <pre>
5567     * StringUtils.ordinalIndexOf("ababab", "aba", 1)   = 0
5568     * StringUtils.ordinalIndexOf("ababab", "aba", 2)   = 2
5569     * StringUtils.ordinalIndexOf("ababab", "aba", 3)   = -1
5570     *
5571     * StringUtils.ordinalIndexOf("abababab", "abab", 1) = 0
5572     * StringUtils.ordinalIndexOf("abababab", "abab", 2) = 2
5573     * StringUtils.ordinalIndexOf("abababab", "abab", 3) = 4
5574     * StringUtils.ordinalIndexOf("abababab", "abab", 4) = -1
5575     * </pre>
5576     *
5577     * <p>
5578     * Note that 'head(CharSequence str, int n)' may be implemented as:
5579     * </p>
5580     *
5581     * <pre>
5582     * str.substring(0, lastOrdinalIndexOf(str, "\n", n))
5583     * </pre>
5584     *
5585     * @param str       The CharSequence to check, may be null.
5586     * @param searchStr The CharSequence to find, may be null.
5587     * @param ordinal   The n-th {@code searchStr} to find.
5588     * @return The n-th index of the search CharSequence, {@code -1} ({@code INDEX_NOT_FOUND}) if no match or {@code null} string input.
5589     * @since 2.1
5590     * @since 3.0 Changed signature from ordinalIndexOf(String, String, int) to ordinalIndexOf(CharSequence, CharSequence, int)
5591     */
5592    public static int ordinalIndexOf(final CharSequence str, final CharSequence searchStr, final int ordinal) {
5593        return ordinalIndexOf(str, searchStr, ordinal, false);
5594    }
5595
5596    /**
5597     * Finds the n-th index within a String, handling {@code null}. This method uses {@link String#indexOf(String)} if possible.
5598     * <p>
5599     * Note that matches may overlap.
5600     * <p>
5601     *
5602     * <p>
5603     * A {@code null} CharSequence will return {@code -1}.
5604     * </p>
5605     *
5606     * @param str       The CharSequence to check, may be null.
5607     * @param searchStr The CharSequence to find, may be null.
5608     * @param ordinal   The n-th {@code searchStr} to find, overlapping matches are allowed.
5609     * @param lastIndex true if lastOrdinalIndexOf() otherwise false if ordinalIndexOf().
5610     * @return The n-th index of the search CharSequence, {@code -1} ({@code INDEX_NOT_FOUND}) if no match or {@code null} string input.
5611     */
5612    // Shared code between ordinalIndexOf(String, String, int) and lastOrdinalIndexOf(String, String, int)
5613    private static int ordinalIndexOf(final CharSequence str, final CharSequence searchStr, final int ordinal, final boolean lastIndex) {
5614        if (str == null || searchStr == null || ordinal <= 0) {
5615            return INDEX_NOT_FOUND;
5616        }
5617        if (isEmpty(searchStr)) {
5618            return lastIndex ? str.length() : 0;
5619        }
5620        int found = 0;
5621        // set the initial index beyond the end of the string
5622        // this is to allow for the initial index decrement/increment
5623        int index = lastIndex ? str.length() : INDEX_NOT_FOUND;
5624        do {
5625            if (lastIndex) {
5626                index = CharSequenceUtils.lastIndexOf(str, searchStr, index - 1); // step backwards through string
5627            } else {
5628                index = CharSequenceUtils.indexOf(str, searchStr, index + 1); // step forwards through string
5629            }
5630            if (index < 0) {
5631                return index;
5632            }
5633            found++;
5634        } while (found < ordinal);
5635        return index;
5636    }
5637
5638    /**
5639     * Overlays part of a String with another String.
5640     *
5641     * <p>
5642     * 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
5643     * length. The start index is always the smaller of the two indices.
5644     * </p>
5645     *
5646     * <pre>
5647     * StringUtils.overlay(null, *, *, *)            = null
5648     * StringUtils.overlay("", "abc", 0, 0)          = "abc"
5649     * StringUtils.overlay("abcdef", null, 2, 4)     = "abef"
5650     * StringUtils.overlay("abcdef", "", 2, 4)       = "abef"
5651     * StringUtils.overlay("abcdef", "", 4, 2)       = "abef"
5652     * StringUtils.overlay("abcdef", "zzzz", 2, 4)   = "abzzzzef"
5653     * StringUtils.overlay("abcdef", "zzzz", 4, 2)   = "abzzzzef"
5654     * StringUtils.overlay("abcdef", "zzzz", -1, 4)  = "zzzzef"
5655     * StringUtils.overlay("abcdef", "zzzz", 2, 8)   = "abzzzz"
5656     * StringUtils.overlay("abcdef", "zzzz", -2, -3) = "zzzzabcdef"
5657     * StringUtils.overlay("abcdef", "zzzz", 8, 10)  = "abcdefzzzz"
5658     * </pre>
5659     *
5660     * @param str     The String to do overlaying in, may be null.
5661     * @param overlay The String to overlay, may be null.
5662     * @param start   The position to start overlaying at.
5663     * @param end     The position to stop overlaying before.
5664     * @return overlaid String, {@code null} if null String input.
5665     * @since 2.0
5666     */
5667    public static String overlay(final String str, String overlay, int start, int end) {
5668        if (str == null) {
5669            return null;
5670        }
5671        if (overlay == null) {
5672            overlay = EMPTY;
5673        }
5674        final int len = str.length();
5675        if (start < 0) {
5676            start = 0;
5677        }
5678        if (start > len) {
5679            start = len;
5680        }
5681        if (end < 0) {
5682            end = 0;
5683        }
5684        if (end > len) {
5685            end = len;
5686        }
5687        if (start > end) {
5688            final int temp = start;
5689            start = end;
5690            end = temp;
5691        }
5692        // keep both cuts off the middle of a surrogate pair so the result is never left holding a lone surrogate
5693        if (splitsSurrogatePair(str, start)) {
5694            start--;
5695        }
5696        if (splitsSurrogatePair(str, end)) {
5697            end++;
5698        }
5699        return str.substring(0, start) + overlay + str.substring(end);
5700    }
5701
5702    /**
5703     * Prepends the prefix to the start of the string if the string does not already start with any of the prefixes.
5704     *
5705     * <pre>
5706     * StringUtils.prependIfMissing(null, null) = null
5707     * StringUtils.prependIfMissing("abc", null) = "abc"
5708     * StringUtils.prependIfMissing("", "xyz") = "xyz"
5709     * StringUtils.prependIfMissing("abc", "xyz") = "xyzabc"
5710     * StringUtils.prependIfMissing("xyzabc", "xyz") = "xyzabc"
5711     * StringUtils.prependIfMissing("XYZabc", "xyz") = "xyzXYZabc"
5712     * </pre>
5713     * <p>
5714     * With additional prefixes,
5715     * </p>
5716     *
5717     * <pre>
5718     * StringUtils.prependIfMissing(null, null, null) = null
5719     * StringUtils.prependIfMissing("abc", null, null) = "abc"
5720     * StringUtils.prependIfMissing("", "xyz", null) = "xyz"
5721     * StringUtils.prependIfMissing("abc", "xyz", new CharSequence[]{null}) = "xyzabc"
5722     * StringUtils.prependIfMissing("abc", "xyz", "") = "abc"
5723     * StringUtils.prependIfMissing("abc", "xyz", "mno") = "xyzabc"
5724     * StringUtils.prependIfMissing("xyzabc", "xyz", "mno") = "xyzabc"
5725     * StringUtils.prependIfMissing("mnoabc", "xyz", "mno") = "mnoabc"
5726     * StringUtils.prependIfMissing("XYZabc", "xyz", "mno") = "xyzXYZabc"
5727     * StringUtils.prependIfMissing("MNOabc", "xyz", "mno") = "xyzMNOabc"
5728     * </pre>
5729     *
5730     * @param str      The string.
5731     * @param prefix   The prefix to prepend to the start of the string.
5732     * @param prefixes Additional prefixes that are valid.
5733     * @return A new String if prefix was prepended, the same string otherwise.
5734     * @since 3.2
5735     * @deprecated Use {@link Strings#prependIfMissing(String, CharSequence, CharSequence...) Strings.CS.prependIfMissing(String, CharSequence,
5736     *             CharSequence...)}.
5737     */
5738    @Deprecated
5739    public static String prependIfMissing(final String str, final CharSequence prefix, final CharSequence... prefixes) {
5740        return Strings.CS.prependIfMissing(str, prefix, prefixes);
5741    }
5742
5743    /**
5744     * Prepends the prefix to the start of the string if the string does not already start, case-insensitive, with any of the prefixes.
5745     *
5746     * <pre>
5747     * StringUtils.prependIfMissingIgnoreCase(null, null) = null
5748     * StringUtils.prependIfMissingIgnoreCase("abc", null) = "abc"
5749     * StringUtils.prependIfMissingIgnoreCase("", "xyz") = "xyz"
5750     * StringUtils.prependIfMissingIgnoreCase("abc", "xyz") = "xyzabc"
5751     * StringUtils.prependIfMissingIgnoreCase("xyzabc", "xyz") = "xyzabc"
5752     * StringUtils.prependIfMissingIgnoreCase("XYZabc", "xyz") = "XYZabc"
5753     * </pre>
5754     * <p>
5755     * With additional prefixes,
5756     * </p>
5757     *
5758     * <pre>
5759     * StringUtils.prependIfMissingIgnoreCase(null, null, null) = null
5760     * StringUtils.prependIfMissingIgnoreCase("abc", null, null) = "abc"
5761     * StringUtils.prependIfMissingIgnoreCase("", "xyz", null) = "xyz"
5762     * StringUtils.prependIfMissingIgnoreCase("abc", "xyz", new CharSequence[]{null}) = "xyzabc"
5763     * StringUtils.prependIfMissingIgnoreCase("abc", "xyz", "") = "abc"
5764     * StringUtils.prependIfMissingIgnoreCase("abc", "xyz", "mno") = "xyzabc"
5765     * StringUtils.prependIfMissingIgnoreCase("xyzabc", "xyz", "mno") = "xyzabc"
5766     * StringUtils.prependIfMissingIgnoreCase("mnoabc", "xyz", "mno") = "mnoabc"
5767     * StringUtils.prependIfMissingIgnoreCase("XYZabc", "xyz", "mno") = "XYZabc"
5768     * StringUtils.prependIfMissingIgnoreCase("MNOabc", "xyz", "mno") = "MNOabc"
5769     * </pre>
5770     *
5771     * @param str      The string.
5772     * @param prefix   The prefix to prepend to the start of the string.
5773     * @param prefixes Additional prefixes that are valid (optional).
5774     * @return A new String if prefix was prepended, the same string otherwise.
5775     * @since 3.2
5776     * @deprecated Use {@link Strings#prependIfMissing(String, CharSequence, CharSequence...) Strings.CI.prependIfMissing(String, CharSequence,
5777     *             CharSequence...)}.
5778     */
5779    @Deprecated
5780    public static String prependIfMissingIgnoreCase(final String str, final CharSequence prefix, final CharSequence... prefixes) {
5781        return Strings.CI.prependIfMissing(str, prefix, prefixes);
5782    }
5783
5784    /**
5785     * Removes all occurrences of a character from within the source string.
5786     *
5787     * <p>
5788     * A {@code null} source string will return {@code null}. An empty ("") source string will return the empty string.
5789     * </p>
5790     *
5791     * <pre>
5792     * StringUtils.remove(null, *)       = null
5793     * StringUtils.remove("", *)         = ""
5794     * StringUtils.remove("queued", 'u') = "qeed"
5795     * StringUtils.remove("queued", 'z') = "queued"
5796     * </pre>
5797     *
5798     * @param str    The source String to search, may be null.
5799     * @param remove The char to search for and remove, may be null.
5800     * @return The substring with the char removed if found, {@code null} if null String input.
5801     * @since 2.1
5802     */
5803    public static String remove(final String str, final char remove) {
5804        if (isEmpty(str) || str.indexOf(remove) == INDEX_NOT_FOUND) {
5805            return str;
5806        }
5807        final char[] chars = str.toCharArray();
5808        int pos = 0;
5809        for (int i = 0; i < chars.length; i++) {
5810            if (chars[i] != remove) {
5811                chars[pos++] = chars[i];
5812            }
5813        }
5814        return new String(chars, 0, pos);
5815    }
5816
5817    /**
5818     * Removes all occurrences of a substring from within the source string.
5819     *
5820     * <p>
5821     * 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
5822     * the source string. An empty ("") remove string will return the source string.
5823     * </p>
5824     *
5825     * <pre>
5826     * StringUtils.remove(null, *)        = null
5827     * StringUtils.remove("", *)          = ""
5828     * StringUtils.remove(*, null)        = *
5829     * StringUtils.remove(*, "")          = *
5830     * StringUtils.remove("queued", "ue") = "qd"
5831     * StringUtils.remove("queued", "zz") = "queued"
5832     * </pre>
5833     *
5834     * @param str    The source String to search, may be null.
5835     * @param remove The String to search for and remove, may be null.
5836     * @return The substring with the string removed if found, {@code null} if null String input.
5837     * @since 2.1
5838     * @deprecated Use {@link Strings#remove(String, String) Strings.CS.remove(String, String)}.
5839     */
5840    @Deprecated
5841    public static String remove(final String str, final String remove) {
5842        return Strings.CS.remove(str, remove);
5843    }
5844
5845    /**
5846     * Removes each substring of the text String that matches the given regular expression.
5847     *
5848     * This method is a {@code null} safe equivalent to:
5849     * <ul>
5850     * <li>{@code text.replaceAll(regex, StringUtils.EMPTY)}</li>
5851     * <li>{@code Pattern.compile(regex).matcher(text).replaceAll(StringUtils.EMPTY)}</li>
5852     * </ul>
5853     *
5854     * <p>
5855     * A {@code null} reference passed to this method is a no-op.
5856     * </p>
5857     *
5858     * <p>
5859     * Unlike in the {@link #removePattern(String, String)} method, the {@link Pattern#DOTALL} option is NOT automatically added. To use the DOTALL option
5860     * prepend {@code "(?s)"} to the regex. DOTALL is also known as single-line mode in Perl.
5861     * </p>
5862     *
5863     * <pre>{@code
5864     * StringUtils.removeAll(null, *)      = null
5865     * StringUtils.removeAll("any", (String) null)  = "any"
5866     * StringUtils.removeAll("any", "")    = "any"
5867     * StringUtils.removeAll("any", ".*")  = ""
5868     * StringUtils.removeAll("any", ".+")  = ""
5869     * StringUtils.removeAll("abc", ".?")  = ""
5870     * StringUtils.removeAll("A<__>\n<__>B", "<.*>")      = "A\nB"
5871     * StringUtils.removeAll("A<__>\n<__>B", "(?s)<.*>")  = "AB"
5872     * StringUtils.removeAll("ABCabc123abc", "[a-z]")     = "ABC123"
5873     * }</pre>
5874     *
5875     * @param text  text to remove from, may be null.
5876     * @param regex The regular expression to which this string is to be matched.
5877     * @return The text with any removes processed, {@code null} if null String input.
5878     * @throws java.util.regex.PatternSyntaxException Thrown if the regular expression's syntax is invalid.
5879     * @see #replaceAll(String, String, String)
5880     * @see #removePattern(String, String)
5881     * @see String#replaceAll(String, String)
5882     * @see java.util.regex.Pattern
5883     * @see java.util.regex.Pattern#DOTALL
5884     * @since 3.5
5885     * @deprecated Use {@link RegExUtils#removeAll(String, String)}.
5886     */
5887    @Deprecated
5888    public static String removeAll(final String text, final String regex) {
5889        return RegExUtils.removeAll(text, regex);
5890    }
5891
5892    /**
5893     * Removes a substring only if it is at the end of a source string, otherwise returns the source string.
5894     *
5895     * <p>
5896     * 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
5897     * the source string.
5898     * </p>
5899     *
5900     * <pre>
5901     * StringUtils.removeEnd(null, *)      = null
5902     * StringUtils.removeEnd("", *)        = ""
5903     * StringUtils.removeEnd(*, null)      = *
5904     * StringUtils.removeEnd("www.domain.com", ".com.")  = "www.domain.com"
5905     * StringUtils.removeEnd("www.domain.com", ".com")   = "www.domain"
5906     * StringUtils.removeEnd("www.domain.com", "domain") = "www.domain.com"
5907     * StringUtils.removeEnd("abc", "")    = "abc"
5908     * </pre>
5909     *
5910     * @param str    The source String to search, may be null.
5911     * @param remove The String to search for and remove, may be null.
5912     * @return The substring with the string removed if found, {@code null} if null String input.
5913     * @since 2.1
5914     * @deprecated Use {@link Strings#removeEnd(String, CharSequence) Strings.CS.removeEnd(String, CharSequence)}.
5915     */
5916    @Deprecated
5917    public static String removeEnd(final String str, final String remove) {
5918        return Strings.CS.removeEnd(str, remove);
5919    }
5920
5921    /**
5922     * Case-insensitive removal of a substring if it is at the end of a source string, otherwise returns the source string.
5923     *
5924     * <p>
5925     * 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
5926     * the source string.
5927     * </p>
5928     *
5929     * <pre>
5930     * StringUtils.removeEndIgnoreCase(null, *)      = null
5931     * StringUtils.removeEndIgnoreCase("", *)        = ""
5932     * StringUtils.removeEndIgnoreCase(*, null)      = *
5933     * StringUtils.removeEndIgnoreCase("www.domain.com", ".com.")  = "www.domain.com"
5934     * StringUtils.removeEndIgnoreCase("www.domain.com", ".com")   = "www.domain"
5935     * StringUtils.removeEndIgnoreCase("www.domain.com", "domain") = "www.domain.com"
5936     * StringUtils.removeEndIgnoreCase("abc", "")    = "abc"
5937     * StringUtils.removeEndIgnoreCase("www.domain.com", ".COM") = "www.domain"
5938     * StringUtils.removeEndIgnoreCase("www.domain.COM", ".com") = "www.domain"
5939     * </pre>
5940     *
5941     * @param str    The source String to search, may be null.
5942     * @param remove The String to search for (case-insensitive) and remove, may be null.
5943     * @return The substring with the string removed if found, {@code null} if null String input.
5944     * @since 2.4
5945     * @deprecated Use {@link Strings#removeEnd(String, CharSequence) Strings.CI.removeEnd(String, CharSequence)}.
5946     */
5947    @Deprecated
5948    public static String removeEndIgnoreCase(final String str, final String remove) {
5949        return Strings.CI.removeEnd(str, remove);
5950    }
5951
5952    /**
5953     * Removes the first substring of the text string that matches the given regular expression.
5954     *
5955     * This method is a {@code null} safe equivalent to:
5956     * <ul>
5957     * <li>{@code text.replaceFirst(regex, StringUtils.EMPTY)}</li>
5958     * <li>{@code Pattern.compile(regex).matcher(text).replaceFirst(StringUtils.EMPTY)}</li>
5959     * </ul>
5960     *
5961     * <p>
5962     * A {@code null} reference passed to this method is a no-op.
5963     * </p>
5964     *
5965     * <p>
5966     * 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
5967     * single-line mode in Perl.
5968     * </p>
5969     *
5970     * <pre>{@code
5971     * StringUtils.removeFirst(null, *)      = null
5972     * StringUtils.removeFirst("any", (String) null)  = "any"
5973     * StringUtils.removeFirst("any", "")    = "any"
5974     * StringUtils.removeFirst("any", ".*")  = ""
5975     * StringUtils.removeFirst("any", ".+")  = ""
5976     * StringUtils.removeFirst("abc", ".?")  = "bc"
5977     * StringUtils.removeFirst("A<__>\n<__>B", "<.*>")      = "A\n<__>B"
5978     * StringUtils.removeFirst("A<__>\n<__>B", "(?s)<.*>")  = "AB"
5979     * StringUtils.removeFirst("ABCabc123", "[a-z]")          = "ABCbc123"
5980     * StringUtils.removeFirst("ABCabc123abc", "[a-z]+")      = "ABC123abc"
5981     * }</pre>
5982     *
5983     * @param text  text to remove from, may be null.
5984     * @param regex The regular expression to which this string is to be matched.
5985     * @return The text with the first replacement processed, {@code null} if null String input.
5986     * @throws java.util.regex.PatternSyntaxException Thrown if the regular expression's syntax is invalid.
5987     * @see #replaceFirst(String, String, String)
5988     * @see String#replaceFirst(String, String)
5989     * @see java.util.regex.Pattern
5990     * @see java.util.regex.Pattern#DOTALL
5991     * @since 3.5
5992     * @deprecated Use {@link RegExUtils#replaceFirst(String, String, String) RegExUtils.replaceFirst(String, String, EMPTY)}.
5993     */
5994    @Deprecated
5995    public static String removeFirst(final String text, final String regex) {
5996        return replaceFirst(text, regex, EMPTY);
5997    }
5998
5999    /**
6000     * Case-insensitive removal of all occurrences of a substring from within the source string.
6001     *
6002     * <p>
6003     * 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
6004     * the source string. An empty ("") remove string will return the source string.
6005     * </p>
6006     *
6007     * <pre>
6008     * StringUtils.removeIgnoreCase(null, *)        = null
6009     * StringUtils.removeIgnoreCase("", *)          = ""
6010     * StringUtils.removeIgnoreCase(*, null)        = *
6011     * StringUtils.removeIgnoreCase(*, "")          = *
6012     * StringUtils.removeIgnoreCase("queued", "ue") = "qd"
6013     * StringUtils.removeIgnoreCase("queued", "zz") = "queued"
6014     * StringUtils.removeIgnoreCase("quEUed", "UE") = "qd"
6015     * StringUtils.removeIgnoreCase("queued", "zZ") = "queued"
6016     * </pre>
6017     *
6018     * @param str    The source String to search, may be null.
6019     * @param remove The String to search for (case-insensitive) and remove, may be null.
6020     * @return The substring with the string removed if found, {@code null} if null String input.
6021     * @since 3.5
6022     * @deprecated Use {@link Strings#remove(String, String) Strings.CI.remove(String, String)}.
6023     */
6024    @Deprecated
6025    public static String removeIgnoreCase(final String str, final String remove) {
6026        return Strings.CI.remove(str, remove);
6027    }
6028
6029    /**
6030     * Removes each substring of the source String that matches the given regular expression using the DOTALL option.
6031     *
6032     * This call is a {@code null} safe equivalent to:
6033     * <ul>
6034     * <li>{@code source.replaceAll(&quot;(?s)&quot; + regex, StringUtils.EMPTY)}</li>
6035     * <li>{@code Pattern.compile(regex, Pattern.DOTALL).matcher(source).replaceAll(StringUtils.EMPTY)}</li>
6036     * </ul>
6037     *
6038     * <p>
6039     * A {@code null} reference passed to this method is a no-op.
6040     * </p>
6041     *
6042     * <pre>{@code
6043     * StringUtils.removePattern(null, *)       = null
6044     * StringUtils.removePattern("any", (String) null)   = "any"
6045     * StringUtils.removePattern("A<__>\n<__>B", "<.*>")  = "AB"
6046     * StringUtils.removePattern("ABCabc123", "[a-z]")    = "ABC123"
6047     * }</pre>
6048     *
6049     * @param source The source string.
6050     * @param regex  The regular expression to which this string is to be matched.
6051     * @return The resulting {@link String}.
6052     * @see #replacePattern(String, String, String)
6053     * @see String#replaceAll(String, String)
6054     * @see Pattern#DOTALL
6055     * @since 3.2
6056     * @since 3.5 Changed {@code null} reference passed to this method is a no-op.
6057     * @deprecated Use {@link RegExUtils#removePattern(CharSequence, String)}.
6058     */
6059    @Deprecated
6060    public static String removePattern(final String source, final String regex) {
6061        return RegExUtils.removePattern(source, regex);
6062    }
6063
6064    /**
6065     * Removes a char only if it is at the beginning of a source string, otherwise returns the source string.
6066     *
6067     * <p>
6068     * 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
6069     * the source string.
6070     * </p>
6071     *
6072     * <pre>
6073     * StringUtils.removeStart(null, *)      = null
6074     * StringUtils.removeStart("", *)        = ""
6075     * StringUtils.removeStart(*, null)      = *
6076     * StringUtils.removeStart("/path", '/') = "path"
6077     * StringUtils.removeStart("path", '/')  = "path"
6078     * StringUtils.removeStart("path", 0)    = "path"
6079     * </pre>
6080     *
6081     * @param str    The source String to search, may be null.
6082     * @param remove The char to search for and remove.
6083     * @return The substring with the char removed if found, {@code null} if null String input.
6084     * @since 3.13.0
6085     */
6086    public static String removeStart(final String str, final char remove) {
6087        if (isEmpty(str)) {
6088            return str;
6089        }
6090        return str.charAt(0) == remove ? str.substring(1) : str;
6091    }
6092
6093    /**
6094     * Removes a substring only if it is at the beginning of a source string, otherwise returns the source string.
6095     *
6096     * <p>
6097     * 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
6098     * the source string.
6099     * </p>
6100     *
6101     * <pre>
6102     * StringUtils.removeStart(null, *)                    = null
6103     * StringUtils.removeStart("", *)                      = ""
6104     * StringUtils.removeStart(*, null)                    = *
6105     * StringUtils.removeStart("www.domain.com", "www.")   = "domain.com"
6106     * StringUtils.removeStart("domain.com", "www.")       = "domain.com"
6107     * StringUtils.removeStart("www.domain.com", "domain") = "www.domain.com"
6108     * StringUtils.removeStart("abc", "")                  = "abc"
6109     * </pre>
6110     *
6111     * @param str    The source String to search, may be null.
6112     * @param remove The String to search for and remove, may be null.
6113     * @return The substring with the string removed if found, {@code null} if null String input.
6114     * @since 2.1
6115     * @deprecated Use {@link Strings#removeStart(String, CharSequence) Strings.CS.removeStart(String, CharSequence)}.
6116     */
6117    @Deprecated
6118    public static String removeStart(final String str, final String remove) {
6119        return Strings.CS.removeStart(str, remove);
6120    }
6121
6122    /**
6123     * Case-insensitive removal of a substring if it is at the beginning of a source string, otherwise returns the source string.
6124     *
6125     * <p>
6126     * 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
6127     * the source string.
6128     * </p>
6129     *
6130     * <pre>
6131     * StringUtils.removeStartIgnoreCase(null, *)                    = null
6132     * StringUtils.removeStartIgnoreCase("", *)                      = ""
6133     * StringUtils.removeStartIgnoreCase(*, null)                    = *
6134     * StringUtils.removeStartIgnoreCase("www.domain.com", "www.")   = "domain.com"
6135     * StringUtils.removeStartIgnoreCase("www.domain.com", "WWW.")   = "domain.com"
6136     * StringUtils.removeStartIgnoreCase("domain.com", "www.")       = "domain.com"
6137     * StringUtils.removeStartIgnoreCase("www.domain.com", "domain") = "www.domain.com"
6138     * StringUtils.removeStartIgnoreCase("abc", "")                  = "abc"
6139     * </pre>
6140     *
6141     * @param str    The source String to search, may be null.
6142     * @param remove The String to search for (case-insensitive) and remove, may be null.
6143     * @return The substring with the string removed if found, {@code null} if null String input.
6144     * @since 2.4
6145     * @deprecated Use {@link Strings#removeStart(String, CharSequence) Strings.CI.removeStart(String, CharSequence)}.
6146     */
6147    @Deprecated
6148    public static String removeStartIgnoreCase(final String str, final String remove) {
6149        return Strings.CI.removeStart(str, remove);
6150    }
6151
6152    /**
6153     * Returns padding using the specified delimiter repeated to a given length.
6154     *
6155     * <pre>
6156     * StringUtils.repeat('e', 0)  = ""
6157     * StringUtils.repeat('e', 3)  = "eee"
6158     * StringUtils.repeat('e', -2) = ""
6159     * </pre>
6160     *
6161     * <p>
6162     * Note: this method does not support padding with <a href="https://www.unicode.org/glossary/#supplementary_character">Unicode Supplementary Characters</a>
6163     * 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
6164     * {@link #repeat(String, int)} instead.
6165     * </p>
6166     *
6167     * @param repeat character to repeat.
6168     * @param count  number of times to repeat char, negative treated as zero.
6169     * @return String with repeated character.
6170     * @see #repeat(String, int)
6171     */
6172    public static String repeat(final char repeat, final int count) {
6173        if (count <= 0) {
6174            return EMPTY;
6175        }
6176        return new String(ArrayFill.fill(new char[count], repeat));
6177    }
6178
6179    /**
6180     * Repeats a String {@code repeat} times to form a new String.
6181     *
6182     * <pre>
6183     * StringUtils.repeat(null, 2) = null
6184     * StringUtils.repeat("", 0)   = ""
6185     * StringUtils.repeat("", 2)   = ""
6186     * StringUtils.repeat("a", 3)  = "aaa"
6187     * StringUtils.repeat("ab", 2) = "abab"
6188     * StringUtils.repeat("a", -2) = ""
6189     * </pre>
6190     *
6191     * @param repeat The String to repeat, may be null.
6192     * @param count  number of times to repeat str, negative treated as zero.
6193     * @return A new String consisting of the original String repeated, {@code null} if null String input.
6194     */
6195    public static String repeat(final String repeat, final int count) {
6196        // Performance tuned for 2.0 (JDK1.4)
6197        if (repeat == null) {
6198            return null;
6199        }
6200        if (count <= 0) {
6201            return EMPTY;
6202        }
6203        final int inputLength = repeat.length();
6204        if (count == 1 || inputLength == 0) {
6205            return repeat;
6206        }
6207        if (inputLength == 1 && count <= PAD_LIMIT) {
6208            return repeat(repeat.charAt(0), count);
6209        }
6210        final int outputLength;
6211        try {
6212            outputLength = Math.multiplyExact(inputLength, count);
6213        } catch (final Exception e) {
6214            throw new IllegalArgumentException("The requested result is too large for a String.");
6215        }
6216        switch (inputLength) {
6217        case 1:
6218            return repeat(repeat.charAt(0), count);
6219        case 2:
6220            final char ch0 = repeat.charAt(0);
6221            final char ch1 = repeat.charAt(1);
6222            final char[] output2 = new char[outputLength];
6223            for (int i = count * 2 - 2; i >= 0; i--, i--) {
6224                output2[i] = ch0;
6225                output2[i + 1] = ch1;
6226            }
6227            return new String(output2);
6228        default:
6229            final StringBuilder buf = new StringBuilder(outputLength);
6230            for (int i = 0; i < count; i++) {
6231                buf.append(repeat);
6232            }
6233            return buf.toString();
6234        }
6235    }
6236
6237    /**
6238     * Repeats a String {@code repeat} times to form a new String, with a String separator injected each time.
6239     *
6240     * <pre>
6241     * StringUtils.repeat(null, null, 2) = null
6242     * StringUtils.repeat(null, "x", 2)  = null
6243     * StringUtils.repeat("", null, 0)   = ""
6244     * StringUtils.repeat("", "", 2)     = ""
6245     * StringUtils.repeat("", "x", 3)    = "xx"
6246     * StringUtils.repeat("?", ", ", 3)  = "?, ?, ?"
6247     * </pre>
6248     *
6249     * @param repeat    The String to repeat, may be null.
6250     * @param separator The String to inject, may be null.
6251     * @param count     number of times to repeat str, negative treated as zero.
6252     * @return A new String consisting of the original String repeated, {@code null} if null String input.
6253     * @since 2.5
6254     */
6255    public static String repeat(final String repeat, final String separator, final int count) {
6256        if (repeat == null || separator == null) {
6257            return repeat(repeat, count);
6258        }
6259        // given that repeat(String, int) is quite optimized, better to rely on it than try and splice this into it
6260        final String result = repeat(repeat + separator, count);
6261        return Strings.CS.removeEnd(result, separator);
6262    }
6263
6264    /**
6265     * Replaces all occurrences of a String within another String.
6266     *
6267     * <p>
6268     * A {@code null} reference passed to this method is a no-op.
6269     * </p>
6270     *
6271     * <pre>
6272     * StringUtils.replace(null, *, *)        = null
6273     * StringUtils.replace("", *, *)          = ""
6274     * StringUtils.replace("any", null, *)    = "any"
6275     * StringUtils.replace("any", *, null)    = "any"
6276     * StringUtils.replace("any", "", *)      = "any"
6277     * StringUtils.replace("aba", "a", null)  = "aba"
6278     * StringUtils.replace("aba", "a", "")    = "b"
6279     * StringUtils.replace("aba", "a", "z")   = "zbz"
6280     * </pre>
6281     *
6282     * @param text         text to search and replace in, may be null.
6283     * @param searchString The String to search for, may be null.
6284     * @param replacement  The String to replace it with, may be null.
6285     * @return The text with any replacements processed, {@code null} if null String input.
6286     * @see #replace(String text, String searchString, String replacement, int max)
6287     * @deprecated Use {@link Strings#replace(String, String, String) Strings.CS.replace(String, String, String)}.
6288     */
6289    @Deprecated
6290    public static String replace(final String text, final String searchString, final String replacement) {
6291        return Strings.CS.replace(text, searchString, replacement);
6292    }
6293
6294    /**
6295     * Replaces a String with another String inside a larger String, for the first {@code max} values of the search String.
6296     *
6297     * <p>
6298     * A {@code null} reference passed to this method is a no-op.
6299     * </p>
6300     *
6301     * <pre>
6302     * StringUtils.replace(null, *, *, *)         = null
6303     * StringUtils.replace("", *, *, *)           = ""
6304     * StringUtils.replace("any", null, *, *)     = "any"
6305     * StringUtils.replace("any", *, null, *)     = "any"
6306     * StringUtils.replace("any", "", *, *)       = "any"
6307     * StringUtils.replace("any", *, *, 0)        = "any"
6308     * StringUtils.replace("abaa", "a", null, -1) = "abaa"
6309     * StringUtils.replace("abaa", "a", "", -1)   = "b"
6310     * StringUtils.replace("abaa", "a", "z", 0)   = "abaa"
6311     * StringUtils.replace("abaa", "a", "z", 1)   = "zbaa"
6312     * StringUtils.replace("abaa", "a", "z", 2)   = "zbza"
6313     * StringUtils.replace("abaa", "a", "z", -1)  = "zbzz"
6314     * </pre>
6315     *
6316     * @param text         text to search and replace in, may be null.
6317     * @param searchString The String to search for, may be null.
6318     * @param replacement  The String to replace it with, may be null.
6319     * @param max          maximum number of values to replace, or {@code -1} if no maximum.
6320     * @return The text with any replacements processed, {@code null} if null String input.
6321     * @deprecated Use {@link Strings#replace(String, String, String, int) Strings.CS.replace(String, String, String, int)}.
6322     */
6323    @Deprecated
6324    public static String replace(final String text, final String searchString, final String replacement, final int max) {
6325        return Strings.CS.replace(text, searchString, replacement, max);
6326    }
6327
6328    /**
6329     * Replaces each substring of the text String that matches the given regular expression with the given replacement.
6330     *
6331     * This method is a {@code null} safe equivalent to:
6332     * <ul>
6333     * <li>{@code text.replaceAll(regex, replacement)}</li>
6334     * <li>{@code Pattern.compile(regex).matcher(text).replaceAll(replacement)}</li>
6335     * </ul>
6336     *
6337     * <p>
6338     * A {@code null} reference passed to this method is a no-op.
6339     * </p>
6340     *
6341     * <p>
6342     * Unlike in the {@link #replacePattern(String, String, String)} method, the {@link Pattern#DOTALL} option is NOT automatically added. To use the DOTALL
6343     * option prepend {@code "(?s)"} to the regex. DOTALL is also known as single-line mode in Perl.
6344     * </p>
6345     *
6346     * <pre>{@code
6347     * StringUtils.replaceAll(null, *, *)                                         = null
6348     * StringUtils.replaceAll("any", (String) null, *)                            = "any"
6349     * StringUtils.replaceAll("any", *, null)                                     = "any"
6350     * StringUtils.replaceAll("", "", "zzz")                                      = "zzz"
6351     * StringUtils.replaceAll("", ".*", "zzz")                                    = "zzz"
6352     * StringUtils.replaceAll("", ".+", "zzz")                                    = ""
6353     * StringUtils.replaceAll("abc", "", "ZZ")                                    = "ZZaZZbZZcZZ"
6354     * StringUtils.replaceAll("<__>\n<__>", "<.*>", "z")                          = "z\nz"
6355     * StringUtils.replaceAll("<__>\n<__>", "(?s)<.*>", "z")                      = "z"
6356     * StringUtils.replaceAll("ABCabc123", "[a-z]", "_")                          = "ABC___123"
6357     * StringUtils.replaceAll("ABCabc123", "[^A-Z0-9]+", "_")                     = "ABC_123"
6358     * StringUtils.replaceAll("ABCabc123", "[^A-Z0-9]+", "")                      = "ABC123"
6359     * StringUtils.replaceAll("Lorem ipsum  dolor   sit", "( +)([a-z]+)", "_$2")  = "Lorem_ipsum_dolor_sit"
6360     * }</pre>
6361     *
6362     * @param text        text to search and replace in, may be null.
6363     * @param regex       The regular expression to which this string is to be matched.
6364     * @param replacement The string to be substituted for each match.
6365     * @return The text with any replacements processed, {@code null} if null String input.
6366     * @throws java.util.regex.PatternSyntaxException Thrown if the regular expression's syntax is invalid.
6367     * @see #replacePattern(String, String, String)
6368     * @see String#replaceAll(String, String)
6369     * @see java.util.regex.Pattern
6370     * @see java.util.regex.Pattern#DOTALL
6371     * @since 3.5
6372     * @deprecated Use {@link RegExUtils#replaceAll(String, String, String)}.
6373     */
6374    @Deprecated
6375    public static String replaceAll(final String text, final String regex, final String replacement) {
6376        return RegExUtils.replaceAll(text, regex, replacement);
6377    }
6378
6379    /**
6380     * Replaces all occurrences of a character in a String with another. This is a null-safe version of {@link String#replace(char, char)}.
6381     *
6382     * <p>
6383     * A {@code null} string input returns {@code null}. An empty ("") string input returns an empty string.
6384     * </p>
6385     *
6386     * <pre>
6387     * StringUtils.replaceChars(null, *, *)        = null
6388     * StringUtils.replaceChars("", *, *)          = ""
6389     * StringUtils.replaceChars("abcba", 'b', 'y') = "aycya"
6390     * StringUtils.replaceChars("abcba", 'z', 'y') = "abcba"
6391     * </pre>
6392     *
6393     * @param str         String to replace characters in, may be null.
6394     * @param searchChar  The character to search for, may be null.
6395     * @param replaceChar The character to replace, may be null.
6396     * @return modified String, {@code null} if null string input.
6397     * @since 2.0
6398     */
6399    public static String replaceChars(final String str, final char searchChar, final char replaceChar) {
6400        if (str == null) {
6401            return null;
6402        }
6403        return str.replace(searchChar, replaceChar);
6404    }
6405
6406    /**
6407     * Replaces multiple characters in a String in one go. This method can also be used to delete characters.
6408     *
6409     * <p>
6410     * For example:
6411     * </p>
6412     * <pre>
6413     * replaceChars(&quot;hello&quot;, &quot;ho&quot;, &quot;jy&quot;) = jelly.
6414     * </pre>
6415     *
6416     * <p>
6417     * 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
6418     * the input string.
6419     * </p>
6420     *
6421     * <p>
6422     * 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
6423     * characters are deleted. If the search characters is shorter, then the extra replace characters are ignored.
6424     * </p>
6425     *
6426     * <pre>
6427     * StringUtils.replaceChars(null, *, *)           = null
6428     * StringUtils.replaceChars("", *, *)             = ""
6429     * StringUtils.replaceChars("abc", null, *)       = "abc"
6430     * StringUtils.replaceChars("abc", "", *)         = "abc"
6431     * StringUtils.replaceChars("abc", "b", null)     = "ac"
6432     * StringUtils.replaceChars("abc", "b", "")       = "ac"
6433     * StringUtils.replaceChars("abcba", "bc", "yz")  = "ayzya"
6434     * StringUtils.replaceChars("abcba", "bc", "y")   = "ayya"
6435     * StringUtils.replaceChars("abcba", "bc", "yzx") = "ayzya"
6436     * </pre>
6437     *
6438     * @param str          String to replace characters in, may be null.
6439     * @param searchChars  A set of characters to search for, may be null.
6440     * @param replaceChars A set of characters to replace, may be null.
6441     * @return modified String, {@code null} if null string input.
6442     * @since 2.0
6443     */
6444    public static String replaceChars(final String str, final String searchChars, String replaceChars) {
6445        if (isEmpty(str) || isEmpty(searchChars)) {
6446            return str;
6447        }
6448        replaceChars = ObjectUtils.toString(replaceChars);
6449        boolean modified = false;
6450        final int replaceCharsLength = replaceChars.length();
6451        final int strLength = str.length();
6452        final StringBuilder buf = new StringBuilder(strLength);
6453        for (int i = 0; i < strLength; i++) {
6454            final char ch = str.charAt(i);
6455            final int index = searchChars.indexOf(ch);
6456            if (index >= 0) {
6457                modified = true;
6458                if (index < replaceCharsLength) {
6459                    buf.append(replaceChars.charAt(index));
6460                }
6461            } else {
6462                buf.append(ch);
6463            }
6464        }
6465        if (modified) {
6466            return buf.toString();
6467        }
6468        return str;
6469    }
6470
6471    /**
6472     * Replaces all occurrences of Strings within another String.
6473     *
6474     * <p>
6475     * 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
6476     * will not repeat. For repeating replaces, call the overloaded method.
6477     * </p>
6478     *
6479     * <pre>
6480     *  StringUtils.replaceEach(null, *, *)                                                = null
6481     *  StringUtils.replaceEach("", *, *)                                                  = ""
6482     *  StringUtils.replaceEach("aba", null, null)                                         = "aba"
6483     *  StringUtils.replaceEach("aba", new String[0], null)                                = "aba"
6484     *  StringUtils.replaceEach("aba", null, new String[0])                                = "aba"
6485     *  StringUtils.replaceEach("aba", new String[]{"a"}, null)                            = "aba"
6486     *  StringUtils.replaceEach("aba", new String[]{"a"}, new String[]{""})                = "b"
6487     *  StringUtils.replaceEach("aba", new String[]{null}, new String[]{"a"})              = "aba"
6488     *  StringUtils.replaceEach("abcde", new String[]{"ab", "d"}, new String[]{"w", "t"})  = "wcte"
6489     *  (example of how it does not repeat)
6490     *  StringUtils.replaceEach("abcde", new String[]{"ab", "d"}, new String[]{"d", "t"})  = "dcte"
6491     * </pre>
6492     *
6493     * @param text            text to search and replace in, no-op if null.
6494     * @param searchList      The Strings to search for, no-op if null.
6495     * @param replacementList The Strings to replace them with, no-op if null.
6496     * @return The text with any replacements processed, {@code null} if null String input.
6497     * @throws IllegalArgumentException Thrown if the lengths of the arrays are not the same (null is ok, and/or size 0).
6498     * @since 2.4
6499     */
6500    public static String replaceEach(final String text, final String[] searchList, final String[] replacementList) {
6501        return replaceEachOnce(text, searchList, replacementList);
6502    }
6503
6504    /**
6505     * Replace all occurrences of Strings within another String, in a single pass. This is a private helper method for
6506     * {@link #replaceEachRepeatedly(String, String[], String[])} and {@link #replaceEach(String, String[], String[])}
6507     *
6508     * <p>
6509     * 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.
6510     * </p>
6511     *
6512     * <pre>
6513     *  StringUtils.replaceEachOnce(null, *, *)                                                = null
6514     *  StringUtils.replaceEachOnce("", *, *)                                                  = ""
6515     *  StringUtils.replaceEachOnce("aba", null, null)                                         = "aba"
6516     *  StringUtils.replaceEachOnce("aba", new String[0], null)                                = "aba"
6517     *  StringUtils.replaceEachOnce("aba", null, new String[0])                                = "aba"
6518     *  StringUtils.replaceEachOnce("aba", new String[]{"a"}, null)                            = "aba"
6519     *  StringUtils.replaceEachOnce("aba", new String[]{"a"}, new String[]{""})                = "b"
6520     *  StringUtils.replaceEachOnce("aba", new String[]{null}, new String[]{"a"})              = "aba"
6521     *  StringUtils.replaceEachOnce("abcde", new String[]{"ab", "d"}, new String[]{"w", "t"})  = "wcte"
6522     *  StringUtils.replaceEachOnce("abcde", new String[]{"ab", "d"}, new String[]{"d", "t"})  = "dcte"
6523     * </pre>
6524     *
6525     * <p>
6526     * When no replacement is performed, the {@code text} argument is returned unchanged (same reference); callers rely on this to detect convergence.
6527     * </p>
6528     *
6529     * @param text            text to search and replace in, no-op if null.
6530     * @param searchList      The Strings to search for, no-op if null.
6531     * @param replacementList The Strings to replace them with, no-op if null.
6532     * @return The text with any replacements processed, {@code null} if null String input.
6533     * @throws IllegalArgumentException Thrown if the lengths of the arrays are not the same (null is ok, and/or size 0).
6534     * @since 2.4
6535     */
6536    private static String replaceEachOnce(final String text, final String[] searchList, final String[] replacementList) {
6537
6538        // Performance note: This creates very few new objects (one major goal)
6539        // let me know if there are performance requests, we can create a harness to measure
6540        if (isEmpty(text) || ArrayUtils.isEmpty(searchList) || ArrayUtils.isEmpty(replacementList)) {
6541            return text;
6542        }
6543
6544        final int searchLength = searchList.length;
6545        final int replacementLength = replacementList.length;
6546
6547        // make sure lengths are ok, these need to be equal
6548        if (searchLength != replacementLength) {
6549            throw new IllegalArgumentException("Search and Replace array lengths don't match: "
6550                + searchLength
6551                + " vs "
6552                + replacementLength);
6553        }
6554
6555        // keep track of which still have matches
6556        final boolean[] noMoreMatchesForReplIndex = new boolean[searchLength];
6557
6558        // index on index that the match was found
6559        int textIndex = -1;
6560        int replaceIndex = -1;
6561        int tempIndex;
6562
6563        // index of replace array that will replace the search string found
6564        // NOTE: logic duplicated below START
6565        for (int i = 0; i < searchLength; i++) {
6566            if (noMoreMatchesForReplIndex[i] || isEmpty(searchList[i]) || replacementList[i] == null) {
6567                continue;
6568            }
6569            tempIndex = text.indexOf(searchList[i]);
6570
6571            // see if we need to keep searching for this
6572            if (tempIndex == -1) {
6573                noMoreMatchesForReplIndex[i] = true;
6574            } else if (textIndex == -1 || tempIndex < textIndex) {
6575                textIndex = tempIndex;
6576                replaceIndex = i;
6577            }
6578        }
6579        // NOTE: logic mostly below END
6580
6581        // no search strings found, we are done
6582        if (textIndex == -1) {
6583            return text;
6584        }
6585
6586        int start = 0;
6587
6588        // get a good guess on the size of the result buffer so it doesn't have to double if it goes over a bit
6589        int increase = 0;
6590
6591        // count the replacement text elements that are larger than their corresponding text being replaced
6592        for (int i = 0; i < searchList.length; i++) {
6593            if (searchList[i] == null || replacementList[i] == null) {
6594                continue;
6595            }
6596            final int greater = replacementList[i].length() - searchList[i].length();
6597            if (greater > 0) {
6598                increase += 3 * greater; // assume 3 matches
6599            }
6600        }
6601        // have upper-bound at 20% increase, then let Java take over
6602        increase = Math.min(increase, text.length() / 5);
6603
6604        final StringBuilder buf = new StringBuilder(text.length() + increase);
6605
6606        while (textIndex != -1) {
6607
6608            for (int i = start; i < textIndex; i++) {
6609                buf.append(text.charAt(i));
6610            }
6611            buf.append(replacementList[replaceIndex]);
6612
6613            start = textIndex + searchList[replaceIndex].length();
6614
6615            textIndex = -1;
6616            replaceIndex = -1;
6617            // find the next earliest match
6618            // NOTE: logic mostly duplicated above START
6619            for (int i = 0; i < searchLength; i++) {
6620                if (noMoreMatchesForReplIndex[i] || isEmpty(searchList[i]) || replacementList[i] == null) {
6621                    continue;
6622                }
6623                tempIndex = text.indexOf(searchList[i], start);
6624
6625                // see if we need to keep searching for this
6626                if (tempIndex == -1) {
6627                    noMoreMatchesForReplIndex[i] = true;
6628                } else if (textIndex == -1 || tempIndex < textIndex) {
6629                    textIndex = tempIndex;
6630                    replaceIndex = i;
6631                }
6632            }
6633            // NOTE: logic duplicated above END
6634
6635        }
6636        final int textLength = text.length();
6637        for (int i = start; i < textLength; i++) {
6638            buf.append(text.charAt(i));
6639        }
6640        return buf.toString();
6641    }
6642
6643    /**
6644     * Replaces all occurrences of Strings within another String.
6645     *
6646     * <p>
6647     * 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.
6648     * </p>
6649     *
6650     * <pre>
6651     *  StringUtils.replaceEachRepeatedly(null, *, *)                                                = null
6652     *  StringUtils.replaceEachRepeatedly("", *, *)                                                  = ""
6653     *  StringUtils.replaceEachRepeatedly("aba", null, null)                                         = "aba"
6654     *  StringUtils.replaceEachRepeatedly("aba", new String[0], null)                                = "aba"
6655     *  StringUtils.replaceEachRepeatedly("aba", null, new String[0])                                = "aba"
6656     *  StringUtils.replaceEachRepeatedly("aba", new String[]{"a"}, null)                            = "aba"
6657     *  StringUtils.replaceEachRepeatedly("aba", new String[]{"a"}, new String[]{""})                = "b"
6658     *  StringUtils.replaceEachRepeatedly("aba", new String[]{null}, new String[]{"a"})              = "aba"
6659     *  StringUtils.replaceEachRepeatedly("abcde", new String[]{"ab", "d"}, new String[]{"w", "t"})  = "wcte"
6660     *  (example of how it repeats)
6661     *  StringUtils.replaceEachRepeatedly("abcde", new String[]{"ab", "d"}, new String[]{"d", "t"})  = "tcte"
6662     *  StringUtils.replaceEachRepeatedly("abcde", new String[]{"ab", "d"}, new String[]{"d", "ab"}) = Throws {@link IllegalStateException}
6663     * </pre>
6664     *
6665     * @param text            text to search and replace in, no-op if null.
6666     * @param searchList      The Strings to search for, no-op if null.
6667     * @param replacementList The Strings to replace them with, no-op if null.
6668     * @return The text with any replacements processed, {@code null} if null String input.
6669     * @throws IllegalStateException    Thrown if the search is repeating and there is an endless loop due to outputs of one being inputs to another.
6670     * @throws IllegalArgumentException Thrown if the lengths of the arrays are not the same (null is ok, and/or size 0).
6671     * @since 2.4
6672     */
6673    public static String replaceEachRepeatedly(final String text, final String[] searchList, final String[] replacementList) {
6674        // The iteration budget is a fixed constant, deliberately independent of the caller-supplied
6675        // searchList length: deriving the budget from the input would let the input size choose the
6676        // recursion depth/amplification (formerly a real StackOverflowError on large search lists).
6677        String result = text;
6678        for (int timeToLive = DEFAULT_TTL; timeToLive >= 0; timeToLive--) {
6679            final String next = replaceEachOnce(result, searchList, replacementList);
6680            if (next == result) {
6681                // No replacement was performed; converged.
6682                return result;
6683            }
6684            result = next;
6685        }
6686        throw new IllegalStateException("Aborting to protect against StackOverflowError - " +
6687            "output of one loop is the input of another");
6688    }
6689
6690    /**
6691     * Replaces the first substring of the text string that matches the given regular expression with the given replacement.
6692     *
6693     * This method is a {@code null} safe equivalent to:
6694     * <ul>
6695     * <li>{@code text.replaceFirst(regex, replacement)}</li>
6696     * <li>{@code Pattern.compile(regex).matcher(text).replaceFirst(replacement)}</li>
6697     * </ul>
6698     *
6699     * <p>
6700     * A {@code null} reference passed to this method is a no-op.
6701     * </p>
6702     *
6703     * <p>
6704     * 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
6705     * single-line mode in Perl.
6706     * </p>
6707     *
6708     * <pre>{@code
6709     * StringUtils.replaceFirst(null, *, *)       = null
6710     * StringUtils.replaceFirst("any", (String) null, *)   = "any"
6711     * StringUtils.replaceFirst("any", *, null)   = "any"
6712     * StringUtils.replaceFirst("", "", "zzz")    = "zzz"
6713     * StringUtils.replaceFirst("", ".*", "zzz")  = "zzz"
6714     * StringUtils.replaceFirst("", ".+", "zzz")  = ""
6715     * StringUtils.replaceFirst("abc", "", "ZZ")  = "ZZabc"
6716     * StringUtils.replaceFirst("<__>\n<__>", "<.*>", "z")      = "z\n<__>"
6717     * StringUtils.replaceFirst("<__>\n<__>", "(?s)<.*>", "z")  = "z"
6718     * StringUtils.replaceFirst("ABCabc123", "[a-z]", "_")          = "ABC_bc123"
6719     * StringUtils.replaceFirst("ABCabc123abc", "[^A-Z0-9]+", "_")  = "ABC_123abc"
6720     * StringUtils.replaceFirst("ABCabc123abc", "[^A-Z0-9]+", "")   = "ABC123abc"
6721     * StringUtils.replaceFirst("Lorem ipsum  dolor   sit", "( +)([a-z]+)", "_$2")  = "Lorem_ipsum  dolor   sit"
6722     * }</pre>
6723     *
6724     * @param text        text to search and replace in, may be null.
6725     * @param regex       The regular expression to which this string is to be matched.
6726     * @param replacement The string to be substituted for the first match.
6727     * @return The text with the first replacement processed, {@code null} if null String input.
6728     * @throws java.util.regex.PatternSyntaxException Thrown if the regular expression's syntax is invalid.
6729     * @see String#replaceFirst(String, String)
6730     * @see java.util.regex.Pattern
6731     * @see java.util.regex.Pattern#DOTALL
6732     * @since 3.5
6733     * @deprecated Use {@link RegExUtils#replaceFirst(String, String, String)}.
6734     */
6735    @Deprecated
6736    public static String replaceFirst(final String text, final String regex, final String replacement) {
6737        return RegExUtils.replaceFirst(text, regex, replacement);
6738    }
6739
6740    /**
6741     * Case insensitively replaces all occurrences of a String within another String.
6742     *
6743     * <p>
6744     * A {@code null} reference passed to this method is a no-op.
6745     * </p>
6746     *
6747     * <pre>
6748     * StringUtils.replaceIgnoreCase(null, *, *)        = null
6749     * StringUtils.replaceIgnoreCase("", *, *)          = ""
6750     * StringUtils.replaceIgnoreCase("any", null, *)    = "any"
6751     * StringUtils.replaceIgnoreCase("any", *, null)    = "any"
6752     * StringUtils.replaceIgnoreCase("any", "", *)      = "any"
6753     * StringUtils.replaceIgnoreCase("aba", "a", null)  = "aba"
6754     * StringUtils.replaceIgnoreCase("abA", "A", "")    = "b"
6755     * StringUtils.replaceIgnoreCase("aba", "A", "z")   = "zbz"
6756     * </pre>
6757     *
6758     * @param text         text to search and replace in, may be null.
6759     * @param searchString The String to search for (case-insensitive), may be null.
6760     * @param replacement  The String to replace it with, may be null.
6761     * @return The text with any replacements processed, {@code null} if null String input.
6762     * @see #replaceIgnoreCase(String text, String searchString, String replacement, int max)
6763     * @since 3.5
6764     * @deprecated Use {@link Strings#replace(String, String, String) Strings.CI.replace(String, String, String)}.
6765     */
6766    @Deprecated
6767    public static String replaceIgnoreCase(final String text, final String searchString, final String replacement) {
6768        return Strings.CI.replace(text, searchString, replacement);
6769    }
6770
6771    /**
6772     * Case insensitively replaces a String with another String inside a larger String, for the first {@code max} values of the search String.
6773     *
6774     * <p>
6775     * A {@code null} reference passed to this method is a no-op.
6776     * </p>
6777     *
6778     * <pre>
6779     * StringUtils.replaceIgnoreCase(null, *, *, *)         = null
6780     * StringUtils.replaceIgnoreCase("", *, *, *)           = ""
6781     * StringUtils.replaceIgnoreCase("any", null, *, *)     = "any"
6782     * StringUtils.replaceIgnoreCase("any", *, null, *)     = "any"
6783     * StringUtils.replaceIgnoreCase("any", "", *, *)       = "any"
6784     * StringUtils.replaceIgnoreCase("any", *, *, 0)        = "any"
6785     * StringUtils.replaceIgnoreCase("abaa", "a", null, -1) = "abaa"
6786     * StringUtils.replaceIgnoreCase("abaa", "a", "", -1)   = "b"
6787     * StringUtils.replaceIgnoreCase("abaa", "a", "z", 0)   = "abaa"
6788     * StringUtils.replaceIgnoreCase("abaa", "A", "z", 1)   = "zbaa"
6789     * StringUtils.replaceIgnoreCase("abAa", "a", "z", 2)   = "zbza"
6790     * StringUtils.replaceIgnoreCase("abAa", "a", "z", -1)  = "zbzz"
6791     * </pre>
6792     *
6793     * @param text         text to search and replace in, may be null.
6794     * @param searchString The String to search for (case-insensitive), may be null.
6795     * @param replacement  The String to replace it with, may be null.
6796     * @param max          maximum number of values to replace, or {@code -1} if no maximum.
6797     * @return The text with any replacements processed, {@code null} if null String input.
6798     * @since 3.5
6799     * @deprecated Use {@link Strings#replace(String, String, String, int) Strings.CI.replace(String, String, String, int)}.
6800     */
6801    @Deprecated
6802    public static String replaceIgnoreCase(final String text, final String searchString, final String replacement, final int max) {
6803        return Strings.CI.replace(text, searchString, replacement, max);
6804    }
6805
6806    /**
6807     * Replaces a String with another String inside a larger String, once.
6808     *
6809     * <p>
6810     * A {@code null} reference passed to this method is a no-op.
6811     * </p>
6812     *
6813     * <pre>
6814     * StringUtils.replaceOnce(null, *, *)        = null
6815     * StringUtils.replaceOnce("", *, *)          = ""
6816     * StringUtils.replaceOnce("any", null, *)    = "any"
6817     * StringUtils.replaceOnce("any", *, null)    = "any"
6818     * StringUtils.replaceOnce("any", "", *)      = "any"
6819     * StringUtils.replaceOnce("aba", "a", null)  = "aba"
6820     * StringUtils.replaceOnce("aba", "a", "")    = "ba"
6821     * StringUtils.replaceOnce("aba", "a", "z")   = "zba"
6822     * </pre>
6823     *
6824     * @param text         text to search and replace in, may be null.
6825     * @param searchString The String to search for, may be null.
6826     * @param replacement  The String to replace with, may be null.
6827     * @return The text with any replacements processed, {@code null} if null String input.
6828     * @see #replace(String text, String searchString, String replacement, int max)
6829     * @deprecated Use {@link Strings#replaceOnce(String, String, String) Strings.CS.replaceOnce(String, String, String)}.
6830     */
6831    @Deprecated
6832    public static String replaceOnce(final String text, final String searchString, final String replacement) {
6833        return Strings.CS.replaceOnce(text, searchString, replacement);
6834    }
6835
6836    /**
6837     * Case insensitively replaces a String with another String inside a larger String, once.
6838     *
6839     * <p>
6840     * A {@code null} reference passed to this method is a no-op.
6841     * </p>
6842     *
6843     * <pre>
6844     * StringUtils.replaceOnceIgnoreCase(null, *, *)        = null
6845     * StringUtils.replaceOnceIgnoreCase("", *, *)          = ""
6846     * StringUtils.replaceOnceIgnoreCase("any", null, *)    = "any"
6847     * StringUtils.replaceOnceIgnoreCase("any", *, null)    = "any"
6848     * StringUtils.replaceOnceIgnoreCase("any", "", *)      = "any"
6849     * StringUtils.replaceOnceIgnoreCase("aba", "a", null)  = "aba"
6850     * StringUtils.replaceOnceIgnoreCase("aba", "a", "")    = "ba"
6851     * StringUtils.replaceOnceIgnoreCase("aba", "a", "z")   = "zba"
6852     * StringUtils.replaceOnceIgnoreCase("FoOFoofoo", "foo", "") = "Foofoo"
6853     * </pre>
6854     *
6855     * @param text         text to search and replace in, may be null.
6856     * @param searchString The String to search for (case-insensitive), may be null.
6857     * @param replacement  The String to replace with, may be null.
6858     * @return The text with any replacements processed, {@code null} if null String input.
6859     * @see #replaceIgnoreCase(String text, String searchString, String replacement, int max)
6860     * @since 3.5
6861     * @deprecated Use {@link Strings#replaceOnce(String, String, String) Strings.CI.replaceOnce(String, String, String)}.
6862     */
6863    @Deprecated
6864    public static String replaceOnceIgnoreCase(final String text, final String searchString, final String replacement) {
6865        return Strings.CI.replaceOnce(text, searchString, replacement);
6866    }
6867
6868    /**
6869     * Replaces each substring of the source String that matches the given regular expression with the given replacement using the {@link Pattern#DOTALL}
6870     * option. DOTALL is also known as single-line mode in Perl.
6871     *
6872     * This call is a {@code null} safe equivalent to:
6873     * <ul>
6874     * <li>{@code source.replaceAll(&quot;(?s)&quot; + regex, replacement)}</li>
6875     * <li>{@code Pattern.compile(regex, Pattern.DOTALL).matcher(source).replaceAll(replacement)}</li>
6876     * </ul>
6877     *
6878     * <p>
6879     * A {@code null} reference passed to this method is a no-op.
6880     * </p>
6881     *
6882     * <pre>{@code
6883     * StringUtils.replacePattern(null, *, *)                                         = null
6884     * StringUtils.replacePattern("any", (String) null, *)                            = "any"
6885     * StringUtils.replacePattern("any", *, null)                                     = "any"
6886     * StringUtils.replacePattern("", "", "zzz")                                      = "zzz"
6887     * StringUtils.replacePattern("", ".*", "zzz")                                    = "zzz"
6888     * StringUtils.replacePattern("", ".+", "zzz")                                    = ""
6889     * StringUtils.replacePattern("<__>\n<__>", "<.*>", "z")                          = "z"
6890     * StringUtils.replacePattern("ABCabc123", "[a-z]", "_")                          = "ABC___123"
6891     * StringUtils.replacePattern("ABCabc123", "[^A-Z0-9]+", "_")                     = "ABC_123"
6892     * StringUtils.replacePattern("ABCabc123", "[^A-Z0-9]+", "")                      = "ABC123"
6893     * StringUtils.replacePattern("Lorem ipsum  dolor   sit", "( +)([a-z]+)", "_$2")  = "Lorem_ipsum_dolor_sit"
6894     * }</pre>
6895     *
6896     * @param source      The source string.
6897     * @param regex       The regular expression to which this string is to be matched.
6898     * @param replacement The string to be substituted for each match.
6899     * @return The resulting {@link String}.
6900     * @see #replaceAll(String, String, String)
6901     * @see String#replaceAll(String, String)
6902     * @see Pattern#DOTALL
6903     * @since 3.2
6904     * @since 3.5 Changed {@code null} reference passed to this method is a no-op.
6905     * @deprecated Use {@link RegExUtils#replacePattern(CharSequence, String, String)}.
6906     */
6907    @Deprecated
6908    public static String replacePattern(final String source, final String regex, final String replacement) {
6909        return RegExUtils.replacePattern(source, regex, replacement);
6910    }
6911
6912    /**
6913     * Reverses a String as per {@link StringBuilder#reverse()}.
6914     *
6915     * <p>
6916     * A {@code null} String returns {@code null}.
6917     * </p>
6918     *
6919     * <pre>
6920     * StringUtils.reverse(null)  = null
6921     * StringUtils.reverse("")    = ""
6922     * StringUtils.reverse("bat") = "tab"
6923     * </pre>
6924     *
6925     * @param str The String to reverse, may be null.
6926     * @return The reversed String, {@code null} if null String input.
6927     */
6928    public static String reverse(final String str) {
6929        if (str == null) {
6930            return null;
6931        }
6932        return new StringBuilder(str).reverse().toString();
6933    }
6934
6935    /**
6936     * Reverses a String that is delimited by a specific character.
6937     *
6938     * <p>
6939     * The Strings between the delimiters are not reversed. Thus java.lang.String becomes String.lang.java (if the delimiter is {@code '.'}).
6940     * </p>
6941     *
6942     * <pre>
6943     * StringUtils.reverseDelimited(null, *)      = null
6944     * StringUtils.reverseDelimited("", *)        = ""
6945     * StringUtils.reverseDelimited("a.b.c", 'x') = "a.b.c"
6946     * StringUtils.reverseDelimited("a.b.c", ".") = "c.b.a"
6947     * </pre>
6948     *
6949     * @param str           The String to reverse, may be null.
6950     * @param separatorChar The separator character to use.
6951     * @return The reversed String, {@code null} if null String input.
6952     * @since 2.0
6953     */
6954    public static String reverseDelimited(final String str, final char separatorChar) {
6955        final String[] strs = split(str, separatorChar);
6956        ArrayUtils.reverse(strs);
6957        return join(strs, separatorChar);
6958    }
6959
6960    /**
6961     * Gets the rightmost {@code len} characters of a String.
6962     *
6963     * <p>
6964     * 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
6965     * returned if len is negative.
6966     * </p>
6967     *
6968     * <pre>
6969     * StringUtils.right(null, *)    = null
6970     * StringUtils.right(*, -ve)     = ""
6971     * StringUtils.right("", *)      = ""
6972     * StringUtils.right("abc", 0)   = ""
6973     * StringUtils.right("abc", 2)   = "bc"
6974     * StringUtils.right("abc", 4)   = "abc"
6975     * </pre>
6976     *
6977     * @param str The String to get the rightmost characters from, may be null.
6978     * @param len The length of the required String.
6979     * @return The rightmost characters, {@code null} if null String input.
6980     */
6981    public static String right(final String str, final int len) {
6982        if (str == null) {
6983            return null;
6984        }
6985        if (len < 0) {
6986            return EMPTY;
6987        }
6988        if (str.length() <= len) {
6989            return str;
6990        }
6991        int start = str.length() - len;
6992        // keep the cut off the middle of a surrogate pair so the result is never left holding a lone surrogate
6993        if (splitsSurrogatePair(str, start)) {
6994            start++;
6995        }
6996        return str.substring(start);
6997    }
6998
6999    /**
7000     * Right pad a String with spaces (' ').
7001     *
7002     * <p>
7003     * The String is padded to the size of {@code size}.
7004     * </p>
7005     *
7006     * <pre>
7007     * StringUtils.rightPad(null, *)   = null
7008     * StringUtils.rightPad("", 3)     = "   "
7009     * StringUtils.rightPad("bat", 3)  = "bat"
7010     * StringUtils.rightPad("bat", 5)  = "bat  "
7011     * StringUtils.rightPad("bat", 1)  = "bat"
7012     * StringUtils.rightPad("bat", -1) = "bat"
7013     * </pre>
7014     *
7015     * @param str  The String to pad out, may be null.
7016     * @param size The size to pad to.
7017     * @return right padded String or original String if no padding is necessary, {@code null} if null String input.
7018     */
7019    public static String rightPad(final String str, final int size) {
7020        return rightPad(str, size, ' ');
7021    }
7022
7023    /**
7024     * Right pad a String with a specified character.
7025     *
7026     * <p>
7027     * The String is padded to the size of {@code size}.
7028     * </p>
7029     *
7030     * <pre>
7031     * StringUtils.rightPad(null, *, *)     = null
7032     * StringUtils.rightPad("", 3, 'z')     = "zzz"
7033     * StringUtils.rightPad("bat", 3, 'z')  = "bat"
7034     * StringUtils.rightPad("bat", 5, 'z')  = "batzz"
7035     * StringUtils.rightPad("bat", 1, 'z')  = "bat"
7036     * StringUtils.rightPad("bat", -1, 'z') = "bat"
7037     * </pre>
7038     *
7039     * @param str     The String to pad out, may be null.
7040     * @param size    The size to pad to.
7041     * @param padChar The character to pad with.
7042     * @return right padded String or original String if no padding is necessary, {@code null} if null String input.
7043     * @since 2.0
7044     */
7045    public static String rightPad(final String str, final int size, final char padChar) {
7046        if (str == null || size <= str.length()) {
7047            return str;
7048        }
7049        final int pads = size - str.length();
7050        if (pads <= 0) {
7051            return str; // returns original String when possible
7052        }
7053        if (pads > PAD_LIMIT) {
7054            return rightPad(str, size, String.valueOf(padChar));
7055        }
7056        return str.concat(repeat(padChar, pads));
7057    }
7058
7059    /**
7060     * Right pad a String with a specified String.
7061     *
7062     * <p>
7063     * The String is padded to the size of {@code size}.
7064     * </p>
7065     *
7066     * <pre>
7067     * StringUtils.rightPad(null, *, *)      = null
7068     * StringUtils.rightPad("", 3, "z")      = "zzz"
7069     * StringUtils.rightPad("bat", 3, "yz")  = "bat"
7070     * StringUtils.rightPad("bat", 5, "yz")  = "batyz"
7071     * StringUtils.rightPad("bat", 8, "yz")  = "batyzyzy"
7072     * StringUtils.rightPad("bat", 1, "yz")  = "bat"
7073     * StringUtils.rightPad("bat", -1, "yz") = "bat"
7074     * StringUtils.rightPad("bat", 5, null)  = "bat  "
7075     * StringUtils.rightPad("bat", 5, "")    = "bat  "
7076     * </pre>
7077     *
7078     * @param str    The String to pad out, may be null.
7079     * @param size   The size to pad to.
7080     * @param padStr The String to pad with, null or empty treated as single space.
7081     * @return right padded String or original String if no padding is necessary, {@code null} if null String input.
7082     */
7083    public static String rightPad(final String str, final int size, String padStr) {
7084        if (str == null || size <= str.length()) {
7085            return str;
7086        }
7087        if (isEmpty(padStr)) {
7088            padStr = SPACE;
7089        }
7090        final int padLen = padStr.length();
7091        final int strLen = str.length();
7092        final int pads = size - strLen;
7093        if (pads <= 0) {
7094            return str; // returns original String when possible
7095        }
7096        if (padLen == 1 && pads <= PAD_LIMIT) {
7097            return rightPad(str, size, padStr.charAt(0));
7098        }
7099        if (pads == padLen) {
7100            return str.concat(padStr);
7101        }
7102        if (pads < padLen) {
7103            return str.concat(padStr.substring(0, pads));
7104        }
7105        final char[] padding = new char[pads];
7106        final char[] padChars = padStr.toCharArray();
7107        for (int i = 0; i < pads; i++) {
7108            padding[i] = padChars[i % padLen];
7109        }
7110        return str.concat(new String(padding));
7111    }
7112
7113    /**
7114     * Rotate (circular shift) a String of {@code shift} characters.
7115     * <ul>
7116     * <li>If {@code shift > 0}, right circular shift (ex : ABCDEF =&gt; FABCDE)</li>
7117     * <li>If {@code shift < 0}, left circular shift (ex : ABCDEF =&gt; BCDEFA)</li>
7118     * </ul>
7119     *
7120     * <pre>
7121     * StringUtils.rotate(null, *)        = null
7122     * StringUtils.rotate("", *)          = ""
7123     * StringUtils.rotate("abcdefg", 0)   = "abcdefg"
7124     * StringUtils.rotate("abcdefg", 2)   = "fgabcde"
7125     * StringUtils.rotate("abcdefg", -2)  = "cdefgab"
7126     * StringUtils.rotate("abcdefg", 7)   = "abcdefg"
7127     * StringUtils.rotate("abcdefg", -7)  = "abcdefg"
7128     * StringUtils.rotate("abcdefg", 9)   = "fgabcde"
7129     * StringUtils.rotate("abcdefg", -9)  = "cdefgab"
7130     * </pre>
7131     *
7132     * @param str   The String to rotate, may be null.
7133     * @param shift number of time to shift (positive : right shift, negative : left shift).
7134     * @return The rotated String, or the original String if {@code shift == 0}, or {@code null} if null String input.
7135     * @since 3.5
7136     */
7137    public static String rotate(final String str, final int shift) {
7138        if (str == null) {
7139            return null;
7140        }
7141        final int strLen = str.length();
7142        if (shift == 0 || strLen == 0 || shift % strLen == 0) {
7143            return str;
7144        }
7145        final StringBuilder builder = new StringBuilder(strLen);
7146        final int offset = -(shift % strLen);
7147        builder.append(substring(str, offset));
7148        builder.append(substring(str, 0, offset));
7149        return builder.toString();
7150    }
7151
7152    /**
7153     * Splits the provided text into an array, using whitespace as the separator. Whitespace is defined by {@link Character#isWhitespace(char)}.
7154     *
7155     * <p>
7156     * 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
7157     * StrTokenizer class.
7158     * </p>
7159     *
7160     * <p>
7161     * A {@code null} input String returns {@code null}.
7162     * </p>
7163     *
7164     * <pre>
7165     * StringUtils.split(null)       = null
7166     * StringUtils.split("")         = []
7167     * StringUtils.split("abc def")  = ["abc", "def"]
7168     * StringUtils.split("abc  def") = ["abc", "def"]
7169     * StringUtils.split(" abc ")    = ["abc"]
7170     * </pre>
7171     *
7172     * @param str The String to parse, may be null.
7173     * @return An array of parsed Strings, {@code null} if null String input.
7174     */
7175    public static String[] split(final String str) {
7176        return split(str, null, -1);
7177    }
7178
7179    /**
7180     * Splits the provided text into an array, separator specified. This is an alternative to using StringTokenizer.
7181     *
7182     * <p>
7183     * 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
7184     * StrTokenizer class.
7185     * </p>
7186     *
7187     * <p>
7188     * A {@code null} input String returns {@code null}.
7189     * </p>
7190     *
7191     * <pre>
7192     * StringUtils.split(null, *)         = null
7193     * StringUtils.split("", *)           = []
7194     * StringUtils.split("a.b.c", '.')    = ["a", "b", "c"]
7195     * StringUtils.split("a..b.c", '.')   = ["a", "b", "c"]
7196     * StringUtils.split("a:b:c", '.')    = ["a:b:c"]
7197     * StringUtils.split("a b c", ' ')    = ["a", "b", "c"]
7198     * </pre>
7199     *
7200     * @param str           The String to parse, may be null.
7201     * @param separatorChar The character used as the delimiter.
7202     * @return An array of parsed Strings, {@code null} if null String input.
7203     * @since 2.0
7204     */
7205    public static String[] split(final String str, final char separatorChar) {
7206        return splitWorker(str, separatorChar, false);
7207    }
7208
7209    /**
7210     * Splits the provided text into an array, separators specified. This is an alternative to using StringTokenizer.
7211     *
7212     * <p>
7213     * 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
7214     * StrTokenizer class.
7215     * </p>
7216     *
7217     * <p>
7218     * A {@code null} input String returns {@code null}. A {@code null} separatorChars splits on whitespace.
7219     * </p>
7220     *
7221     * <pre>
7222     * StringUtils.split(null, *)         = null
7223     * StringUtils.split("", *)           = []
7224     * StringUtils.split("abc def", null) = ["abc", "def"]
7225     * StringUtils.split("abc def", " ")  = ["abc", "def"]
7226     * StringUtils.split("abc  def", " ") = ["abc", "def"]
7227     * StringUtils.split("ab:cd:ef", ":") = ["ab", "cd", "ef"]
7228     * </pre>
7229     *
7230     * @param str            The String to parse, may be null.
7231     * @param separatorChars The characters used as the delimiters, {@code null} splits on whitespace.
7232     * @return An array of parsed Strings, {@code null} if null String input.
7233     */
7234    public static String[] split(final String str, final String separatorChars) {
7235        return splitWorker(str, separatorChars, -1, false);
7236    }
7237
7238    /**
7239     * Splits the provided text into an array with a maximum length, separators specified.
7240     *
7241     * <p>
7242     * The separator is not included in the returned String array. Adjacent separators are treated as one separator.
7243     * </p>
7244     *
7245     * <p>
7246     * A {@code null} input String returns {@code null}. A {@code null} separatorChars splits on whitespace.
7247     * </p>
7248     *
7249     * <p>
7250     * If more than {@code max} delimited substrings are found, the last returned string includes all characters after the first {@code max - 1} returned
7251     * strings (including separator characters).
7252     * </p>
7253     *
7254     * <pre>
7255     * StringUtils.split(null, *, *)            = null
7256     * StringUtils.split("", *, *)              = []
7257     * StringUtils.split("ab cd ef", null, 0)   = ["ab", "cd", "ef"]
7258     * StringUtils.split("ab   cd ef", null, 0) = ["ab", "cd", "ef"]
7259     * StringUtils.split("ab:cd:ef", ":", 0)    = ["ab", "cd", "ef"]
7260     * StringUtils.split("ab:cd:ef", ":", 2)    = ["ab", "cd:ef"]
7261     * </pre>
7262     *
7263     * @param str            The String to parse, may be null.
7264     * @param separatorChars The characters used as the delimiters, {@code null} splits on whitespace.
7265     * @param max            The maximum number of elements to include in the array. A zero or negative value implies no limit.
7266     * @return An array of parsed Strings, {@code null} if null String input.
7267     */
7268    public static String[] split(final String str, final String separatorChars, final int max) {
7269        return splitWorker(str, separatorChars, max, false);
7270    }
7271
7272    /**
7273     * Splits a String by Character type as returned by {@link Character#getType(int)}. Groups of contiguous characters of the same type are returned
7274     * as complete tokens.
7275     *
7276     * <pre>
7277     * StringUtils.splitByCharacterType(null)         = null
7278     * StringUtils.splitByCharacterType("")           = []
7279     * StringUtils.splitByCharacterType("ab de fg")   = ["ab", " ", "de", " ", "fg"]
7280     * StringUtils.splitByCharacterType("ab   de fg") = ["ab", "   ", "de", " ", "fg"]
7281     * StringUtils.splitByCharacterType("ab:cd:ef")   = ["ab", ":", "cd", ":", "ef"]
7282     * StringUtils.splitByCharacterType("number5")    = ["number", "5"]
7283     * StringUtils.splitByCharacterType("fooBar")     = ["foo", "B", "ar"]
7284     * StringUtils.splitByCharacterType("foo200Bar")  = ["foo", "200", "B", "ar"]
7285     * StringUtils.splitByCharacterType("ASFRules")   = ["ASFR", "ules"]
7286     * </pre>
7287     *
7288     * @param str The String to split, may be {@code null}.
7289     * @return An array of parsed Strings, {@code null} if null String input.
7290     * @see Character#getType(int)
7291     * @since 2.4
7292     */
7293    public static String[] splitByCharacterType(final String str) {
7294        return splitByCharacterType(str, false);
7295    }
7296
7297    /**
7298     * 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
7299     * as complete tokens, with the following exception: if {@code camelCase} is {@code true}, the character of type {@link Character#UPPERCASE_LETTER}, if any,
7300     * immediately preceding a token of type {@link Character#LOWERCASE_LETTER} will belong to the following token rather than to the preceding, if any,
7301     * {@link Character#UPPERCASE_LETTER} token.
7302     *
7303     * @param str       The String to split, may be {@code null}.
7304     * @param camelCase whether to use so-called "camel-case" for letter types.
7305     * @return An array of parsed Strings, {@code null} if null String input.
7306     * @since 2.4
7307     */
7308    private static String[] splitByCharacterType(final String str, final boolean camelCase) {
7309        if (str == null) {
7310            return null;
7311        }
7312        if (str.isEmpty()) {
7313            return ArrayUtils.EMPTY_STRING_ARRAY;
7314        }
7315        final char[] c = str.toCharArray();
7316        final List<String> list = new ArrayList<>();
7317        int tokenStart = 0;
7318        int currentType = Character.getType(Character.codePointAt(c, tokenStart));
7319        for (int pos = tokenStart + Character.charCount(Character.codePointAt(c, tokenStart)); pos < c.length;) {
7320            final int codePoint = Character.codePointAt(c, pos);
7321            final int type = Character.getType(codePoint);
7322            final int count = Character.charCount(codePoint);
7323            if (type == currentType) {
7324                pos += count;
7325                continue;
7326            }
7327            if (camelCase && type == Character.LOWERCASE_LETTER && currentType == Character.UPPERCASE_LETTER) {
7328                final int newTokenStart = pos - Character.charCount(Character.codePointBefore(c, pos));
7329                if (newTokenStart != tokenStart) {
7330                    list.add(new String(c, tokenStart, newTokenStart - tokenStart));
7331                    tokenStart = newTokenStart;
7332                }
7333            } else {
7334                list.add(new String(c, tokenStart, pos - tokenStart));
7335                tokenStart = pos;
7336            }
7337            currentType = type;
7338            pos += count;
7339        }
7340        list.add(new String(c, tokenStart, c.length - tokenStart));
7341        return list.toArray(ArrayUtils.EMPTY_STRING_ARRAY);
7342    }
7343
7344    /**
7345     * Splits a String by Character type as returned by {@link Character#getType(int)}. Groups of contiguous characters of the same type are returned
7346     * as complete tokens, with the following exception: the character of type {@link Character#UPPERCASE_LETTER}, if any, immediately preceding a token of type
7347     * {@link Character#LOWERCASE_LETTER} will belong to the following token rather than to the preceding, if any, {@link Character#UPPERCASE_LETTER} token.
7348     *
7349     * <pre>
7350     * StringUtils.splitByCharacterTypeCamelCase(null)         = null
7351     * StringUtils.splitByCharacterTypeCamelCase("")           = []
7352     * StringUtils.splitByCharacterTypeCamelCase("ab de fg")   = ["ab", " ", "de", " ", "fg"]
7353     * StringUtils.splitByCharacterTypeCamelCase("ab   de fg") = ["ab", "   ", "de", " ", "fg"]
7354     * StringUtils.splitByCharacterTypeCamelCase("ab:cd:ef")   = ["ab", ":", "cd", ":", "ef"]
7355     * StringUtils.splitByCharacterTypeCamelCase("number5")    = ["number", "5"]
7356     * StringUtils.splitByCharacterTypeCamelCase("fooBar")     = ["foo", "Bar"]
7357     * StringUtils.splitByCharacterTypeCamelCase("foo200Bar")  = ["foo", "200", "Bar"]
7358     * StringUtils.splitByCharacterTypeCamelCase("ASFRules")   = ["ASF", "Rules"]
7359     * </pre>
7360     *
7361     * @param str The String to split, may be {@code null}.
7362     * @return An array of parsed Strings, {@code null} if null String input.
7363     * @see Character#getType(int)
7364     * @since 2.4
7365     */
7366    public static String[] splitByCharacterTypeCamelCase(final String str) {
7367        return splitByCharacterType(str, true);
7368    }
7369
7370    /**
7371     * Splits the provided text into an array, separator string specified.
7372     *
7373     * <p>
7374     * The separator(s) will not be included in the returned String array. Adjacent separators are treated as one separator.
7375     * </p>
7376     *
7377     * <p>
7378     * A {@code null} input String returns {@code null}. A {@code null} separator splits on whitespace.
7379     * </p>
7380     *
7381     * <pre>
7382     * StringUtils.splitByWholeSeparator(null, *)               = null
7383     * StringUtils.splitByWholeSeparator("", *)                 = []
7384     * StringUtils.splitByWholeSeparator("ab de fg", null)      = ["ab", "de", "fg"]
7385     * StringUtils.splitByWholeSeparator("ab   de fg", null)    = ["ab", "de", "fg"]
7386     * StringUtils.splitByWholeSeparator("ab:cd:ef", ":")       = ["ab", "cd", "ef"]
7387     * StringUtils.splitByWholeSeparator("ab-!-cd-!-ef", "-!-") = ["ab", "cd", "ef"]
7388     * </pre>
7389     *
7390     * @param str       The String to parse, may be null.
7391     * @param separator String containing the String to be used as a delimiter, {@code null} splits on whitespace.
7392     * @return An array of parsed Strings, {@code null} if null String was input.
7393     */
7394    public static String[] splitByWholeSeparator(final String str, final String separator) {
7395        return splitByWholeSeparatorWorker(str, separator, -1, false);
7396    }
7397
7398    /**
7399     * Splits the provided text into an array, separator string specified. Returns a maximum of {@code max} substrings.
7400     *
7401     * <p>
7402     * The separator(s) will not be included in the returned String array. Adjacent separators are treated as one separator.
7403     * </p>
7404     *
7405     * <p>
7406     * A {@code null} input String returns {@code null}. A {@code null} separator splits on whitespace.
7407     * </p>
7408     *
7409     * <pre>
7410     * StringUtils.splitByWholeSeparator(null, *, *)               = null
7411     * StringUtils.splitByWholeSeparator("", *, *)                 = []
7412     * StringUtils.splitByWholeSeparator("ab de fg", null, 0)      = ["ab", "de", "fg"]
7413     * StringUtils.splitByWholeSeparator("ab   de fg", null, 0)    = ["ab", "de", "fg"]
7414     * StringUtils.splitByWholeSeparator("ab:cd:ef", ":", 2)       = ["ab", "cd:ef"]
7415     * StringUtils.splitByWholeSeparator("ab-!-cd-!-ef", "-!-", 5) = ["ab", "cd", "ef"]
7416     * StringUtils.splitByWholeSeparator("ab-!-cd-!-ef", "-!-", 2) = ["ab", "cd-!-ef"]
7417     * </pre>
7418     *
7419     * @param str       The String to parse, may be null.
7420     * @param separator String containing the String to be used as a delimiter, {@code null} splits on whitespace.
7421     * @param max       The maximum number of elements to include in the returned array. A zero or negative value implies no limit.
7422     * @return An array of parsed Strings, {@code null} if null String was input.
7423     */
7424    public static String[] splitByWholeSeparator(final String str, final String separator, final int max) {
7425        return splitByWholeSeparatorWorker(str, separator, max, false);
7426    }
7427
7428    /**
7429     * Splits the provided text into an array, separator string specified.
7430     *
7431     * <p>
7432     * The separator is not included in the returned String array. Adjacent separators are treated as separators for empty tokens. For more control over the
7433     * split use the StrTokenizer class.
7434     * </p>
7435     *
7436     * <p>
7437     * A {@code null} input String returns {@code null}. A {@code null} separator splits on whitespace.
7438     * </p>
7439     *
7440     * <pre>
7441     * StringUtils.splitByWholeSeparatorPreserveAllTokens(null, *)               = null
7442     * StringUtils.splitByWholeSeparatorPreserveAllTokens("", *)                 = []
7443     * StringUtils.splitByWholeSeparatorPreserveAllTokens("ab de fg", null)      = ["ab", "de", "fg"]
7444     * StringUtils.splitByWholeSeparatorPreserveAllTokens("ab   de fg", null)    = ["ab", "", "", "de", "fg"]
7445     * StringUtils.splitByWholeSeparatorPreserveAllTokens("ab:cd:ef", ":")       = ["ab", "cd", "ef"]
7446     * StringUtils.splitByWholeSeparatorPreserveAllTokens("ab-!-cd-!-ef", "-!-") = ["ab", "cd", "ef"]
7447     * </pre>
7448     *
7449     * @param str       The String to parse, may be null.
7450     * @param separator String containing the String to be used as a delimiter, {@code null} splits on whitespace.
7451     * @return An array of parsed Strings, {@code null} if null String was input.
7452     * @since 2.4
7453     */
7454    public static String[] splitByWholeSeparatorPreserveAllTokens(final String str, final String separator) {
7455        return splitByWholeSeparatorWorker(str, separator, -1, true);
7456    }
7457
7458    /**
7459     * Splits the provided text into an array, separator string specified. Returns a maximum of {@code max} substrings.
7460     *
7461     * <p>
7462     * The separator is not included in the returned String array. Adjacent separators are treated as separators for empty tokens. For more control over the
7463     * split use the StrTokenizer class.
7464     * </p>
7465     *
7466     * <p>
7467     * A {@code null} input String returns {@code null}. A {@code null} separator splits on whitespace.
7468     * </p>
7469     *
7470     * <pre>
7471     * StringUtils.splitByWholeSeparatorPreserveAllTokens(null, *, *)               = null
7472     * StringUtils.splitByWholeSeparatorPreserveAllTokens("", *, *)                 = []
7473     * StringUtils.splitByWholeSeparatorPreserveAllTokens("ab de fg", null, 0)      = ["ab", "de", "fg"]
7474     * StringUtils.splitByWholeSeparatorPreserveAllTokens("ab   de fg", null, 0)    = ["ab", "", "", "de", "fg"]
7475     * StringUtils.splitByWholeSeparatorPreserveAllTokens("ab:cd:ef", ":", 2)       = ["ab", "cd:ef"]
7476     * StringUtils.splitByWholeSeparatorPreserveAllTokens("ab-!-cd-!-ef", "-!-", 5) = ["ab", "cd", "ef"]
7477     * StringUtils.splitByWholeSeparatorPreserveAllTokens("ab-!-cd-!-ef", "-!-", 2) = ["ab", "cd-!-ef"]
7478     * </pre>
7479     *
7480     * @param str       The String to parse, may be null.
7481     * @param separator String containing the String to be used as a delimiter, {@code null} splits on whitespace.
7482     * @param max       The maximum number of elements to include in the returned array. A zero or negative value implies no limit.
7483     * @return An array of parsed Strings, {@code null} if null String was input.
7484     * @since 2.4
7485     */
7486    public static String[] splitByWholeSeparatorPreserveAllTokens(final String str, final String separator, final int max) {
7487        return splitByWholeSeparatorWorker(str, separator, max, true);
7488    }
7489
7490    /**
7491     * Performs the logic for the {@code splitByWholeSeparatorPreserveAllTokens} methods.
7492     *
7493     * @param str               The String to parse, may be {@code null}.
7494     * @param separator         String containing the String to be used as a delimiter, {@code null} splits on whitespace.
7495     * @param max               The maximum number of elements to include in the returned array. A zero or negative value implies no limit.
7496     * @param preserveAllTokens if {@code true}, adjacent separators are treated as empty token separators; if {@code false}, adjacent separators are treated as
7497     *                          one separator.
7498     * @return An array of parsed Strings, {@code null} if null String input.
7499     * @since 2.4
7500     */
7501    private static String[] splitByWholeSeparatorWorker(final String str, final String separator, final int max, final boolean preserveAllTokens) {
7502        if (str == null) {
7503            return null;
7504        }
7505        final int len = str.length();
7506        if (len == 0) {
7507            return ArrayUtils.EMPTY_STRING_ARRAY;
7508        }
7509        if (separator == null || EMPTY.equals(separator)) {
7510            // Split on whitespace.
7511            return splitWorker(str, null, max, preserveAllTokens);
7512        }
7513        final int separatorLength = separator.length();
7514        final ArrayList<String> substrings = new ArrayList<>();
7515        int numberOfSubstrings = 0;
7516        int beg = 0;
7517        int end = 0;
7518        while (end < len) {
7519            end = str.indexOf(separator, beg);
7520            if (end > -1) {
7521                if (end > beg) {
7522                    numberOfSubstrings += 1;
7523                    if (numberOfSubstrings == max) {
7524                        end = len;
7525                        substrings.add(str.substring(beg));
7526                    } else {
7527                        // The following is OK, because String.substring( beg, end ) excludes
7528                        // the character at the position 'end'.
7529                        substrings.add(str.substring(beg, end));
7530                        // Set the starting point for the next search.
7531                        // The following is equivalent to beg = end + (separatorLength - 1) + 1,
7532                        // which is the right calculation:
7533                        beg = end + separatorLength;
7534                    }
7535                } else {
7536                    // We found a consecutive occurrence of the separator, so skip it.
7537                    if (preserveAllTokens) {
7538                        numberOfSubstrings += 1;
7539                        if (numberOfSubstrings == max) {
7540                            end = len;
7541                            substrings.add(str.substring(beg));
7542                        } else {
7543                            substrings.add(EMPTY);
7544                        }
7545                    }
7546                    beg = end + separatorLength;
7547                }
7548            } else {
7549                // String.substring( beg ) goes from 'beg' to the end of the String.
7550                // beg == len means the String ended on a separator, so the trailing
7551                // token is empty and must be dropped unless empty tokens are preserved.
7552                if (preserveAllTokens || beg < len) {
7553                    substrings.add(str.substring(beg));
7554                }
7555                end = len;
7556            }
7557        }
7558        return substrings.toArray(ArrayUtils.EMPTY_STRING_ARRAY);
7559    }
7560
7561    /**
7562     * Splits the provided text into an array, using whitespace as the separator, preserving all tokens, including empty tokens created by adjacent separators.
7563     * This is an alternative to using StringTokenizer. Whitespace is defined by {@link Character#isWhitespace(char)}.
7564     *
7565     * <p>
7566     * The separator is not included in the returned String array. Adjacent separators are treated as separators for empty tokens. For more control over the
7567     * split use the StrTokenizer class.
7568     * </p>
7569     *
7570     * <p>
7571     * A {@code null} input String returns {@code null}.
7572     * </p>
7573     *
7574     * <pre>
7575     * StringUtils.splitPreserveAllTokens(null)       = null
7576     * StringUtils.splitPreserveAllTokens("")         = []
7577     * StringUtils.splitPreserveAllTokens("abc def")  = ["abc", "def"]
7578     * StringUtils.splitPreserveAllTokens("abc  def") = ["abc", "", "def"]
7579     * StringUtils.splitPreserveAllTokens(" abc ")    = ["", "abc", ""]
7580     * </pre>
7581     *
7582     * @param str The String to parse, may be {@code null}.
7583     * @return An array of parsed Strings, {@code null} if null String input.
7584     * @since 2.1
7585     */
7586    public static String[] splitPreserveAllTokens(final String str) {
7587        return splitWorker(str, null, -1, true);
7588    }
7589
7590    /**
7591     * Splits the provided text into an array, separator specified, preserving all tokens, including empty tokens created by adjacent separators. This is an
7592     * alternative to using StringTokenizer.
7593     *
7594     * <p>
7595     * The separator is not included in the returned String array. Adjacent separators are treated as separators for empty tokens. For more control over the
7596     * split use the StrTokenizer class.
7597     * </p>
7598     *
7599     * <p>
7600     * A {@code null} input String returns {@code null}.
7601     * </p>
7602     *
7603     * <pre>
7604     * StringUtils.splitPreserveAllTokens(null, *)         = null
7605     * StringUtils.splitPreserveAllTokens("", *)           = []
7606     * StringUtils.splitPreserveAllTokens("a.b.c", '.')    = ["a", "b", "c"]
7607     * StringUtils.splitPreserveAllTokens("a..b.c", '.')   = ["a", "", "b", "c"]
7608     * StringUtils.splitPreserveAllTokens("a:b:c", '.')    = ["a:b:c"]
7609     * StringUtils.splitPreserveAllTokens("a\tb\nc", null) = ["a", "b", "c"]
7610     * StringUtils.splitPreserveAllTokens("a b c", ' ')    = ["a", "b", "c"]
7611     * StringUtils.splitPreserveAllTokens("a b c ", ' ')   = ["a", "b", "c", ""]
7612     * StringUtils.splitPreserveAllTokens("a b c  ", ' ')  = ["a", "b", "c", "", ""]
7613     * StringUtils.splitPreserveAllTokens(" a b c", ' ')   = ["", "a", "b", "c"]
7614     * StringUtils.splitPreserveAllTokens("  a b c", ' ')  = ["", "", "a", "b", "c"]
7615     * StringUtils.splitPreserveAllTokens(" a b c ", ' ')  = ["", "a", "b", "c", ""]
7616     * </pre>
7617     *
7618     * @param str           The String to parse, may be {@code null}.
7619     * @param separatorChar The character used as the delimiter, {@code null} splits on whitespace.
7620     * @return An array of parsed Strings, {@code null} if null String input.
7621     * @since 2.1
7622     */
7623    public static String[] splitPreserveAllTokens(final String str, final char separatorChar) {
7624        return splitWorker(str, separatorChar, true);
7625    }
7626
7627    /**
7628     * Splits the provided text into an array, separators specified, preserving all tokens, including empty tokens created by adjacent separators. This is an
7629     * alternative to using StringTokenizer.
7630     *
7631     * <p>
7632     * The separator is not included in the returned String array. Adjacent separators are treated as separators for empty tokens. For more control over the
7633     * split use the StrTokenizer class.
7634     * </p>
7635     *
7636     * <p>
7637     * A {@code null} input String returns {@code null}. A {@code null} separatorChars splits on whitespace.
7638     * </p>
7639     *
7640     * <pre>
7641     * StringUtils.splitPreserveAllTokens(null, *)           = null
7642     * StringUtils.splitPreserveAllTokens("", *)             = []
7643     * StringUtils.splitPreserveAllTokens("abc def", null)   = ["abc", "def"]
7644     * StringUtils.splitPreserveAllTokens("abc def", " ")    = ["abc", "def"]
7645     * StringUtils.splitPreserveAllTokens("abc  def", " ")   = ["abc", "", "def"]
7646     * StringUtils.splitPreserveAllTokens("ab:cd:ef", ":")   = ["ab", "cd", "ef"]
7647     * StringUtils.splitPreserveAllTokens("ab:cd:ef:", ":")  = ["ab", "cd", "ef", ""]
7648     * StringUtils.splitPreserveAllTokens("ab:cd:ef::", ":") = ["ab", "cd", "ef", "", ""]
7649     * StringUtils.splitPreserveAllTokens("ab::cd:ef", ":")  = ["ab", "", "cd", "ef"]
7650     * StringUtils.splitPreserveAllTokens(":cd:ef", ":")     = ["", "cd", "ef"]
7651     * StringUtils.splitPreserveAllTokens("::cd:ef", ":")    = ["", "", "cd", "ef"]
7652     * StringUtils.splitPreserveAllTokens(":cd:ef:", ":")    = ["", "cd", "ef", ""]
7653     * </pre>
7654     *
7655     * @param str            The String to parse, may be {@code null}.
7656     * @param separatorChars The characters used as the delimiters, {@code null} splits on whitespace.
7657     * @return An array of parsed Strings, {@code null} if null String input.
7658     * @since 2.1
7659     */
7660    public static String[] splitPreserveAllTokens(final String str, final String separatorChars) {
7661        return splitWorker(str, separatorChars, -1, true);
7662    }
7663
7664    /**
7665     * Splits the provided text into an array with a maximum length, separators specified, preserving all tokens, including empty tokens created by adjacent
7666     * separators.
7667     *
7668     * <p>
7669     * The separator is not included in the returned String array. Adjacent separators are treated as separators for empty tokens. Adjacent separators are
7670     * treated as one separator.
7671     * </p>
7672     *
7673     * <p>
7674     * A {@code null} input String returns {@code null}. A {@code null} separatorChars splits on whitespace.
7675     * </p>
7676     *
7677     * <p>
7678     * If more than {@code max} delimited substrings are found, the last returned string includes all characters after the first {@code max - 1} returned
7679     * strings (including separator characters).
7680     * </p>
7681     *
7682     * <pre>
7683     * StringUtils.splitPreserveAllTokens(null, *, *)            = null
7684     * StringUtils.splitPreserveAllTokens("", *, *)              = []
7685     * StringUtils.splitPreserveAllTokens("ab de fg", null, 0)   = ["ab", "de", "fg"]
7686     * StringUtils.splitPreserveAllTokens("ab   de fg", null, 0) = ["ab", "", "", "de", "fg"]
7687     * StringUtils.splitPreserveAllTokens("ab:cd:ef", ":", 0)    = ["ab", "cd", "ef"]
7688     * StringUtils.splitPreserveAllTokens("ab:cd:ef", ":", 2)    = ["ab", "cd:ef"]
7689     * StringUtils.splitPreserveAllTokens("ab   de fg", null, 2) = ["ab", "  de fg"]
7690     * StringUtils.splitPreserveAllTokens("ab   de fg", null, 3) = ["ab", "", " de fg"]
7691     * StringUtils.splitPreserveAllTokens("ab   de fg", null, 4) = ["ab", "", "", "de fg"]
7692     * </pre>
7693     *
7694     * @param str            The String to parse, may be {@code null}.
7695     * @param separatorChars The characters used as the delimiters, {@code null} splits on whitespace.
7696     * @param max            The maximum number of elements to include in the array. A zero or negative value implies no limit.
7697     * @return An array of parsed Strings, {@code null} if null String input.
7698     * @since 2.1
7699     */
7700    public static String[] splitPreserveAllTokens(final String str, final String separatorChars, final int max) {
7701        return splitWorker(str, separatorChars, max, true);
7702    }
7703
7704    /**
7705     * Tests whether a {@link String#substring} boundary at {@code index} would fall between the two halves of a surrogate pair, that is the char before
7706     * {@code index} is a high surrogate and the char at {@code index} is its low surrogate. Slicing there leaves a lone surrogate in the result.
7707     *
7708     * @param str   The String being sliced.
7709     * @param index A candidate substring boundary, in {@code char} units.
7710     * @return whether slicing at {@code index} would split a surrogate pair.
7711     */
7712    private static boolean splitsSurrogatePair(final String str, final int index) {
7713        return index > 0 && index < str.length() && Character.isHighSurrogate(str.charAt(index - 1)) && Character.isLowSurrogate(str.charAt(index));
7714    }
7715
7716    /**
7717     * Performs the logic for the {@code split} and {@code splitPreserveAllTokens} methods that do not return a maximum array length.
7718     *
7719     * @param str               The String to parse, may be {@code null}.
7720     * @param separatorChar     The separate character.
7721     * @param preserveAllTokens if {@code true}, adjacent separators are treated as empty token separators; if {@code false}, adjacent separators are treated as
7722     *                          one separator.
7723     * @return An array of parsed Strings, {@code null} if null String input.
7724     */
7725    private static String[] splitWorker(final String str, final char separatorChar, final boolean preserveAllTokens) {
7726        // Performance tuned for 2.0 (JDK1.4)
7727        if (str == null) {
7728            return null;
7729        }
7730        final int len = str.length();
7731        if (len == 0) {
7732            return ArrayUtils.EMPTY_STRING_ARRAY;
7733        }
7734        final List<String> list = new ArrayList<>();
7735        int i = 0;
7736        int start = 0;
7737        boolean match = false;
7738        boolean lastMatch = false;
7739        while (i < len) {
7740            if (str.charAt(i) == separatorChar) {
7741                if (match || preserveAllTokens) {
7742                    list.add(str.substring(start, i));
7743                    match = false;
7744                    lastMatch = true;
7745                }
7746                start = ++i;
7747                continue;
7748            }
7749            lastMatch = false;
7750            match = true;
7751            i++;
7752        }
7753        if (match || preserveAllTokens && lastMatch) {
7754            list.add(str.substring(start, i));
7755        }
7756        return list.toArray(ArrayUtils.EMPTY_STRING_ARRAY);
7757    }
7758
7759    /**
7760     * Performs the logic for the {@code split} and {@code splitPreserveAllTokens} methods that return a maximum array length.
7761     *
7762     * @param str               The String to parse, may be {@code null}.
7763     * @param separatorChars    The separate character.
7764     * @param max               The maximum number of elements to include in the array. A zero or negative value implies no limit.
7765     * @param preserveAllTokens if {@code true}, adjacent separators are treated as empty token separators; if {@code false}, adjacent separators are treated as
7766     *                          one separator.
7767     * @return An array of parsed Strings, {@code null} if null String input.
7768     */
7769    private static String[] splitWorker(final String str, final String separatorChars, final int max, final boolean preserveAllTokens) {
7770        // Performance tuned for 2.0 (JDK1.4)
7771        // Direct code is quicker than StringTokenizer.
7772        // Also, StringTokenizer uses isSpace() not isWhitespace()
7773        if (str == null) {
7774            return null;
7775        }
7776        final int len = str.length();
7777        if (len == 0) {
7778            return ArrayUtils.EMPTY_STRING_ARRAY;
7779        }
7780        final List<String> list = new ArrayList<>();
7781        int sizePlus1 = 1;
7782        int i = 0;
7783        int start = 0;
7784        boolean match = false;
7785        boolean lastMatch = false;
7786        if (separatorChars == null) {
7787            // Null separator means use whitespace
7788            while (i < len) {
7789                if (Character.isWhitespace(str.charAt(i))) {
7790                    if (match || preserveAllTokens) {
7791                        lastMatch = true;
7792                        if (sizePlus1++ == max) {
7793                            i = len;
7794                            lastMatch = false;
7795                        }
7796                        list.add(str.substring(start, i));
7797                        match = false;
7798                    }
7799                    start = ++i;
7800                    continue;
7801                }
7802                lastMatch = false;
7803                match = true;
7804                i++;
7805            }
7806        } else if (separatorChars.length() == 1) {
7807            // Optimize 1 character case
7808            final char sep = separatorChars.charAt(0);
7809            while (i < len) {
7810                if (str.charAt(i) == sep) {
7811                    if (match || preserveAllTokens) {
7812                        lastMatch = true;
7813                        if (sizePlus1++ == max) {
7814                            i = len;
7815                            lastMatch = false;
7816                        }
7817                        list.add(str.substring(start, i));
7818                        match = false;
7819                    }
7820                    start = ++i;
7821                    continue;
7822                }
7823                lastMatch = false;
7824                match = true;
7825                i++;
7826            }
7827        } else {
7828            // standard case
7829            while (i < len) {
7830                if (separatorChars.indexOf(str.charAt(i)) >= 0) {
7831                    if (match || preserveAllTokens) {
7832                        lastMatch = true;
7833                        if (sizePlus1++ == max) {
7834                            i = len;
7835                            lastMatch = false;
7836                        }
7837                        list.add(str.substring(start, i));
7838                        match = false;
7839                    }
7840                    start = ++i;
7841                    continue;
7842                }
7843                lastMatch = false;
7844                match = true;
7845                i++;
7846            }
7847        }
7848        if (match || preserveAllTokens && lastMatch) {
7849            list.add(str.substring(start, i));
7850        }
7851        return list.toArray(ArrayUtils.EMPTY_STRING_ARRAY);
7852    }
7853
7854    /**
7855     * Tests if a CharSequence starts with a specified prefix.
7856     *
7857     * <p>
7858     * {@code null}s are handled without exceptions. Two {@code null} references are considered to be equal. The comparison is case-sensitive.
7859     * </p>
7860     *
7861     * <pre>
7862     * StringUtils.startsWith(null, null)      = true
7863     * StringUtils.startsWith(null, "abc")     = false
7864     * StringUtils.startsWith("abcdef", null)  = false
7865     * StringUtils.startsWith("abcdef", "abc") = true
7866     * StringUtils.startsWith("ABCDEF", "abc") = false
7867     * </pre>
7868     *
7869     * @param str    The CharSequence to check, may be null.
7870     * @param prefix The prefix to find, may be null.
7871     * @return {@code true} if the CharSequence starts with the prefix, case-sensitive, or both {@code null}.
7872     * @see String#startsWith(String)
7873     * @since 2.4
7874     * @since 3.0 Changed signature from startsWith(String, String) to startsWith(CharSequence, CharSequence)
7875     * @deprecated Use {@link Strings#startsWith(CharSequence, CharSequence) Strings.CS.startsWith(CharSequence, CharSequence)}.
7876     */
7877    @Deprecated
7878    public static boolean startsWith(final CharSequence str, final CharSequence prefix) {
7879        return Strings.CS.startsWith(str, prefix);
7880    }
7881
7882    /**
7883     * Tests if a CharSequence starts with any of the provided case-sensitive prefixes.
7884     *
7885     * <pre>
7886     * StringUtils.startsWithAny(null, null)      = false
7887     * StringUtils.startsWithAny(null, new String[] {"abc"})  = false
7888     * StringUtils.startsWithAny("abcxyz", null)     = false
7889     * StringUtils.startsWithAny("abcxyz", new String[] {""}) = true
7890     * StringUtils.startsWithAny("abcxyz", new String[] {"abc"}) = true
7891     * StringUtils.startsWithAny("abcxyz", new String[] {null, "xyz", "abc"}) = true
7892     * StringUtils.startsWithAny("abcxyz", null, "xyz", "ABCX") = false
7893     * StringUtils.startsWithAny("ABCXYZ", null, "xyz", "abc") = false
7894     * </pre>
7895     *
7896     * @param sequence      The CharSequence to check, may be null.
7897     * @param searchStrings The case-sensitive CharSequence prefixes, may be empty or contain {@code null}.
7898     * @return {@code true} if the input {@code sequence} is {@code null} AND no {@code searchStrings} are provided, or the input {@code sequence} begins with
7899     *         any of the provided case-sensitive {@code searchStrings}.
7900     * @see StringUtils#startsWith(CharSequence, CharSequence)
7901     * @since 2.5
7902     * @since 3.0 Changed signature from startsWithAny(String, String[]) to startsWithAny(CharSequence, CharSequence...)
7903     * @deprecated Use {@link Strings#startsWithAny(CharSequence, CharSequence...) Strings.CS.startsWithAny(CharSequence, CharSequence...)}.
7904     */
7905    @Deprecated
7906    public static boolean startsWithAny(final CharSequence sequence, final CharSequence... searchStrings) {
7907        return Strings.CS.startsWithAny(sequence, searchStrings);
7908    }
7909
7910    /**
7911     * Case-insensitive check if a CharSequence starts with a specified prefix.
7912     *
7913     * <p>
7914     * {@code null}s are handled without exceptions. Two {@code null} references are considered to be equal. The comparison is case insensitive.
7915     * </p>
7916     *
7917     * <pre>
7918     * StringUtils.startsWithIgnoreCase(null, null)      = true
7919     * StringUtils.startsWithIgnoreCase(null, "abc")     = false
7920     * StringUtils.startsWithIgnoreCase("abcdef", null)  = false
7921     * StringUtils.startsWithIgnoreCase("abcdef", "abc") = true
7922     * StringUtils.startsWithIgnoreCase("ABCDEF", "abc") = true
7923     * </pre>
7924     *
7925     * @param str    The CharSequence to check, may be null.
7926     * @param prefix The prefix to find, may be null.
7927     * @return {@code true} if the CharSequence starts with the prefix, case-insensitive, or both {@code null}.
7928     * @see String#startsWith(String)
7929     * @since 2.4
7930     * @since 3.0 Changed signature from startsWithIgnoreCase(String, String) to startsWithIgnoreCase(CharSequence, CharSequence)
7931     * @deprecated Use {@link Strings#startsWith(CharSequence, CharSequence) Strings.CI.startsWith(CharSequence, CharSequence)}.
7932     */
7933    @Deprecated
7934    public static boolean startsWithIgnoreCase(final CharSequence str, final CharSequence prefix) {
7935        return Strings.CI.startsWith(str, prefix);
7936    }
7937
7938    /**
7939     * Strips whitespace from the start and end of a String.
7940     *
7941     * <p>
7942     * This is similar to {@link #trim(String)} but removes whitespace. Whitespace is defined by {@link Character#isWhitespace(char)}.
7943     * </p>
7944     *
7945     * <p>
7946     * A {@code null} input String returns {@code null}.
7947     * </p>
7948     *
7949     * <pre>
7950     * StringUtils.strip(null)     = null
7951     * StringUtils.strip("")       = ""
7952     * StringUtils.strip("   ")    = ""
7953     * StringUtils.strip("abc")    = "abc"
7954     * StringUtils.strip("  abc")  = "abc"
7955     * StringUtils.strip("abc  ")  = "abc"
7956     * StringUtils.strip(" abc ")  = "abc"
7957     * StringUtils.strip(" ab c ") = "ab c"
7958     * </pre>
7959     *
7960     * @param str The String to remove whitespace from, may be null.
7961     * @return The stripped String, {@code null} if null String input.
7962     */
7963    public static String strip(final String str) {
7964        return strip(str, null);
7965    }
7966
7967    /**
7968     * 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
7969     * to be controlled.
7970     *
7971     * <p>
7972     * A {@code null} input String returns {@code null}. An empty string ("") input returns the empty string.
7973     * </p>
7974     *
7975     * <p>
7976     * If the stripChars String is {@code null}, whitespace is stripped as defined by {@link Character#isWhitespace(char)}. Alternatively use
7977     * {@link #strip(String)}.
7978     * </p>
7979     *
7980     * <pre>
7981     * StringUtils.strip(null, *)          = null
7982     * StringUtils.strip("", *)            = ""
7983     * StringUtils.strip("abc", null)      = "abc"
7984     * StringUtils.strip("  abc", null)    = "abc"
7985     * StringUtils.strip("abc  ", null)    = "abc"
7986     * StringUtils.strip(" abc ", null)    = "abc"
7987     * StringUtils.strip("  abcyx", "xyz") = "  abc"
7988     * </pre>
7989     *
7990     * @param str        The String to remove characters from, may be null.
7991     * @param stripChars The characters to remove, null treated as whitespace.
7992     * @return The stripped String, {@code null} if null String input.
7993     */
7994    public static String strip(String str, final String stripChars) {
7995        str = stripStart(str, stripChars);
7996        return stripEnd(str, stripChars);
7997    }
7998
7999    /**
8000     * Removes diacritics (~= accents) from a string. The case will not be altered.
8001     * <p>
8002     * For instance, '&agrave;' will be replaced by 'a'.
8003     * </p>
8004     * <p>
8005     * Decomposes ligatures and digraphs per the KD column in the <a href = "https://www.unicode.org/charts/normalization/">Unicode Normalization Chart.</a>
8006     * </p>
8007     * <p>
8008     * Be aware that this NFKD compatibility decomposition can map non-letter compatibility forms (fullwidth, small-form, math-symbol variants of {@code <},
8009     * {@code >}, {@code /}, and so on) to their ASCII counterparts.
8010     * </p>
8011     *
8012     * <pre>
8013     * StringUtils.stripAccents(null)         = null
8014     * StringUtils.stripAccents("")           = ""
8015     * StringUtils.stripAccents("control")    = "control"
8016     * StringUtils.stripAccents("&eacute;clair")     = "eclair"
8017     * StringUtils.stripAccents("\u1d43\u1d47\u1d9c\u00b9\u00b2\u00b3")     = "abc123"
8018     * StringUtils.stripAccents("\u00BC \u00BD \u00BE")      = "1⁄4 1⁄2 3⁄4"
8019     * </pre>
8020     * <p>
8021     * See also <a href="https://www.unicode.org/unicode/reports/tr15/tr15-23.html">Unicode Standard Annex #15 Unicode Normalization Forms</a>.
8022     * </p>
8023     *
8024     * @param input String to be stripped.
8025     * @return input text with diacritics removed.
8026     * @since 3.0
8027     */
8028    // See also Lucene's ASCIIFoldingFilter (Lucene 2.9) that replaces accented characters by their unaccented equivalent (and uncommitted bug fix:
8029    // https://issues.apache.org/jira/browse/LUCENE-1343?focusedCommentId=12858907&page=com.atlassian.jira.plugin.system.issuetabpanels%3Acomment-tabpanel#action_12858907).
8030    public static String stripAccents(final String input) {
8031        if (isEmpty(input)) {
8032            return input;
8033        }
8034        final StringBuilder decomposed = new StringBuilder(Normalizer.normalize(input, Normalizer.Form.NFKD));
8035        convertRemainingAccentCharacters(decomposed);
8036        return STRIP_ACCENTS_PATTERN.matcher(decomposed).replaceAll(EMPTY);
8037    }
8038
8039    /**
8040     * Strips whitespace from the start and end of every String in an array. Whitespace is defined by {@link Character#isWhitespace(char)}.
8041     *
8042     * <p>
8043     * 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
8044     * {@code null} array entry will be ignored.
8045     * </p>
8046     *
8047     * <pre>
8048     * StringUtils.stripAll(null)             = null
8049     * StringUtils.stripAll([])               = []
8050     * StringUtils.stripAll(["abc", "  abc"]) = ["abc", "abc"]
8051     * StringUtils.stripAll(["abc  ", null])  = ["abc", null]
8052     * </pre>
8053     *
8054     * @param strs The array to remove whitespace from, may be null.
8055     * @return The stripped Strings, {@code null} if null array input.
8056     */
8057    public static String[] stripAll(final String... strs) {
8058        return stripAll(strs, null);
8059    }
8060
8061    /**
8062     * Strips any of a set of characters from the start and end of every String in an array.
8063     * <p>
8064     * Whitespace is defined by {@link Character#isWhitespace(char)}.
8065     * </p>
8066     *
8067     * <p>
8068     * 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
8069     * {@code null} array entry will be ignored. A {@code null} stripChars will strip whitespace as defined by {@link Character#isWhitespace(char)}.
8070     * </p>
8071     *
8072     * <pre>
8073     * StringUtils.stripAll(null, *)                = null
8074     * StringUtils.stripAll([], *)                  = []
8075     * StringUtils.stripAll(["abc", "  abc"], null) = ["abc", "abc"]
8076     * StringUtils.stripAll(["abc  ", null], null)  = ["abc", null]
8077     * StringUtils.stripAll(["abc  ", null], "yz")  = ["abc  ", null]
8078     * StringUtils.stripAll(["yabcz", null], "yz")  = ["abc", null]
8079     * </pre>
8080     *
8081     * @param strs       The array to remove characters from, may be null.
8082     * @param stripChars The characters to remove, null treated as whitespace.
8083     * @return The stripped Strings, {@code null} if null array input.
8084     */
8085    public static String[] stripAll(final String[] strs, final String stripChars) {
8086        final int strsLen = ArrayUtils.getLength(strs);
8087        if (strsLen == 0) {
8088            return strs;
8089        }
8090        return ArrayUtils.setAll(new String[strsLen], i -> strip(strs[i], stripChars));
8091    }
8092
8093    /**
8094     * Strips any of a set of characters from the end of a String.
8095     *
8096     * <p>
8097     * A {@code null} input String returns {@code null}. An empty string ("") input returns the empty string.
8098     * </p>
8099     *
8100     * <p>
8101     * If the stripChars String is {@code null}, whitespace is stripped as defined by {@link Character#isWhitespace(char)}.
8102     * </p>
8103     *
8104     * <pre>
8105     * StringUtils.stripEnd(null, *)          = null
8106     * StringUtils.stripEnd("", *)            = ""
8107     * StringUtils.stripEnd("abc", "")        = "abc"
8108     * StringUtils.stripEnd("abc", null)      = "abc"
8109     * StringUtils.stripEnd("  abc", null)    = "  abc"
8110     * StringUtils.stripEnd("abc  ", null)    = "abc"
8111     * StringUtils.stripEnd(" abc ", null)    = " abc"
8112     * StringUtils.stripEnd("  abcyx", "xyz") = "  abc"
8113     * StringUtils.stripEnd("120.00", ".0")   = "12"
8114     * </pre>
8115     *
8116     * @param str        The String to remove characters from, may be null.
8117     * @param stripChars The set of characters to remove, null treated as whitespace.
8118     * @return The stripped String, {@code null} if null String input.
8119     */
8120    public static String stripEnd(final String str, final String stripChars) {
8121        int end = length(str);
8122        if (end == 0) {
8123            return str;
8124        }
8125        if (stripChars == null) {
8126            while (end != 0 && Character.isWhitespace(str.charAt(end - 1))) {
8127                end--;
8128            }
8129        } else if (stripChars.isEmpty()) {
8130            return str;
8131        } else {
8132            while (end != 0) {
8133                final int codePoint = str.codePointBefore(end);
8134                if (stripChars.indexOf(codePoint) == INDEX_NOT_FOUND) {
8135                    break;
8136                }
8137                end -= Character.charCount(codePoint);
8138            }
8139        }
8140        return str.substring(0, end);
8141    }
8142
8143    /**
8144     * Strips any of a set of characters from the start of a String.
8145     *
8146     * <p>
8147     * A {@code null} input String returns {@code null}. An empty string ("") input returns the empty string.
8148     * </p>
8149     *
8150     * <p>
8151     * If the stripChars String is {@code null}, whitespace is stripped as defined by {@link Character#isWhitespace(char)}.
8152     * </p>
8153     *
8154     * <pre>
8155     * StringUtils.stripStart(null, *)          = null
8156     * StringUtils.stripStart("", *)            = ""
8157     * StringUtils.stripStart("abc", "")        = "abc"
8158     * StringUtils.stripStart("abc", null)      = "abc"
8159     * StringUtils.stripStart("  abc", null)    = "abc"
8160     * StringUtils.stripStart("abc  ", null)    = "abc  "
8161     * StringUtils.stripStart(" abc ", null)    = "abc "
8162     * StringUtils.stripStart("yxabc  ", "xyz") = "abc  "
8163     * </pre>
8164     *
8165     * @param str        The String to remove characters from, may be null.
8166     * @param stripChars The characters to remove, null treated as whitespace.
8167     * @return The stripped String, {@code null} if null String input.
8168     */
8169    public static String stripStart(final String str, final String stripChars) {
8170        final int strLen = length(str);
8171        if (strLen == 0) {
8172            return str;
8173        }
8174        int start = 0;
8175        if (stripChars == null) {
8176            while (start != strLen && Character.isWhitespace(str.charAt(start))) {
8177                start++;
8178            }
8179        } else if (stripChars.isEmpty()) {
8180            return str;
8181        } else {
8182            while (start != strLen) {
8183                final int codePoint = str.codePointAt(start);
8184                if (stripChars.indexOf(codePoint) == INDEX_NOT_FOUND) {
8185                    break;
8186                }
8187                start += Character.charCount(codePoint);
8188            }
8189        }
8190        return str.substring(start);
8191    }
8192
8193    /**
8194     * Strips whitespace from the start and end of a String returning an empty String if {@code null} input.
8195     *
8196     * <p>
8197     * This is similar to {@link #trimToEmpty(String)} but removes whitespace. Whitespace is defined by {@link Character#isWhitespace(char)}.
8198     * </p>
8199     *
8200     * <pre>
8201     * StringUtils.stripToEmpty(null)     = ""
8202     * StringUtils.stripToEmpty("")       = ""
8203     * StringUtils.stripToEmpty("   ")    = ""
8204     * StringUtils.stripToEmpty("abc")    = "abc"
8205     * StringUtils.stripToEmpty("  abc")  = "abc"
8206     * StringUtils.stripToEmpty("abc  ")  = "abc"
8207     * StringUtils.stripToEmpty(" abc ")  = "abc"
8208     * StringUtils.stripToEmpty(" ab c ") = "ab c"
8209     * </pre>
8210     *
8211     * @param str The String to be stripped, may be null.
8212     * @return The trimmed String, or an empty String if {@code null} input.
8213     * @since 2.0
8214     */
8215    public static String stripToEmpty(final String str) {
8216        return str == null ? EMPTY : strip(str, null);
8217    }
8218
8219    /**
8220     * Strips whitespace from the start and end of a String returning {@code null} if the String is empty ("") after the strip.
8221     *
8222     * <p>
8223     * This is similar to {@link #trimToNull(String)} but removes whitespace. Whitespace is defined by {@link Character#isWhitespace(char)}.
8224     * </p>
8225     *
8226     * <pre>
8227     * StringUtils.stripToNull(null)     = null
8228     * StringUtils.stripToNull("")       = null
8229     * StringUtils.stripToNull("   ")    = null
8230     * StringUtils.stripToNull("abc")    = "abc"
8231     * StringUtils.stripToNull("  abc")  = "abc"
8232     * StringUtils.stripToNull("abc  ")  = "abc"
8233     * StringUtils.stripToNull(" abc ")  = "abc"
8234     * StringUtils.stripToNull(" ab c ") = "ab c"
8235     * </pre>
8236     *
8237     * @param str The String to be stripped, may be null.
8238     * @return The stripped String, {@code null} if whitespace, empty or null String input.
8239     * @since 2.0
8240     */
8241    public static String stripToNull(String str) {
8242        if (str == null) {
8243            return null;
8244        }
8245        str = strip(str, null);
8246        return str.isEmpty() ? null : str; // NOSONARLINT str cannot be null here
8247    }
8248
8249    /**
8250     * Gets a substring from the specified String avoiding exceptions.
8251     *
8252     * <p>
8253     * A negative start position can be used to start {@code n} characters from the end of the String.
8254     * </p>
8255     *
8256     * <p>
8257     * A {@code null} String will return {@code null}. An empty ("") String will return "".
8258     * </p>
8259     *
8260     * <pre>
8261     * StringUtils.substring(null, *)   = null
8262     * StringUtils.substring("", *)     = ""
8263     * StringUtils.substring("abc", 0)  = "abc"
8264     * StringUtils.substring("abc", 2)  = "c"
8265     * StringUtils.substring("abc", 4)  = ""
8266     * StringUtils.substring("abc", -2) = "bc"
8267     * StringUtils.substring("abc", -4) = "abc"
8268     * </pre>
8269     *
8270     * @param str   The String to get the substring from, may be null.
8271     * @param start The position to start from, negative means count back from the end of the String by this many characters.
8272     * @return substring from start position, {@code null} if null String input.
8273     */
8274    public static String substring(final String str, int start) {
8275        if (str == null) {
8276            return null;
8277        }
8278        // handle negatives, which means last n characters
8279        if (start < 0) {
8280            start = str.length() + start; // remember start is negative
8281        }
8282        if (start < 0) {
8283            start = 0;
8284        }
8285        if (start > str.length()) {
8286            return EMPTY;
8287        }
8288        return str.substring(start);
8289    }
8290
8291    /**
8292     * Gets a substring from the specified String avoiding exceptions.
8293     *
8294     * <p>
8295     * A negative start position can be used to start/end {@code n} characters from the end of the String.
8296     * </p>
8297     *
8298     * <p>
8299     * The returned substring starts with the character in the {@code start} position and ends before the {@code end} position. All position counting is
8300     * 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
8301     * relative to the end of the String.
8302     * </p>
8303     *
8304     * <p>
8305     * If {@code start} is not strictly to the left of {@code end}, "" is returned.
8306     * </p>
8307     *
8308     * <pre>
8309     * StringUtils.substring(null, *, *)    = null
8310     * StringUtils.substring("", * ,  *)    = "";
8311     * StringUtils.substring("abc", 0, 2)   = "ab"
8312     * StringUtils.substring("abc", 2, 0)   = ""
8313     * StringUtils.substring("abc", 2, 4)   = "c"
8314     * StringUtils.substring("abc", 4, 6)   = ""
8315     * StringUtils.substring("abc", 2, 2)   = ""
8316     * StringUtils.substring("abc", -2, -1) = "b"
8317     * StringUtils.substring("abc", -4, 2)  = "ab"
8318     * </pre>
8319     *
8320     * @param str   The String to get the substring from, may be null.
8321     * @param start The position to start from, negative means count back from the end of the String by this many characters.
8322     * @param end   The position to end at (exclusive), negative means count back from the end of the String by this many characters.
8323     * @return substring from start position to end position, {@code null} if null String input.
8324     */
8325    public static String substring(final String str, int start, int end) {
8326        if (str == null) {
8327            return null;
8328        }
8329        // handle negatives
8330        if (end < 0) {
8331            end = str.length() + end; // remember end is negative
8332        }
8333        if (start < 0) {
8334            start = str.length() + start; // remember start is negative
8335        }
8336        // check length next
8337        if (end > str.length()) {
8338            end = str.length();
8339        }
8340        // if start is greater than end, return ""
8341        if (start > end) {
8342            return EMPTY;
8343        }
8344        if (start < 0) {
8345            start = 0;
8346        }
8347        if (end < 0) {
8348            end = 0;
8349        }
8350        return str.substring(start, end);
8351    }
8352
8353    /**
8354     * Gets the substring after the first occurrence of a separator. The separator is not returned.
8355     *
8356     * <p>
8357     * A {@code null} string input will return {@code null}. An empty ("") string input will return the empty string.
8358     * </p>
8359     *
8360     * <p>
8361     * If nothing is found, the empty string is returned.
8362     * </p>
8363     *
8364     * <pre>
8365     * StringUtils.substringAfter(null, *)      = null
8366     * StringUtils.substringAfter("", *)        = ""
8367     * StringUtils.substringAfter("abc", 'a')   = "bc"
8368     * StringUtils.substringAfter("abcba", 'b') = "cba"
8369     * StringUtils.substringAfter("abc", 'c')   = ""
8370     * StringUtils.substringAfter("abc", 'd')   = ""
8371     * StringUtils.substringAfter(" abc", 32)   = "abc"
8372     * </pre>
8373     *
8374     * @param str       The String to get a substring from, may be null.
8375     * @param find The character (Unicode code point) to find.
8376     * @return The substring after the first occurrence of the specified character, {@code null} if null String input.
8377     * @since 3.11
8378     */
8379    public static String substringAfter(final String str, final int find) {
8380        if (isEmpty(str)) {
8381            return str;
8382        }
8383        final int pos = str.indexOf(find);
8384        if (pos == INDEX_NOT_FOUND) {
8385            return EMPTY;
8386        }
8387        return str.substring(pos + Character.charCount(find));
8388    }
8389
8390    /**
8391     * Gets the substring after the first occurrence of a separator. The separator is not returned.
8392     *
8393     * <p>
8394     * 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
8395     * empty string if the input string is not {@code null}.
8396     * </p>
8397     *
8398     * <p>
8399     * If nothing is found, the empty string is returned.
8400     * </p>
8401     *
8402     * <pre>
8403     * StringUtils.substringAfter(null, *)      = null
8404     * StringUtils.substringAfter("", *)        = ""
8405     * StringUtils.substringAfter(*, null)      = ""
8406     * StringUtils.substringAfter("abc", "a")   = "bc"
8407     * StringUtils.substringAfter("abcba", "b") = "cba"
8408     * StringUtils.substringAfter("abc", "c")   = ""
8409     * StringUtils.substringAfter("abc", "d")   = ""
8410     * StringUtils.substringAfter("abc", "")    = "abc"
8411     * </pre>
8412     *
8413     * @param str       The String to get a substring from, may be null.
8414     * @param find The String to find, may be null.
8415     * @return The substring after the first occurrence of the specified string, {@code null} if null String input.
8416     * @since 2.0
8417     */
8418    public static String substringAfter(final String str, final String find) {
8419        if (isEmpty(str)) {
8420            return str;
8421        }
8422        if (find == null) {
8423            return EMPTY;
8424        }
8425        final int pos = str.indexOf(find);
8426        if (pos == INDEX_NOT_FOUND) {
8427            return EMPTY;
8428        }
8429        return str.substring(pos + find.length());
8430    }
8431
8432    /**
8433     * Gets the substring after the last occurrence of a separator. The separator is not returned.
8434     *
8435     * <p>
8436     * A {@code null} string input will return {@code null}. An empty ("") string input will return the empty string.
8437     * </p>
8438     *
8439     * <p>
8440     * If nothing is found, the empty string is returned.
8441     * </p>
8442     *
8443     * <pre>
8444     * StringUtils.substringAfterLast(null, *)      = null
8445     * StringUtils.substringAfterLast("", *)        = ""
8446     * StringUtils.substringAfterLast("abc", 'a')   = "bc"
8447     * StringUtils.substringAfterLast(" bc", 32)    = "bc"
8448     * StringUtils.substringAfterLast("abcba", 'b') = "a"
8449     * StringUtils.substringAfterLast("abc", 'c')   = ""
8450     * StringUtils.substringAfterLast("a", 'a')     = ""
8451     * StringUtils.substringAfterLast("a", 'z')     = ""
8452     * </pre>
8453     *
8454     * @param str       The String to get a substring from, may be null.
8455     * @param find The character (Unicode code point) to find.
8456     * @return The substring after the last occurrence of the specified character, {@code null} if null String input.
8457     * @since 3.11
8458     */
8459    public static String substringAfterLast(final String str, final int find) {
8460        if (isEmpty(str)) {
8461            return str;
8462        }
8463        final int pos = str.lastIndexOf(find);
8464        if (pos == INDEX_NOT_FOUND || pos == str.length() - Character.charCount(find)) {
8465            return EMPTY;
8466        }
8467        return str.substring(pos + Character.charCount(find));
8468    }
8469
8470    /**
8471     * Gets the substring after the last occurrence of a separator. The separator is not returned.
8472     *
8473     * <p>
8474     * 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
8475     * return the empty string if the input string is not {@code null}.
8476     * </p>
8477     *
8478     * <p>
8479     * If nothing is found, the empty string is returned.
8480     * </p>
8481     *
8482     * <pre>
8483     * StringUtils.substringAfterLast(null, *)      = null
8484     * StringUtils.substringAfterLast("", *)        = ""
8485     * StringUtils.substringAfterLast(*, "")        = ""
8486     * StringUtils.substringAfterLast(*, null)      = ""
8487     * StringUtils.substringAfterLast("abc", "a")   = "bc"
8488     * StringUtils.substringAfterLast("abcba", "b") = "a"
8489     * StringUtils.substringAfterLast("abc", "c")   = ""
8490     * StringUtils.substringAfterLast("a", "a")     = ""
8491     * StringUtils.substringAfterLast("a", "z")     = ""
8492     * </pre>
8493     *
8494     * @param str       The String to get a substring from, may be null.
8495     * @param find The String to find, may be null.
8496     * @return The substring after the last occurrence of the specified string, {@code null} if null String input.
8497     * @since 2.0
8498     */
8499    public static String substringAfterLast(final String str, final String find) {
8500        if (isEmpty(str)) {
8501            return str;
8502        }
8503        if (isEmpty(find)) {
8504            return EMPTY;
8505        }
8506        final int pos = str.lastIndexOf(find);
8507        if (pos == INDEX_NOT_FOUND || pos == str.length() - find.length()) {
8508            return EMPTY;
8509        }
8510        return str.substring(pos + find.length());
8511    }
8512
8513    /**
8514     * Gets the substring before the first occurrence of a separator. The separator is not returned.
8515     *
8516     * <p>
8517     * A {@code null} string input will return {@code null}. An empty ("") string input will return the empty string.
8518     * </p>
8519     *
8520     * <p>
8521     * If nothing is found, the string input is returned.
8522     * </p>
8523     *
8524     * <pre>
8525     * StringUtils.substringBefore(null, *)      = null
8526     * StringUtils.substringBefore("", *)        = ""
8527     * StringUtils.substringBefore("abc", 'a')   = ""
8528     * StringUtils.substringBefore("abcba", 'b') = "a"
8529     * StringUtils.substringBefore("abc", 'c')   = "ab"
8530     * StringUtils.substringBefore("abc", 'd')   = "abc"
8531     * </pre>
8532     *
8533     * @param str       The String to get a substring from, may be null.
8534     * @param find The character (Unicode code point) to find.
8535     * @return The substring before the first occurrence of the specified character, {@code null} if null String input.
8536     * @since 3.12.0
8537     */
8538    public static String substringBefore(final String str, final int find) {
8539        if (isEmpty(str)) {
8540            return str;
8541        }
8542        final int pos = str.indexOf(find);
8543        if (pos == INDEX_NOT_FOUND) {
8544            return str;
8545        }
8546        return str.substring(0, pos);
8547    }
8548
8549    /**
8550     * Gets the substring before the first occurrence of a separator. The separator is not returned.
8551     *
8552     * <p>
8553     * 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
8554     * input string.
8555     * </p>
8556     *
8557     * <p>
8558     * If nothing is found, the string input is returned.
8559     * </p>
8560     *
8561     * <pre>
8562     * StringUtils.substringBefore(null, *)      = null
8563     * StringUtils.substringBefore("", *)        = ""
8564     * StringUtils.substringBefore("abc", "a")   = ""
8565     * StringUtils.substringBefore("abcba", "b") = "a"
8566     * StringUtils.substringBefore("abc", "c")   = "ab"
8567     * StringUtils.substringBefore("abc", "d")   = "abc"
8568     * StringUtils.substringBefore("abc", "")    = ""
8569     * StringUtils.substringBefore("abc", null)  = "abc"
8570     * </pre>
8571     *
8572     * @param str       The String to get a substring from, may be null.
8573     * @param find The String to find, may be null.
8574     * @return The substring before the first occurrence of the specified string, {@code null} if null String input.
8575     * @since 2.0
8576     */
8577    public static String substringBefore(final String str, final String find) {
8578        if (isEmpty(str) || find == null) {
8579            return str;
8580        }
8581        if (find.isEmpty()) {
8582            return EMPTY;
8583        }
8584        final int pos = str.indexOf(find);
8585        if (pos == INDEX_NOT_FOUND) {
8586            return str;
8587        }
8588        return str.substring(0, pos);
8589    }
8590
8591    /**
8592     * Gets the substring before the last occurrence of a separator. The separator is not returned.
8593     *
8594     * <p>
8595     * 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
8596     * return the input string.
8597     * </p>
8598     *
8599     * <p>
8600     * If nothing is found, the string input is returned.
8601     * </p>
8602     *
8603     * <pre>
8604     * StringUtils.substringBeforeLast(null, *)      = null
8605     * StringUtils.substringBeforeLast("", *)        = ""
8606     * StringUtils.substringBeforeLast("abcba", "b") = "abc"
8607     * StringUtils.substringBeforeLast("abc", "c")   = "ab"
8608     * StringUtils.substringBeforeLast("a", "a")     = ""
8609     * StringUtils.substringBeforeLast("a", "z")     = "a"
8610     * StringUtils.substringBeforeLast("a", null)    = "a"
8611     * StringUtils.substringBeforeLast("a", "")      = "a"
8612     * </pre>
8613     *
8614     * @param str       The String to get a substring from, may be null.
8615     * @param find The String to find, may be null.
8616     * @return The substring before the last occurrence of the specified string, {@code null} if null String input.
8617     * @since 2.0
8618     */
8619    public static String substringBeforeLast(final String str, final String find) {
8620        if (isEmpty(str) || isEmpty(find)) {
8621            return str;
8622        }
8623        final int pos = str.lastIndexOf(find);
8624        if (pos == INDEX_NOT_FOUND) {
8625            return str;
8626        }
8627        return str.substring(0, pos);
8628    }
8629
8630    /**
8631     * Gets the String that is nested in between two instances of the same String.
8632     *
8633     * <p>
8634     * A {@code null} input String returns {@code null}. A {@code null} tag returns {@code null}.
8635     * </p>
8636     *
8637     * <pre>
8638     * StringUtils.substringBetween(null, *)            = null
8639     * StringUtils.substringBetween("", "")             = ""
8640     * StringUtils.substringBetween("", "tag")          = null
8641     * StringUtils.substringBetween("tagabctag", null)  = null
8642     * StringUtils.substringBetween("tagabctag", "")    = ""
8643     * StringUtils.substringBetween("tagabctag", "tag") = "abc"
8644     * </pre>
8645     *
8646     * @param str The String containing the substring, may be null.
8647     * @param tag The String before and after the substring, may be null.
8648     * @return The substring, {@code null} if no match.
8649     * @since 2.0
8650     */
8651    public static String substringBetween(final String str, final String tag) {
8652        return substringBetween(str, tag, tag);
8653    }
8654
8655    /**
8656     * Gets the String that is nested in between two Strings. Only the first match is returned.
8657     *
8658     * <p>
8659     * 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
8660     * empty string.
8661     * </p>
8662     *
8663     * <pre>
8664     * StringUtils.substringBetween("wx[b]yz", "[", "]") = "b"
8665     * StringUtils.substringBetween(null, *, *)          = null
8666     * StringUtils.substringBetween(*, null, *)          = null
8667     * StringUtils.substringBetween(*, *, null)          = null
8668     * StringUtils.substringBetween("", "", "")          = ""
8669     * StringUtils.substringBetween("", "", "]")         = null
8670     * StringUtils.substringBetween("", "[", "]")        = null
8671     * StringUtils.substringBetween("yabcz", "", "")     = ""
8672     * StringUtils.substringBetween("yabcz", "y", "z")   = "abc"
8673     * StringUtils.substringBetween("yabczyabcz", "y", "z")   = "abc"
8674     * </pre>
8675     *
8676     * @param str   The String containing the substring, may be null.
8677     * @param open  The String before the substring, may be null.
8678     * @param close The String after the substring, may be null.
8679     * @return The substring, {@code null} if no match.
8680     * @since 2.0
8681     */
8682    public static String substringBetween(final String str, final String open, final String close) {
8683        if (!ObjectUtils.allNotNull(str, open, close)) {
8684            return null;
8685        }
8686        final int start = str.indexOf(open);
8687        if (start != INDEX_NOT_FOUND) {
8688            final int end = str.indexOf(close, start + open.length());
8689            if (end != INDEX_NOT_FOUND) {
8690                return str.substring(start + open.length(), end);
8691            }
8692        }
8693        return null;
8694    }
8695
8696    /**
8697     * Searches a String for substrings delimited by a start and end tag, returning all matching substrings in an array.
8698     *
8699     * <p>
8700     * A {@code null} input String returns {@code null}. A {@code null} open/close returns {@code null} (no match). An empty ("") open/close returns
8701     * {@code null} (no match).
8702     * </p>
8703     *
8704     * <pre>
8705     * StringUtils.substringsBetween("[a][b][c]", "[", "]") = ["a","b","c"]
8706     * StringUtils.substringsBetween(null, *, *)            = null
8707     * StringUtils.substringsBetween(*, null, *)            = null
8708     * StringUtils.substringsBetween(*, *, null)            = null
8709     * StringUtils.substringsBetween("", "[", "]")          = []
8710     * </pre>
8711     *
8712     * @param str   The String containing the substrings, null returns null, empty returns empty.
8713     * @param open  The String identifying the start of the substring, empty returns null.
8714     * @param close The String identifying the end of the substring, empty returns null.
8715     * @return A String Array of substrings, or {@code null} if no match.
8716     * @since 2.3
8717     */
8718    public static String[] substringsBetween(final String str, final String open, final String close) {
8719        if (str == null || isEmpty(open) || isEmpty(close)) {
8720            return null;
8721        }
8722        final int strLen = str.length();
8723        if (strLen == 0) {
8724            return ArrayUtils.EMPTY_STRING_ARRAY;
8725        }
8726        final int closeLen = close.length();
8727        final int openLen = open.length();
8728        final List<String> list = new ArrayList<>();
8729        int pos = 0;
8730        while (pos < strLen - closeLen) {
8731            int start = str.indexOf(open, pos);
8732            if (start < 0) {
8733                break;
8734            }
8735            start += openLen;
8736            final int end = str.indexOf(close, start);
8737            if (end < 0) {
8738                break;
8739            }
8740            list.add(str.substring(start, end));
8741            pos = end + closeLen;
8742        }
8743        if (list.isEmpty()) {
8744            return null;
8745        }
8746        return list.toArray(ArrayUtils.EMPTY_STRING_ARRAY);
8747    }
8748
8749    /**
8750     * Swaps the case of a String changing upper and title case to lower case, and lower case to upper case.
8751     *
8752     * <ul>
8753     * <li>Upper case character converts to Lower case</li>
8754     * <li>Title case character converts to Lower case</li>
8755     * <li>Lower case character converts to Upper case</li>
8756     * </ul>
8757     *
8758     * <p>
8759     * For a word based algorithm, see {@link org.apache.commons.text.WordUtils#swapCase(String)}. A {@code null} input String returns {@code null}.
8760     * </p>
8761     *
8762     * <pre>
8763     * StringUtils.swapCase(null)                 = null
8764     * StringUtils.swapCase("")                   = ""
8765     * StringUtils.swapCase("The dog has a BONE") = "tHE DOG HAS A bone"
8766     * </pre>
8767     *
8768     * <p>
8769     * 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
8770     * functionality is available in org.apache.commons.lang3.text.WordUtils.
8771     * </p>
8772     *
8773     * @param str The String to swap case, may be null.
8774     * @return The changed String, {@code null} if null String input.
8775     */
8776    public static String swapCase(final String str) {
8777        if (isEmpty(str)) {
8778            return str;
8779        }
8780        final int strLen = str.length();
8781        final int[] newCodePoints = new int[strLen]; // cannot be longer than the char array
8782        int outOffset = 0;
8783        for (int i = 0; i < strLen;) {
8784            final int oldCodepoint = str.codePointAt(i);
8785            final int newCodePoint;
8786            if (Character.isUpperCase(oldCodepoint) || Character.isTitleCase(oldCodepoint)) {
8787                newCodePoint = Character.toLowerCase(oldCodepoint);
8788            } else if (Character.isLowerCase(oldCodepoint)) {
8789                newCodePoint = Character.toUpperCase(oldCodepoint);
8790            } else {
8791                newCodePoint = oldCodepoint;
8792            }
8793            newCodePoints[outOffset++] = newCodePoint;
8794            i += Character.charCount(newCodePoint);
8795        }
8796        return new String(newCodePoints, 0, outOffset);
8797    }
8798
8799    /**
8800     * Converts a {@link CharSequence} into an array of code points.
8801     *
8802     * <p>
8803     * 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
8804     * followed by a low surrogate or a low surrogate not preceded by a high surrogate) will be returned as-is.
8805     * </p>
8806     *
8807     * <pre>
8808     * StringUtils.toCodePoints(null)   =  null
8809     * StringUtils.toCodePoints("")     =  []  // empty array
8810     * </pre>
8811     *
8812     * @param cs The character sequence to convert.
8813     * @return An array of code points.
8814     * @since 3.6
8815     */
8816    public static int[] toCodePoints(final CharSequence cs) {
8817        if (cs == null) {
8818            return null;
8819        }
8820        if (isEmpty(cs)) {
8821            return ArrayUtils.EMPTY_INT_ARRAY;
8822        }
8823        return cs.toString().codePoints().toArray();
8824    }
8825
8826    /**
8827     * Converts a {@code byte[]} to a String using the specified character encoding.
8828     *
8829     * @param bytes   The byte array to read from.
8830     * @param charset The encoding to use, if null then use the platform default.
8831     * @return A new String.
8832     * @throws NullPointerException Thrown if {@code bytes} is null.
8833     * @since 3.2
8834     * @since 3.3 No longer throws {@link UnsupportedEncodingException}.
8835     */
8836    public static String toEncodedString(final byte[] bytes, final Charset charset) {
8837        return new String(bytes, Charsets.toCharset(charset));
8838    }
8839
8840    /**
8841     * Converts the given source String as a lower-case using the {@link Locale#ROOT} locale in a null-safe manner.
8842     *
8843     * @param source A source String or null.
8844     * @return The given source String as a lower-case using the {@link Locale#ROOT} locale or null.
8845     * @since 3.10
8846     */
8847    public static String toRootLowerCase(final String source) {
8848        return source == null ? null : source.toLowerCase(Locale.ROOT);
8849    }
8850
8851    /**
8852     * Converts the given source String as an upper-case using the {@link Locale#ROOT} locale in a null-safe manner.
8853     *
8854     * @param source A source String or null.
8855     * @return The given source String as an upper-case using the {@link Locale#ROOT} locale or null.
8856     * @since 3.10
8857     */
8858    public static String toRootUpperCase(final String source) {
8859        return source == null ? null : source.toUpperCase(Locale.ROOT);
8860    }
8861
8862    /**
8863     * Converts a {@code byte[]} to a String using the specified character encoding.
8864     *
8865     * @param bytes       The byte array to read from.
8866     * @param charsetName The encoding to use, if null then use the platform default.
8867     * @return A new String.
8868     * @throws NullPointerException Thrown if the input is null.
8869     * @since 3.1
8870     * @deprecated Use {@link StringUtils#toEncodedString(byte[], Charset)} instead of String constants in your code.
8871     */
8872    @Deprecated
8873    public static String toString(final byte[] bytes, final String charsetName) {
8874        return new String(bytes, Charsets.toCharset(charsetName));
8875    }
8876
8877    /**
8878     * Removes control characters plus space (char &lt;= 32) from both ends of this String, handling {@code null} by returning {@code null}.
8879     *
8880     * <p>
8881     * The String is trimmed using {@link String#trim()}. Trim removes start and end characters &lt;= 32. To strip whitespace use {@link #strip(String)}.
8882     * </p>
8883     *
8884     * <p>
8885     * To trim your choice of characters, use the {@link #strip(String, String)} methods.
8886     * </p>
8887     *
8888     * <pre>
8889     * StringUtils.trim(null)          = null
8890     * StringUtils.trim("")            = ""
8891     * StringUtils.trim("     ")       = ""
8892     * StringUtils.trim("abc")         = "abc"
8893     * StringUtils.trim("    abc    ") = "abc"
8894     * </pre>
8895     *
8896     * @param str The String to be trimmed, may be null.
8897     * @return The trimmed string, {@code null} if null String input.
8898     */
8899    public static String trim(final String str) {
8900        return str == null ? null : str.trim();
8901    }
8902
8903    /**
8904     * Removes {@link CharUtils#isAsciiControl(char) ASCII control characters} (char &lt;= 31 or char == 127) from both ends of this String, handling
8905     * {@code null} by returning {@code null}.
8906     *
8907     * <p>
8908     * To trim your choice of characters, use the {@link #strip(String, String)} methods.
8909     * </p>
8910     *
8911     * <pre>{@code
8912     * StringUtils.trimAsciiControl(null)          = null
8913     * StringUtils.trimAsciiControl("")            = ""
8914     * StringUtils.trimAsciiControl("abc\u0000")   = "abc"
8915     * StringUtils.trimAsciiControl("abc")         = "abc"
8916     * StringUtils.trimAsciiControl(" abc ")       = " abc "
8917     * }</pre>
8918     *
8919     * @param str The String to be trimmed, may be null.
8920     * @return The trimmed string, {@code null} if null String input.
8921     * @since 3.21.0
8922     */
8923    public static String trimAsciiControl(final String str) {
8924        if (str == null) {
8925            return null;
8926        }
8927        int len = str.length();
8928        int st = 0;
8929        while (st < len && CharUtils.isAsciiControl(str.charAt(st))) {
8930            st++;
8931        }
8932        while (st < len && CharUtils.isAsciiControl(str.charAt(len - 1))) {
8933            len--;
8934        }
8935        return st > 0 || len < str.length() ? str.substring(st, len) : str;
8936    }
8937
8938    /**
8939     * 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
8940     * it is {@code null}.
8941     *
8942     * <p>
8943     * The String is trimmed using {@link String#trim()}. Trim removes start and end characters &lt;= 32. To strip whitespace use {@link #stripToEmpty(String)}.
8944     * </p>
8945     *
8946     * <pre>
8947     * StringUtils.trimToEmpty(null)          = ""
8948     * StringUtils.trimToEmpty("")            = ""
8949     * StringUtils.trimToEmpty("     ")       = ""
8950     * StringUtils.trimToEmpty("abc")         = "abc"
8951     * StringUtils.trimToEmpty("    abc    ") = "abc"
8952     * </pre>
8953     *
8954     * @param str The String to be trimmed, may be null.
8955     * @return The trimmed String, or an empty String if {@code null} input.
8956     * @since 2.0
8957     */
8958    public static String trimToEmpty(final String str) {
8959        return str == null ? EMPTY : str.trim();
8960    }
8961
8962    /**
8963     * 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
8964     * {@code null}.
8965     *
8966     * <p>
8967     * The String is trimmed using {@link String#trim()}. Trim removes start and end characters &lt;= 32. To strip whitespace use {@link #stripToNull(String)}.
8968     * </p>
8969     *
8970     * <pre>
8971     * StringUtils.trimToNull(null)          = null
8972     * StringUtils.trimToNull("")            = null
8973     * StringUtils.trimToNull("     ")       = null
8974     * StringUtils.trimToNull("abc")         = "abc"
8975     * StringUtils.trimToNull("    abc    ") = "abc"
8976     * </pre>
8977     *
8978     * @param str The String to be trimmed, may be null.
8979     * @return The trimmed String, {@code null} if only chars &lt;= 32, empty or null String input.
8980     * @since 2.0
8981     */
8982    public static String trimToNull(final String str) {
8983        final String ts = trim(str);
8984        return isEmpty(ts) ? null : ts;
8985    }
8986
8987    /**
8988     * Truncates a String. This will turn "Now is the time for all good men" into "Now is the time for".
8989     *
8990     * <p>
8991     * Specifically:
8992     * </p>
8993     * <ul>
8994     * <li>If {@code str} is less than {@code maxWidth} characters long, return it.</li>
8995     * <li>Else truncate it to {@code substring(str, 0, maxWidth)}.</li>
8996     * <li>If {@code maxWidth} is less than {@code 0}, throw an {@link IllegalArgumentException}.</li>
8997     * <li>In no case will it return a String of length greater than {@code maxWidth}.</li>
8998     * </ul>
8999     *
9000     * <pre>
9001     * StringUtils.truncate(null, 0)       = null
9002     * StringUtils.truncate(null, 2)       = null
9003     * StringUtils.truncate("", 4)         = ""
9004     * StringUtils.truncate("abcdefg", 4)  = "abcd"
9005     * StringUtils.truncate("abcdefg", 6)  = "abcdef"
9006     * StringUtils.truncate("abcdefg", 7)  = "abcdefg"
9007     * StringUtils.truncate("abcdefg", 8)  = "abcdefg"
9008     * StringUtils.truncate("abcdefg", -1) = throws an IllegalArgumentException
9009     * </pre>
9010     *
9011     * @param str      The String to truncate, may be null.
9012     * @param maxWidth maximum length of result String, must be non-negative.
9013     * @return truncated String, {@code null} if null String input.
9014     * @throws IllegalArgumentException Thrown if {@code maxWidth} is less than {@code 0}.
9015     * @since 3.5
9016     */
9017    public static String truncate(final String str, final int maxWidth) {
9018        return truncate(str, 0, maxWidth);
9019    }
9020
9021    /**
9022     * Truncates a String. This will turn "Now is the time for all good men" into "is the time for all".
9023     *
9024     * <p>
9025     * Works like {@code truncate(String, int)}, but allows you to specify a "left edge" offset.
9026     * </p>
9027     *
9028     * <p>
9029     * Specifically:
9030     * </p>
9031     * <ul>
9032     * <li>If {@code str} is less than {@code maxWidth} characters long, return it.</li>
9033     * <li>Else truncate it to {@code substring(str, offset, maxWidth)}.</li>
9034     * <li>If {@code maxWidth} is less than {@code 0}, throw an {@link IllegalArgumentException}.</li>
9035     * <li>If {@code offset} is less than {@code 0}, throw an {@link IllegalArgumentException}.</li>
9036     * <li>In no case will it return a String of length greater than {@code maxWidth}.</li>
9037     * </ul>
9038     *
9039     * <pre>
9040     * StringUtils.truncate(null, 0, 0) = null
9041     * StringUtils.truncate(null, 2, 4) = null
9042     * StringUtils.truncate("", 0, 10) = ""
9043     * StringUtils.truncate("", 2, 10) = ""
9044     * StringUtils.truncate("abcdefghij", 0, 3) = "abc"
9045     * StringUtils.truncate("abcdefghij", 5, 6) = "fghij"
9046     * StringUtils.truncate("raspberry peach", 10, 15) = "peach"
9047     * StringUtils.truncate("abcdefghijklmno", 0, 10) = "abcdefghij"
9048     * StringUtils.truncate("abcdefghijklmno", -1, 10) = throws an IllegalArgumentException
9049     * StringUtils.truncate("abcdefghijklmno", Integer.MIN_VALUE, 10) = throws an IllegalArgumentException
9050     * StringUtils.truncate("abcdefghijklmno", Integer.MIN_VALUE, Integer.MAX_VALUE) = throws an IllegalArgumentException
9051     * StringUtils.truncate("abcdefghijklmno", 0, Integer.MAX_VALUE) = "abcdefghijklmno"
9052     * StringUtils.truncate("abcdefghijklmno", 1, 10) = "bcdefghijk"
9053     * StringUtils.truncate("abcdefghijklmno", 2, 10) = "cdefghijkl"
9054     * StringUtils.truncate("abcdefghijklmno", 3, 10) = "defghijklm"
9055     * StringUtils.truncate("abcdefghijklmno", 4, 10) = "efghijklmn"
9056     * StringUtils.truncate("abcdefghijklmno", 5, 10) = "fghijklmno"
9057     * StringUtils.truncate("abcdefghijklmno", 5, 5) = "fghij"
9058     * StringUtils.truncate("abcdefghijklmno", 5, 3) = "fgh"
9059     * StringUtils.truncate("abcdefghijklmno", 10, 3) = "klm"
9060     * StringUtils.truncate("abcdefghijklmno", 10, Integer.MAX_VALUE) = "klmno"
9061     * StringUtils.truncate("abcdefghijklmno", 13, 1) = "n"
9062     * StringUtils.truncate("abcdefghijklmno", 13, Integer.MAX_VALUE) = "no"
9063     * StringUtils.truncate("abcdefghijklmno", 14, 1) = "o"
9064     * StringUtils.truncate("abcdefghijklmno", 14, Integer.MAX_VALUE) = "o"
9065     * StringUtils.truncate("abcdefghijklmno", 15, 1) = ""
9066     * StringUtils.truncate("abcdefghijklmno", 15, Integer.MAX_VALUE) = ""
9067     * StringUtils.truncate("abcdefghijklmno", Integer.MAX_VALUE, Integer.MAX_VALUE) = ""
9068     * StringUtils.truncate("abcdefghij", 3, -1) = throws an IllegalArgumentException
9069     * StringUtils.truncate("abcdefghij", -2, 4) = throws an IllegalArgumentException
9070     * </pre>
9071     *
9072     * @param str      The String to truncate, may be null.
9073     * @param offset   left edge of source String.
9074     * @param maxWidth maximum length of result String, must be non-negative.
9075     * @return truncated String, {@code null} if null String input.
9076     * @throws IllegalArgumentException Thrown if {@code offset} or {@code maxWidth} is less than {@code 0}.
9077     * @since 3.5
9078     */
9079    public static String truncate(final String str, final int offset, final int maxWidth) {
9080        if (offset < 0) {
9081            throw new IllegalArgumentException("offset cannot be negative");
9082        }
9083        if (maxWidth < 0) {
9084            throw new IllegalArgumentException("maxWidth cannot be negative");
9085        }
9086        if (str == null) {
9087            return null;
9088        }
9089        final int len = str.length();
9090        int start = Math.min(offset, len);
9091        int end = Math.min(offset > len - maxWidth ? len : offset + maxWidth, len);
9092        // keep both edges off the middle of a surrogate pair so the result is never left holding a lone surrogate
9093        if (splitsSurrogatePair(str, start)) {
9094            start++;
9095        }
9096        if (splitsSurrogatePair(str, end)) {
9097            end--;
9098        }
9099        return str.substring(start, Math.max(start, end));
9100    }
9101
9102    /**
9103     * Uncapitalizes a String, changing the first character to lower case as per {@link Character#toLowerCase(int)}. No other characters are changed.
9104     *
9105     * <p>
9106     * For a word based algorithm, see {@link org.apache.commons.text.WordUtils#uncapitalize(String)}. A {@code null} input String returns {@code null}.
9107     * </p>
9108     *
9109     * <pre>
9110     * StringUtils.uncapitalize(null)  = null
9111     * StringUtils.uncapitalize("")    = ""
9112     * StringUtils.uncapitalize("cat") = "cat"
9113     * StringUtils.uncapitalize("Cat") = "cat"
9114     * StringUtils.uncapitalize("CAT") = "cAT"
9115     * </pre>
9116     *
9117     * @param str The String to uncapitalize, may be null.
9118     * @return The uncapitalized String, {@code null} if null String input.
9119     * @see org.apache.commons.text.WordUtils#uncapitalize(String)
9120     * @see #capitalize(String)
9121     * @since 2.0
9122     */
9123    public static String uncapitalize(final String str) {
9124        final int strLen = length(str);
9125        if (strLen == 0) {
9126            return str;
9127        }
9128        final int firstCodePoint = str.codePointAt(0);
9129        final int newCodePoint = Character.toLowerCase(firstCodePoint);
9130        if (firstCodePoint == newCodePoint) {
9131            // already uncapitalized
9132            return str;
9133        }
9134        final int[] newCodePoints = str.codePoints().toArray();
9135        newCodePoints[0] = newCodePoint; // copy the first code point
9136        return new String(newCodePoints, 0, newCodePoints.length);
9137    }
9138
9139    /**
9140     * Unwraps a given string from a character.
9141     *
9142     * <pre>
9143     * StringUtils.unwrap(null, null)         = null
9144     * StringUtils.unwrap(null, '\0')         = null
9145     * StringUtils.unwrap(null, '1')          = null
9146     * StringUtils.unwrap("a", 'a')           = "a"
9147     * StringUtils.unwrap("aa", 'a')           = ""
9148     * StringUtils.unwrap("\'abc\'", '\'')    = "abc"
9149     * StringUtils.unwrap("AABabcBAA", 'A')   = "ABabcBA"
9150     * StringUtils.unwrap("A", '#')           = "A"
9151     * StringUtils.unwrap("#A", '#')          = "#A"
9152     * StringUtils.unwrap("A#", '#')          = "A#"
9153     * </pre>
9154     *
9155     * @param str      The String to be unwrapped, can be null.
9156     * @param wrapChar The character used to unwrap.
9157     * @return unwrapped String or the original string if it is not quoted properly with the wrapChar.
9158     * @since 3.6
9159     */
9160    public static String unwrap(final String str, final char wrapChar) {
9161        if (isEmpty(str) || wrapChar == CharUtils.NUL || str.length() == 1) {
9162            return str;
9163        }
9164        if (str.charAt(0) == wrapChar && str.charAt(str.length() - 1) == wrapChar) {
9165            final int startIndex = 0;
9166            final int endIndex = str.length() - 1;
9167            return str.substring(startIndex + 1, endIndex);
9168        }
9169        return str;
9170    }
9171
9172    /**
9173     * Unwraps a given string from another string.
9174     *
9175     * <pre>
9176     * StringUtils.unwrap(null, null)         = null
9177     * StringUtils.unwrap(null, "")           = null
9178     * StringUtils.unwrap(null, "1")          = null
9179     * StringUtils.unwrap("a", "a")           = "a"
9180     * StringUtils.unwrap("aa", "a")          = ""
9181     * StringUtils.unwrap("\'abc\'", "\'")    = "abc"
9182     * StringUtils.unwrap("\"abc\"", "\"")    = "abc"
9183     * StringUtils.unwrap("AABabcBAA", "AA")  = "BabcB"
9184     * StringUtils.unwrap("A", "#")           = "A"
9185     * StringUtils.unwrap("#A", "#")          = "#A"
9186     * StringUtils.unwrap("A#", "#")          = "A#"
9187     * </pre>
9188     *
9189     * @param str       The String to be unwrapped, can be null.
9190     * @param wrapToken The String used to unwrap.
9191     * @return unwrapped String or the original string if it is not quoted properly with the wrapToken.
9192     * @since 3.6
9193     */
9194    public static String unwrap(final String str, final String wrapToken) {
9195        if (isEmpty(str) || isEmpty(wrapToken) || str.length() < 2 * wrapToken.length()) {
9196            return str;
9197        }
9198        if (Strings.CS.startsWith(str, wrapToken) && Strings.CS.endsWith(str, wrapToken)) {
9199            return str.substring(wrapToken.length(), str.lastIndexOf(wrapToken));
9200        }
9201        return str;
9202    }
9203
9204    /**
9205     * Converts a String to upper case as per {@link String#toUpperCase()}.
9206     *
9207     * <p>
9208     * A {@code null} input String returns {@code null}.
9209     * </p>
9210     *
9211     * <pre>
9212     * StringUtils.upperCase(null)  = null
9213     * StringUtils.upperCase("")    = ""
9214     * StringUtils.upperCase("aBc") = "ABC"
9215     * </pre>
9216     *
9217     * <p>
9218     * <strong>Note:</strong> As described in the documentation for {@link String#toUpperCase()}, the result of this method is affected by the current locale.
9219     * For platform-independent case transformations, the method {@link #upperCase(String, Locale)} should be used with a specific locale (e.g.
9220     * {@link Locale#ENGLISH}).
9221     * </p>
9222     *
9223     * @param str The String to upper case, may be null.
9224     * @return The upper-cased String, {@code null} if null String input.
9225     */
9226    public static String upperCase(final String str) {
9227        if (str == null) {
9228            return null;
9229        }
9230        return str.toUpperCase();
9231    }
9232
9233    /**
9234     * Converts a String to upper case as per {@link String#toUpperCase(Locale)}.
9235     *
9236     * <p>
9237     * A {@code null} input String returns {@code null}.
9238     * </p>
9239     *
9240     * <pre>
9241     * StringUtils.upperCase(null, Locale.ENGLISH)  = null
9242     * StringUtils.upperCase("", Locale.ENGLISH)    = ""
9243     * StringUtils.upperCase("aBc", Locale.ENGLISH) = "ABC"
9244     * </pre>
9245     *
9246     * @param str    The String to upper case, may be null.
9247     * @param locale The locale that defines the case transformation rules, must not be null.
9248     * @return The upper-cased String, {@code null} if null String input.
9249     * @since 2.5
9250     */
9251    public static String upperCase(final String str, final Locale locale) {
9252        if (str == null) {
9253            return null;
9254        }
9255        return str.toUpperCase(LocaleUtils.toLocale(locale));
9256    }
9257
9258    /**
9259     * Returns the string representation of the {@code char} array or null.
9260     *
9261     * @param value The character array.
9262     * @return A String or null.
9263     * @see String#valueOf(char[])
9264     * @since 3.9
9265     */
9266    public static String valueOf(final char[] value) {
9267        return value == null ? null : String.valueOf(value);
9268    }
9269
9270    /**
9271     * Wraps a string with a char.
9272     *
9273     * <pre>
9274     * StringUtils.wrap(null, *)        = null
9275     * StringUtils.wrap("", *)          = ""
9276     * StringUtils.wrap("ab", '\0')     = "ab"
9277     * StringUtils.wrap("ab", 'x')      = "xabx"
9278     * StringUtils.wrap("ab", '\'')     = "'ab'"
9279     * StringUtils.wrap("\"ab\"", '\"') = "\"\"ab\"\""
9280     * </pre>
9281     *
9282     * @param str      The string to be wrapped, may be {@code null}.
9283     * @param wrapWith The char that will wrap {@code str}.
9284     * @return The wrapped string, or {@code null} if {@code str == null}.
9285     * @since 3.4
9286     */
9287    public static String wrap(final String str, final char wrapWith) {
9288        if (isEmpty(str) || wrapWith == CharUtils.NUL) {
9289            return str;
9290        }
9291        return wrapWith + str + wrapWith;
9292    }
9293
9294    /**
9295     * Wraps a String with another String.
9296     *
9297     * <p>
9298     * A {@code null} input String returns {@code null}.
9299     * </p>
9300     *
9301     * <pre>
9302     * StringUtils.wrap(null, *)         = null
9303     * StringUtils.wrap("", *)           = ""
9304     * StringUtils.wrap("ab", null)      = "ab"
9305     * StringUtils.wrap("ab", "x")       = "xabx"
9306     * StringUtils.wrap("ab", "\"")      = "\"ab\""
9307     * StringUtils.wrap("\"ab\"", "\"")  = "\"\"ab\"\""
9308     * StringUtils.wrap("ab", "'")       = "'ab'"
9309     * StringUtils.wrap("'abcd'", "'")   = "''abcd''"
9310     * StringUtils.wrap("\"abcd\"", "'") = "'\"abcd\"'"
9311     * StringUtils.wrap("'abcd'", "\"")  = "\"'abcd'\""
9312     * </pre>
9313     *
9314     * @param str      The String to be wrapper, may be null.
9315     * @param wrapWith The String that will wrap str.
9316     * @return wrapped String, {@code null} if null String input.
9317     * @since 3.4
9318     */
9319    public static String wrap(final String str, final String wrapWith) {
9320        if (isEmpty(str) || isEmpty(wrapWith)) {
9321            return str;
9322        }
9323        return wrapWith.concat(str).concat(wrapWith);
9324    }
9325
9326    /**
9327     * Wraps a string with a char if that char is missing from the start or end of the given string.
9328     *
9329     * <p>
9330     * A new {@link String} will not be created if {@code str} is already wrapped.
9331     * </p>
9332     *
9333     * <pre>
9334     * StringUtils.wrapIfMissing(null, *)        = null
9335     * StringUtils.wrapIfMissing("", *)          = ""
9336     * StringUtils.wrapIfMissing("ab", '\0')     = "ab"
9337     * StringUtils.wrapIfMissing("ab", 'x')      = "xabx"
9338     * StringUtils.wrapIfMissing("ab", '\'')     = "'ab'"
9339     * StringUtils.wrapIfMissing("\"ab\"", '\"') = "\"ab\""
9340     * StringUtils.wrapIfMissing("/", '/')  = "/"
9341     * StringUtils.wrapIfMissing("a/b/c", '/')  = "/a/b/c/"
9342     * StringUtils.wrapIfMissing("/a/b/c", '/')  = "/a/b/c/"
9343     * StringUtils.wrapIfMissing("a/b/c/", '/')  = "/a/b/c/"
9344     * </pre>
9345     *
9346     * @param str      The string to be wrapped, may be {@code null}.
9347     * @param wrapWith The char that will wrap {@code str}.
9348     * @return The wrapped string, or {@code null} if {@code str == null}.
9349     * @since 3.5
9350     */
9351    public static String wrapIfMissing(final String str, final char wrapWith) {
9352        if (isEmpty(str) || wrapWith == CharUtils.NUL) {
9353            return str;
9354        }
9355        final boolean wrapStart = str.charAt(0) != wrapWith;
9356        final boolean wrapEnd = str.charAt(str.length() - 1) != wrapWith;
9357        if (!wrapStart && !wrapEnd) {
9358            return str;
9359        }
9360        final StringBuilder builder = new StringBuilder(str.length() + 2);
9361        if (wrapStart) {
9362            builder.append(wrapWith);
9363        }
9364        builder.append(str);
9365        if (wrapEnd) {
9366            builder.append(wrapWith);
9367        }
9368        return builder.toString();
9369    }
9370
9371    /**
9372     * Wraps a string with a string if that string is missing from the start or end of the given string.
9373     *
9374     * <p>
9375     * A new {@link String} will not be created if {@code str} is already wrapped.
9376     * </p>
9377     *
9378     * <pre>
9379     * StringUtils.wrapIfMissing(null, *)         = null
9380     * StringUtils.wrapIfMissing("", *)           = ""
9381     * StringUtils.wrapIfMissing("ab", null)      = "ab"
9382     * StringUtils.wrapIfMissing("ab", "x")       = "xabx"
9383     * StringUtils.wrapIfMissing("ab", "\"")      = "\"ab\""
9384     * StringUtils.wrapIfMissing("\"ab\"", "\"")  = "\"ab\""
9385     * StringUtils.wrapIfMissing("ab", "'")       = "'ab'"
9386     * StringUtils.wrapIfMissing("'abcd'", "'")   = "'abcd'"
9387     * StringUtils.wrapIfMissing("\"abcd\"", "'") = "'\"abcd\"'"
9388     * StringUtils.wrapIfMissing("'abcd'", "\"")  = "\"'abcd'\""
9389     * StringUtils.wrapIfMissing("/", "/")  = "/"
9390     * StringUtils.wrapIfMissing("a/b/c", "/")  = "/a/b/c/"
9391     * StringUtils.wrapIfMissing("/a/b/c", "/")  = "/a/b/c/"
9392     * StringUtils.wrapIfMissing("a/b/c/", "/")  = "/a/b/c/"
9393     * </pre>
9394     *
9395     * @param str      The string to be wrapped, may be {@code null}.
9396     * @param wrapWith The string that will wrap {@code str}.
9397     * @return The wrapped string, or {@code null} if {@code str == null}.
9398     * @since 3.5
9399     */
9400    public static String wrapIfMissing(final String str, final String wrapWith) {
9401        if (isEmpty(str) || isEmpty(wrapWith)) {
9402            return str;
9403        }
9404        final boolean wrapStart = !str.startsWith(wrapWith);
9405        final boolean wrapEnd = !str.endsWith(wrapWith);
9406        if (!wrapStart && !wrapEnd) {
9407            return str;
9408        }
9409        final StringBuilder builder = new StringBuilder(str.length() + wrapWith.length() + wrapWith.length());
9410        if (wrapStart) {
9411            builder.append(wrapWith);
9412        }
9413        builder.append(str);
9414        if (wrapEnd) {
9415            builder.append(wrapWith);
9416        }
9417        return builder.toString();
9418    }
9419
9420    /**
9421     * {@link StringUtils} instances should NOT be constructed in standard programming. Instead, the class should be used as {@code StringUtils.trim(" foo ");}.
9422     *
9423     * <p>
9424     * This constructor is public to permit tools that require a JavaBean instance to operate.
9425     * </p>
9426     *
9427     * @deprecated TODO Make private in 4.0.
9428     */
9429    @Deprecated
9430    public StringUtils() {
9431        // empty
9432    }
9433
9434}