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>Wrap</strong>
076 *      - wraps a String with a character or another String</li>
077 *  <li><strong>WrapIfMissing</strong>
078 *      - wraps a String only where the wrapping character or String is missing</li>
079 *  <li><strong>Unwrap</strong>
080 *      - removes matching wrapping characters or Strings from both ends of a String</li>
081 *  <li><strong>LeftPad/RightPad/Center/Repeat</strong>
082 *      - pads a String</li>
083 *  <li><strong>UpperCase/LowerCase/SwapCase/Capitalize/Uncapitalize</strong>
084 *      - changes the case of a String</li>
085 *  <li><strong>CountMatches</strong>
086 *      - counts the number of occurrences of one String in another</li>
087 *  <li><strong>IsAlpha/IsNumeric/IsWhitespace/IsAsciiPrintable</strong>
088 *      - checks the characters in a String</li>
089 *  <li><strong>DefaultString</strong>
090 *      - protects against a null input String</li>
091 *  <li><strong>Rotate</strong>
092 *      - rotate (circular shift) a String</li>
093 *  <li><strong>Reverse/ReverseDelimited</strong>
094 *      - reverses a String</li>
095 *  <li><strong>Abbreviate</strong>
096 *      - abbreviates a string using ellipses or another given String</li>
097 *  <li><strong>Difference</strong>
098 *      - compares Strings and reports on their differences</li>
099 *  <li><strong>LevenshteinDistance</strong>
100 *      - the number of changes needed to change one String into another</li>
101 * </ul>
102 *
103 * <p>
104 * The {@link StringUtils} class defines certain words related to
105 * String handling.
106 * </p>
107 *
108 * <ul>
109 *  <li>null - {@code null}</li>
110 *  <li>empty - a zero-length string ({@code ""})</li>
111 *  <li>space - the space character ({@code ' '}, char 32)</li>
112 *  <li>whitespace - the characters defined by {@link Character#isWhitespace(char)}</li>
113 *  <li>trim - the characters &lt;= 32 as in {@link String#trim()}</li>
114 * </ul>
115 *
116 * <p>
117 * {@link StringUtils} handles {@code null} input Strings quietly.
118 * That is to say that a {@code null} input will return {@code null}.
119 * Where a {@code boolean} or {@code int} is being returned
120 * details vary by method.
121 * </p>
122 *
123 * <p>
124 * A side effect of the {@code null} handling is that a
125 * {@link NullPointerException} should be considered a bug in
126 * {@link StringUtils}.
127 * </p>
128 *
129 * <p>
130 * Methods in this class include sample code in their Javadoc comments to explain their operation.
131 * The symbol {@code *} is used to indicate any input including {@code null}.
132 * </p>
133 *
134 * <p>
135 * #ThreadSafe#
136 * </p>
137 *
138 * @see String
139 * @since 1.0
140 */
141//@Immutable
142public class StringUtils {
143
144    // Performance testing notes (JDK 1.4, Jul03, scolebourne)
145    // Whitespace:
146    // Character.isWhitespace() is faster than WHITESPACE.indexOf()
147    // where WHITESPACE is a string of all whitespace characters
148    //
149    // Character access:
150    // String.charAt(n) versus toCharArray(), then array[n]
151    // String.charAt(n) is about 15% worse for a 10K string
152    // They are about equal for a length 50 string
153    // String.charAt(n) is about 4 times better for a length 3 string
154    // String.charAt(n) is best bet overall
155    //
156    // Append:
157    // String.concat about twice as fast as StringBuffer.append
158    // (not sure who tested this)
159
160    /**
161     * This is a 3 character version of an ellipsis. There is a Unicode character for a HORIZONTAL ELLIPSIS, U+2026 '…', this isn't it.
162     */
163    private static final String ELLIPSIS3 = "...";
164
165    /**
166     * A String for a space character.
167     *
168     * @since 3.2
169     */
170    public static final String SPACE = " ";
171
172    /**
173     * The empty String {@code ""}.
174     *
175     * @since 2.0
176     */
177    public static final String EMPTY = "";
178
179    /**
180     * The null String {@code null}. Package-private only.
181     */
182    static final String NULL = null;
183
184    /**
185     * A String for linefeed LF ("\n").
186     *
187     * @see <a href="https://docs.oracle.com/javase/specs/jls/se8/html/jls-3.html#jls-3.10.6">JLF: Escape Sequences
188     *      for Character and String Literals</a>
189     * @since 3.2
190     */
191    public static final String LF = "\n";
192
193    /**
194     * A String for carriage return CR ("\r").
195     *
196     * @see <a href="https://docs.oracle.com/javase/specs/jls/se8/html/jls-3.html#jls-3.10.6">JLF: Escape Sequences
197     *      for Character and String Literals</a>
198     * @since 3.2
199     */
200    public static final String CR = "\r";
201
202    /**
203     * Represents a failed index search.
204     *
205     * @since 2.1
206     */
207    public static final int INDEX_NOT_FOUND = -1;
208
209    /**
210     * The maximum size to which the padding constant(s) can expand.
211     */
212    private static final int PAD_LIMIT = 8192;
213
214    /**
215     * The default maximum depth at which recursive replacement will continue until no further search replacements are possible.
216     */
217    private static final int DEFAULT_TTL = 5;
218
219    /**
220     * Pattern used in {@link #stripAccents(String)}.
221     */
222    private static final Pattern STRIP_ACCENTS_PATTERN = Pattern.compile("\\p{InCombiningDiacriticalMarks}+"); //$NON-NLS-1$
223
224    /**
225     * Abbreviates a String using ellipses. This will convert "Now is the time for all good men" into "Now is the time for..."
226     *
227     * <p>
228     * Specifically:
229     * </p>
230     * <ul>
231     * <li>If the number of characters in {@code str} is less than or equal to {@code maxWidth}, return {@code str}.</li>
232     * <li>Else abbreviate it to {@code (substring(str, 0, max - 3) + "...")}.</li>
233     * <li>If {@code maxWidth} is less than {@code 4}, throw an {@link IllegalArgumentException}.</li>
234     * <li>In no case will it return a String of length greater than {@code maxWidth}.</li>
235     * </ul>
236     *
237     * <pre>
238     * StringUtils.abbreviate(null, *)      = null
239     * StringUtils.abbreviate("", 4)        = ""
240     * StringUtils.abbreviate("abcdefg", 6) = "abc..."
241     * StringUtils.abbreviate("abcdefg", 7) = "abcdefg"
242     * StringUtils.abbreviate("abcdefg", 8) = "abcdefg"
243     * StringUtils.abbreviate("abcdefg", 4) = "a..."
244     * StringUtils.abbreviate("abcdefg", 3) = Throws {@link IllegalArgumentException}.
245     * </pre>
246     *
247     * @param str      The String to check, may be null.
248     * @param maxWidth maximum length of result String, must be at least 4.
249     * @return abbreviated String, {@code null} if null String input.
250     * @throws IllegalArgumentException Thrown if the width is too small.
251     * @since 2.0
252     */
253    public static String abbreviate(final String str, final int maxWidth) {
254        return abbreviate(str, ELLIPSIS3, 0, maxWidth);
255    }
256
257    /**
258     * Abbreviates a String using ellipses. This will convert "Now is the time for all good men" into "...is the time for...".
259     *
260     * <p>
261     * 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
262     * leftmost character in the result, or the first character following the ellipses, but it will appear somewhere in the result.
263     * </p>
264     * <p>
265     * In no case will it return a String of length greater than {@code maxWidth}.
266     * </p>
267     *
268     * <pre>
269     * StringUtils.abbreviate(null, *, *)                = null
270     * StringUtils.abbreviate("", 0, 4)                  = ""
271     * StringUtils.abbreviate("abcdefghijklmno", -1, 10) = "abcdefg..."
272     * StringUtils.abbreviate("abcdefghijklmno", 0, 10)  = "abcdefg..."
273     * StringUtils.abbreviate("abcdefghijklmno", 1, 10)  = "abcdefg..."
274     * StringUtils.abbreviate("abcdefghijklmno", 4, 10)  = "abcdefg..."
275     * StringUtils.abbreviate("abcdefghijklmno", 5, 10)  = "...fghi..."
276     * StringUtils.abbreviate("abcdefghijklmno", 6, 10)  = "...ghij..."
277     * StringUtils.abbreviate("abcdefghijklmno", 8, 10)  = "...ijklmno"
278     * StringUtils.abbreviate("abcdefghijklmno", 10, 10) = "...ijklmno"
279     * StringUtils.abbreviate("abcdefghijklmno", 12, 10) = "...ijklmno"
280     * StringUtils.abbreviate("abcdefghij", 0, 3)        = Throws {@link IllegalArgumentException}.
281     * StringUtils.abbreviate("abcdefghij", 5, 6)        = Throws {@link IllegalArgumentException}.
282     * </pre>
283     *
284     * @param str      The String to check, may be null.
285     * @param offset   left edge of source String.
286     * @param maxWidth maximum length of result String, must be at least 4.
287     * @return abbreviated String, {@code null} if null String input.
288     * @throws IllegalArgumentException Thrown if the width is too small.
289     * @since 2.0
290     */
291    public static String abbreviate(final String str, final int offset, final int maxWidth) {
292        return abbreviate(str, ELLIPSIS3, offset, maxWidth);
293    }
294
295    /**
296     * 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..."
297     * when "..." is the replacement marker.
298     *
299     * <p>
300     * Specifically:
301     * </p>
302     * <ul>
303     * <li>If the number of characters in {@code str} is less than or equal to {@code maxWidth}, return {@code str}.</li>
304     * <li>Else abbreviate it to {@code (substring(str, 0, max - abbrevMarker.length) + abbrevMarker)}.</li>
305     * <li>If {@code maxWidth} is less than {@code abbrevMarker.length + 1}, throw an {@link IllegalArgumentException}.</li>
306     * <li>In no case will it return a String of length greater than {@code maxWidth}.</li>
307     * </ul>
308     *
309     * <pre>
310     * StringUtils.abbreviate(null, "...", *)      = null
311     * StringUtils.abbreviate("abcdefg", null, *)  = "abcdefg"
312     * StringUtils.abbreviate("", "...", 4)        = ""
313     * StringUtils.abbreviate("abcdefg", ".", 5)   = "abcd."
314     * StringUtils.abbreviate("abcdefg", ".", 7)   = "abcdefg"
315     * StringUtils.abbreviate("abcdefg", ".", 8)   = "abcdefg"
316     * StringUtils.abbreviate("abcdefg", "..", 4)  = "ab.."
317     * StringUtils.abbreviate("abcdefg", "..", 3)  = "a.."
318     * StringUtils.abbreviate("abcdefg", "..", 2)  = Throws {@link IllegalArgumentException}.
319     * StringUtils.abbreviate("abcdefg", "...", 3) = Throws {@link IllegalArgumentException}.
320     * </pre>
321     *
322     * @param str          The String to check, may be null.
323     * @param abbrevMarker The String used as replacement marker.
324     * @param maxWidth     maximum length of result String, must be at least {@code abbrevMarker.length + 1}.
325     * @return abbreviated String, {@code null} if null String input.
326     * @throws IllegalArgumentException Thrown if the width is too small.
327     * @since 3.6
328     */
329    public static String abbreviate(final String str, final String abbrevMarker, final int maxWidth) {
330        return abbreviate(str, abbrevMarker, 0, maxWidth);
331    }
332
333    /**
334     * 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
335     * the replacement marker.
336     * <p>
337     * 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
338     * be the leftmost character in the result, or the first character following the replacement marker, but it will appear somewhere in the result.
339     * </p>
340     * <p>
341     * In no case will it return a String of length greater than {@code maxWidth}.
342     * </p>
343     *
344     * <pre>
345     * StringUtils.abbreviate(null, null, *, *)                 = null
346     * StringUtils.abbreviate("abcdefghijklmno", null, *, *)    = "abcdefghijklmno"
347     * StringUtils.abbreviate("", "...", 0, 4)                  = ""
348     * StringUtils.abbreviate("abcdefghijklmno", "---", -1, 10) = "abcdefg---"
349     * StringUtils.abbreviate("abcdefghijklmno", ",", 0, 10)    = "abcdefghi,"
350     * StringUtils.abbreviate("abcdefghijklmno", ",", 1, 10)    = "abcdefghi,"
351     * StringUtils.abbreviate("abcdefghijklmno", ",", 2, 10)    = "abcdefghi,"
352     * StringUtils.abbreviate("abcdefghijklmno", "::", 4, 10)   = "::efghij::"
353     * StringUtils.abbreviate("abcdefghijklmno", "...", 6, 10)  = "...ghij..."
354     * StringUtils.abbreviate("abcdefghijklmno", "…", 6, 10)    = "…ghijklmno"
355     * StringUtils.abbreviate("abcdefghijklmno", "*", 9, 10)    = "*ghijklmno"
356     * StringUtils.abbreviate("abcdefghijklmno", "'", 10, 10)   = "'ghijklmno"
357     * StringUtils.abbreviate("abcdefghijklmno", "!", 12, 10)   = "!ghijklmno"
358     * StringUtils.abbreviate("abcdefghij", "abra", 0, 4)       = Throws {@link IllegalArgumentException}.
359     * StringUtils.abbreviate("abcdefghij", "...", 5, 6)        = Throws {@link IllegalArgumentException}.
360     * </pre>
361     *
362     * @param str          The String to check, may be null.
363     * @param abbrevMarker The String used as replacement marker, for example "...", or Unicode HORIZONTAL ELLIPSIS, U+2026 '…'.
364     * @param offset       left edge of source String.
365     * @param maxWidth     maximum length of result String, must be at least 4.
366     * @return abbreviated String, {@code null} if null String input.
367     * @throws IllegalArgumentException Thrown if the width is too small.
368     * @since 3.6
369     */
370    public static String abbreviate(final String str, String abbrevMarker, final int offset, final int maxWidth) {
371        if (isEmpty(str)) {
372            return str;
373        }
374        if (abbrevMarker == null) {
375            abbrevMarker = EMPTY;
376        }
377        final int abbrevMarkerLength = abbrevMarker.length();
378        final int minAbbrevWidth = abbrevMarkerLength + 1;
379        final int minAbbrevWidthOffset = abbrevMarkerLength + abbrevMarkerLength + 1;
380
381        if (maxWidth < minAbbrevWidth) {
382            throw new IllegalArgumentException(String.format("Minimum abbreviation width is %d", minAbbrevWidth));
383        }
384        final int strLen = str.length();
385        if (strLen <= maxWidth) {
386            return str;
387        }
388        if (strLen - offset <= maxWidth - abbrevMarkerLength) {
389            int tailStart = strLen - (maxWidth - abbrevMarkerLength);
390            if (splitsSurrogatePair(str, tailStart)) {
391                tailStart++;
392            }
393            return abbrevMarker + str.substring(tailStart);
394        }
395        if (offset <= abbrevMarkerLength + 1) {
396            int headEnd = maxWidth - abbrevMarkerLength;
397            if (splitsSurrogatePair(str, headEnd)) {
398                headEnd--;
399            }
400            return str.substring(0, headEnd) + abbrevMarker;
401        }
402        if (maxWidth < minAbbrevWidthOffset) {
403            throw new IllegalArgumentException(String.format("Minimum abbreviation width with offset is %d", minAbbrevWidthOffset));
404        }
405        int from = offset;
406        if (splitsSurrogatePair(str, from)) {
407            from++;
408        }
409        return abbrevMarker + abbreviate(str.substring(from), abbrevMarker, maxWidth - abbrevMarkerLength);
410    }
411
412    /**
413     * Abbreviates a String to the length passed, replacing the middle characters with the supplied replacement String.
414     *
415     * <p>
416     * This abbreviation only occurs if the following criteria is met:
417     * </p>
418     * <ul>
419     * <li>Neither the String for abbreviation nor the replacement String are null or empty</li>
420     * <li>The length to truncate to is less than the length of the supplied String</li>
421     * <li>The length to truncate to is greater than 0</li>
422     * <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
423     * abbreviation</li>
424     * </ul>
425     * <p>
426     * Otherwise, the returned String will be the same as the supplied String for abbreviation.
427     * </p>
428     *
429     * <pre>
430     * StringUtils.abbreviateMiddle(null, null, 0)    = null
431     * StringUtils.abbreviateMiddle("abc", null, 0)   = "abc"
432     * StringUtils.abbreviateMiddle("abc", ".", 0)    = "abc"
433     * StringUtils.abbreviateMiddle("abc", ".", 3)    = "abc"
434     * StringUtils.abbreviateMiddle("abcdef", ".", 4) = "ab.f"
435     * </pre>
436     *
437     * @param str    The String to abbreviate, may be null.
438     * @param middle The String to replace the middle characters with, may be null.
439     * @param length The length to abbreviate {@code str} to.
440     * @return The abbreviated String if the above criteria is met, or the original String supplied for abbreviation.
441     * @since 2.5
442     */
443    public static String abbreviateMiddle(final String str, final String middle, final int length) {
444        if (isAnyEmpty(str, middle) || length >= str.length() || length < middle.length() + 2) {
445            return str;
446        }
447        final int targetString = length - middle.length();
448        int startOffset = targetString / 2 + targetString % 2;
449        int endOffset = str.length() - targetString / 2;
450        // keep both cuts off the middle of a surrogate pair so the result is never left holding a lone surrogate
451        if (splitsSurrogatePair(str, startOffset)) {
452            startOffset--;
453        }
454        if (splitsSurrogatePair(str, endOffset)) {
455            endOffset++;
456        }
457        return str.substring(0, startOffset) + middle + str.substring(endOffset);
458    }
459
460    /**
461     * Appends the suffix to the end of the string if the string does not already end with any of the suffixes.
462     *
463     * <pre>
464     * StringUtils.appendIfMissing(null, null)      = null
465     * StringUtils.appendIfMissing("abc", null)     = "abc"
466     * StringUtils.appendIfMissing("", "xyz")       = "xyz"
467     * StringUtils.appendIfMissing("abc", "xyz")    = "abcxyz"
468     * StringUtils.appendIfMissing("abcxyz", "xyz") = "abcxyz"
469     * StringUtils.appendIfMissing("abcXYZ", "xyz") = "abcXYZxyz"
470     * </pre>
471     * <p>
472     * With additional suffixes,
473     * </p>
474     *
475     * <pre>
476     * StringUtils.appendIfMissing(null, null, null)       = null
477     * StringUtils.appendIfMissing("abc", null, null)      = "abc"
478     * StringUtils.appendIfMissing("", "xyz", null)        = "xyz"
479     * StringUtils.appendIfMissing("abc", "xyz", new CharSequence[]{null}) = "abcxyz"
480     * StringUtils.appendIfMissing("abc", "xyz", "")       = "abc"
481     * StringUtils.appendIfMissing("abc", "xyz", "mno")    = "abcxyz"
482     * StringUtils.appendIfMissing("abcxyz", "xyz", "mno") = "abcxyz"
483     * StringUtils.appendIfMissing("abcmno", "xyz", "mno") = "abcmno"
484     * StringUtils.appendIfMissing("abcXYZ", "xyz", "mno") = "abcXYZxyz"
485     * StringUtils.appendIfMissing("abcMNO", "xyz", "mno") = "abcMNOxyz"
486     * </pre>
487     *
488     * @param str      The string.
489     * @param suffix   The suffix to append to the end of the string.
490     * @param suffixes Additional suffixes that are valid terminators.
491     * @return A new String if suffix was appended, the same string otherwise.
492     * @since 3.2
493     * @deprecated Use {@link Strings#appendIfMissing(String, CharSequence, CharSequence...) Strings.CS.appendIfMissing(String, CharSequence, CharSequence...)}.
494     */
495    @Deprecated
496    public static String appendIfMissing(final String str, final CharSequence suffix, final CharSequence... suffixes) {
497        return Strings.CS.appendIfMissing(str, suffix, suffixes);
498    }
499
500    /**
501     * Appends the suffix to the end of the string if the string does not
502     * already end, case-insensitive, with any of the suffixes.
503     *
504     * <pre>
505     * StringUtils.appendIfMissingIgnoreCase(null, null)      = null
506     * StringUtils.appendIfMissingIgnoreCase("abc", null)     = "abc"
507     * StringUtils.appendIfMissingIgnoreCase("", "xyz")       = "xyz"
508     * StringUtils.appendIfMissingIgnoreCase("abc", "xyz")    = "abcxyz"
509     * StringUtils.appendIfMissingIgnoreCase("abcxyz", "xyz") = "abcxyz"
510     * StringUtils.appendIfMissingIgnoreCase("abcXYZ", "xyz") = "abcXYZ"
511     * </pre>
512     * <p>
513     * With additional suffixes,
514     * </p>
515     * <pre>
516     * StringUtils.appendIfMissingIgnoreCase(null, null, null)       = null
517     * StringUtils.appendIfMissingIgnoreCase("abc", null, null)      = "abc"
518     * StringUtils.appendIfMissingIgnoreCase("", "xyz", null)        = "xyz"
519     * StringUtils.appendIfMissingIgnoreCase("abc", "xyz", new CharSequence[]{null}) = "abcxyz"
520     * StringUtils.appendIfMissingIgnoreCase("abc", "xyz", "")       = "abc"
521     * StringUtils.appendIfMissingIgnoreCase("abc", "xyz", "mno")    = "abcxyz"
522     * StringUtils.appendIfMissingIgnoreCase("abcxyz", "xyz", "mno") = "abcxyz"
523     * StringUtils.appendIfMissingIgnoreCase("abcmno", "xyz", "mno") = "abcmno"
524     * StringUtils.appendIfMissingIgnoreCase("abcXYZ", "xyz", "mno") = "abcXYZ"
525     * StringUtils.appendIfMissingIgnoreCase("abcMNO", "xyz", "mno") = "abcMNO"
526     * </pre>
527     *
528     * @param str The string.
529     * @param suffix The suffix to append to the end of the string.
530     * @param suffixes Additional suffixes that are valid terminators.
531     * @return A new String if suffix was appended, the same string otherwise.
532     * @since 3.2
533     * @deprecated Use {@link Strings#appendIfMissing(String, CharSequence, CharSequence...) Strings.CI.appendIfMissing(String, CharSequence, CharSequence...)}.
534     */
535    @Deprecated
536    public static String appendIfMissingIgnoreCase(final String str, final CharSequence suffix, final CharSequence... suffixes) {
537        return Strings.CI.appendIfMissing(str, suffix, suffixes);
538    }
539
540    /**
541     * Computes the capacity required for a StringBuilder to hold {@code items} of {@code maxElementChars} characters plus the separators between them. The
542     * separator is assumed to be 1 character.
543     *
544     * @param count           The number of items.
545     * @param maxElementChars The maximum number of characters per item.
546     * @return A StringBuilder with the appropriate capacity.
547     */
548    private static StringBuilder capacity(final int count, final byte maxElementChars) {
549        return new StringBuilder(count * maxElementChars + count - 1);
550    }
551
552    /**
553     * Capitalizes a String changing the first character to title case as per {@link Character#toTitleCase(int)}. No other characters are changed.
554     *
555     * <p>
556     * For a word based algorithm, see {@link org.apache.commons.text.WordUtils#capitalize(String)}. A {@code null} input String returns {@code null}.
557     * </p>
558     *
559     * <pre>
560     * StringUtils.capitalize(null)    = null
561     * StringUtils.capitalize("")      = ""
562     * StringUtils.capitalize("cat")   = "Cat"
563     * StringUtils.capitalize("cAt")   = "CAt"
564     * StringUtils.capitalize("'cat'") = "'cat'"
565     * </pre>
566     *
567     * @param str The String to capitalize, may be null.
568     * @return The capitalized String, {@code null} if null String input.
569     * @see org.apache.commons.text.WordUtils#capitalize(String)
570     * @see #uncapitalize(String)
571     * @since 2.0
572     */
573    public static String capitalize(final String str) {
574        if (isEmpty(str)) {
575            return str;
576        }
577        final int firstCodepoint = str.codePointAt(0);
578        final int newCodePoint = Character.toTitleCase(firstCodepoint);
579        if (firstCodepoint == newCodePoint) {
580            // already capitalized
581            return str;
582        }
583        final int[] newCodePoints = str.codePoints().toArray();
584        newCodePoints[0] = newCodePoint; // copy the first code point
585        return new String(newCodePoints, 0, newCodePoints.length);
586    }
587
588    /**
589     * Centers a String in a larger String of size {@code size} using the space character (' ').
590     *
591     * <p>
592     * 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
593     * zero.
594     * </p>
595     *
596     * <p>
597     * Equivalent to {@code center(str, size, " ")}.
598     * </p>
599     *
600     * <pre>
601     * StringUtils.center(null, *)   = null
602     * StringUtils.center("", 4)     = "    "
603     * StringUtils.center("ab", -1)  = "ab"
604     * StringUtils.center("ab", 4)   = " ab "
605     * StringUtils.center("abcd", 2) = "abcd"
606     * StringUtils.center("a", 4)    = " a  "
607     * </pre>
608     *
609     * @param str  The String to center, may be null.
610     * @param size The int size of new String, negative treated as zero.
611     * @return centered String, {@code null} if null String input.
612     */
613    public static String center(final String str, final int size) {
614        return center(str, size, ' ');
615    }
616
617    /**
618     * Centers a String in a larger String of size {@code size}. Uses a supplied character as the value to pad the String with.
619     *
620     * <p>
621     * 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.
622     * </p>
623     *
624     * <pre>
625     * StringUtils.center(null, *, *)     = null
626     * StringUtils.center("", 4, ' ')     = "    "
627     * StringUtils.center("ab", -1, ' ')  = "ab"
628     * StringUtils.center("ab", 4, ' ')   = " ab "
629     * StringUtils.center("abcd", 2, ' ') = "abcd"
630     * StringUtils.center("a", 4, ' ')    = " a  "
631     * StringUtils.center("a", 4, 'y')    = "yayy"
632     * </pre>
633     *
634     * @param str     The String to center, may be null.
635     * @param size    The int size of new String, negative treated as zero.
636     * @param padChar The character to pad the new String with.
637     * @return centered String, {@code null} if null String input.
638     * @since 2.0
639     */
640    public static String center(String str, final int size, final char padChar) {
641        if (str == null || size <= 0) {
642            return str;
643        }
644        final int strLen = str.length();
645        final int pads = size - strLen;
646        if (pads <= 0) {
647            return str;
648        }
649        str = leftPad(str, strLen + pads / 2, padChar);
650        return rightPad(str, size, padChar);
651    }
652
653    /**
654     * Centers a String in a larger String of size {@code size}. Uses a supplied String as the value to pad the String with.
655     *
656     * <p>
657     * 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.
658     * If the requested padding length on either side would split a Unicode surrogate pair in {@code padStr}, the padding is shortened by one {@code char}
659     * (via delegation to {@link #leftPad(String, int, String)} and {@link #rightPad(String, int, String)}) to avoid introducing an unpaired
660     * surrogate by splitting the pair. In that case, the returned String may be shorter than {@code size}, but by no more than one {@code char}.
661     * </p>
662     *
663     * <pre>
664     * StringUtils.center(null, *, *)     = null
665     * StringUtils.center("", 4, " ")     = "    "
666     * StringUtils.center("ab", -1, " ")  = "ab"
667     * StringUtils.center("ab", 4, " ")   = " ab "
668     * StringUtils.center("abcd", 2, " ") = "abcd"
669     * StringUtils.center("a", 4, " ")    = " a  "
670     * StringUtils.center("a", 4, "yz")   = "yayz"
671     * StringUtils.center("abc", 7, null) = "  abc  "
672     * StringUtils.center("abc", 7, "")   = "  abc  "
673     * StringUtils.center("a", 2, "\uD83D\uDE00")   = "a"
674     * StringUtils.center("a", 3, "\uD83D\uDE00")   = "a\uD83D\uDE00"
675     * </pre>
676     *
677     * @param str    The String to center, may be null.
678     * @param size   The int size of new String, negative treated as zero.
679     * @param padStr The String to pad the new String with, must not be null or empty.
680     * @return centered String, {@code null} if null String input.
681     * @throws IllegalArgumentException Thrown if padStr is {@code null} or empty.
682     */
683    public static String center(String str, final int size, String padStr) {
684        if (str == null || size <= 0) {
685            return str;
686        }
687        if (isEmpty(padStr)) {
688            padStr = SPACE;
689        }
690        final int strLen = str.length();
691        final int pads = size - strLen;
692        if (pads <= 0) {
693            return str;
694        }
695        str = leftPad(str, strLen + pads / 2, padStr);
696        return rightPad(str, size, padStr);
697    }
698
699    private static void checkFromToIndex(final int startIndex, final int endIndex, final int length) {
700        if (startIndex < 0) {
701            throw new ArrayIndexOutOfBoundsException(startIndex);
702        }
703        if (endIndex > length) {
704            throw new ArrayIndexOutOfBoundsException(endIndex);
705        }
706    }
707
708    /**
709     * 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
710     * &quot;{@code \r\n}&quot;.
711     *
712     * <p>
713     * NOTE: This method changed in 2.0. It now more closely matches Perl chomp.
714     * </p>
715     *
716     * <pre>
717     * StringUtils.chomp(null)          = null
718     * StringUtils.chomp("")            = ""
719     * StringUtils.chomp("abc \r")      = "abc "
720     * StringUtils.chomp("abc\n")       = "abc"
721     * StringUtils.chomp("abc\r\n")     = "abc"
722     * StringUtils.chomp("abc\r\n\r\n") = "abc\r\n"
723     * StringUtils.chomp("abc\n\r")     = "abc\n"
724     * StringUtils.chomp("abc\n\rabc")  = "abc\n\rabc"
725     * StringUtils.chomp("\r")          = ""
726     * StringUtils.chomp("\n")          = ""
727     * StringUtils.chomp("\r\n")        = ""
728     * </pre>
729     *
730     * @param str The String to chomp a newline from, may be null.
731     * @return String without newline, {@code null} if null String input.
732     */
733    public static String chomp(final String str) {
734        if (isEmpty(str)) {
735            return str;
736        }
737        if (str.length() == 1) {
738            final char ch = str.charAt(0);
739            if (ch == CharUtils.CR || ch == CharUtils.LF) {
740                return EMPTY;
741            }
742            return str;
743        }
744        int lastIdx = str.length() - 1;
745        final char last = str.charAt(lastIdx);
746        if (last == CharUtils.LF) {
747            if (str.charAt(lastIdx - 1) == CharUtils.CR) {
748                lastIdx--;
749            }
750        } else if (last != CharUtils.CR) {
751            lastIdx++;
752        }
753        return str.substring(0, lastIdx);
754    }
755
756    /**
757     * Removes {@code separator} from the end of {@code str} if it's there, otherwise leave it alone.
758     *
759     * <p>
760     * NOTE: This method changed in version 2.0. It now more closely matches Perl chomp. For the previous behavior, use
761     * {@link #substringBeforeLast(String, String)}. This method uses {@link String#endsWith(String)}.
762     * </p>
763     *
764     * <pre>
765     * StringUtils.chomp(null, *)         = null
766     * StringUtils.chomp("", *)           = ""
767     * StringUtils.chomp("foobar", "bar") = "foo"
768     * StringUtils.chomp("foobar", "baz") = "foobar"
769     * StringUtils.chomp("foo", "foo")    = ""
770     * StringUtils.chomp("foo ", "foo")   = "foo "
771     * StringUtils.chomp(" foo", "foo")   = " "
772     * StringUtils.chomp("foo", "foooo")  = "foo"
773     * StringUtils.chomp("foo", "")       = "foo"
774     * StringUtils.chomp("foo", null)     = "foo"
775     * </pre>
776     *
777     * @param str       The String to chomp from, may be null.
778     * @param separator separator String, may be null.
779     * @return String without trailing separator, {@code null} if null String input.
780     * @deprecated This feature will be removed in Lang 4, use {@link StringUtils#removeEnd(String, String)} instead.
781     */
782    @Deprecated
783    public static String chomp(final String str, final String separator) {
784        return Strings.CS.removeEnd(str, separator);
785    }
786
787    /**
788     * Removes the last character from a String.
789     *
790     * <p>
791     * If the String ends in {@code \r\n}, then remove both of them.
792     * </p>
793     *
794     * <pre>
795     * StringUtils.chop(null)          = null
796     * StringUtils.chop("")            = ""
797     * StringUtils.chop("abc \r")      = "abc "
798     * StringUtils.chop("abc\n")       = "abc"
799     * StringUtils.chop("abc\r\n")     = "abc"
800     * StringUtils.chop("abc")         = "ab"
801     * StringUtils.chop("abc\nabc")    = "abc\nab"
802     * StringUtils.chop("a")           = ""
803     * StringUtils.chop("\r")          = ""
804     * StringUtils.chop("\n")          = ""
805     * StringUtils.chop("\r\n")        = ""
806     * </pre>
807     *
808     * @param str The String to chop last character from, may be null.
809     * @return String without last character, {@code null} if null String input.
810     */
811    public static String chop(final String str) {
812        if (str == null) {
813            return null;
814        }
815        final int strLen = str.length();
816        if (strLen < 2) {
817            return EMPTY;
818        }
819        final int lastIdx = strLen - 1;
820        // keep the cut off the middle of a surrogate pair so the result is never left holding a lone surrogate
821        if (splitsSurrogatePair(str, lastIdx)) {
822            return str.substring(0, lastIdx - 1);
823        }
824        final String ret = str.substring(0, lastIdx);
825        final char last = str.charAt(lastIdx);
826        if (last == CharUtils.LF && ret.charAt(lastIdx - 1) == CharUtils.CR) {
827            return ret.substring(0, lastIdx - 1);
828        }
829        return ret;
830    }
831
832    /**
833     * Compares two Strings lexicographically, as per {@link String#compareTo(String)}, returning :
834     * <ul>
835     * <li>{@code int = 0}, if {@code str1} is equal to {@code str2} (or both {@code null})</li>
836     * <li>{@code int < 0}, if {@code str1} is less than {@code str2}</li>
837     * <li>{@code int > 0}, if {@code str1} is greater than {@code str2}</li>
838     * </ul>
839     *
840     * <p>
841     * This is a {@code null} safe version of:
842     * </p>
843     *
844     * <pre>
845     * str1.compareTo(str2)
846     * </pre>
847     *
848     * <p>
849     * {@code null} value is considered less than non-{@code null} value. Two {@code null} references are considered equal.
850     * </p>
851     *
852     * <pre>{@code
853     * StringUtils.compare(null, null)   = 0
854     * StringUtils.compare(null , "a")   < 0
855     * StringUtils.compare("a", null)   > 0
856     * StringUtils.compare("abc", "abc") = 0
857     * StringUtils.compare("a", "b")     < 0
858     * StringUtils.compare("b", "a")     > 0
859     * StringUtils.compare("a", "B")     > 0
860     * StringUtils.compare("ab", "abc")  < 0
861     * }</pre>
862     *
863     * @param str1 The String to compare from.
864     * @param str2 The String to compare to.
865     * @return &lt; 0, 0, &gt; 0, if {@code str1} is respectively less, equal or greater than {@code str2}.
866     * @see #compare(String, String, boolean)
867     * @see String#compareTo(String)
868     * @since 3.5
869     * @deprecated Use {@link Strings#compare(String, String) Strings.CS.compare(String, String)}.
870     */
871    @Deprecated
872    public static int compare(final String str1, final String str2) {
873        return Strings.CS.compare(str1, str2);
874    }
875
876    /**
877     * Compares two Strings lexicographically, as per {@link String#compareTo(String)}, returning :
878     * <ul>
879     * <li>{@code int = 0}, if {@code str1} is equal to {@code str2} (or both {@code null})</li>
880     * <li>{@code int < 0}, if {@code str1} is less than {@code str2}</li>
881     * <li>{@code int > 0}, if {@code str1} is greater than {@code str2}</li>
882     * </ul>
883     *
884     * <p>
885     * This is a {@code null} safe version of :
886     * </p>
887     *
888     * <pre>
889     * str1.compareTo(str2)
890     * </pre>
891     *
892     * <p>
893     * {@code null} inputs are handled according to the {@code nullIsLess} parameter. Two {@code null} references are considered equal.
894     * </p>
895     *
896     * <pre>{@code
897     * StringUtils.compare(null, null, *)     = 0
898     * StringUtils.compare(null , "a", true)  < 0
899     * StringUtils.compare(null , "a", false) > 0
900     * StringUtils.compare("a", null, true)   > 0
901     * StringUtils.compare("a", null, false)  < 0
902     * StringUtils.compare("abc", "abc", *)   = 0
903     * StringUtils.compare("a", "b", *)       < 0
904     * StringUtils.compare("b", "a", *)       > 0
905     * StringUtils.compare("a", "B", *)       > 0
906     * StringUtils.compare("ab", "abc", *)    < 0
907     * }</pre>
908     *
909     * @param str1       The String to compare from.
910     * @param str2       The String to compare to.
911     * @param nullIsLess whether consider {@code null} value less than non-{@code null} value.
912     * @return &lt; 0, 0, &gt; 0, if {@code str1} is respectively less, equal ou greater than {@code str2}.
913     * @see String#compareTo(String)
914     * @since 3.5
915     */
916    public static int compare(final String str1, final String str2, final boolean nullIsLess) {
917        if (str1 == str2) { // NOSONARLINT this intentionally uses == to allow for both null
918            return 0;
919        }
920        if (str1 == null) {
921            return nullIsLess ? -1 : 1;
922        }
923        if (str2 == null) {
924            return nullIsLess ? 1 : -1;
925        }
926        return str1.compareTo(str2);
927    }
928
929    /**
930     * Compares two Strings lexicographically, ignoring case differences, as per {@link String#compareToIgnoreCase(String)}, returning :
931     * <ul>
932     * <li>{@code int = 0}, if {@code str1} is equal to {@code str2} (or both {@code null})</li>
933     * <li>{@code int < 0}, if {@code str1} is less than {@code str2}</li>
934     * <li>{@code int > 0}, if {@code str1} is greater than {@code str2}</li>
935     * </ul>
936     *
937     * <p>
938     * This is a {@code null} safe version of:
939     * </p>
940     *
941     * <pre>
942     * str1.compareToIgnoreCase(str2)
943     * </pre>
944     *
945     * <p>
946     * {@code null} value is considered less than non-{@code null} value. Two {@code null} references are considered equal. Comparison is case insensitive.
947     * </p>
948     *
949     * <pre>{@code
950     * StringUtils.compareIgnoreCase(null, null)   = 0
951     * StringUtils.compareIgnoreCase(null , "a")   < 0
952     * StringUtils.compareIgnoreCase("a", null)    > 0
953     * StringUtils.compareIgnoreCase("abc", "abc") = 0
954     * StringUtils.compareIgnoreCase("abc", "ABC") = 0
955     * StringUtils.compareIgnoreCase("a", "b")     < 0
956     * StringUtils.compareIgnoreCase("b", "a")     > 0
957     * StringUtils.compareIgnoreCase("a", "B")     < 0
958     * StringUtils.compareIgnoreCase("A", "b")     < 0
959     * StringUtils.compareIgnoreCase("ab", "ABC")  < 0
960     * }</pre>
961     *
962     * @param str1 The String to compare from.
963     * @param str2 The String to compare to.
964     * @return &lt; 0, 0, &gt; 0, if {@code str1} is respectively less, equal ou greater than {@code str2}, ignoring case differences.
965     * @see #compareIgnoreCase(String, String, boolean)
966     * @see String#compareToIgnoreCase(String)
967     * @since 3.5
968     * @deprecated Use {@link Strings#compare(String, String) Strings.CI.compare(String, String)}.
969     */
970    @Deprecated
971    public static int compareIgnoreCase(final String str1, final String str2) {
972        return Strings.CI.compare(str1, str2);
973    }
974
975    /**
976     * Compares two Strings lexicographically, ignoring case differences, as per {@link String#compareToIgnoreCase(String)}, returning :
977     * <ul>
978     * <li>{@code int = 0}, if {@code str1} is equal to {@code str2} (or both {@code null})</li>
979     * <li>{@code int < 0}, if {@code str1} is less than {@code str2}</li>
980     * <li>{@code int > 0}, if {@code str1} is greater than {@code str2}</li>
981     * </ul>
982     *
983     * <p>
984     * This is a {@code null} safe version of :
985     * </p>
986     * <pre>
987     * str1.compareToIgnoreCase(str2)
988     * </pre>
989     *
990     * <p>
991     * {@code null} inputs are handled according to the {@code nullIsLess} parameter. Two {@code null} references are considered equal. Comparison is case
992     * insensitive.
993     * </p>
994     *
995     * <pre>{@code
996     * StringUtils.compareIgnoreCase(null, null, *)     = 0
997     * StringUtils.compareIgnoreCase(null , "a", true)  < 0
998     * StringUtils.compareIgnoreCase(null , "a", false) > 0
999     * StringUtils.compareIgnoreCase("a", null, true)   > 0
1000     * StringUtils.compareIgnoreCase("a", null, false)  < 0
1001     * StringUtils.compareIgnoreCase("abc", "abc", *)   = 0
1002     * StringUtils.compareIgnoreCase("abc", "ABC", *)   = 0
1003     * StringUtils.compareIgnoreCase("a", "b", *)       < 0
1004     * StringUtils.compareIgnoreCase("b", "a", *)       > 0
1005     * StringUtils.compareIgnoreCase("a", "B", *)       < 0
1006     * StringUtils.compareIgnoreCase("A", "b", *)       < 0
1007     * StringUtils.compareIgnoreCase("ab", "abc", *)    < 0
1008     * }</pre>
1009     *
1010     * @param str1       The String to compare from.
1011     * @param str2       The String to compare to.
1012     * @param nullIsLess whether consider {@code null} value less than non-{@code null} value.
1013     * @return &lt; 0, 0, &gt; 0, if {@code str1} is respectively less, equal ou greater than {@code str2}, ignoring case differences.
1014     * @see String#compareToIgnoreCase(String)
1015     * @since 3.5
1016     */
1017    public static int compareIgnoreCase(final String str1, final String str2, final boolean nullIsLess) {
1018        if (str1 == str2) { // NOSONARLINT this intentionally uses == to allow for both null
1019            return 0;
1020        }
1021        if (str1 == null) {
1022            return nullIsLess ? -1 : 1;
1023        }
1024        if (str2 == null) {
1025            return nullIsLess ? 1 : -1;
1026        }
1027        return str1.compareToIgnoreCase(str2);
1028    }
1029
1030    /**
1031     * Tests if CharSequence contains a search CharSequence, handling {@code null}.
1032     * This method uses {@link String#indexOf(String)} if possible.
1033     *
1034     * <p>
1035     * A {@code null} CharSequence will return {@code false}.
1036     * </p>
1037     *
1038     * <pre>
1039     * StringUtils.contains(null, *)     = false
1040     * StringUtils.contains(*, null)     = false
1041     * StringUtils.contains("", "")      = true
1042     * StringUtils.contains("abc", "")   = true
1043     * StringUtils.contains("abc", "a")  = true
1044     * StringUtils.contains("abc", "z")  = false
1045     * </pre>
1046     *
1047     * @param seq  The CharSequence to check, may be null
1048     * @param searchSeq  The CharSequence to find, may be null
1049     * @return true if the CharSequence contains the search CharSequence,
1050     *  false if not or {@code null} string input
1051     * @since 2.0
1052     * @since 3.0 Changed signature from contains(String, String) to contains(CharSequence, CharSequence)
1053     * @deprecated Use {@link Strings#contains(CharSequence, CharSequence) Strings.CS.contains(CharSequence, CharSequence)}.
1054     */
1055    @Deprecated
1056    public static boolean contains(final CharSequence seq, final CharSequence searchSeq) {
1057        return Strings.CS.contains(seq, searchSeq);
1058    }
1059
1060    /**
1061     * Tests if CharSequence contains a search character, handling {@code null}. This method uses {@link String#indexOf(int)} if possible.
1062     *
1063     * <p>
1064     * A {@code null} or empty ("") CharSequence will return {@code false}.
1065     * </p>
1066     *
1067     * <pre>
1068     * StringUtils.contains(null, *)    = false
1069     * StringUtils.contains("", *)      = false
1070     * StringUtils.contains("abc", 'a') = true
1071     * StringUtils.contains("abc", 'z') = false
1072     * </pre>
1073     *
1074     * @param seq        The CharSequence to check, may be null
1075     * @param searchChar The character to find
1076     * @return true if the CharSequence contains the search character, false if not or {@code null} string input
1077     * @since 2.0
1078     * @since 3.0 Changed signature from contains(String, int) to contains(CharSequence, int)
1079     */
1080    public static boolean contains(final CharSequence seq, final int searchChar) {
1081        if (isEmpty(seq)) {
1082            return false;
1083        }
1084        return CharSequenceUtils.indexOf(seq, searchChar, 0) >= 0;
1085    }
1086
1087    /**
1088     * Tests if the CharSequence contains any character in the given set of characters.
1089     *
1090     * <p>
1091     * A {@code null} CharSequence will return {@code false}. A {@code null} or zero length search array will return {@code false}.
1092     * </p>
1093     *
1094     * <pre>
1095     * StringUtils.containsAny(null, *)                  = false
1096     * StringUtils.containsAny("", *)                    = false
1097     * StringUtils.containsAny(*, null)                  = false
1098     * StringUtils.containsAny(*, [])                    = false
1099     * StringUtils.containsAny("zzabyycdxx", 'z', 'a')   = true
1100     * StringUtils.containsAny("zzabyycdxx", 'b', 'y')   = true
1101     * StringUtils.containsAny("zzabyycdxx", 'z', 'y')   = true
1102     * StringUtils.containsAny("aba", 'z])               = false
1103     * </pre>
1104     *
1105     * @param cs          The CharSequence to check, may be null.
1106     * @param searchChars The chars to search for, may be null.
1107     * @return The {@code true} if any of the chars are found, {@code false} if no match or null input.
1108     * @since 2.4
1109     * @since 3.0 Changed signature from containsAny(String, char[]) to containsAny(CharSequence, char...)
1110     */
1111    public static boolean containsAny(final CharSequence cs, final char... searchChars) {
1112        if (isEmpty(cs) || ArrayUtils.isEmpty(searchChars)) {
1113            return false;
1114        }
1115        final int csLength = cs.length();
1116        final int searchLength = searchChars.length;
1117        final int csLast = csLength - 1;
1118        final int searchLast = searchLength - 1;
1119        for (int i = 0; i < csLength; i++) {
1120            final char ch = cs.charAt(i);
1121            for (int j = 0; j < searchLength; j++) {
1122                if (searchChars[j] == ch) {
1123                    if (Character.isHighSurrogate(ch)
1124                            ? j == searchLast || i < csLast && searchChars[j + 1] == cs.charAt(i + 1)
1125                            : j == 0 || !Character.isLowSurrogate(ch) || !Character.isHighSurrogate(searchChars[j - 1]) || i > 0 && searchChars[j - 1] == cs.charAt(i - 1)) {
1126                        return true;
1127                    }
1128                }
1129            }
1130        }
1131        return false;
1132    }
1133
1134    /**
1135     * Tests if the CharSequence contains any character in the given set of characters.
1136     *
1137     * <p>
1138     * A {@code null} CharSequence will return {@code false}. A {@code null} search CharSequence will return {@code false}.
1139     * </p>
1140     *
1141     * <pre>
1142     * StringUtils.containsAny(null, *)               = false
1143     * StringUtils.containsAny("", *)                 = false
1144     * StringUtils.containsAny(*, null)               = false
1145     * StringUtils.containsAny(*, "")                 = false
1146     * StringUtils.containsAny("zzabyycdxx", "za")    = true
1147     * StringUtils.containsAny("zzabyycdxx", "by")    = true
1148     * StringUtils.containsAny("zzabyycdxx", "zy")    = true
1149     * StringUtils.containsAny("zzabyycdxx", "\tx")   = true
1150     * StringUtils.containsAny("zzabyycdxx", "$.#yF") = true
1151     * StringUtils.containsAny("aba", "z")            = false
1152     * </pre>
1153     *
1154     * @param cs          The CharSequence to check, may be null.
1155     * @param searchChars The chars to search for, may be null.
1156     * @return The {@code true} if any of the chars are found, {@code false} if no match or null input.
1157     * @since 2.4
1158     * @since 3.0 Changed signature from containsAny(String, String) to containsAny(CharSequence, CharSequence)
1159     */
1160    public static boolean containsAny(final CharSequence cs, final CharSequence searchChars) {
1161        if (searchChars == null) {
1162            return false;
1163        }
1164        return containsAny(cs, CharSequenceUtils.toCharArray(searchChars));
1165    }
1166
1167    /**
1168     * Tests if the CharSequence contains any of the CharSequences in the given array.
1169     *
1170     * <p>
1171     * A {@code null} {@code cs} CharSequence will return {@code false}. A {@code null} or zero length search array will
1172     * return {@code false}.
1173     * </p>
1174     *
1175     * <pre>
1176     * StringUtils.containsAny(null, *)            = false
1177     * StringUtils.containsAny("", *)              = false
1178     * StringUtils.containsAny(*, null)            = false
1179     * StringUtils.containsAny(*, [])              = false
1180     * StringUtils.containsAny("abcd", "ab", null) = true
1181     * StringUtils.containsAny("abcd", "ab", "cd") = true
1182     * StringUtils.containsAny("abc", "d", "abc")  = true
1183     * </pre>
1184     *
1185     * @param cs The CharSequence to check, may be null.
1186     * @param searchCharSequences The array of CharSequences to search for, may be null. Individual CharSequences may be
1187     *        null as well.
1188     * @return {@code true} if any of the search CharSequences are found, {@code false} otherwise.
1189     * @since 3.4
1190     * @deprecated Use {@link Strings#containsAny(CharSequence, CharSequence...) Strings.CS.containsAny(CharSequence, CharSequence...)}.
1191     */
1192    @Deprecated
1193    public static boolean containsAny(final CharSequence cs, final CharSequence... searchCharSequences) {
1194        return Strings.CS.containsAny(cs, searchCharSequences);
1195    }
1196
1197    /**
1198     * Tests if the CharSequence contains any of the CharSequences in the given array, ignoring case.
1199     *
1200     * <p>
1201     * A {@code null} {@code cs} CharSequence will return {@code false}. A {@code null} or zero length search array will
1202     * return {@code false}.
1203     * </p>
1204     *
1205     * <pre>
1206     * StringUtils.containsAnyIgnoreCase(null, *)            = false
1207     * StringUtils.containsAnyIgnoreCase("", *)              = false
1208     * StringUtils.containsAnyIgnoreCase(*, null)            = false
1209     * StringUtils.containsAnyIgnoreCase(*, [])              = false
1210     * StringUtils.containsAnyIgnoreCase("abcd", "ab", null) = true
1211     * StringUtils.containsAnyIgnoreCase("abcd", "ab", "cd") = true
1212     * StringUtils.containsAnyIgnoreCase("abc", "d", "abc")  = true
1213     * StringUtils.containsAnyIgnoreCase("abc", "D", "ABC")  = true
1214     * StringUtils.containsAnyIgnoreCase("ABC", "d", "abc")  = true
1215     * </pre>
1216     *
1217     * @param cs The CharSequence to check, may be null.
1218     * @param searchCharSequences The array of CharSequences to search for, may be null. Individual CharSequences may be
1219     *        null as well.
1220     * @return {@code true} if any of the search CharSequences are found, {@code false} otherwise
1221     * @since 3.12.0
1222     * @deprecated Use {@link Strings#containsAny(CharSequence, CharSequence...) Strings.CI.containsAny(CharSequence, CharSequence...)}.
1223     */
1224    @Deprecated
1225    public static boolean containsAnyIgnoreCase(final CharSequence cs, final CharSequence... searchCharSequences) {
1226        return Strings.CI.containsAny(cs, searchCharSequences);
1227    }
1228
1229    /**
1230     * Tests if CharSequence contains a search CharSequence irrespective of case, handling {@code null}. Case-insensitivity is defined as by
1231     * {@link String#equalsIgnoreCase(String)}.
1232     *
1233     * <p>
1234     * A {@code null} CharSequence will return {@code false}.
1235     * </p>
1236     *
1237     * <pre>
1238     * StringUtils.containsIgnoreCase(null, *)    = false
1239     * StringUtils.containsIgnoreCase(*, null)    = false
1240     * StringUtils.containsIgnoreCase("", "")     = true
1241     * StringUtils.containsIgnoreCase("abc", "")  = true
1242     * StringUtils.containsIgnoreCase("abc", "a") = true
1243     * StringUtils.containsIgnoreCase("abc", "z") = false
1244     * StringUtils.containsIgnoreCase("abc", "A") = true
1245     * StringUtils.containsIgnoreCase("abc", "Z") = false
1246     * </pre>
1247     *
1248     * @param str       The CharSequence to check, may be null.
1249     * @param searchStr The CharSequence to find, may be null.
1250     * @return true if the CharSequence contains the search CharSequence irrespective of case or false if not or {@code null} string input.
1251     * @since 3.0 Changed signature from containsIgnoreCase(String, String) to containsIgnoreCase(CharSequence, CharSequence).
1252     * @deprecated Use {@link Strings#contains(CharSequence, CharSequence) Strings.CI.contains(CharSequence, CharSequence)}.
1253     */
1254    @Deprecated
1255    public static boolean containsIgnoreCase(final CharSequence str, final CharSequence searchStr) {
1256        return Strings.CI.contains(str, searchStr);
1257    }
1258
1259    /**
1260     * Tests that the CharSequence does not contain certain characters.
1261     *
1262     * <p>
1263     * A {@code null} CharSequence will return {@code true}. A {@code null} invalid character array will return {@code true}. An empty CharSequence (length()=0)
1264     * always returns true.
1265     * </p>
1266     *
1267     * <pre>
1268     * StringUtils.containsNone(null, *)               = true
1269     * StringUtils.containsNone(*, null)               = true
1270     * StringUtils.containsNone("", *)                 = true
1271     * StringUtils.containsNone("ab", '')              = true
1272     * StringUtils.containsNone("abab", 'x', 'y', 'z') = true
1273     * StringUtils.containsNone("ab1", 'x', 'y', 'z')  = true
1274     * StringUtils.containsNone("abz", 'x', 'y', 'z')  = false
1275     * </pre>
1276     *
1277     * @param cs          The CharSequence to check, may be null.
1278     * @param searchChars An array of invalid chars, may be null.
1279     * @return true if it contains none of the invalid chars, or is null.
1280     * @since 2.0
1281     * @since 3.0 Changed signature from containsNone(String, char[]) to containsNone(CharSequence, char...)
1282     */
1283    public static boolean containsNone(final CharSequence cs, final char... searchChars) {
1284        if (cs == null || searchChars == null) {
1285            return true;
1286        }
1287        final int csLen = cs.length();
1288        final int csLast = csLen - 1;
1289        final int searchLen = searchChars.length;
1290        final int searchLast = searchLen - 1;
1291        for (int i = 0; i < csLen; i++) {
1292            final char ch = cs.charAt(i);
1293            for (int j = 0; j < searchLen; j++) {
1294                if (searchChars[j] == ch) {
1295                    if (Character.isHighSurrogate(ch)
1296                            ? j == searchLast || i < csLast && searchChars[j + 1] == cs.charAt(i + 1)
1297                            : j == 0 || !Character.isLowSurrogate(ch) || !Character.isHighSurrogate(searchChars[j - 1]) || i > 0 && searchChars[j - 1] == cs.charAt(i - 1)) {
1298                        return false;
1299                    }
1300                }
1301            }
1302        }
1303        return true;
1304    }
1305
1306    /**
1307     * Tests that the CharSequence does not contain certain characters.
1308     *
1309     * <p>
1310     * A {@code null} CharSequence will return {@code true}. A {@code null} invalid character array will return {@code true}. An empty String ("") always
1311     * returns true.
1312     * </p>
1313     *
1314     * <pre>
1315     * StringUtils.containsNone(null, *)       = true
1316     * StringUtils.containsNone(*, null)       = true
1317     * StringUtils.containsNone("", *)         = true
1318     * StringUtils.containsNone("ab", "")      = true
1319     * StringUtils.containsNone("abab", "xyz") = true
1320     * StringUtils.containsNone("ab1", "xyz")  = true
1321     * StringUtils.containsNone("abz", "xyz")  = false
1322     * </pre>
1323     *
1324     * @param cs           The CharSequence to check, may be null.
1325     * @param invalidChars A String of invalid chars, may be null.
1326     * @return true if it contains none of the invalid chars, or is null.
1327     * @since 2.0
1328     * @since 3.0 Changed signature from containsNone(String, String) to containsNone(CharSequence, String)
1329     */
1330    public static boolean containsNone(final CharSequence cs, final String invalidChars) {
1331        if (invalidChars == null) {
1332            return true;
1333        }
1334        return containsNone(cs, invalidChars.toCharArray());
1335    }
1336
1337    /**
1338     * Tests if the CharSequence contains only certain characters.
1339     *
1340     * <p>
1341     * A {@code null} CharSequence will return {@code false}. A {@code null} valid character array will return {@code false}. An empty CharSequence (length()=0)
1342     * always returns {@code true}.
1343     * </p>
1344     *
1345     * <pre>
1346     * StringUtils.containsOnly(null, *)               = false
1347     * StringUtils.containsOnly(*, null)               = false
1348     * StringUtils.containsOnly("", *)                 = true
1349     * StringUtils.containsOnly("ab", '')              = false
1350     * StringUtils.containsOnly("abab", 'a', 'b', 'c') = true
1351     * StringUtils.containsOnly("ab1", 'a', 'b', 'c')  = false
1352     * StringUtils.containsOnly("abz", 'a', 'b', 'c')  = false
1353     * </pre>
1354     *
1355     * @param cs    The String to check, may be null.
1356     * @param valid An array of valid chars, may be null.
1357     * @return true if it only contains valid chars and is non-null.
1358     * @since 3.0 Changed signature from containsOnly(String, char[]) to containsOnly(CharSequence, char...)
1359     */
1360    public static boolean containsOnly(final CharSequence cs, final char... valid) {
1361        // All these pre-checks are to maintain API with an older version
1362        if (valid == null || cs == null) {
1363            return false;
1364        }
1365        if (isEmpty(cs)) {
1366            return true;
1367        }
1368        if (valid.length == 0) {
1369            return false;
1370        }
1371        return indexOfAnyBut(cs, valid) == INDEX_NOT_FOUND;
1372    }
1373
1374    /**
1375     * Tests if the CharSequence contains only certain characters.
1376     *
1377     * <p>
1378     * A {@code null} CharSequence will return {@code false}. A {@code null} valid character String will return {@code false}. An empty String (length()=0)
1379     * always returns {@code true}.
1380     * </p>
1381     *
1382     * <pre>
1383     * StringUtils.containsOnly(null, *)       = false
1384     * StringUtils.containsOnly(*, null)       = false
1385     * StringUtils.containsOnly("", *)         = true
1386     * StringUtils.containsOnly("ab", "")      = false
1387     * StringUtils.containsOnly("abab", "abc") = true
1388     * StringUtils.containsOnly("ab1", "abc")  = false
1389     * StringUtils.containsOnly("abz", "abc")  = false
1390     * </pre>
1391     *
1392     * @param cs         The CharSequence to check, may be null.
1393     * @param validChars A String of valid chars, may be null.
1394     * @return true if it only contains valid chars and is non-null.
1395     * @since 2.0
1396     * @since 3.0 Changed signature from containsOnly(String, String) to containsOnly(CharSequence, String)
1397     */
1398    public static boolean containsOnly(final CharSequence cs, final String validChars) {
1399        if (cs == null || validChars == null) {
1400            return false;
1401        }
1402        return containsOnly(cs, validChars.toCharArray());
1403    }
1404
1405    /**
1406     * Tests whether the given CharSequence contains any whitespace characters.
1407     *
1408     * <p>
1409     * Whitespace is defined by {@link Character#isWhitespace(char)}.
1410     * </p>
1411     *
1412     * <pre>
1413     * StringUtils.containsWhitespace(null)       = false
1414     * StringUtils.containsWhitespace("")         = false
1415     * StringUtils.containsWhitespace("ab")       = false
1416     * StringUtils.containsWhitespace(" ab")      = true
1417     * StringUtils.containsWhitespace("a b")      = true
1418     * StringUtils.containsWhitespace("ab ")      = true
1419     * </pre>
1420     *
1421     * @param seq The CharSequence to check (may be {@code null}).
1422     * @return {@code true} if the CharSequence is not empty and contains at least 1 (breaking) whitespace character.
1423     * @since 3.0
1424     */
1425    public static boolean containsWhitespace(final CharSequence seq) {
1426        if (isEmpty(seq)) {
1427            return false;
1428        }
1429        final int strLen = seq.length();
1430        for (int i = 0; i < strLen; i++) {
1431            if (Character.isWhitespace(seq.charAt(i))) {
1432                return true;
1433            }
1434        }
1435        return false;
1436    }
1437
1438    private static void convertRemainingAccentCharacters(final StringBuilder decomposed) {
1439        for (int i = 0; i < decomposed.length(); i++) {
1440            final char charAt = decomposed.charAt(i);
1441            switch (charAt) {
1442            case '\u0141':
1443                decomposed.setCharAt(i, 'L');
1444                break;
1445            case '\u0142':
1446                decomposed.setCharAt(i, 'l');
1447                break;
1448            // D with stroke
1449            case '\u0110':
1450                // LATIN CAPITAL LETTER D WITH STROKE
1451                decomposed.setCharAt(i, 'D');
1452                break;
1453            case '\u0111':
1454                // LATIN SMALL LETTER D WITH STROKE
1455                decomposed.setCharAt(i, 'd');
1456                break;
1457            // I with bar
1458            case '\u0197':
1459                decomposed.setCharAt(i, 'I');
1460                break;
1461            case '\u0268':
1462                decomposed.setCharAt(i, 'i');
1463                break;
1464            case '\u1D7B':
1465                decomposed.setCharAt(i, 'I');
1466                break;
1467            case '\u1DA4':
1468                decomposed.setCharAt(i, 'i');
1469                break;
1470            case '\u1DA7':
1471                decomposed.setCharAt(i, 'I');
1472                break;
1473            // U with bar
1474            case '\u0244':
1475                // LATIN CAPITAL LETTER U BAR
1476                decomposed.setCharAt(i, 'U');
1477                break;
1478            case '\u0289':
1479                // LATIN SMALL LETTER U BAR
1480                decomposed.setCharAt(i, 'u');
1481                break;
1482            case '\u1D7E':
1483                // LATIN SMALL CAPITAL LETTER U WITH STROKE
1484                decomposed.setCharAt(i, 'U');
1485                break;
1486            case '\u1DB6':
1487                // MODIFIER LETTER SMALL U BAR
1488                decomposed.setCharAt(i, 'u');
1489                break;
1490            // T with stroke
1491            case '\u0166':
1492                // LATIN CAPITAL LETTER T WITH STROKE
1493                decomposed.setCharAt(i, 'T');
1494                break;
1495            case '\u0167':
1496                // LATIN SMALL LETTER T WITH STROKE
1497                decomposed.setCharAt(i, 't');
1498                break;
1499            default:
1500                break;
1501            }
1502        }
1503    }
1504
1505    /**
1506     * Counts how many times the char appears in the given string.
1507     *
1508     * <p>
1509     * A {@code null} or empty ("") String input returns {@code 0}.
1510     * </p>
1511     *
1512     * <pre>
1513     * StringUtils.countMatches(null, *)      = 0
1514     * StringUtils.countMatches("", *)        = 0
1515     * StringUtils.countMatches("abba", '\0') = 0
1516     * StringUtils.countMatches("abba", 'a')  = 2
1517     * StringUtils.countMatches("abba", 'b')  = 2
1518     * StringUtils.countMatches("abba", 'x')  = 0
1519     * </pre>
1520     *
1521     * @param str The CharSequence to check, may be null.
1522     * @param ch  The char to count.
1523     * @return The number of occurrences, 0 if the CharSequence is {@code null}.
1524     * @since 3.4
1525     */
1526    public static int countMatches(final CharSequence str, final char ch) {
1527        if (isEmpty(str)) {
1528            return 0;
1529        }
1530        int count = 0;
1531        // We could also call str.toCharArray() for faster lookups but that would generate more garbage.
1532        for (int i = 0; i < str.length(); i++) {
1533            if (ch == str.charAt(i)) {
1534                count++;
1535            }
1536        }
1537        return count;
1538    }
1539
1540    /**
1541     * Counts how many times the substring appears in the larger string. Note that the code only counts non-overlapping matches.
1542     *
1543     * <p>
1544     * A {@code null} or empty ("") String input returns {@code 0}.
1545     * </p>
1546     *
1547     * <pre>
1548     * StringUtils.countMatches(null, *)        = 0
1549     * StringUtils.countMatches("", *)          = 0
1550     * StringUtils.countMatches("abba", null)   = 0
1551     * StringUtils.countMatches("abba", "")     = 0
1552     * StringUtils.countMatches("abba", "a")    = 2
1553     * StringUtils.countMatches("abba", "ab")   = 1
1554     * StringUtils.countMatches("abba", "xxx")  = 0
1555     * StringUtils.countMatches("ababa", "aba") = 1
1556     * </pre>
1557     *
1558     * @param str The CharSequence to check, may be null.
1559     * @param sub The substring to count, may be null.
1560     * @return The number of occurrences, 0 if either CharSequence is {@code null}.
1561     * @since 3.0 Changed signature from countMatches(String, String) to countMatches(CharSequence, CharSequence)
1562     */
1563    public static int countMatches(final CharSequence str, final CharSequence sub) {
1564        if (isEmpty(str) || isEmpty(sub)) {
1565            return 0;
1566        }
1567        int count = 0;
1568        int idx = 0;
1569        while ((idx = CharSequenceUtils.indexOf(str, sub, idx)) != INDEX_NOT_FOUND) {
1570            count++;
1571            idx += sub.length();
1572        }
1573        return count;
1574    }
1575
1576    /**
1577     * Returns either the passed in CharSequence, or if the CharSequence is {@link #isBlank(CharSequence) blank} (whitespaces, empty ({@code ""}), or
1578     * {@code null}), the value of {@code defaultStr}.
1579     *
1580     * <p>
1581     * Whitespace is defined by {@link Character#isWhitespace(char)}.
1582     * </p>
1583     *
1584     * <pre>
1585     * StringUtils.defaultIfBlank(null, "NULL")  = "NULL"
1586     * StringUtils.defaultIfBlank("", "NULL")    = "NULL"
1587     * StringUtils.defaultIfBlank(" ", "NULL")   = "NULL"
1588     * StringUtils.defaultIfBlank("bat", "NULL") = "bat"
1589     * StringUtils.defaultIfBlank("", null)      = null
1590     * </pre>
1591     *
1592     * @param <T>        the specific kind of CharSequence.
1593     * @param str        The CharSequence to check, may be null.
1594     * @param defaultStr The default CharSequence to return if {@code str} is {@link #isBlank(CharSequence) blank} (whitespaces, empty ({@code ""}), or
1595     *                   {@code null}); may be null.
1596     * @return The passed in CharSequence, or the default.
1597     * @see StringUtils#defaultString(String, String)
1598     * @see #isBlank(CharSequence)
1599     */
1600    public static <T extends CharSequence> T defaultIfBlank(final T str, final T defaultStr) {
1601        return isBlank(str) ? defaultStr : str;
1602    }
1603
1604    /**
1605     * Returns either the passed in CharSequence, or if the CharSequence is empty or {@code null}, the value of {@code defaultStr}.
1606     *
1607     * <pre>
1608     * StringUtils.defaultIfEmpty(null, "NULL")  = "NULL"
1609     * StringUtils.defaultIfEmpty("", "NULL")    = "NULL"
1610     * StringUtils.defaultIfEmpty(" ", "NULL")   = " "
1611     * StringUtils.defaultIfEmpty("bat", "NULL") = "bat"
1612     * StringUtils.defaultIfEmpty("", null)      = null
1613     * </pre>
1614     *
1615     * @param <T>        the specific kind of CharSequence.
1616     * @param str        The CharSequence to check, may be null.
1617     * @param defaultStr The default CharSequence to return if the input is empty ("") or {@code null}, may be null.
1618     * @return The passed in CharSequence, or the default.
1619     * @see StringUtils#defaultString(String, String)
1620     */
1621    public static <T extends CharSequence> T defaultIfEmpty(final T str, final T defaultStr) {
1622        return isEmpty(str) ? defaultStr : str;
1623    }
1624
1625    /**
1626     * Returns either the passed in String, or if the String is {@code null}, an empty String ("").
1627     *
1628     * <pre>
1629     * StringUtils.defaultString(null)  = ""
1630     * StringUtils.defaultString("")    = ""
1631     * StringUtils.defaultString("bat") = "bat"
1632     * </pre>
1633     *
1634     * @param str The String to check, may be null.
1635     * @return The passed in String, or the empty String if it was {@code null}.
1636     * @see Objects#toString(Object, String)
1637     * @see String#valueOf(Object)
1638     */
1639    public static String defaultString(final String str) {
1640        return Objects.toString(str, EMPTY);
1641    }
1642
1643    /**
1644     * Returns either the given String, or if the String is {@code null}, {@code nullDefault}.
1645     *
1646     * <pre>
1647     * StringUtils.defaultString(null, "NULL")  = "NULL"
1648     * StringUtils.defaultString("", "NULL")    = ""
1649     * StringUtils.defaultString("bat", "NULL") = "bat"
1650     * </pre>
1651     * <p>
1652     * Since this is now provided by Java, instead call {@link Objects#toString(Object, String)}:
1653     * </p>
1654     *
1655     * <pre>
1656     * Objects.toString(null, "NULL")  = "NULL"
1657     * Objects.toString("", "NULL")    = ""
1658     * Objects.toString("bat", "NULL") = "bat"
1659     * </pre>
1660     *
1661     * @param str         The String to check, may be null.
1662     * @param nullDefault The default String to return if the input is {@code null}, may be null.
1663     * @return The passed in String, or the default if it was {@code null}.
1664     * @see Objects#toString(Object, String)
1665     * @see String#valueOf(Object)
1666     * @deprecated Use {@link Objects#toString(Object, String)}.
1667     */
1668    @Deprecated
1669    public static String defaultString(final String str, final String nullDefault) {
1670        return Objects.toString(str, nullDefault);
1671    }
1672
1673    /**
1674     * Deletes all whitespaces from a String as defined by {@link Character#isWhitespace(char)}.
1675     *
1676     * <pre>
1677     * StringUtils.deleteWhitespace(null)         = null
1678     * StringUtils.deleteWhitespace("")           = ""
1679     * StringUtils.deleteWhitespace("abc")        = "abc"
1680     * StringUtils.deleteWhitespace("   ab  c  ") = "abc"
1681     * </pre>
1682     *
1683     * @param str The String to delete whitespace from, may be null.
1684     * @return The String without whitespaces, {@code null} if null String input.
1685     */
1686    public static String deleteWhitespace(final String str) {
1687        if (isEmpty(str)) {
1688            return str;
1689        }
1690        final int sz = str.length();
1691        final char[] chs = new char[sz];
1692        int count = 0;
1693        for (int i = 0; i < sz; i++) {
1694            if (!Character.isWhitespace(str.charAt(i))) {
1695                chs[count++] = str.charAt(i);
1696            }
1697        }
1698        if (count == sz) {
1699            return str;
1700        }
1701        if (count == 0) {
1702            return EMPTY;
1703        }
1704        return new String(chs, 0, count);
1705    }
1706
1707    /**
1708     * Compares two Strings, and returns the portion where they differ. More precisely, return the remainder of the second String, starting from where it's
1709     * different from the first. This means that the difference between "abc" and "ab" is the empty String and not "c".
1710     *
1711     * <p>
1712     * For example, {@code difference("i am a machine", "i am a robot") -> "robot"}.
1713     * </p>
1714     *
1715     * <pre>
1716     * StringUtils.difference(null, null)       = null
1717     * StringUtils.difference("", "")           = ""
1718     * StringUtils.difference("", "abc")        = "abc"
1719     * StringUtils.difference("abc", "")        = ""
1720     * StringUtils.difference("abc", "abc")     = ""
1721     * StringUtils.difference("abc", "ab")      = ""
1722     * StringUtils.difference("ab", "abxyz")    = "xyz"
1723     * StringUtils.difference("abcde", "abxyz") = "xyz"
1724     * StringUtils.difference("abcde", "xyz")   = "xyz"
1725     * </pre>
1726     *
1727     * @param str1 The first String, may be null.
1728     * @param str2 The second String, may be null.
1729     * @return The portion of str2 where it differs from str1; returns the empty String if they are equal.
1730     * @see #indexOfDifference(CharSequence,CharSequence)
1731     * @since 2.0
1732     */
1733    public static String difference(final String str1, final String str2) {
1734        if (str1 == null) {
1735            return str2;
1736        }
1737        if (str2 == null) {
1738            return str1;
1739        }
1740        final int at = indexOfDifference(str1, str2);
1741        if (at == INDEX_NOT_FOUND) {
1742            return EMPTY;
1743        }
1744        return str2.substring(at);
1745    }
1746
1747    /**
1748     * Tests if a CharSequence ends with a specified suffix.
1749     *
1750     * <p>
1751     * {@code null}s are handled without exceptions. Two {@code null} references are considered to be equal. The comparison is case-sensitive.
1752     * </p>
1753     *
1754     * <pre>
1755     * StringUtils.endsWith(null, null)      = true
1756     * StringUtils.endsWith(null, "def")     = false
1757     * StringUtils.endsWith("abcdef", null)  = false
1758     * StringUtils.endsWith("abcdef", "def") = true
1759     * StringUtils.endsWith("ABCDEF", "def") = false
1760     * StringUtils.endsWith("ABCDEF", "cde") = false
1761     * StringUtils.endsWith("ABCDEF", "")    = true
1762     * </pre>
1763     *
1764     * @param str    The CharSequence to check, may be null.
1765     * @param suffix The suffix to find, may be null.
1766     * @return {@code true} if the CharSequence ends with the suffix, case-sensitive, or both {@code null}.
1767     * @see String#endsWith(String)
1768     * @since 2.4
1769     * @since 3.0 Changed signature from endsWith(String, String) to endsWith(CharSequence, CharSequence)
1770     * @deprecated Use {@link Strings#endsWith(CharSequence, CharSequence) Strings.CS.endsWith(CharSequence, CharSequence)}.
1771     */
1772    @Deprecated
1773    public static boolean endsWith(final CharSequence str, final CharSequence suffix) {
1774        return Strings.CS.endsWith(str, suffix);
1775    }
1776
1777    /**
1778     * Tests if a CharSequence ends with any of the provided case-sensitive suffixes.
1779     *
1780     * <pre>
1781     * StringUtils.endsWithAny(null, null)                  = false
1782     * StringUtils.endsWithAny(null, new String[] {"abc"})  = false
1783     * StringUtils.endsWithAny("abcxyz", null)              = false
1784     * StringUtils.endsWithAny("abcxyz", new String[] {""}) = true
1785     * StringUtils.endsWithAny("abcxyz", new String[] {"xyz"}) = true
1786     * StringUtils.endsWithAny("abcxyz", new String[] {null, "xyz", "abc"}) = true
1787     * StringUtils.endsWithAny("abcXYZ", "def", "XYZ")      = true
1788     * StringUtils.endsWithAny("abcXYZ", "def", "xyz")      = false
1789     * </pre>
1790     *
1791     * @param sequence      The CharSequence to check, may be null.
1792     * @param searchStrings The case-sensitive CharSequences to find, may be empty or contain {@code null}.
1793     * @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
1794     *         of the provided case-sensitive {@code searchStrings}.
1795     * @see StringUtils#endsWith(CharSequence, CharSequence)
1796     * @since 3.0
1797     * @deprecated Use {@link Strings#endsWithAny(CharSequence, CharSequence...) Strings.CS.endsWithAny(CharSequence, CharSequence...)}.
1798     */
1799    @Deprecated
1800    public static boolean endsWithAny(final CharSequence sequence, final CharSequence... searchStrings) {
1801        return Strings.CS.endsWithAny(sequence, searchStrings);
1802    }
1803
1804    /**
1805     * Case-insensitive check if a CharSequence ends with a specified suffix.
1806     *
1807     * <p>
1808     * {@code null}s are handled without exceptions. Two {@code null} references are considered to be equal. The comparison is case insensitive.
1809     * </p>
1810     *
1811     * <pre>
1812     * StringUtils.endsWithIgnoreCase(null, null)      = true
1813     * StringUtils.endsWithIgnoreCase(null, "def")     = false
1814     * StringUtils.endsWithIgnoreCase("abcdef", null)  = false
1815     * StringUtils.endsWithIgnoreCase("abcdef", "def") = true
1816     * StringUtils.endsWithIgnoreCase("ABCDEF", "def") = true
1817     * StringUtils.endsWithIgnoreCase("ABCDEF", "cde") = false
1818     * </pre>
1819     *
1820     * @param str    The CharSequence to check, may be null
1821     * @param suffix The suffix to find, may be null
1822     * @return {@code true} if the CharSequence ends with the suffix, case-insensitive, or both {@code null}
1823     * @see String#endsWith(String)
1824     * @since 2.4
1825     * @since 3.0 Changed signature from endsWithIgnoreCase(String, String) to endsWithIgnoreCase(CharSequence, CharSequence)
1826     * @deprecated Use {@link Strings#endsWith(CharSequence, CharSequence) Strings.CI.endsWith(CharSequence, CharSequence)}.
1827     */
1828    @Deprecated
1829    public static boolean endsWithIgnoreCase(final CharSequence str, final CharSequence suffix) {
1830        return Strings.CI.endsWith(str, suffix);
1831    }
1832
1833    /**
1834     * Compares two CharSequences, returning {@code true} if they represent equal sequences of characters.
1835     *
1836     * <p>
1837     * {@code null}s are handled without exceptions. Two {@code null} references are considered to be equal. The comparison is <strong>case-sensitive</strong>.
1838     * </p>
1839     *
1840     * <pre>
1841     * StringUtils.equals(null, null)   = true
1842     * StringUtils.equals(null, "abc")  = false
1843     * StringUtils.equals("abc", null)  = false
1844     * StringUtils.equals("abc", "abc") = true
1845     * StringUtils.equals("abc", "ABC") = false
1846     * </pre>
1847     *
1848     * @param cs1 The first CharSequence, may be {@code null}.
1849     * @param cs2 The second CharSequence, may be {@code null}.
1850     * @return {@code true} if the CharSequences are equal (case-sensitive), or both {@code null}.
1851     * @since 3.0 Changed signature from equals(String, String) to equals(CharSequence, CharSequence)
1852     * @see Object#equals(Object)
1853     * @see #equalsIgnoreCase(CharSequence, CharSequence)
1854     * @deprecated Use {@link Strings#equals(CharSequence, CharSequence) Strings.CS.equals(CharSequence, CharSequence)}.
1855     */
1856    @Deprecated
1857    public static boolean equals(final CharSequence cs1, final CharSequence cs2) {
1858        return Strings.CS.equals(cs1, cs2);
1859    }
1860
1861    /**
1862     * Compares given {@code string} to a CharSequences vararg of {@code searchStrings}, returning {@code true} if the {@code string} is equal to any of the
1863     * {@code searchStrings}.
1864     *
1865     * <pre>
1866     * StringUtils.equalsAny(null, (CharSequence[]) null) = false
1867     * StringUtils.equalsAny(null, null, null)    = true
1868     * StringUtils.equalsAny(null, "abc", "def")  = false
1869     * StringUtils.equalsAny("abc", null, "def")  = false
1870     * StringUtils.equalsAny("abc", "abc", "def") = true
1871     * StringUtils.equalsAny("abc", "ABC", "DEF") = false
1872     * </pre>
1873     *
1874     * @param string        to compare, may be {@code null}.
1875     * @param searchStrings A vararg of strings, may be {@code null}.
1876     * @return {@code true} if the string is equal (case-sensitive) to any other element of {@code searchStrings}; {@code false} if {@code searchStrings} is
1877     *         null or contains no matches.
1878     * @since 3.5
1879     * @deprecated Use {@link Strings#equalsAny(CharSequence, CharSequence...) Strings.CS.equalsAny(CharSequence, CharSequence...)}.
1880     */
1881    @Deprecated
1882    public static boolean equalsAny(final CharSequence string, final CharSequence... searchStrings) {
1883        return Strings.CS.equalsAny(string, searchStrings);
1884    }
1885
1886    /**
1887     * Compares given {@code string} to a CharSequences vararg of {@code searchStrings},
1888     * returning {@code true} if the {@code string} is equal to any of the {@code searchStrings}, ignoring case.
1889     *
1890     * <pre>
1891     * StringUtils.equalsAnyIgnoreCase(null, (CharSequence[]) null) = false
1892     * StringUtils.equalsAnyIgnoreCase(null, null, null)    = true
1893     * StringUtils.equalsAnyIgnoreCase(null, "abc", "def")  = false
1894     * StringUtils.equalsAnyIgnoreCase("abc", null, "def")  = false
1895     * StringUtils.equalsAnyIgnoreCase("abc", "abc", "def") = true
1896     * StringUtils.equalsAnyIgnoreCase("abc", "ABC", "DEF") = true
1897     * </pre>
1898     *
1899     * @param string to compare, may be {@code null}.
1900     * @param searchStrings A vararg of strings, may be {@code null}.
1901     * @return {@code true} if the string is equal (case-insensitive) to any other element of {@code searchStrings};
1902     * {@code false} if {@code searchStrings} is null or contains no matches.
1903     * @since 3.5
1904     * @deprecated Use {@link Strings#equalsAny(CharSequence, CharSequence...) Strings.CI.equalsAny(CharSequence, CharSequence...)}.
1905     */
1906    @Deprecated
1907    public static boolean equalsAnyIgnoreCase(final CharSequence string, final CharSequence... searchStrings) {
1908        return Strings.CI.equalsAny(string, searchStrings);
1909    }
1910
1911    /**
1912     * Compares two CharSequences, returning {@code true} if they represent equal sequences of characters, ignoring case.
1913     *
1914     * <p>
1915     * {@code null}s are handled without exceptions. Two {@code null} references are considered equal. The comparison is <strong>case insensitive</strong>.
1916     * </p>
1917     *
1918     * <pre>
1919     * StringUtils.equalsIgnoreCase(null, null)   = true
1920     * StringUtils.equalsIgnoreCase(null, "abc")  = false
1921     * StringUtils.equalsIgnoreCase("abc", null)  = false
1922     * StringUtils.equalsIgnoreCase("abc", "abc") = true
1923     * StringUtils.equalsIgnoreCase("abc", "ABC") = true
1924     * </pre>
1925     *
1926     * @param cs1 The first CharSequence, may be {@code null}.
1927     * @param cs2 The second CharSequence, may be {@code null}.
1928     * @return {@code true} if the CharSequences are equal (case-insensitive), or both {@code null}.
1929     * @since 3.0 Changed signature from equalsIgnoreCase(String, String) to equalsIgnoreCase(CharSequence, CharSequence)
1930     * @see #equals(CharSequence, CharSequence)
1931     * @deprecated Use {@link Strings#equals(CharSequence, CharSequence) Strings.CI.equals(CharSequence, CharSequence)}.
1932     */
1933    @Deprecated
1934    public static boolean equalsIgnoreCase(final CharSequence cs1, final CharSequence cs2) {
1935        return Strings.CI.equals(cs1, cs2);
1936    }
1937
1938    /**
1939     * Returns the first value in the array which is not empty (""), {@code null} or whitespace only.
1940     *
1941     * <p>
1942     * Whitespace is defined by {@link Character#isWhitespace(char)}.
1943     * </p>
1944     *
1945     * <p>
1946     * If all values are blank or the array is {@code null} or empty then {@code null} is returned.
1947     * </p>
1948     *
1949     * <pre>
1950     * StringUtils.firstNonBlank(null, null, null)     = null
1951     * StringUtils.firstNonBlank(null, "", " ")        = null
1952     * StringUtils.firstNonBlank("abc")                = "abc"
1953     * StringUtils.firstNonBlank(null, "xyz")          = "xyz"
1954     * StringUtils.firstNonBlank(null, "", " ", "xyz") = "xyz"
1955     * StringUtils.firstNonBlank(null, "xyz", "abc")   = "xyz"
1956     * StringUtils.firstNonBlank()                     = null
1957     * </pre>
1958     *
1959     * @param <T>    the specific kind of CharSequence.
1960     * @param values The values to test, may be {@code null} or empty.
1961     * @return The first value from {@code values} which is not blank, or {@code null} if there are no non-blank values.
1962     * @since 3.8
1963     */
1964    @SafeVarargs
1965    public static <T extends CharSequence> T firstNonBlank(final T... values) {
1966        if (values != null) {
1967            for (final T val : values) {
1968                if (isNotBlank(val)) {
1969                    return val;
1970                }
1971            }
1972        }
1973        return null;
1974    }
1975
1976    /**
1977     * Returns the first value in the array which is not empty.
1978     *
1979     * <p>
1980     * If all values are empty or the array is {@code null} or empty then {@code null} is returned.
1981     * </p>
1982     *
1983     * <pre>
1984     * StringUtils.firstNonEmpty(null, null, null)   = null
1985     * StringUtils.firstNonEmpty(null, null, "")     = null
1986     * StringUtils.firstNonEmpty(null, "", " ")      = " "
1987     * StringUtils.firstNonEmpty("abc")              = "abc"
1988     * StringUtils.firstNonEmpty(null, "xyz")        = "xyz"
1989     * StringUtils.firstNonEmpty("", "xyz")          = "xyz"
1990     * StringUtils.firstNonEmpty(null, "xyz", "abc") = "xyz"
1991     * StringUtils.firstNonEmpty()                   = null
1992     * </pre>
1993     *
1994     * @param <T>    the specific kind of CharSequence.
1995     * @param values The values to test, may be {@code null} or empty.
1996     * @return The first value from {@code values} which is not empty, or {@code null} if there are no non-empty values.
1997     * @since 3.8
1998     */
1999    @SafeVarargs
2000    public static <T extends CharSequence> T firstNonEmpty(final T... values) {
2001        if (values != null) {
2002            for (final T val : values) {
2003                if (isNotEmpty(val)) {
2004                    return val;
2005                }
2006            }
2007        }
2008        return null;
2009    }
2010
2011    /**
2012     * Gets the bytes of the string using {@link String#getBytes(Charset)}, handling {@code null} safely.
2013     *
2014     * @param string input string.
2015     * @param charset The {@link Charset} to encode the {@link String}. If null, then use the default Charset.
2016     * @return The empty byte[] if {@code string} is null, the result of {@link String#getBytes(Charset)} otherwise.
2017     * @see String#getBytes(Charset)
2018     * @since 3.10
2019     */
2020    public static byte[] getBytes(final String string, final Charset charset) {
2021        return string == null ? ArrayUtils.EMPTY_BYTE_ARRAY : string.getBytes(Charsets.toCharset(charset));
2022    }
2023
2024    /**
2025     * Gets the bytes of the string using {@link String#getBytes(String)}, handling {@code null} safely.
2026     *
2027     * @param string input string.
2028     * @param charset The {@link Charset} name to encode the {@link String}. If null, then use the default Charset.
2029     * @return The empty byte[] if {@code string} is null, the result of {@link String#getBytes(String)} otherwise.
2030     * @throws UnsupportedEncodingException Thrown when the named charset is not supported.
2031     * @see String#getBytes(String)
2032     * @since 3.10
2033     */
2034    public static byte[] getBytes(final String string, final String charset) throws UnsupportedEncodingException {
2035        return string == null ? ArrayUtils.EMPTY_BYTE_ARRAY : string.getBytes(Charsets.toCharsetName(charset));
2036    }
2037
2038    /**
2039     * Gets the initial sequence of characters common to all strings in the array.
2040     *
2041     * <p>
2042     * For example, {@code getCommonPrefix("i am a machine", "i am a robot") -&gt; "i am a "}
2043     * </p>
2044     *
2045     * <pre>
2046     * StringUtils.getCommonPrefix(null)                             = ""
2047     * StringUtils.getCommonPrefix(new String[] {})                  = ""
2048     * StringUtils.getCommonPrefix(new String[] {"abc"})             = "abc"
2049     * StringUtils.getCommonPrefix(new String[] {null, null})        = ""
2050     * StringUtils.getCommonPrefix(new String[] {"", ""})            = ""
2051     * StringUtils.getCommonPrefix(new String[] {"", null})          = ""
2052     * StringUtils.getCommonPrefix(new String[] {"abc", null, null}) = ""
2053     * StringUtils.getCommonPrefix(new String[] {null, null, "abc"}) = ""
2054     * StringUtils.getCommonPrefix(new String[] {"", "abc"})         = ""
2055     * StringUtils.getCommonPrefix(new String[] {"abc", ""})         = ""
2056     * StringUtils.getCommonPrefix(new String[] {"abc", "abc"})      = "abc"
2057     * StringUtils.getCommonPrefix(new String[] {"abc", "a"})        = "a"
2058     * StringUtils.getCommonPrefix(new String[] {"ab", "abxyz"})     = "ab"
2059     * StringUtils.getCommonPrefix(new String[] {"abcde", "abxyz"})  = "ab"
2060     * StringUtils.getCommonPrefix(new String[] {"abcde", "xyz"})    = ""
2061     * StringUtils.getCommonPrefix(new String[] {"xyz", "abcde"})    = ""
2062     * StringUtils.getCommonPrefix(new String[] {"i am a machine", "i am a robot"}) = "i am a "
2063     * </pre>
2064     *
2065     * @param strs array of String objects, entries may be null.
2066     * @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
2067     *         if there is no common prefix.
2068     * @since 2.4
2069     */
2070    public static String getCommonPrefix(final String... strs) {
2071        if (ArrayUtils.isEmpty(strs)) {
2072            return EMPTY;
2073        }
2074        final int smallestIndexOfDiff = indexOfDifference(strs);
2075        if (smallestIndexOfDiff == INDEX_NOT_FOUND) {
2076            // all strings were identical
2077            if (strs[0] == null) {
2078                return EMPTY;
2079            }
2080            return strs[0];
2081        }
2082        if (smallestIndexOfDiff == 0) {
2083            // there were no common initial characters
2084            return EMPTY;
2085        }
2086        // we found a common initial character sequence
2087        return strs[0].substring(0, smallestIndexOfDiff);
2088    }
2089
2090    /**
2091     * Gets the Unicode digits in {@code str}, concatenated in their original order.
2092     *
2093     * <p>
2094     * An empty ("") String will be returned if no digits are found in {@code str}.
2095     * </p>
2096     *
2097     * <pre>
2098     * StringUtils.getDigits(null)                 = null
2099     * StringUtils.getDigits("")                   = ""
2100     * StringUtils.getDigits("abc")                = ""
2101     * StringUtils.getDigits("1000$")              = "1000"
2102     * StringUtils.getDigits("1123~45")            = "112345"
2103     * StringUtils.getDigits("(541) 754-3010")     = "5417543010"
2104     * StringUtils.getDigits("\u0967\u0968\u0969") = "\u0967\u0968\u0969"
2105     * </pre>
2106     *
2107     * @param str The String to extract digits from, may be null.
2108     * @return String with only digits, or an empty ("") String if no digits are found, or {@code null} String if {@code str} is null.
2109     * @since 3.6
2110     */
2111    public static String getDigits(final String str) {
2112        if (isEmpty(str)) {
2113            return str;
2114        }
2115        final int len = str.length();
2116        final char[] buffer = new char[len];
2117        int count = 0;
2118
2119        for (int i = 0; i < len;) {
2120            final int codePoint = str.codePointAt(i);
2121            if (Character.isDigit(codePoint)) {
2122                count += Character.toChars(codePoint, buffer, count);
2123            }
2124            i += Character.charCount(codePoint);
2125        }
2126        return new String(buffer, 0, count);
2127    }
2128
2129    /**
2130     * Gets the Fuzzy Distance which indicates the similarity score between two Strings.
2131     *
2132     * <p>
2133     * 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
2134     * matched character. Subsequent matches yield two bonus points. A higher score indicates a higher similarity.
2135     * </p>
2136     *
2137     * <pre>
2138     * StringUtils.getFuzzyDistance(null, null, null)                                    = Throws {@link IllegalArgumentException}
2139     * StringUtils.getFuzzyDistance("", "", Locale.ENGLISH)                              = 0
2140     * StringUtils.getFuzzyDistance("Workshop", "b", Locale.ENGLISH)                     = 0
2141     * StringUtils.getFuzzyDistance("Room", "o", Locale.ENGLISH)                         = 1
2142     * StringUtils.getFuzzyDistance("Workshop", "w", Locale.ENGLISH)                     = 1
2143     * StringUtils.getFuzzyDistance("Workshop", "ws", Locale.ENGLISH)                    = 2
2144     * StringUtils.getFuzzyDistance("Workshop", "wo", Locale.ENGLISH)                    = 4
2145     * StringUtils.getFuzzyDistance("Apache Software Foundation", "asf", Locale.ENGLISH) = 3
2146     * </pre>
2147     *
2148     * @param term   A full term that should be matched against, must not be null.
2149     * @param query  The query that will be matched against a term, must not be null.
2150     * @param locale This string matching logic is case-insensitive. A locale is necessary to normalize both Strings to lower case.
2151     * @return result score.
2152     * @throws IllegalArgumentException Thrown if either String input {@code null} or Locale input {@code null}.
2153     * @since 3.4
2154     * @deprecated As of 3.6, use Apache Commons Text
2155     *             <a href="https://commons.apache.org/proper/commons-text/javadocs/api-release/org/apache/commons/text/similarity/FuzzyScore.html">
2156     *             FuzzyScore</a> instead.
2157     */
2158    @Deprecated
2159    public static int getFuzzyDistance(final CharSequence term, final CharSequence query, final Locale locale) {
2160        if (term == null || query == null) {
2161            throw new IllegalArgumentException("Strings must not be null");
2162        }
2163        if (locale == null) {
2164            throw new IllegalArgumentException("Locale must not be null");
2165        }
2166        // fuzzy logic is case-insensitive. We normalize the Strings to lower
2167        // case right from the start. Turning characters to lower case
2168        // via Character.toLowerCase(char) is unfortunately insufficient
2169        // as it does not accept a locale.
2170        final String termLowerCase = term.toString().toLowerCase(locale);
2171        final String queryLowerCase = query.toString().toLowerCase(locale);
2172        // the resulting score
2173        int score = 0;
2174        // the position in the term which will be scanned next for potential
2175        // query character matches
2176        int termIndex = 0;
2177        // index of the previously matched character in the term
2178        int previousMatchingCharacterIndex = Integer.MIN_VALUE;
2179        for (int queryIndex = 0; queryIndex < queryLowerCase.length(); queryIndex++) {
2180            final char queryChar = queryLowerCase.charAt(queryIndex);
2181            boolean termCharacterMatchFound = false;
2182            for (; termIndex < termLowerCase.length() && !termCharacterMatchFound; termIndex++) {
2183                final char termChar = termLowerCase.charAt(termIndex);
2184                if (queryChar == termChar) {
2185                    // simple character matches result in one point
2186                    score++;
2187                    // subsequent character matches further improve
2188                    // the score.
2189                    if (previousMatchingCharacterIndex + 1 == termIndex) {
2190                        score += 2;
2191                    }
2192                    previousMatchingCharacterIndex = termIndex;
2193                    // we can leave the nested loop. Every character in the
2194                    // query can match at most one character in the term.
2195                    termCharacterMatchFound = true;
2196                }
2197            }
2198        }
2199        return score;
2200    }
2201
2202    /**
2203     * Gets either the passed in CharSequence, or if the CharSequence is {@link #isBlank(CharSequence) blank} (whitespaces, empty ({@code ""}), or
2204     * {@code null}), the value supplied by {@code defaultStrSupplier}.
2205     *
2206     * <p>
2207     * Whitespace is defined by {@link Character#isWhitespace(char)}.
2208     * </p>
2209     *
2210     * <p>
2211     * The caller is responsible for thread safety and exception handling for the default value supplier.
2212     * </p>
2213     *
2214     * <pre>
2215     * {@code
2216     * StringUtils.getIfBlank(null, () -> "NULL")   = "NULL"
2217     * StringUtils.getIfBlank("", () -> "NULL")     = "NULL"
2218     * StringUtils.getIfBlank(" ", () -> "NULL")    = "NULL"
2219     * StringUtils.getIfBlank("bat", () -> "NULL")  = "bat"
2220     * StringUtils.getIfBlank("", () -> null)       = null
2221     * StringUtils.getIfBlank("", null)             = null
2222     * }</pre>
2223     *
2224     * @param <T>             the specific kind of CharSequence.
2225     * @param str             The CharSequence to check, may be null.
2226     * @param defaultSupplier The supplier of default CharSequence to return if the input is {@link #isBlank(CharSequence) blank} (whitespaces, empty
2227     *                        ({@code ""}), or {@code null}); may be null.
2228     * @return The passed in CharSequence, or the default
2229     * @see StringUtils#defaultString(String, String)
2230     * @see #isBlank(CharSequence)
2231     * @since 3.10
2232     */
2233    public static <T extends CharSequence> T getIfBlank(final T str, final Supplier<T> defaultSupplier) {
2234        return isBlank(str) ? Suppliers.get(defaultSupplier) : str;
2235    }
2236
2237    /**
2238     * Gets either the passed in CharSequence, or if the CharSequence is empty or {@code null}, the value supplied by {@code defaultStrSupplier}.
2239     *
2240     * <p>
2241     * The caller is responsible for thread safety and exception handling for the default value supplier.
2242     * </p>
2243     *
2244     * <pre>
2245     * {@code
2246     * StringUtils.getIfEmpty(null, () -> "NULL")    = "NULL"
2247     * StringUtils.getIfEmpty("", () -> "NULL")      = "NULL"
2248     * StringUtils.getIfEmpty(" ", () -> "NULL")     = " "
2249     * StringUtils.getIfEmpty("bat", () -> "NULL")   = "bat"
2250     * StringUtils.getIfEmpty("", () -> null)        = null
2251     * StringUtils.getIfEmpty("", null)              = null
2252     * }
2253     * </pre>
2254     *
2255     * @param <T>             the specific kind of CharSequence.
2256     * @param str             The CharSequence to check, may be null.
2257     * @param defaultSupplier The supplier of default CharSequence to return if the input is empty ("") or {@code null}, may be null.
2258     * @return The passed in CharSequence, or the default.
2259     * @see StringUtils#defaultString(String, String)
2260     * @since 3.10
2261     */
2262    public static <T extends CharSequence> T getIfEmpty(final T str, final Supplier<T> defaultSupplier) {
2263        return isEmpty(str) ? Suppliers.get(defaultSupplier) : str;
2264    }
2265
2266    /**
2267     * Gets the Jaro Winkler Distance which indicates the similarity score between two Strings.
2268     *
2269     * <p>
2270     * The Jaro measure is the weighted sum of percentage of matched characters from each file and transposed characters. Winkler increased this measure for
2271     * matching initial characters.
2272     * </p>
2273     *
2274     * <p>
2275     * This implementation is based on the Jaro Winkler similarity algorithm from
2276     * <a href="https://en.wikipedia.org/wiki/Jaro%E2%80%93Winkler_distance">https://en.wikipedia.org/wiki/Jaro%E2%80%93Winkler_distance</a>.
2277     * </p>
2278     *
2279     * <pre>
2280     * StringUtils.getJaroWinklerDistance(null, null)          = Throws {@link IllegalArgumentException}
2281     * StringUtils.getJaroWinklerDistance("", "")              = 0.0
2282     * StringUtils.getJaroWinklerDistance("", "a")             = 0.0
2283     * StringUtils.getJaroWinklerDistance("aaapppp", "")       = 0.0
2284     * StringUtils.getJaroWinklerDistance("frog", "fog")       = 0.93
2285     * StringUtils.getJaroWinklerDistance("fly", "ant")        = 0.0
2286     * StringUtils.getJaroWinklerDistance("elephant", "hippo") = 0.44
2287     * StringUtils.getJaroWinklerDistance("hippo", "elephant") = 0.44
2288     * StringUtils.getJaroWinklerDistance("hippo", "zzzzzzzz") = 0.0
2289     * StringUtils.getJaroWinklerDistance("hello", "hallo")    = 0.88
2290     * StringUtils.getJaroWinklerDistance("ABC Corporation", "ABC Corp") = 0.93
2291     * StringUtils.getJaroWinklerDistance("D N H Enterprises Inc", "D &amp; H Enterprises, Inc.") = 0.95
2292     * StringUtils.getJaroWinklerDistance("My Gym Children's Fitness Center", "My Gym. Childrens Fitness") = 0.92
2293     * StringUtils.getJaroWinklerDistance("PENNSYLVANIA", "PENNCISYLVNIA") = 0.88
2294     * </pre>
2295     *
2296     * @param first  The first String, must not be null.
2297     * @param second The second String, must not be null.
2298     * @return result distance.
2299     * @throws IllegalArgumentException Thrown if either String input {@code null}.
2300     * @since 3.3
2301     * @deprecated As of 3.6, use Apache Commons Text
2302     *             <a href="https://commons.apache.org/proper/commons-text/javadocs/api-release/org/apache/commons/text/similarity/JaroWinklerDistance.html">
2303     *             JaroWinklerDistance</a> instead.
2304     */
2305    @Deprecated
2306    public static double getJaroWinklerDistance(final CharSequence first, final CharSequence second) {
2307        final double DEFAULT_SCALING_FACTOR = 0.1;
2308
2309        if (first == null || second == null) {
2310            throw new IllegalArgumentException("Strings must not be null");
2311        }
2312
2313        final int[] mtp = matches(first, second);
2314        final double m = mtp[0];
2315        if (m == 0) {
2316            return 0D;
2317        }
2318        final double j = (m / first.length() + m / second.length() + (m - mtp[1]) / m) / 3;
2319        final double jw = j < 0.7D ? j : j + Math.min(DEFAULT_SCALING_FACTOR, 1D / mtp[3]) * mtp[2] * (1D - j);
2320        return Math.round(jw * 100.0D) / 100.0D;
2321    }
2322
2323    /**
2324     * Gets the Levenshtein distance between two Strings.
2325     *
2326     * <p>
2327     * This is the number of changes needed to change one String into another, where each change is a single character modification (deletion, insertion or
2328     * substitution).
2329     * </p>
2330     *
2331     * <p>
2332     * The implementation uses a single-dimensional array of length s.length() + 1. See
2333     * <a href="https://blog.softwx.net/2014/12/optimizing-levenshtein-algorithm-in-c.html">
2334     * https://blog.softwx.net/2014/12/optimizing-levenshtein-algorithm-in-c.html</a> for details.
2335     * </p>
2336     *
2337     * <pre>
2338     * StringUtils.getLevenshteinDistance(null, *)             = Throws {@link IllegalArgumentException}
2339     * StringUtils.getLevenshteinDistance(*, null)             = Throws {@link IllegalArgumentException}
2340     * StringUtils.getLevenshteinDistance("", "")              = 0
2341     * StringUtils.getLevenshteinDistance("", "a")             = 1
2342     * StringUtils.getLevenshteinDistance("aaapppp", "")       = 7
2343     * StringUtils.getLevenshteinDistance("frog", "fog")       = 1
2344     * StringUtils.getLevenshteinDistance("fly", "ant")        = 3
2345     * StringUtils.getLevenshteinDistance("elephant", "hippo") = 7
2346     * StringUtils.getLevenshteinDistance("hippo", "elephant") = 7
2347     * StringUtils.getLevenshteinDistance("hippo", "zzzzzzzz") = 8
2348     * StringUtils.getLevenshteinDistance("hello", "hallo")    = 1
2349     * </pre>
2350     *
2351     * @param s The first String, must not be null.
2352     * @param t The second String, must not be null.
2353     * @return result distance.
2354     * @throws IllegalArgumentException Thrown if either String input {@code null}.
2355     * @since 3.0 Changed signature from getLevenshteinDistance(String, String) to getLevenshteinDistance(CharSequence, CharSequence)
2356     * @deprecated As of 3.6, use Apache Commons Text
2357     *             <a href="https://commons.apache.org/proper/commons-text/javadocs/api-release/org/apache/commons/text/similarity/LevenshteinDistance.html">
2358     *             LevenshteinDistance</a> instead.
2359     */
2360    @Deprecated
2361    public static int getLevenshteinDistance(CharSequence s, CharSequence t) {
2362        if (s == null || t == null) {
2363            throw new IllegalArgumentException("Strings must not be null");
2364        }
2365
2366        int n = s.length();
2367        int m = t.length();
2368
2369        if (n == 0) {
2370            return m;
2371        }
2372        if (m == 0) {
2373            return n;
2374        }
2375
2376        if (n > m) {
2377            // swap the input strings to consume less memory
2378            final CharSequence tmp = s;
2379            s = t;
2380            t = tmp;
2381            n = m;
2382            m = t.length();
2383        }
2384
2385        final int[] p = new int[n + 1];
2386        // indexes into strings s and t
2387        int i; // iterates through s
2388        int j; // iterates through t
2389        int upperleft;
2390        int upper;
2391
2392        char jOfT; // jth character of t
2393        int cost;
2394
2395        for (i = 0; i <= n; i++) {
2396            p[i] = i;
2397        }
2398
2399        for (j = 1; j <= m; j++) {
2400            upperleft = p[0];
2401            jOfT = t.charAt(j - 1);
2402            p[0] = j;
2403
2404            for (i = 1; i <= n; i++) {
2405                upper = p[i];
2406                cost = s.charAt(i - 1) == jOfT ? 0 : 1;
2407                // minimum of cell to the left+1, to the top+1, diagonally left and up +cost
2408                p[i] = Math.min(Math.min(p[i - 1] + 1, p[i] + 1), upperleft + cost);
2409                upperleft = upper;
2410            }
2411        }
2412
2413        return p[n];
2414    }
2415
2416    /**
2417     * Gets the Levenshtein distance between two Strings if it's less than or equal to a given threshold.
2418     *
2419     * <p>
2420     * This is the number of changes needed to change one String into another, where each change is a single character modification (deletion, insertion or
2421     * substitution).
2422     * </p>
2423     *
2424     * <p>
2425     * This implementation follows from Algorithms on Strings, Trees and Sequences by Dan Gusfield and Chas Emerick's implementation of the Levenshtein distance
2426     * algorithm.
2427     * </p>
2428     *
2429     * <pre>
2430     * StringUtils.getLevenshteinDistance(null, *, *)             = Throws {@link IllegalArgumentException}
2431     * StringUtils.getLevenshteinDistance(*, null, *)             = Throws {@link IllegalArgumentException}
2432     * StringUtils.getLevenshteinDistance(*, *, -1)               = Throws {@link IllegalArgumentException}
2433     * StringUtils.getLevenshteinDistance("", "", 0)              = 0
2434     * StringUtils.getLevenshteinDistance("aaapppp", "", 8)       = 7
2435     * StringUtils.getLevenshteinDistance("aaapppp", "", 7)       = 7
2436     * StringUtils.getLevenshteinDistance("aaapppp", "", 6))      = -1
2437     * StringUtils.getLevenshteinDistance("elephant", "hippo", 7) = 7
2438     * StringUtils.getLevenshteinDistance("elephant", "hippo", 6) = -1
2439     * StringUtils.getLevenshteinDistance("hippo", "elephant", 7) = 7
2440     * StringUtils.getLevenshteinDistance("hippo", "elephant", 6) = -1
2441     * </pre>
2442     *
2443     * @param s         The first String, must not be null.
2444     * @param t         The second String, must not be null.
2445     * @param threshold The target threshold, must not be negative.
2446     * @return result distance, or {@code -1} if the distance would be greater than the threshold.
2447     * @throws IllegalArgumentException Thrown if either String input {@code null} or negative threshold.
2448     * @deprecated As of 3.6, use Apache Commons Text
2449     *             <a href="https://commons.apache.org/proper/commons-text/javadocs/api-release/org/apache/commons/text/similarity/LevenshteinDistance.html">
2450     *             LevenshteinDistance</a> instead.
2451     */
2452    @Deprecated
2453    public static int getLevenshteinDistance(CharSequence s, CharSequence t, final int threshold) {
2454        if (s == null || t == null) {
2455            throw new IllegalArgumentException("Strings must not be null");
2456        }
2457        if (threshold < 0) {
2458            throw new IllegalArgumentException("Threshold must not be negative");
2459        }
2460
2461        /*
2462        This implementation only computes the distance if it's less than or equal to the
2463        threshold value, returning -1 if it's greater.  The advantage is performance: unbounded
2464        distance is O(nm), but a bound of k allows us to reduce it to O(km) time by only
2465        computing a diagonal stripe of width 2k + 1 of the cost table.
2466        It is also possible to use this to compute the unbounded Levenshtein distance by starting
2467        the threshold at 1 and doubling each time until the distance is found; this is O(dm), where
2468        d is the distance.
2469
2470        One subtlety comes from needing to ignore entries on the border of our stripe
2471        for example,
2472        p[] = |#|#|#|*
2473        d[] =  *|#|#|#|
2474        We must ignore the entry to the left of the leftmost member
2475        We must ignore the entry above the rightmost member
2476
2477        Another subtlety comes from our stripe running off the matrix if the strings aren't
2478        of the same size.  Since string s is always swapped to be the shorter of the two,
2479        the stripe will always run off to the upper right instead of the lower left of the matrix.
2480
2481        As a concrete example, suppose s is of length 5, t is of length 7, and our threshold is 1.
2482        In this case we're going to walk a stripe of length 3.  The matrix would look like so:
2483
2484           1 2 3 4 5
2485        1 |#|#| | | |
2486        2 |#|#|#| | |
2487        3 | |#|#|#| |
2488        4 | | |#|#|#|
2489        5 | | | |#|#|
2490        6 | | | | |#|
2491        7 | | | | | |
2492
2493        Note how the stripe leads off the table as there is no possible way to turn a string of length 5
2494        into one of length 7 in edit distance of 1.
2495
2496        Additionally, this implementation decreases memory usage by using two
2497        single-dimensional arrays and swapping them back and forth instead of allocating
2498        an entire n by m matrix.  This requires a few minor changes, such as immediately returning
2499        when it's detected that the stripe has run off the matrix and initially filling the arrays with
2500        large values so that entries we don't compute are ignored.
2501
2502        See Algorithms on Strings, Trees and Sequences by Dan Gusfield for some discussion.
2503         */
2504
2505        int n = s.length(); // length of s
2506        int m = t.length(); // length of t
2507
2508        // if one string is empty, the edit distance is necessarily the length of the other
2509        if (n == 0) {
2510            return m <= threshold ? m : -1;
2511        }
2512        if (m == 0) {
2513            return n <= threshold ? n : -1;
2514        }
2515        if (Math.abs(n - m) > threshold) {
2516            // no need to calculate the distance if the length difference is greater than the threshold
2517            return -1;
2518        }
2519
2520        if (n > m) {
2521            // swap the two strings to consume less memory
2522            final CharSequence tmp = s;
2523            s = t;
2524            t = tmp;
2525            n = m;
2526            m = t.length();
2527        }
2528
2529        int[] p = new int[n + 1]; // 'previous' cost array, horizontally
2530        int[] d = new int[n + 1]; // cost array, horizontally
2531        int[] tmp; // placeholder to assist in swapping p and d
2532
2533        // fill in starting table values
2534        final int boundary = Math.min(n, threshold) + 1;
2535        for (int i = 0; i < boundary; i++) {
2536            p[i] = i;
2537        }
2538        // these fills ensure that the value above the rightmost entry of our
2539        // stripe will be ignored in following loop iterations
2540        Arrays.fill(p, boundary, p.length, Integer.MAX_VALUE);
2541        Arrays.fill(d, Integer.MAX_VALUE);
2542
2543        // iterates through t
2544        for (int j = 1; j <= m; j++) {
2545            final char jOfT = t.charAt(j - 1); // jth character of t
2546            d[0] = j;
2547
2548            // compute stripe indices, constrain to array size
2549            final int min = Math.max(1, j - threshold);
2550            final int max = j > Integer.MAX_VALUE - threshold ? n : Math.min(n, j + threshold);
2551
2552            // the stripe may lead off of the table if s and t are of different sizes
2553            if (min > max) {
2554                return -1;
2555            }
2556
2557            // ignore entry left of leftmost
2558            if (min > 1) {
2559                d[min - 1] = Integer.MAX_VALUE;
2560            }
2561
2562            // iterates through [min, max] in s
2563            for (int i = min; i <= max; i++) {
2564                if (s.charAt(i - 1) == jOfT) {
2565                    // diagonally left and up
2566                    d[i] = p[i - 1];
2567                } else {
2568                    // 1 + minimum of cell to the left, to the top, diagonally left and up
2569                    d[i] = 1 + Math.min(Math.min(d[i - 1], p[i]), p[i - 1]);
2570                }
2571            }
2572
2573            // copy current distance counts to 'previous row' distance counts
2574            tmp = p;
2575            p = d;
2576            d = tmp;
2577        }
2578
2579        // if p[n] is greater than the threshold, there's no guarantee on it being the correct
2580        // distance
2581        if (p[n] <= threshold) {
2582            return p[n];
2583        }
2584        return -1;
2585    }
2586
2587    /**
2588     * Finds the first index within a CharSequence, handling {@code null}. This method uses {@link String#indexOf(String, int)} if possible.
2589     *
2590     * <p>
2591     * A {@code null} CharSequence will return {@code -1}.
2592     * </p>
2593     *
2594     * <pre>
2595     * StringUtils.indexOf(null, *)          = -1
2596     * StringUtils.indexOf(*, null)          = -1
2597     * StringUtils.indexOf("", "")           = 0
2598     * StringUtils.indexOf("", *)            = -1 (except when * = "")
2599     * StringUtils.indexOf("aabaabaa", "a")  = 0
2600     * StringUtils.indexOf("aabaabaa", "b")  = 2
2601     * StringUtils.indexOf("aabaabaa", "ab") = 1
2602     * StringUtils.indexOf("aabaabaa", "")   = 0
2603     * </pre>
2604     *
2605     * @param seq       The CharSequence to check, may be null.
2606     * @param searchSeq The CharSequence to find, may be null.
2607     * @return The first index of the search CharSequence, -1 if no match or {@code null} string input.
2608     * @since 2.0
2609     * @since 3.0 Changed signature from indexOf(String, String) to indexOf(CharSequence, CharSequence)
2610     * @deprecated Use {@link Strings#indexOf(CharSequence, CharSequence) Strings.CS.indexOf(CharSequence, CharSequence)}.
2611     */
2612    @Deprecated
2613    public static int indexOf(final CharSequence seq, final CharSequence searchSeq) {
2614        return Strings.CS.indexOf(seq, searchSeq);
2615    }
2616
2617    /**
2618     * Finds the first index within a CharSequence, handling {@code null}. This method uses {@link String#indexOf(String, int)} if possible.
2619     *
2620     * <p>
2621     * A {@code null} CharSequence will return {@code -1}. A negative start position is treated as zero. An empty ("") search CharSequence always matches. A
2622     * start position greater than the string length only matches an empty search CharSequence.
2623     * </p>
2624     *
2625     * <pre>
2626     * StringUtils.indexOf(null, *, *)          = -1
2627     * StringUtils.indexOf(*, null, *)          = -1
2628     * StringUtils.indexOf("", "", 0)           = 0
2629     * StringUtils.indexOf("", *, 0)            = -1 (except when * = "")
2630     * StringUtils.indexOf("aabaabaa", "a", 0)  = 0
2631     * StringUtils.indexOf("aabaabaa", "b", 0)  = 2
2632     * StringUtils.indexOf("aabaabaa", "ab", 0) = 1
2633     * StringUtils.indexOf("aabaabaa", "b", 3)  = 5
2634     * StringUtils.indexOf("aabaabaa", "b", 9)  = -1
2635     * StringUtils.indexOf("aabaabaa", "b", -1) = 2
2636     * StringUtils.indexOf("aabaabaa", "", 2)   = 2
2637     * StringUtils.indexOf("abc", "", 9)        = 3
2638     * </pre>
2639     *
2640     * @param seq       The CharSequence to check, may be null.
2641     * @param searchSeq The CharSequence to find, may be null.
2642     * @param startPos  The start position, negative treated as zero.
2643     * @return The first index of the search CharSequence (always &ge; startPos), -1 if no match or {@code null} string input.
2644     * @since 2.0
2645     * @since 3.0 Changed signature from indexOf(String, String, int) to indexOf(CharSequence, CharSequence, int)
2646     * @deprecated Use {@link Strings#indexOf(CharSequence, CharSequence, int) Strings.CS.indexOf(CharSequence, CharSequence, int)}.
2647     */
2648    @Deprecated
2649    public static int indexOf(final CharSequence seq, final CharSequence searchSeq, final int startPos) {
2650        return Strings.CS.indexOf(seq, searchSeq, startPos);
2651    }
2652
2653    /**
2654     * Returns the index within {@code seq} of the first occurrence of the specified character. If a character with value {@code searchChar} occurs in the
2655     * character sequence represented by {@code seq} {@link CharSequence} object, then the index (in Unicode code units) of the first such occurrence is
2656     * returned. For values of {@code searchChar} in the range from 0 to 0xFFFF (inclusive), this is the smallest value <em>k</em> such that:
2657     *
2658     * <pre>
2659     * this.charAt(<em>k</em>) == searchChar
2660     * </pre>
2661     *
2662     * <p>
2663     * is true. For other values of {@code searchChar}, it is the smallest value <em>k</em> such that:
2664     * </p>
2665     *
2666     * <pre>
2667     * this.codePointAt(<em>k</em>) == searchChar
2668     * </pre>
2669     *
2670     * <p>
2671     * is true. In either case, if no such character occurs in {@code seq}, then {@code INDEX_NOT_FOUND (-1)} is returned.
2672     * </p>
2673     *
2674     * <p>
2675     * Furthermore, a {@code null} or empty ("") CharSequence will return {@code INDEX_NOT_FOUND (-1)}.
2676     * </p>
2677     *
2678     * <pre>
2679     * StringUtils.indexOf(null, *)         = -1
2680     * StringUtils.indexOf("", *)           = -1
2681     * StringUtils.indexOf("aabaabaa", 'a') = 0
2682     * StringUtils.indexOf("aabaabaa", 'b') = 2
2683     * StringUtils.indexOf("aaaaaaaa", 'Z') = -1
2684     * </pre>
2685     *
2686     * @param seq        The CharSequence to check, may be null.
2687     * @param searchChar The character to find.
2688     * @return The first index of the search character, -1 if no match or {@code null} string input.
2689     * @since 2.0
2690     * @since 3.0 Changed signature from indexOf(String, int) to indexOf(CharSequence, int)
2691     * @since 3.6 Updated {@link CharSequenceUtils} call to behave more like {@link String}
2692     */
2693    public static int indexOf(final CharSequence seq, final int searchChar) {
2694        if (isEmpty(seq)) {
2695            return INDEX_NOT_FOUND;
2696        }
2697        return CharSequenceUtils.indexOf(seq, searchChar, 0);
2698    }
2699
2700    /**
2701     * Returns the index within {@code seq} of the first occurrence of the specified character, starting the search at the specified index.
2702     * <p>
2703     * If a character with value {@code searchChar} occurs in the character sequence represented by the {@code seq} {@link CharSequence} object at an index no
2704     * 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
2705     * (inclusive), this is the smallest value <em>k</em> such that:
2706     * </p>
2707     *
2708     * <pre>
2709     * (this.charAt(<em>k</em>) == searchChar) &amp;&amp; (<em>k</em> &gt;= startPos)
2710     * </pre>
2711     *
2712     * <p>
2713     * is true. For other values of {@code searchChar}, it is the smallest value <em>k</em> such that:
2714     * </p>
2715     *
2716     * <pre>
2717     * (this.codePointAt(<em>k</em>) == searchChar) &amp;&amp; (<em>k</em> &gt;= startPos)
2718     * </pre>
2719     *
2720     * <p>
2721     * is true. In either case, if no such character occurs in {@code seq} at or after position {@code startPos}, then {@code -1} is returned.
2722     * </p>
2723     *
2724     * <p>
2725     * 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
2726     * 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:
2727     * {@code (INDEX_NOT_FOUND) -1} is returned. Furthermore, a {@code null} or empty ("") CharSequence will return {@code (INDEX_NOT_FOUND) -1}.
2728     * </p>
2729     * <p>
2730     * All indices are specified in {@code char} values (Unicode code units).
2731     * </p>
2732     *
2733     * <pre>
2734     * StringUtils.indexOf(null, *, *)          = -1
2735     * StringUtils.indexOf("", *, *)            = -1
2736     * StringUtils.indexOf("aabaabaa", 'b', 0)  = 2
2737     * StringUtils.indexOf("aabaabaa", 'b', 3)  = 5
2738     * StringUtils.indexOf("aabaabaa", 'b', 9)  = -1
2739     * StringUtils.indexOf("aabaabaa", 'b', -1) = 2
2740     * </pre>
2741     *
2742     * @param seq        The CharSequence to check, may be null.
2743     * @param searchChar The character to find.
2744     * @param startPos   The start position, negative treated as zero.
2745     * @return The first index of the search character (always &ge; startPos), -1 if no match or {@code null} string input.
2746     * @since 2.0
2747     * @since 3.0 Changed signature from indexOf(String, int, int) to indexOf(CharSequence, int, int)
2748     * @since 3.6 Updated {@link CharSequenceUtils} call to behave more like {@link String}
2749     */
2750    public static int indexOf(final CharSequence seq, final int searchChar, final int startPos) {
2751        if (isEmpty(seq)) {
2752            return INDEX_NOT_FOUND;
2753        }
2754        return CharSequenceUtils.indexOf(seq, searchChar, startPos);
2755    }
2756
2757    /**
2758     * Search a CharSequence to find the first index of any character in the given set of characters.
2759     *
2760     * <p>
2761     * A {@code null} String will return {@code -1}. A {@code null} or zero length search array will return {@code -1}.
2762     * </p>
2763     *
2764     * <pre>
2765     * StringUtils.indexOfAny(null, *)                  = -1
2766     * StringUtils.indexOfAny("", *)                    = -1
2767     * StringUtils.indexOfAny(*, null)                  = -1
2768     * StringUtils.indexOfAny(*, [])                    = -1
2769     * StringUtils.indexOfAny("zzabyycdxx", 'z', 'a')   = 0
2770     * StringUtils.indexOfAny("zzabyycdxx", 'b', 'y')   = 3
2771     * StringUtils.indexOfAny("aba", 'z')               = -1
2772     * </pre>
2773     *
2774     * @param cs          The CharSequence to check, may be null.
2775     * @param searchChars The chars to search for, may be null.
2776     * @return The index of any of the chars, -1 if no match or null input.
2777     * @since 2.0
2778     * @since 3.0 Changed signature from indexOfAny(String, char[]) to indexOfAny(CharSequence, char...)
2779     */
2780    public static int indexOfAny(final CharSequence cs, final char... searchChars) {
2781        return indexOfAny(cs, 0, searchChars);
2782    }
2783
2784    /**
2785     * Find the first index of any of a set of potential substrings.
2786     *
2787     * <p>
2788     * 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
2789     * 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
2790     * possible.
2791     * </p>
2792     *
2793     * <pre>
2794     * StringUtils.indexOfAny(null, *)                    = -1
2795     * StringUtils.indexOfAny(*, null)                    = -1
2796     * StringUtils.indexOfAny(*, [])                      = -1
2797     * StringUtils.indexOfAny("zzabyycdxx", "ab", "cd")   = 2
2798     * StringUtils.indexOfAny("zzabyycdxx", "cd", "ab")   = 2
2799     * StringUtils.indexOfAny("zzabyycdxx", "mn", "op")   = -1
2800     * StringUtils.indexOfAny("zzabyycdxx", "zab", "aby") = 1
2801     * StringUtils.indexOfAny("zzabyycdxx", new CharSequence[] { "" }) = 0
2802     * StringUtils.indexOfAny("", new CharSequence[] { "" })           = 0
2803     * StringUtils.indexOfAny("", new CharSequence[] { "a" })          = -1
2804     * </pre>
2805     *
2806     * <p>
2807     * Use an explicit array when searching for a single substring. Passing a single {@link String} as the second argument instead selects
2808     * {@link #indexOfAny(CharSequence, String)}, which searches for individual characters.
2809     * </p>
2810     *
2811     * @param str        The CharSequence to check, may be null.
2812     * @param searchStrs The CharSequences to search for, may be null.
2813     * @return The first index of any of the searchStrs in str, -1 if no match.
2814     * @since 3.0 Changed signature from indexOfAny(String, String[]) to indexOfAny(CharSequence, CharSequence...)
2815     */
2816    public static int indexOfAny(final CharSequence str, final CharSequence... searchStrs) {
2817        if (str == null || searchStrs == null) {
2818            return INDEX_NOT_FOUND;
2819        }
2820        // String's can't have a MAX_VALUEth index.
2821        int ret = Integer.MAX_VALUE;
2822        int tmp;
2823        for (final CharSequence search : searchStrs) {
2824            if (search == null) {
2825                continue;
2826            }
2827            tmp = CharSequenceUtils.indexOf(str, search, 0);
2828            if (tmp == INDEX_NOT_FOUND) {
2829                continue;
2830            }
2831            if (tmp < ret) {
2832                ret = tmp;
2833            }
2834        }
2835        return ret == Integer.MAX_VALUE ? INDEX_NOT_FOUND : ret;
2836    }
2837
2838    /**
2839     * Search a CharSequence to find the first index of any character in the given set of characters.
2840     *
2841     * <p>
2842     * A {@code null} String will return {@code -1}. A {@code null} or zero length search array will return {@code -1}.
2843     * </p>
2844     * <p>
2845     * The following is the same as {@code indexOfAny(cs, 0, searchChars)}.
2846     * </p>
2847     * <pre>
2848     * StringUtils.indexOfAny(null, 0, *)                  = -1
2849     * StringUtils.indexOfAny("", 0, *)                    = -1
2850     * StringUtils.indexOfAny(*, 0, null)                  = -1
2851     * StringUtils.indexOfAny(*, 0, [])                    = -1
2852     * StringUtils.indexOfAny("zzabyycdxx", 0, ['z', 'a']) = 0
2853     * StringUtils.indexOfAny("zzabyycdxx", 0, ['b', 'y']) = 3
2854     * StringUtils.indexOfAny("aba", 0, ['z'])             = -1
2855     * </pre>
2856     *
2857     * @param cs          The CharSequence to check, may be null.
2858     * @param csStart Start searching the input {@code cs} at this index.
2859     * @param searchChars The chars to search for, may be null.
2860     * @return The index of any of the chars, -1 if no match or null input.
2861     * @since 2.0
2862     * @since 3.0 Changed signature from indexOfAny(String, char[]) to indexOfAny(CharSequence, char...)
2863     */
2864    public static int indexOfAny(final CharSequence cs, final int csStart, final char... searchChars) {
2865        if (isEmpty(cs) || ArrayUtils.isEmpty(searchChars)) {
2866            return INDEX_NOT_FOUND;
2867        }
2868        final int csLen = cs.length();
2869        final int csLast = csLen - 1;
2870        final int searchLen = searchChars.length;
2871        final int searchLast = searchLen - 1;
2872        for (int i = Math.max(csStart, 0); i < csLen; i++) {
2873            final char ch = cs.charAt(i);
2874            for (int j = 0; j < searchLen; j++) {
2875                if (searchChars[j] == ch) {
2876                    if (Character.isHighSurrogate(ch)
2877                            ? j == searchLast || i < csLast && searchChars[j + 1] == cs.charAt(i + 1)
2878                            : j == 0 || !Character.isLowSurrogate(ch) || !Character.isHighSurrogate(searchChars[j - 1]) || i > 0 && searchChars[j - 1] == cs.charAt(i - 1)) {
2879                        return i;
2880                    }
2881                }
2882            }
2883        }
2884        return INDEX_NOT_FOUND;
2885    }
2886
2887    /**
2888     * Search a CharSequence to find the first index of any character in the given set of characters.
2889     *
2890     * <p>
2891     * A {@code null} String will return {@code -1}. A {@code null} search string will return {@code -1}.
2892     * </p>
2893     *
2894     * <pre>
2895     * StringUtils.indexOfAny(null, *)            = -1
2896     * StringUtils.indexOfAny("", *)              = -1
2897     * StringUtils.indexOfAny(*, null)            = -1
2898     * StringUtils.indexOfAny(*, "")              = -1
2899     * StringUtils.indexOfAny("zzabyycdxx", "za") = 0
2900     * StringUtils.indexOfAny("zzabyycdxx", "by") = 3
2901     * StringUtils.indexOfAny("aba", "z")         = -1
2902     * </pre>
2903     *
2904     * @param cs          The CharSequence to check, may be null.
2905     * @param searchChars The chars to search for, may be null.
2906     * @return The index of any of the chars, -1 if no match or null input.
2907     * @since 2.0
2908     * @since 3.0 Changed signature from indexOfAny(String, String) to indexOfAny(CharSequence, String)
2909     */
2910    public static int indexOfAny(final CharSequence cs, final String searchChars) {
2911        if (isEmpty(cs) || isEmpty(searchChars)) {
2912            return INDEX_NOT_FOUND;
2913        }
2914        return indexOfAny(cs, searchChars.toCharArray());
2915    }
2916
2917    /**
2918     * 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
2919     * (cs.codePointAt(i) ∉ { x ∈ codepoints(searchChars) })
2920     *
2921     * <p>
2922     * A {@code null} CharSequence will return {@code -1}. A {@code null} or zero length search array will return {@code -1}.
2923     * </p>
2924     *
2925     * <pre>
2926     * StringUtils.indexOfAnyBut(null, *)                              = -1
2927     * StringUtils.indexOfAnyBut("", *)                                = -1
2928     * StringUtils.indexOfAnyBut(*, null)                              = -1
2929     * StringUtils.indexOfAnyBut(*, [])                                = -1
2930     * StringUtils.indexOfAnyBut("zzabyycdxx", new char[] {'z', 'a'} ) = 3
2931     * StringUtils.indexOfAnyBut("aba", new char[] {'z'} )             = 0
2932     * StringUtils.indexOfAnyBut("aba", new char[] {'a', 'b'} )        = -1
2933     * </pre>
2934     *
2935     * @param cs          The CharSequence to check, may be null.
2936     * @param searchChars The chars to search for, may be null.
2937     * @return The index of any of the chars, -1 if no match or null input.
2938     * @since 2.0
2939     * @since 3.0 Changed signature from indexOfAnyBut(String, char[]) to indexOfAnyBut(CharSequence, char...)
2940     */
2941    public static int indexOfAnyBut(final CharSequence cs, final char... searchChars) {
2942        if (isEmpty(cs) || ArrayUtils.isEmpty(searchChars)) {
2943            return INDEX_NOT_FOUND;
2944        }
2945        return indexOfAnyBut(cs, CharBuffer.wrap(searchChars));
2946    }
2947
2948    /**
2949     * 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
2950     * (seq.codePointAt(i) ∉ { x ∈ codepoints(searchChars) })
2951     *
2952     * <p>
2953     * A {@code null} CharSequence will return {@code -1}. A {@code null} or empty search string will return {@code -1}.
2954     * </p>
2955     *
2956     * <pre>
2957     * StringUtils.indexOfAnyBut(null, *)            = -1
2958     * StringUtils.indexOfAnyBut("", *)              = -1
2959     * StringUtils.indexOfAnyBut(*, null)            = -1
2960     * StringUtils.indexOfAnyBut(*, "")              = -1
2961     * StringUtils.indexOfAnyBut("zzabyycdxx", "za") = 3
2962     * StringUtils.indexOfAnyBut("zzabyycdxx", "")   = -1
2963     * StringUtils.indexOfAnyBut("aba", "ab")        = -1
2964     * </pre>
2965     *
2966     * @param seq         The CharSequence to check, may be null.
2967     * @param searchChars The chars to search for, may be null.
2968     * @return The index of any of the chars, -1 if no match or null input.
2969     * @since 2.0
2970     * @since 3.0 Changed signature from indexOfAnyBut(String, String) to indexOfAnyBut(CharSequence, CharSequence)
2971     */
2972    public static int indexOfAnyBut(final CharSequence seq, final CharSequence searchChars) {
2973        if (isEmpty(seq) || isEmpty(searchChars)) {
2974            return INDEX_NOT_FOUND;
2975        }
2976        final Set<Integer> searchSetCodePoints = searchChars.codePoints()
2977                .boxed().collect(Collectors.toSet());
2978        // advance character index from one interpreted codepoint to the next
2979        for (int curSeqCharIdx = 0; curSeqCharIdx < seq.length();) {
2980            final int curSeqCodePoint = Character.codePointAt(seq, curSeqCharIdx);
2981            if (!searchSetCodePoints.contains(curSeqCodePoint)) {
2982                return curSeqCharIdx;
2983            }
2984            curSeqCharIdx += Character.charCount(curSeqCodePoint); // skip indices to paired low-surrogates
2985        }
2986        return INDEX_NOT_FOUND;
2987    }
2988
2989    /**
2990     * Compares all CharSequences in an array and returns the index at which the CharSequences begin to differ.
2991     *
2992     * <p>
2993     * For example, {@code indexOfDifference(new String[] {"i am a machine", "i am a robot"}) -> 7}
2994     * </p>
2995     *
2996     * <pre>
2997     * StringUtils.indexOfDifference(null)                             = -1
2998     * StringUtils.indexOfDifference(new String[] {})                  = -1
2999     * StringUtils.indexOfDifference(new String[] {"abc"})             = -1
3000     * StringUtils.indexOfDifference(new String[] {null, null})        = -1
3001     * StringUtils.indexOfDifference(new String[] {"", ""})            = -1
3002     * StringUtils.indexOfDifference(new String[] {"", null})          = 0
3003     * StringUtils.indexOfDifference(new String[] {"abc", null, null}) = 0
3004     * StringUtils.indexOfDifference(new String[] {null, null, "abc"}) = 0
3005     * StringUtils.indexOfDifference(new String[] {"", "abc"})         = 0
3006     * StringUtils.indexOfDifference(new String[] {"abc", ""})         = 0
3007     * StringUtils.indexOfDifference(new String[] {"abc", "abc"})      = -1
3008     * StringUtils.indexOfDifference(new String[] {"abc", "a"})        = 1
3009     * StringUtils.indexOfDifference(new String[] {"ab", "abxyz"})     = 2
3010     * StringUtils.indexOfDifference(new String[] {"abcde", "abxyz"})  = 2
3011     * StringUtils.indexOfDifference(new String[] {"abcde", "xyz"})    = 0
3012     * StringUtils.indexOfDifference(new String[] {"xyz", "abcde"})    = 0
3013     * StringUtils.indexOfDifference(new String[] {"i am a machine", "i am a robot"}) = 7
3014     * </pre>
3015     *
3016     * @param css array of CharSequences, entries may be null.
3017     * @return The index where the strings begin to differ; -1 if they are all equal.
3018     * @since 2.4
3019     * @since 3.0 Changed signature from indexOfDifference(String...) to indexOfDifference(CharSequence...)
3020     */
3021    public static int indexOfDifference(final CharSequence... css) {
3022        if (ArrayUtils.getLength(css) <= 1) {
3023            return INDEX_NOT_FOUND;
3024        }
3025        boolean anyStringNull = false;
3026        boolean allStringsNull = true;
3027        final int arrayLen = css.length;
3028        int shortestStrLen = Integer.MAX_VALUE;
3029        int longestStrLen = 0;
3030        // find the min and max string lengths; this avoids checking to make
3031        // sure we are not exceeding the length of the string each time through
3032        // the bottom loop.
3033        for (final CharSequence cs : css) {
3034            if (cs == null) {
3035                anyStringNull = true;
3036                shortestStrLen = 0;
3037            } else {
3038                allStringsNull = false;
3039                shortestStrLen = Math.min(cs.length(), shortestStrLen);
3040                longestStrLen = Math.max(cs.length(), longestStrLen);
3041            }
3042        }
3043        // handle lists containing all nulls or all empty strings
3044        if (allStringsNull || longestStrLen == 0 && !anyStringNull) {
3045            return INDEX_NOT_FOUND;
3046        }
3047        // handle lists containing some nulls or some empty strings
3048        if (shortestStrLen == 0) {
3049            return 0;
3050        }
3051        // find the position with the first difference across all strings
3052        int firstDiff = -1;
3053        for (int stringPos = 0; stringPos < shortestStrLen; stringPos++) {
3054            final char comparisonChar = css[0].charAt(stringPos);
3055            for (int arrayPos = 1; arrayPos < arrayLen; arrayPos++) {
3056                if (css[arrayPos].charAt(stringPos) != comparisonChar) {
3057                    firstDiff = stringPos;
3058                    break;
3059                }
3060            }
3061            if (firstDiff != -1) {
3062                break;
3063            }
3064        }
3065        if (firstDiff > 0 && Character.isLowSurrogate(css[0].charAt(firstDiff))
3066                && Character.isHighSurrogate(css[0].charAt(firstDiff - 1))) {
3067            // the difference splits a surrogate pair whose high half is common; report the start of the
3068            // pair so getCommonPrefix never slices it in half and leaves a stray high surrogate.
3069            firstDiff--;
3070        }
3071        if (firstDiff == -1 && shortestStrLen != longestStrLen) {
3072            // we compared all of the characters up to the length of the
3073            // shortest string and didn't find a match, but the string lengths
3074            // vary, so return the length of the shortest string.
3075            return shortestStrLen;
3076        }
3077        return firstDiff;
3078    }
3079
3080    /**
3081     * Compares two CharSequences, and returns the index at which the CharSequences begin to differ.
3082     *
3083     * <p>
3084     * For example, {@code indexOfDifference("i am a machine", "i am a robot") -> 7}
3085     * </p>
3086     *
3087     * <pre>
3088     * StringUtils.indexOfDifference(null, null)       = -1
3089     * StringUtils.indexOfDifference("", "")           = -1
3090     * StringUtils.indexOfDifference("", "abc")        = 0
3091     * StringUtils.indexOfDifference("abc", "")        = 0
3092     * StringUtils.indexOfDifference("abc", "abc")     = -1
3093     * StringUtils.indexOfDifference("ab", "abxyz")    = 2
3094     * StringUtils.indexOfDifference("abcde", "abxyz") = 2
3095     * StringUtils.indexOfDifference("abcde", "xyz")   = 0
3096     * </pre>
3097     *
3098     * @param cs1 The first CharSequence, may be null.
3099     * @param cs2 The second CharSequence, may be null.
3100     * @return The index where cs1 and cs2 begin to differ; -1 if they are equal.
3101     * @since 2.0
3102     * @since 3.0 Changed signature from indexOfDifference(String, String) to indexOfDifference(CharSequence, CharSequence)
3103     */
3104    public static int indexOfDifference(final CharSequence cs1, final CharSequence cs2) {
3105        if (cs1 == cs2) {
3106            return INDEX_NOT_FOUND;
3107        }
3108        if (cs1 == null || cs2 == null) {
3109            return 0;
3110        }
3111        int i;
3112        for (i = 0; i < cs1.length() && i < cs2.length(); ++i) {
3113            if (cs1.charAt(i) != cs2.charAt(i)) {
3114                break;
3115            }
3116        }
3117        if (i > 0 && i < cs1.length() && i < cs2.length() && Character.isHighSurrogate(cs1.charAt(i - 1))
3118                && (Character.isLowSurrogate(cs1.charAt(i)) || Character.isLowSurrogate(cs2.charAt(i)))) {
3119            // the difference splits a surrogate pair whose high half is common; report the start of the
3120            // pair so difference does not return a string that begins with a stray low surrogate.
3121            i--;
3122        }
3123        if (i < cs2.length() || i < cs1.length()) {
3124            return i;
3125        }
3126        return INDEX_NOT_FOUND;
3127    }
3128
3129    /**
3130     * Case insensitive find of the first index within a CharSequence.
3131     *
3132     * <p>
3133     * A {@code null} CharSequence will return {@code -1}. A negative start position is treated as zero. An empty ("") search CharSequence always matches. A
3134     * start position greater than the string length only matches an empty search CharSequence.
3135     * </p>
3136     *
3137     * <pre>
3138     * StringUtils.indexOfIgnoreCase(null, *)          = -1
3139     * StringUtils.indexOfIgnoreCase(*, null)          = -1
3140     * StringUtils.indexOfIgnoreCase("", "")           = 0
3141     * StringUtils.indexOfIgnoreCase(" ", " ")         = 0
3142     * StringUtils.indexOfIgnoreCase("aabaabaa", "a")  = 0
3143     * StringUtils.indexOfIgnoreCase("aabaabaa", "b")  = 2
3144     * StringUtils.indexOfIgnoreCase("aabaabaa", "ab") = 1
3145     * </pre>
3146     *
3147     * @param str       The CharSequence to check, may be null.
3148     * @param searchStr The CharSequence to find, may be null.
3149     * @return The first index of the search CharSequence, -1 if no match or {@code null} string input.
3150     * @since 2.5
3151     * @since 3.0 Changed signature from indexOfIgnoreCase(String, String) to indexOfIgnoreCase(CharSequence, CharSequence)
3152     * @deprecated Use {@link Strings#indexOf(CharSequence, CharSequence) Strings.CI.indexOf(CharSequence, CharSequence)}.
3153     */
3154    @Deprecated
3155    public static int indexOfIgnoreCase(final CharSequence str, final CharSequence searchStr) {
3156        return Strings.CI.indexOf(str, searchStr);
3157    }
3158
3159    /**
3160     * Case insensitive find of the first index within a CharSequence from the specified position.
3161     *
3162     * <p>
3163     * A {@code null} CharSequence will return {@code -1}. A negative start position is treated as zero. An empty ("") search CharSequence always matches. A
3164     * start position greater than the string length only matches an empty search CharSequence.
3165     * </p>
3166     *
3167     * <pre>
3168     * StringUtils.indexOfIgnoreCase(null, *, *)          = -1
3169     * StringUtils.indexOfIgnoreCase(*, null, *)          = -1
3170     * StringUtils.indexOfIgnoreCase("", "", 0)           = 0
3171     * StringUtils.indexOfIgnoreCase("aabaabaa", "A", 0)  = 0
3172     * StringUtils.indexOfIgnoreCase("aabaabaa", "B", 0)  = 2
3173     * StringUtils.indexOfIgnoreCase("aabaabaa", "AB", 0) = 1
3174     * StringUtils.indexOfIgnoreCase("aabaabaa", "B", 3)  = 5
3175     * StringUtils.indexOfIgnoreCase("aabaabaa", "B", 9)  = -1
3176     * StringUtils.indexOfIgnoreCase("aabaabaa", "B", -1) = 2
3177     * StringUtils.indexOfIgnoreCase("aabaabaa", "", 2)   = 2
3178     * StringUtils.indexOfIgnoreCase("abc", "", 9)        = -1
3179     * </pre>
3180     *
3181     * @param str       The CharSequence to check, may be null.
3182     * @param searchStr The CharSequence to find, may be null.
3183     * @param startPos  The start position, negative treated as zero.
3184     * @return The first index of the search CharSequence (always &ge; startPos), -1 if no match or {@code null} string input.
3185     * @since 2.5
3186     * @since 3.0 Changed signature from indexOfIgnoreCase(String, String, int) to indexOfIgnoreCase(CharSequence, CharSequence, int)
3187     * @deprecated Use {@link Strings#indexOf(CharSequence, CharSequence, int) Strings.CI.indexOf(CharSequence, CharSequence, int)}.
3188     */
3189    @Deprecated
3190    public static int indexOfIgnoreCase(final CharSequence str, final CharSequence searchStr, final int startPos) {
3191        return Strings.CI.indexOf(str, searchStr, startPos);
3192    }
3193
3194    /**
3195     * Tests if all of the CharSequences are empty (""), null or whitespace only.
3196     *
3197     * <p>
3198     * Whitespace is defined by {@link Character#isWhitespace(char)}.
3199     * </p>
3200     *
3201     * <pre>
3202     * StringUtils.isAllBlank(null)             = true
3203     * StringUtils.isAllBlank(null, "foo")      = false
3204     * StringUtils.isAllBlank(null, null)       = true
3205     * StringUtils.isAllBlank("", "bar")        = false
3206     * StringUtils.isAllBlank("bob", "")        = false
3207     * StringUtils.isAllBlank("  bob  ", null)  = false
3208     * StringUtils.isAllBlank(" ", "bar")       = false
3209     * StringUtils.isAllBlank("foo", "bar")     = false
3210     * StringUtils.isAllBlank(new String[] {})  = true
3211     * </pre>
3212     *
3213     * @param css The CharSequences to check, may be null or empty.
3214     * @return {@code true} if all of the CharSequences are empty or null or whitespace only.
3215     * @since 3.6
3216     */
3217    public static boolean isAllBlank(final CharSequence... css) {
3218        if (ArrayUtils.isEmpty(css)) {
3219            return true;
3220        }
3221        for (final CharSequence cs : css) {
3222            if (isNotBlank(cs)) {
3223                return false;
3224            }
3225        }
3226        return true;
3227    }
3228
3229    /**
3230     * Tests if all of the CharSequences are empty ("") or null.
3231     *
3232     * <pre>
3233     * StringUtils.isAllEmpty(null)             = true
3234     * StringUtils.isAllEmpty(null, "")         = true
3235     * StringUtils.isAllEmpty(new String[] {})  = true
3236     * StringUtils.isAllEmpty(null, "foo")      = false
3237     * StringUtils.isAllEmpty("", "bar")        = false
3238     * StringUtils.isAllEmpty("bob", "")        = false
3239     * StringUtils.isAllEmpty("  bob  ", null)  = false
3240     * StringUtils.isAllEmpty(" ", "bar")       = false
3241     * StringUtils.isAllEmpty("foo", "bar")     = false
3242     * </pre>
3243     *
3244     * @param css The CharSequences to check, may be null or empty.
3245     * @return {@code true} if all of the CharSequences are empty or null.
3246     * @since 3.6
3247     */
3248    public static boolean isAllEmpty(final CharSequence... css) {
3249        if (ArrayUtils.isEmpty(css)) {
3250            return true;
3251        }
3252        for (final CharSequence cs : css) {
3253            if (isNotEmpty(cs)) {
3254                return false;
3255            }
3256        }
3257        return true;
3258    }
3259
3260    /**
3261     * Tests if the CharSequence contains only lowercase characters.
3262     *
3263     * <p>
3264     * {@code null} will return {@code false}. An empty CharSequence (length()=0) will return {@code false}.
3265     * </p>
3266     *
3267     * <pre>
3268     * StringUtils.isAllLowerCase(null)   = false
3269     * StringUtils.isAllLowerCase("")     = false
3270     * StringUtils.isAllLowerCase("  ")   = false
3271     * StringUtils.isAllLowerCase("abc")  = true
3272     * StringUtils.isAllLowerCase("abC")  = false
3273     * StringUtils.isAllLowerCase("ab c") = false
3274     * StringUtils.isAllLowerCase("ab1c") = false
3275     * StringUtils.isAllLowerCase("ab/c") = false
3276     * </pre>
3277     *
3278     * @param cs The CharSequence to check, may be null.
3279     * @return {@code true} if only contains lowercase characters, and is non-null.
3280     * @since 2.5
3281     * @since 3.0 Changed signature from isAllLowerCase(String) to isAllLowerCase(CharSequence)
3282     */
3283    public static boolean isAllLowerCase(final CharSequence cs) {
3284        if (isEmpty(cs)) {
3285            return false;
3286        }
3287        final int sz = cs.length();
3288        for (int i = 0; i < sz;) {
3289            final int codePoint = Character.codePointAt(cs, i);
3290            if (!Character.isLowerCase(codePoint)) {
3291                return false;
3292            }
3293            i += Character.charCount(codePoint);
3294        }
3295        return true;
3296    }
3297
3298    /**
3299     * Tests if the CharSequence contains only uppercase characters.
3300     *
3301     * <p>
3302     * {@code null} will return {@code false}.
3303     * An empty String (length()=0) will return {@code false}.
3304     * </p>
3305     *
3306     * <pre>
3307     * StringUtils.isAllUpperCase(null)   = false
3308     * StringUtils.isAllUpperCase("")     = false
3309     * StringUtils.isAllUpperCase("  ")   = false
3310     * StringUtils.isAllUpperCase("ABC")  = true
3311     * StringUtils.isAllUpperCase("aBC")  = false
3312     * StringUtils.isAllUpperCase("A C")  = false
3313     * StringUtils.isAllUpperCase("A1C")  = false
3314     * StringUtils.isAllUpperCase("A/C")  = false
3315     * </pre>
3316     *
3317     * @param cs The CharSequence to check, may be null.
3318     * @return {@code true} if only contains uppercase characters, and is non-null.
3319     * @since 2.5
3320     * @since 3.0 Changed signature from isAllUpperCase(String) to isAllUpperCase(CharSequence)
3321     */
3322    public static boolean isAllUpperCase(final CharSequence cs) {
3323        if (isEmpty(cs)) {
3324            return false;
3325        }
3326        final int sz = cs.length();
3327        for (int i = 0; i < sz;) {
3328            final int codePoint = Character.codePointAt(cs, i);
3329            if (!Character.isUpperCase(codePoint)) {
3330                return false;
3331            }
3332            i += Character.charCount(codePoint);
3333        }
3334        return true;
3335    }
3336
3337    /**
3338     * Tests if the CharSequence contains only Unicode letters.
3339     *
3340     * <p>
3341     * {@code null} will return {@code false}. An empty CharSequence (length()=0) will return {@code false}.
3342     * </p>
3343     *
3344     * <pre>
3345     * StringUtils.isAlpha(null)   = false
3346     * StringUtils.isAlpha("")     = false
3347     * StringUtils.isAlpha("  ")   = false
3348     * StringUtils.isAlpha("abc")  = true
3349     * StringUtils.isAlpha("ab2c") = false
3350     * StringUtils.isAlpha("ab-c") = false
3351     * </pre>
3352     *
3353     * @param cs The CharSequence to check, may be null.
3354     * @return {@code true} if only contains letters, and is non-null.
3355     * @since 3.0 Changed signature from isAlpha(String) to isAlpha(CharSequence)
3356     * @since 3.0 Changed "" to return false and not true
3357     */
3358    public static boolean isAlpha(final CharSequence cs) {
3359        if (isEmpty(cs)) {
3360            return false;
3361        }
3362        final int sz = cs.length();
3363        for (int i = 0; i < sz;) {
3364            final int codePoint = Character.codePointAt(cs, i);
3365            if (!Character.isLetter(codePoint)) {
3366                return false;
3367            }
3368            i += Character.charCount(codePoint);
3369        }
3370        return true;
3371    }
3372
3373    /**
3374     * Tests if the CharSequence contains only Unicode letters or digits.
3375     *
3376     * <p>
3377     * {@code null} will return {@code false}. An empty CharSequence (length()=0) will return {@code false}.
3378     * </p>
3379     *
3380     * <pre>
3381     * StringUtils.isAlphanumeric(null)   = false
3382     * StringUtils.isAlphanumeric("")     = false
3383     * StringUtils.isAlphanumeric("  ")   = false
3384     * StringUtils.isAlphanumeric("abc")  = true
3385     * StringUtils.isAlphanumeric("ab c") = false
3386     * StringUtils.isAlphanumeric("ab2c") = true
3387     * StringUtils.isAlphanumeric("ab-c") = false
3388     * </pre>
3389     *
3390     * @param cs The CharSequence to check, may be null.
3391     * @return {@code true} if only contains letters or digits, and is non-null.
3392     * @since 3.0 Changed signature from isAlphanumeric(String) to isAlphanumeric(CharSequence)
3393     * @since 3.0 Changed "" to return false and not true
3394     */
3395    public static boolean isAlphanumeric(final CharSequence cs) {
3396        if (isEmpty(cs)) {
3397            return false;
3398        }
3399        final int sz = cs.length();
3400        for (int i = 0; i < sz;) {
3401            final int codePoint = Character.codePointAt(cs, i);
3402            if (!Character.isLetterOrDigit(codePoint)) {
3403                return false;
3404            }
3405            i += Character.charCount(codePoint);
3406        }
3407        return true;
3408    }
3409
3410    /**
3411     * Tests if the CharSequence contains only Unicode letters, digits or space ({@code ' '}).
3412     *
3413     * <p>
3414     * {@code null} will return {@code false}. An empty CharSequence (length()=0) will return {@code true}.
3415     * </p>
3416     *
3417     * <pre>
3418     * StringUtils.isAlphanumericSpace(null)   = false
3419     * StringUtils.isAlphanumericSpace("")     = true
3420     * StringUtils.isAlphanumericSpace("  ")   = true
3421     * StringUtils.isAlphanumericSpace("abc")  = true
3422     * StringUtils.isAlphanumericSpace("ab c") = true
3423     * StringUtils.isAlphanumericSpace("ab2c") = true
3424     * StringUtils.isAlphanumericSpace("ab-c") = false
3425     * </pre>
3426     *
3427     * @param cs The CharSequence to check, may be null.
3428     * @return {@code true} if only contains letters, digits or space, and is non-null.
3429     * @since 3.0 Changed signature from isAlphanumericSpace(String) to isAlphanumericSpace(CharSequence)
3430     */
3431    public static boolean isAlphanumericSpace(final CharSequence cs) {
3432        if (cs == null) {
3433            return false;
3434        }
3435        final int sz = cs.length();
3436        for (int i = 0; i < sz;) {
3437            final int codePoint = Character.codePointAt(cs, i);
3438            if (codePoint != ' ' && !Character.isLetterOrDigit(codePoint)) {
3439                return false;
3440            }
3441            i += Character.charCount(codePoint);
3442        }
3443        return true;
3444    }
3445
3446    /**
3447     * Tests if the CharSequence contains only Unicode letters and space (' ').
3448     *
3449     * <p>
3450     * {@code null} will return {@code false} An empty CharSequence (length()=0) will return {@code true}.
3451     * </p>
3452     *
3453     * <pre>
3454     * StringUtils.isAlphaSpace(null)   = false
3455     * StringUtils.isAlphaSpace("")     = true
3456     * StringUtils.isAlphaSpace("  ")   = true
3457     * StringUtils.isAlphaSpace("abc")  = true
3458     * StringUtils.isAlphaSpace("ab c") = true
3459     * StringUtils.isAlphaSpace("ab2c") = false
3460     * StringUtils.isAlphaSpace("ab-c") = false
3461     * </pre>
3462     *
3463     * @param cs The CharSequence to check, may be null.
3464     * @return {@code true} if only contains letters and space, and is non-null.
3465     * @since 3.0 Changed signature from isAlphaSpace(String) to isAlphaSpace(CharSequence)
3466     */
3467    public static boolean isAlphaSpace(final CharSequence cs) {
3468        if (cs == null) {
3469            return false;
3470        }
3471        final int sz = cs.length();
3472        for (int i = 0; i < sz;) {
3473            final int codePoint = Character.codePointAt(cs, i);
3474            if (codePoint != ' ' && !Character.isLetter(codePoint)) {
3475                return false;
3476            }
3477            i += Character.charCount(codePoint);
3478        }
3479        return true;
3480    }
3481
3482    /**
3483     * Tests if any of the CharSequences are {@link #isBlank(CharSequence) blank} (whitespaces, empty ({@code ""}), or {@code null}).
3484     *
3485     * <p>
3486     * Whitespace is defined by {@link Character#isWhitespace(char)}.
3487     * </p>
3488     *
3489     * <pre>
3490     * StringUtils.isAnyBlank((String) null)    = true
3491     * StringUtils.isAnyBlank((String[]) null)  = false
3492     * StringUtils.isAnyBlank(null, "foo")      = true
3493     * StringUtils.isAnyBlank(null, null)       = true
3494     * StringUtils.isAnyBlank("", "bar")        = true
3495     * StringUtils.isAnyBlank("bob", "")        = true
3496     * StringUtils.isAnyBlank("  bob  ", null)  = true
3497     * StringUtils.isAnyBlank(" ", "bar")       = true
3498     * StringUtils.isAnyBlank(new String[] {})  = false
3499     * StringUtils.isAnyBlank(new String[]{""}) = true
3500     * StringUtils.isAnyBlank("foo", "bar")     = false
3501     * </pre>
3502     *
3503     * @param css The CharSequences to check, may be null or empty.
3504     * @return {@code true} if any of the CharSequences are {@link #isBlank(CharSequence) blank} (whitespaces, empty ({@code ""}), or {@code null}).
3505     * @see #isBlank(CharSequence)
3506     * @since 3.2
3507     */
3508    public static boolean isAnyBlank(final CharSequence... css) {
3509        if (ArrayUtils.isEmpty(css)) {
3510            return false;
3511        }
3512        for (final CharSequence cs : css) {
3513            if (isBlank(cs)) {
3514                return true;
3515            }
3516        }
3517        return false;
3518    }
3519
3520    /**
3521     * Tests if any of the CharSequences are empty ("") or null.
3522     *
3523     * <pre>
3524     * StringUtils.isAnyEmpty((String) null)    = true
3525     * StringUtils.isAnyEmpty((String[]) null)  = false
3526     * StringUtils.isAnyEmpty(null, "foo")      = true
3527     * StringUtils.isAnyEmpty("", "bar")        = true
3528     * StringUtils.isAnyEmpty("bob", "")        = true
3529     * StringUtils.isAnyEmpty("  bob  ", null)  = true
3530     * StringUtils.isAnyEmpty(" ", "bar")       = false
3531     * StringUtils.isAnyEmpty("foo", "bar")     = false
3532     * StringUtils.isAnyEmpty(new String[]{})   = false
3533     * StringUtils.isAnyEmpty(new String[]{""}) = true
3534     * </pre>
3535     *
3536     * @param css  The CharSequences to check, may be null or empty.
3537     * @return {@code true} if any of the CharSequences are empty or null.
3538     * @since 3.2
3539     */
3540    public static boolean isAnyEmpty(final CharSequence... css) {
3541        if (ArrayUtils.isEmpty(css)) {
3542            return false;
3543        }
3544        for (final CharSequence cs : css) {
3545            if (isEmpty(cs)) {
3546                return true;
3547            }
3548        }
3549        return false;
3550    }
3551
3552    /**
3553     * Tests if the CharSequence contains only ASCII printable characters.
3554     *
3555     * <p>
3556     * {@code null} will return {@code false}. An empty CharSequence (length()=0) will return {@code true}.
3557     * </p>
3558     *
3559     * <pre>
3560     * StringUtils.isAsciiPrintable(null)     = false
3561     * StringUtils.isAsciiPrintable("")       = true
3562     * StringUtils.isAsciiPrintable(" ")      = true
3563     * StringUtils.isAsciiPrintable("Ceki")   = true
3564     * StringUtils.isAsciiPrintable("ab2c")   = true
3565     * StringUtils.isAsciiPrintable("!ab-c~") = true
3566     * StringUtils.isAsciiPrintable("\u0020") = true
3567     * StringUtils.isAsciiPrintable("\u0021") = true
3568     * StringUtils.isAsciiPrintable("\u007e") = true
3569     * StringUtils.isAsciiPrintable("\u007f") = false
3570     * StringUtils.isAsciiPrintable("Ceki G\u00fclc\u00fc") = false
3571     * </pre>
3572     *
3573     * @param cs The CharSequence to check, may be null.
3574     * @return {@code true} if every character is in the range 32 through 126.
3575     * @since 2.1
3576     * @since 3.0 Changed signature from isAsciiPrintable(String) to isAsciiPrintable(CharSequence)
3577     */
3578    public static boolean isAsciiPrintable(final CharSequence cs) {
3579        if (cs == null) {
3580            return false;
3581        }
3582        final int sz = cs.length();
3583        for (int i = 0; i < sz; i++) {
3584            if (!CharUtils.isAsciiPrintable(cs.charAt(i))) {
3585                return false;
3586            }
3587        }
3588        return true;
3589    }
3590
3591    /**
3592     * Tests if a CharSequence is empty ({@code "")}, null, or contains only whitespace as defined by {@link Character#isWhitespace(char)}.
3593     *
3594     * <pre>
3595     * StringUtils.isBlank(null)      = true
3596     * StringUtils.isBlank("")        = true
3597     * StringUtils.isBlank(" ")       = true
3598     * StringUtils.isBlank("bob")     = false
3599     * StringUtils.isBlank("  bob  ") = false
3600     * </pre>
3601     *
3602     * @param cs The CharSequence to check, may be null.
3603     * @return {@code true} if the CharSequence is null, empty or whitespace only.
3604     * @since 2.0
3605     * @since 3.0 Changed signature from isBlank(String) to isBlank(CharSequence)
3606     */
3607    public static boolean isBlank(final CharSequence cs) {
3608        final int strLen = length(cs);
3609        for (int i = 0; i < strLen; i++) {
3610            if (!Character.isWhitespace(cs.charAt(i))) {
3611                return false;
3612            }
3613        }
3614        return true;
3615    }
3616
3617    /**
3618     * Tests if a CharSequence is empty ("") or null.
3619     *
3620     * <pre>
3621     * StringUtils.isEmpty(null)      = true
3622     * StringUtils.isEmpty("")        = true
3623     * StringUtils.isEmpty(" ")       = false
3624     * StringUtils.isEmpty("bob")     = false
3625     * StringUtils.isEmpty("  bob  ") = false
3626     * </pre>
3627     *
3628     * <p>
3629     * NOTE: This method changed in Lang version 2.0. It no longer trims the CharSequence. That functionality is available in isBlank().
3630     * </p>
3631     *
3632     * @param cs The CharSequence to check, may be null.
3633     * @return {@code true} if the CharSequence is empty or null.
3634     * @since 3.0 Changed signature from isEmpty(String) to isEmpty(CharSequence)
3635     */
3636    public static boolean isEmpty(final CharSequence cs) {
3637        return cs == null || cs.length() == 0;
3638    }
3639
3640    /**
3641     * Tests if the CharSequence contains mixed casing of both uppercase and lowercase characters.
3642     *
3643     * <p>
3644     * {@code null} will return {@code false}. An empty CharSequence ({@code length()=0}) will return {@code false}.
3645     * </p>
3646     *
3647     * <pre>
3648     * StringUtils.isMixedCase(null)    = false
3649     * StringUtils.isMixedCase("")      = false
3650     * StringUtils.isMixedCase(" ")     = false
3651     * StringUtils.isMixedCase("ABC")   = false
3652     * StringUtils.isMixedCase("abc")   = false
3653     * StringUtils.isMixedCase("aBc")   = true
3654     * StringUtils.isMixedCase("A c")   = true
3655     * StringUtils.isMixedCase("A1c")   = true
3656     * StringUtils.isMixedCase("a/C")   = true
3657     * StringUtils.isMixedCase("aC\t")  = true
3658     * </pre>
3659     *
3660     * @param cs The CharSequence to check, may be null.
3661     * @return {@code true} if the CharSequence contains both uppercase and lowercase characters.
3662     * @since 3.5
3663     */
3664    public static boolean isMixedCase(final CharSequence cs) {
3665        if (isEmpty(cs) || cs.length() == 1) {
3666            return false;
3667        }
3668        boolean containsUppercase = false;
3669        boolean containsLowercase = false;
3670        final int sz = cs.length();
3671        for (int i = 0; i < sz;) {
3672            final int codePoint = Character.codePointAt(cs, i);
3673            if (Character.isUpperCase(codePoint)) {
3674                containsUppercase = true;
3675            } else if (Character.isLowerCase(codePoint)) {
3676                containsLowercase = true;
3677            }
3678            if (containsUppercase && containsLowercase) {
3679                return true;
3680            }
3681            i += Character.charCount(codePoint);
3682        }
3683        return false;
3684    }
3685
3686    /**
3687     * Tests if none of the CharSequences are empty (""), null or whitespace only.
3688     *
3689     * <p>
3690     * Whitespace is defined by {@link Character#isWhitespace(char)}.
3691     * </p>
3692     *
3693     * <pre>
3694     * StringUtils.isNoneBlank((String) null)    = false
3695     * StringUtils.isNoneBlank((String[]) null)  = true
3696     * StringUtils.isNoneBlank(null, "foo")      = false
3697     * StringUtils.isNoneBlank(null, null)       = false
3698     * StringUtils.isNoneBlank("", "bar")        = false
3699     * StringUtils.isNoneBlank("bob", "")        = false
3700     * StringUtils.isNoneBlank("  bob  ", null)  = false
3701     * StringUtils.isNoneBlank(" ", "bar")       = false
3702     * StringUtils.isNoneBlank(new String[] {})  = true
3703     * StringUtils.isNoneBlank(new String[]{""}) = false
3704     * StringUtils.isNoneBlank("foo", "bar")     = true
3705     * </pre>
3706     *
3707     * @param css The CharSequences to check, may be null or empty.
3708     * @return {@code true} if none of the CharSequences are empty or null or whitespace only.
3709     * @since 3.2
3710     */
3711    public static boolean isNoneBlank(final CharSequence... css) {
3712        return !isAnyBlank(css);
3713    }
3714
3715    /**
3716     * Tests if none of the CharSequences are empty ("") or null.
3717     *
3718     * <pre>
3719     * StringUtils.isNoneEmpty((String) null)    = false
3720     * StringUtils.isNoneEmpty((String[]) null)  = true
3721     * StringUtils.isNoneEmpty(null, "foo")      = false
3722     * StringUtils.isNoneEmpty("", "bar")        = false
3723     * StringUtils.isNoneEmpty("bob", "")        = false
3724     * StringUtils.isNoneEmpty("  bob  ", null)  = false
3725     * StringUtils.isNoneEmpty(new String[] {})  = true
3726     * StringUtils.isNoneEmpty(new String[]{""}) = false
3727     * StringUtils.isNoneEmpty(" ", "bar")       = true
3728     * StringUtils.isNoneEmpty("foo", "bar")     = true
3729     * </pre>
3730     *
3731     * @param css  The CharSequences to check, may be null or empty.
3732     * @return {@code true} if none of the CharSequences are empty or null.
3733     * @since 3.2
3734     */
3735    public static boolean isNoneEmpty(final CharSequence... css) {
3736        return !isAnyEmpty(css);
3737    }
3738
3739    /**
3740     * Tests if a CharSequence is not {@link #isBlank(CharSequence) blank} (whitespaces, empty ({@code ""}), or {@code null}).
3741     *
3742     * <p>
3743     * Whitespace is defined by {@link Character#isWhitespace(char)}.
3744     * </p>
3745     *
3746     * <pre>
3747     * StringUtils.isNotBlank(null)      = false
3748     * StringUtils.isNotBlank("")        = false
3749     * StringUtils.isNotBlank(" ")       = false
3750     * StringUtils.isNotBlank("bob")     = true
3751     * StringUtils.isNotBlank("  bob  ") = true
3752     * </pre>
3753     *
3754     * @param cs The CharSequence to check, may be null.
3755     * @return {@code true} if the CharSequence is not {@link #isBlank(CharSequence) blank} (whitespaces, empty ({@code ""}), or {@code null}).
3756     * @see #isBlank(CharSequence)
3757     * @since 2.0
3758     * @since 3.0 Changed signature from isNotBlank(String) to isNotBlank(CharSequence)
3759     */
3760    public static boolean isNotBlank(final CharSequence cs) {
3761        return !isBlank(cs);
3762    }
3763
3764    /**
3765     * Tests if a CharSequence is not empty ("") and not null.
3766     *
3767     * <pre>
3768     * StringUtils.isNotEmpty(null)      = false
3769     * StringUtils.isNotEmpty("")        = false
3770     * StringUtils.isNotEmpty(" ")       = true
3771     * StringUtils.isNotEmpty("bob")     = true
3772     * StringUtils.isNotEmpty("  bob  ") = true
3773     * </pre>
3774     *
3775     * @param cs  The CharSequence to check, may be null.
3776     * @return {@code true} if the CharSequence is not empty and not null.
3777     * @since 3.0 Changed signature from isNotEmpty(String) to isNotEmpty(CharSequence)
3778     */
3779    public static boolean isNotEmpty(final CharSequence cs) {
3780        return !isEmpty(cs);
3781    }
3782
3783    /**
3784     * Tests if the CharSequence contains only Unicode digits. A decimal point is not a Unicode digit and returns false.
3785     *
3786     * <p>
3787     * {@code null} will return {@code false}. An empty CharSequence (length()=0) will return {@code false}.
3788     * </p>
3789     *
3790     * <p>
3791     * 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
3792     * NumberFormatException when parsed by Integer.parseInt or Long.parseLong, e.g. if the value is outside the range for int or long respectively.
3793     * </p>
3794     *
3795     * <pre>
3796     * StringUtils.isNumeric(null)   = false
3797     * StringUtils.isNumeric("")     = false
3798     * StringUtils.isNumeric("  ")   = false
3799     * StringUtils.isNumeric("123")  = true
3800     * StringUtils.isNumeric("\u0967\u0968\u0969")  = true
3801     * StringUtils.isNumeric("12 3") = false
3802     * StringUtils.isNumeric("ab2c") = false
3803     * StringUtils.isNumeric("12-3") = false
3804     * StringUtils.isNumeric("12.3") = false
3805     * StringUtils.isNumeric("-123") = false
3806     * StringUtils.isNumeric("+123") = false
3807     * </pre>
3808     *
3809     * @param cs The CharSequence to check, may be null.
3810     * @return {@code true} if only contains digits, and is non-null.
3811     * @since 3.0 Changed signature from isNumeric(String) to isNumeric(CharSequence)
3812     * @since 3.0 Changed "" to return false and not true
3813     */
3814    public static boolean isNumeric(final CharSequence cs) {
3815        if (isEmpty(cs)) {
3816            return false;
3817        }
3818        final int sz = cs.length();
3819        for (int i = 0; i < sz;) {
3820            final int codePoint = Character.codePointAt(cs, i);
3821            if (!Character.isDigit(codePoint)) {
3822                return false;
3823            }
3824            i += Character.charCount(codePoint);
3825        }
3826        return true;
3827    }
3828
3829    /**
3830     * Tests if the CharSequence contains only Unicode digits or space ({@code ' '}). A decimal point is not a Unicode digit and returns false.
3831     *
3832     * <p>
3833     * {@code null} will return {@code false}. An empty CharSequence (length()=0) will return {@code true}.
3834     * </p>
3835     *
3836     * <pre>
3837     * StringUtils.isNumericSpace(null)   = false
3838     * StringUtils.isNumericSpace("")     = true
3839     * StringUtils.isNumericSpace("  ")   = true
3840     * StringUtils.isNumericSpace("123")  = true
3841     * StringUtils.isNumericSpace("12 3") = true
3842     * StringUtils.isNumericSpace("\u0967\u0968\u0969")   = true
3843     * StringUtils.isNumericSpace("\u0967\u0968 \u0969")  = true
3844     * StringUtils.isNumericSpace("ab2c") = false
3845     * StringUtils.isNumericSpace("12-3") = false
3846     * StringUtils.isNumericSpace("12.3") = false
3847     * </pre>
3848     *
3849     * @param cs The CharSequence to check, may be null.
3850     * @return {@code true} if only contains digits or space, and is non-null.
3851     * @since 3.0 Changed signature from isNumericSpace(String) to isNumericSpace(CharSequence)
3852     */
3853    public static boolean isNumericSpace(final CharSequence cs) {
3854        if (cs == null) {
3855            return false;
3856        }
3857        final int sz = cs.length();
3858        for (int i = 0; i < sz;) {
3859            final int codePoint = Character.codePointAt(cs, i);
3860            if (codePoint != ' ' && !Character.isDigit(codePoint)) {
3861                return false;
3862            }
3863            i += Character.charCount(codePoint);
3864        }
3865        return true;
3866    }
3867
3868    /**
3869     * Tests if the CharSequence contains only whitespace.
3870     *
3871     * <p>
3872     * Whitespace is defined by {@link Character#isWhitespace(char)}.
3873     * </p>
3874     *
3875     * <p>
3876     * {@code null} will return {@code false}. An empty CharSequence (length()=0) will return {@code true}.
3877     * </p>
3878     *
3879     * <pre>
3880     * StringUtils.isWhitespace(null)   = false
3881     * StringUtils.isWhitespace("")     = true
3882     * StringUtils.isWhitespace("  ")   = true
3883     * StringUtils.isWhitespace("abc")  = false
3884     * StringUtils.isWhitespace("ab2c") = false
3885     * StringUtils.isWhitespace("ab-c") = false
3886     * </pre>
3887     *
3888     * @param cs The CharSequence to check, may be null.
3889     * @return {@code true} if only contains whitespace, and is non-null.
3890     * @since 2.0
3891     * @since 3.0 Changed signature from isWhitespace(String) to isWhitespace(CharSequence)
3892     */
3893    public static boolean isWhitespace(final CharSequence cs) {
3894        if (cs == null) {
3895            return false;
3896        }
3897        final int sz = cs.length();
3898        for (int i = 0; i < sz; i++) {
3899            if (!Character.isWhitespace(cs.charAt(i))) {
3900                return false;
3901            }
3902        }
3903        return true;
3904    }
3905
3906    /**
3907     * Joins the elements of the provided array into a single String containing the provided list of elements.
3908     *
3909     * <p>
3910     * No delimiter is added before or after the list. Null objects or empty strings within the array are represented by empty strings.
3911     * </p>
3912     *
3913     * <pre>
3914     * StringUtils.join(null, *)             = null
3915     * StringUtils.join([], *)               = ""
3916     * StringUtils.join([null], *)           = ""
3917     * StringUtils.join([false, false], ';') = "false;false"
3918     * </pre>
3919     *
3920     * @param array     The array of values to join together, may be null.
3921     * @param delimiter The separator character to use.
3922     * @return The joined String, {@code null} if null array input.
3923     * @since 3.12.0
3924     */
3925    public static String join(final boolean[] array, final char delimiter) {
3926        if (array == null) {
3927            return null;
3928        }
3929        return join(array, delimiter, 0, array.length);
3930    }
3931
3932    /**
3933     * Joins the elements of the provided array into a single String containing the provided list of elements.
3934     *
3935     * <p>
3936     * No delimiter is added before or after the list. Null objects or empty strings within the array are represented
3937     * by empty strings.
3938     * </p>
3939     *
3940     * <pre>
3941     * StringUtils.join(null, *)                  = null
3942     * StringUtils.join([], *)                    = ""
3943     * StringUtils.join([null], *)                = ""
3944     * StringUtils.join([true, false, true], ';') = "true;false;true"
3945     * </pre>
3946     *
3947     * @param array
3948     *            the array of values to join together, may be null.
3949     * @param delimiter
3950     *            the separator character to use.
3951     * @param startIndex
3952     *            the first index to start joining from. It is an error to pass in a start index past the end of the
3953     *            array.
3954     * @param endIndex
3955     *            the index to stop joining from (exclusive). It is an error to pass in an end index past the end of
3956     *            the array.
3957     * @return The joined String, {@code null} if null array input.
3958     * @since 3.12.0
3959     */
3960    public static String join(final boolean[] array, final char delimiter, final int startIndex, final int endIndex) {
3961        // See StringUtilsJoinBenchmark
3962        if (array == null) {
3963            return null;
3964        }
3965        checkFromToIndex(startIndex, endIndex, array.length);
3966        final int count = endIndex - startIndex;
3967        if (count <= 0) {
3968            return EMPTY;
3969        }
3970        final byte maxElementChars = 5; // "false"
3971        final StringBuilder stringBuilder = capacity(count, maxElementChars);
3972        stringBuilder.append(array[startIndex]);
3973        for (int i = startIndex + 1; i < endIndex; i++) {
3974            stringBuilder.append(delimiter).append(array[i]);
3975        }
3976        return stringBuilder.toString();
3977    }
3978
3979    /**
3980     * Joins the elements of the provided array into a single String containing the provided list of elements.
3981     *
3982     * <p>
3983     * No delimiter is added before or after the list. Null objects or empty strings within the array are represented
3984     * by empty strings.
3985     * </p>
3986     *
3987     * <pre>
3988     * StringUtils.join(null, *)         = null
3989     * StringUtils.join([], *)           = ""
3990     * StringUtils.join([null], *)       = ""
3991     * StringUtils.join([1, 2, 3], ';')  = "1;2;3"
3992     * StringUtils.join([1, 2, 3], null) = "123"
3993     * </pre>
3994     *
3995     * @param array
3996     *            the array of values to join together, may be null.
3997     * @param delimiter
3998     *            the separator character to use.
3999     * @return The joined String, {@code null} if null array input.
4000     * @since 3.2
4001     */
4002    public static String join(final byte[] array, final char delimiter) {
4003        if (array == null) {
4004            return null;
4005        }
4006        return join(array, delimiter, 0, array.length);
4007    }
4008
4009    /**
4010     * Joins the elements of the provided array into a single String containing the provided list of elements.
4011     *
4012     * <p>
4013     * No delimiter is added before or after the list. Null objects or empty strings within the array are represented
4014     * by empty strings.
4015     * </p>
4016     *
4017     * <pre>
4018     * StringUtils.join(null, *)         = null
4019     * StringUtils.join([], *)           = ""
4020     * StringUtils.join([null], *)       = ""
4021     * StringUtils.join([1, 2, 3], ';')  = "1;2;3"
4022     * StringUtils.join([1, 2, 3], null) = "123"
4023     * </pre>
4024     *
4025     * @param array
4026     *            the array of values to join together, may be null.
4027     * @param delimiter
4028     *            the separator character to use.
4029     * @param startIndex
4030     *            the first index to start joining from. It is an error to pass in a start index past the end of the
4031     *            array.
4032     * @param endIndex
4033     *            the index to stop joining from (exclusive). It is an error to pass in an end index past the end of
4034     *            the array.
4035     * @return The joined String, {@code null} if null array input.
4036     * @since 3.2
4037     */
4038    public static String join(final byte[] array, final char delimiter, final int startIndex, final int endIndex) {
4039        // See StringUtilsJoinBenchmark
4040        if (array == null) {
4041            return null;
4042        }
4043        checkFromToIndex(startIndex, endIndex, array.length);
4044        final int count = endIndex - startIndex;
4045        if (count <= 0) {
4046            return EMPTY;
4047        }
4048        final byte maxElementChars = 4; // "-128"
4049        final StringBuilder stringBuilder = capacity(count, maxElementChars);
4050        stringBuilder.append(array[startIndex]);
4051        for (int i = startIndex + 1; i < endIndex; i++) {
4052            stringBuilder.append(delimiter).append(array[i]);
4053        }
4054        return stringBuilder.toString();
4055    }
4056
4057    /**
4058     * Joins the elements of the provided array into a single String containing the provided list of elements.
4059     *
4060     * <p>
4061     * No delimiter is added before or after the list. Null objects or empty strings within the array are represented
4062     * by empty strings.
4063     * </p>
4064     *
4065     * <pre>
4066     * StringUtils.join(null, *)         = null
4067     * StringUtils.join([], *)           = ""
4068     * StringUtils.join([null], *)       = ""
4069     * StringUtils.join([1, 2, 3], ';')  = "1;2;3"
4070     * StringUtils.join([1, 2, 3], null) = "123"
4071     * </pre>
4072     *
4073     * @param array
4074     *            the array of values to join together, may be null.
4075     * @param delimiter
4076     *            the separator character to use.
4077     * @return The joined String, {@code null} if null array input.
4078     * @since 3.2
4079     */
4080    public static String join(final char[] array, final char delimiter) {
4081        if (array == null) {
4082            return null;
4083        }
4084        return join(array, delimiter, 0, array.length);
4085    }
4086
4087    /**
4088     * Joins the elements of the provided array into a single String containing the provided list of elements.
4089     *
4090     * <p>
4091     * No delimiter is added before or after the list. Null objects or empty strings within the array are represented
4092     * by empty strings.
4093     * </p>
4094     *
4095     * <pre>
4096     * StringUtils.join(null, *)         = null
4097     * StringUtils.join([], *)           = ""
4098     * StringUtils.join([null], *)       = ""
4099     * StringUtils.join([1, 2, 3], ';')  = "1;2;3"
4100     * StringUtils.join([1, 2, 3], null) = "123"
4101     * </pre>
4102     *
4103     * @param array
4104     *            the array of values to join together, may be null.
4105     * @param delimiter
4106     *            the separator character to use.
4107     * @param startIndex
4108     *            the first index to start joining from. It is an error to pass in a start index past the end of the
4109     *            array.
4110     * @param endIndex
4111     *            the index to stop joining from (exclusive). It is an error to pass in an end index past the end of
4112     *            the array.
4113     * @return The joined String, {@code null} if null array input.
4114     * @since 3.2
4115     */
4116    public static String join(final char[] array, final char delimiter, final int startIndex, final int endIndex) {
4117        // See StringUtilsJoinBenchmark
4118        if (array == null) {
4119            return null;
4120        }
4121        checkFromToIndex(startIndex, endIndex, array.length);
4122        final int count = endIndex - startIndex;
4123        if (count <= 0) {
4124            return EMPTY;
4125        }
4126        final byte maxElementChars = 1;
4127        final StringBuilder stringBuilder = capacity(count, maxElementChars);
4128        stringBuilder.append(array[startIndex]);
4129        for (int i = startIndex + 1; i < endIndex; i++) {
4130            stringBuilder.append(delimiter).append(array[i]);
4131        }
4132        return stringBuilder.toString();
4133    }
4134
4135    /**
4136     * Joins the elements of the provided array into a single String containing the provided list of elements.
4137     *
4138     * <p>
4139     * No delimiter is added before or after the list. Null objects or empty strings within the array are represented
4140     * by empty strings.
4141     * </p>
4142     *
4143     * <pre>
4144     * StringUtils.join(null, *)          = null
4145     * StringUtils.join([], *)            = ""
4146     * StringUtils.join([null], *)        = ""
4147     * StringUtils.join([1, 2, 3], ';')   = "1;2;3"
4148     * StringUtils.join([1, 2, 3], null)  = "123"
4149     * </pre>
4150     *
4151     * @param array
4152     *            the array of values to join together, may be null.
4153     * @param delimiter
4154     *            the separator character to use.
4155     * @return The joined String, {@code null} if null array input.
4156     * @since 3.2
4157     */
4158    public static String join(final double[] array, final char delimiter) {
4159        if (array == null) {
4160            return null;
4161        }
4162        return join(array, delimiter, 0, array.length);
4163    }
4164
4165    /**
4166     * Joins the elements of the provided array into a single String containing the provided list of elements.
4167     *
4168     * <p>
4169     * No delimiter is added before or after the list. Null objects or empty strings within the array are represented
4170     * by empty strings.
4171     * </p>
4172     *
4173     * <pre>
4174     * StringUtils.join(null, *)          = null
4175     * StringUtils.join([], *)            = ""
4176     * StringUtils.join([null], *)        = ""
4177     * StringUtils.join([1, 2, 3], ';')   = "1;2;3"
4178     * StringUtils.join([1, 2, 3], null)  = "123"
4179     * </pre>
4180     *
4181     * @param array
4182     *            the array of values to join together, may be null.
4183     * @param delimiter
4184     *            the separator character to use.
4185     * @param startIndex
4186     *            the first index to start joining from. It is an error to pass in a start index past the end of the
4187     *            array.
4188     * @param endIndex
4189     *            the index to stop joining from (exclusive). It is an error to pass in an end index past the end of
4190     *            the array.
4191     * @return The joined String, {@code null} if null array input.
4192     * @since 3.2
4193     */
4194    public static String join(final double[] array, final char delimiter, final int startIndex, final int endIndex) {
4195        // See StringUtilsJoinBenchmark
4196        if (array == null) {
4197            return null;
4198        }
4199        checkFromToIndex(startIndex, endIndex, array.length);
4200        final int count = endIndex - startIndex;
4201        if (count <= 0) {
4202            return EMPTY;
4203        }
4204        final byte maxElementChars = 22; // "1.7976931348623157E308"
4205        final StringBuilder stringBuilder = capacity(count, maxElementChars);
4206        stringBuilder.append(array[startIndex]);
4207        for (int i = startIndex + 1; i < endIndex; i++) {
4208            stringBuilder.append(delimiter).append(array[i]);
4209        }
4210        return stringBuilder.toString();
4211    }
4212
4213    /**
4214     * Joins the elements of the provided array into a single String containing the provided list of elements.
4215     *
4216     * <p>
4217     * No delimiter is added before or after the list. Null objects or empty strings within the array are represented
4218     * by empty strings.
4219     * </p>
4220     *
4221     * <pre>
4222     * StringUtils.join(null, *)          = null
4223     * StringUtils.join([], *)            = ""
4224     * StringUtils.join([null], *)        = ""
4225     * StringUtils.join([1, 2, 3], ';')   = "1;2;3"
4226     * StringUtils.join([1, 2, 3], null)  = "123"
4227     * </pre>
4228     *
4229     * @param array
4230     *            the array of values to join together, may be null.
4231     * @param delimiter
4232     *            the separator character to use.
4233     * @return The joined String, {@code null} if null array input
4234     * @since 3.2
4235     */
4236    public static String join(final float[] array, final char delimiter) {
4237        if (array == null) {
4238            return null;
4239        }
4240        return join(array, delimiter, 0, array.length);
4241    }
4242
4243    /**
4244     * Joins the elements of the provided array into a single String containing the provided list of elements.
4245     *
4246     * <p>
4247     * No delimiter is added before or after the list. Null objects or empty strings within the array are represented
4248     * by empty strings.
4249     * </p>
4250     *
4251     * <pre>
4252     * StringUtils.join(null, *)          = null
4253     * StringUtils.join([], *)            = ""
4254     * StringUtils.join([null], *)        = ""
4255     * StringUtils.join([1, 2, 3], ';')   = "1;2;3"
4256     * StringUtils.join([1, 2, 3], null)  = "123"
4257     * </pre>
4258     *
4259     * @param array
4260     *            the array of values to join together, may be null.
4261     * @param delimiter
4262     *            the separator character to use.
4263     * @param startIndex
4264     *            the first index to start joining from. It is an error to pass in a start index past the end of the
4265     *            array.
4266     * @param endIndex
4267     *            the index to stop joining from (exclusive). It is an error to pass in an end index past the end of
4268     *            the array.
4269     * @return The joined String, {@code null} if null array input.
4270     * @since 3.2
4271     */
4272    public static String join(final float[] array, final char delimiter, final int startIndex, final int endIndex) {
4273        // See StringUtilsJoinBenchmark
4274        if (array == null) {
4275            return null;
4276        }
4277        checkFromToIndex(startIndex, endIndex, array.length);
4278        final int count = endIndex - startIndex;
4279        if (count <= 0) {
4280            return EMPTY;
4281        }
4282        final byte maxElementChars = 12; // "3.4028235E38"
4283        final StringBuilder stringBuilder = capacity(count, maxElementChars);
4284        stringBuilder.append(array[startIndex]);
4285        for (int i = startIndex + 1; i < endIndex; i++) {
4286            stringBuilder.append(delimiter).append(array[i]);
4287        }
4288        return stringBuilder.toString();
4289    }
4290
4291    /**
4292     * Joins the elements of the provided array into a single String containing the provided list of elements.
4293     *
4294     * <p>
4295     * No delimiter is added before or after the list. Null objects or empty strings within the array are represented
4296     * by empty strings.
4297     * </p>
4298     *
4299     * <pre>
4300     * StringUtils.join(null, *)          = null
4301     * StringUtils.join([], *)            = ""
4302     * StringUtils.join([null], *)        = ""
4303     * StringUtils.join([1, 2, 3], ';')   = "1;2;3"
4304     * StringUtils.join([1, 2, 3], null)  = "123"
4305     * </pre>
4306     *
4307     * @param array
4308     *            the array of values to join together, may be null.
4309     * @param separator
4310     *            the separator character to use.
4311     * @return The joined String, {@code null} if null array input.
4312     * @since 3.2
4313     */
4314    public static String join(final int[] array, final char separator) {
4315        if (array == null) {
4316            return null;
4317        }
4318        return join(array, separator, 0, array.length);
4319    }
4320
4321    /**
4322     * Joins the elements of the provided array into a single String containing the provided list of elements.
4323     *
4324     * <p>
4325     * No delimiter is added before or after the list. Null objects or empty strings within the array are represented
4326     * by empty strings.
4327     * </p>
4328     *
4329     * <pre>
4330     * StringUtils.join(null, *)          = null
4331     * StringUtils.join([], *)            = ""
4332     * StringUtils.join([null], *)        = ""
4333     * StringUtils.join([1, 2, 3], ';')   = "1;2;3"
4334     * StringUtils.join([1, 2, 3], null)  = "123"
4335     * </pre>
4336     *
4337     * @param array
4338     *            the array of values to join together, may be null.
4339     * @param delimiter
4340     *            the separator character to use.
4341     * @param startIndex
4342     *            the first index to start joining from. It is an error to pass in a start index past the end of the
4343     *            array.
4344     * @param endIndex
4345     *            the index to stop joining from (exclusive). It is an error to pass in an end index past the end of
4346     *            the array.
4347     * @return The joined String, {@code null} if null array input.
4348     * @since 3.2
4349     */
4350    public static String join(final int[] array, final char delimiter, final int startIndex, final int endIndex) {
4351        // See StringUtilsJoinBenchmark
4352        if (array == null) {
4353            return null;
4354        }
4355        checkFromToIndex(startIndex, endIndex, array.length);
4356        final int count = endIndex - startIndex;
4357        if (count <= 0) {
4358            return EMPTY;
4359        }
4360        final byte maxElementChars = 11; // "-2147483648"
4361        final StringBuilder stringBuilder = capacity(count, maxElementChars);
4362        stringBuilder.append(array[startIndex]);
4363        for (int i = startIndex + 1; i < endIndex; i++) {
4364            stringBuilder.append(delimiter).append(array[i]);
4365        }
4366        return stringBuilder.toString();
4367    }
4368
4369    /**
4370     * Joins the elements of the provided {@link Iterable} into a single String containing the provided elements.
4371     *
4372     * <p>
4373     * No delimiter is added before or after the list. Null objects or empty strings within the iteration are represented by empty strings.
4374     * </p>
4375     *
4376     * <p>
4377     * See the examples here: {@link #join(Object[],char)}.
4378     * </p>
4379     *
4380     * @param iterable  The {@link Iterable} providing the values to join together, may be null.
4381     * @param separator The separator character to use.
4382     * @return The joined String, {@code null} if null iterator input.
4383     * @since 2.3
4384     */
4385    public static String join(final Iterable<?> iterable, final char separator) {
4386        return iterable != null ? join(iterable.iterator(), separator) : null;
4387    }
4388
4389    /**
4390     * Joins the elements of the provided {@link Iterable} into a single String containing the provided elements.
4391     *
4392     * <p>
4393     * No delimiter is added before or after the list. A {@code null} separator is the same as an empty String ("").
4394     * </p>
4395     *
4396     * <p>
4397     * See the examples here: {@link #join(Object[],String)}.
4398     * </p>
4399     *
4400     * @param iterable  The {@link Iterable} providing the values to join together, may be null.
4401     * @param separator The separator character to use, null treated as "".
4402     * @return The joined String, {@code null} if null iterator input.
4403     * @since 2.3
4404     */
4405    public static String join(final Iterable<?> iterable, final String separator) {
4406        return iterable != null ? join(iterable.iterator(), separator) : null;
4407    }
4408
4409    /**
4410     * Joins the elements of the provided {@link Iterator} into a single String containing the provided elements.
4411     *
4412     * <p>
4413     * No delimiter is added before or after the list. Null objects or empty strings within the iteration are represented by empty strings.
4414     * </p>
4415     *
4416     * <p>
4417     * See the examples here: {@link #join(Object[],char)}.
4418     * </p>
4419     *
4420     * @param iterator  The {@link Iterator} of values to join together, may be null.
4421     * @param separator The separator character to use.
4422     * @return The joined String, {@code null} if null iterator input.
4423     * @since 2.0
4424     */
4425    public static String join(final Iterator<?> iterator, final char separator) {
4426        // handle null, zero and one elements before building a buffer
4427        if (iterator == null) {
4428            return null;
4429        }
4430        if (!iterator.hasNext()) {
4431            return EMPTY;
4432        }
4433        return Streams.of(iterator).collect(LangCollectors.joining(ObjectUtils.toString(String.valueOf(separator)), EMPTY, EMPTY, ObjectUtils::toString));
4434    }
4435
4436    /**
4437     * Joins the elements of the provided {@link Iterator} into a single String containing the provided elements.
4438     *
4439     * <p>
4440     * No delimiter is added before or after the list. A {@code null} separator is the same as an empty String ("").
4441     * </p>
4442     *
4443     * <p>
4444     * See the examples here: {@link #join(Object[],String)}.
4445     * </p>
4446     *
4447     * @param iterator  The {@link Iterator} of values to join together, may be null.
4448     * @param separator The separator character to use, null treated as "".
4449     * @return The joined String, {@code null} if null iterator input.
4450     */
4451    public static String join(final Iterator<?> iterator, final String separator) {
4452        // handle null, zero and one elements before building a buffer
4453        if (iterator == null) {
4454            return null;
4455        }
4456        if (!iterator.hasNext()) {
4457            return EMPTY;
4458        }
4459        return Streams.of(iterator).collect(LangCollectors.joining(ObjectUtils.toString(separator), EMPTY, EMPTY, ObjectUtils::toString));
4460    }
4461
4462    /**
4463     * Joins the elements of the provided {@link List} into a single String containing the provided list of elements.
4464     *
4465     * <p>
4466     * No delimiter is added before or after the list. Null objects or empty strings within the array are represented by empty strings.
4467     * </p>
4468     *
4469     * <pre>
4470     * StringUtils.join(null, *)               = null
4471     * StringUtils.join([], *)                 = ""
4472     * StringUtils.join([null], *)             = ""
4473     * StringUtils.join(["a", "b", "c"], ';')  = "a;b;c"
4474     * StringUtils.join(["a", "b", "c"], null) = "abc"
4475     * StringUtils.join([null, "", "a"], ';')  = ";;a"
4476     * </pre>
4477     *
4478     * @param list       The {@link List} of values to join together, may be null.
4479     * @param separator  The separator character to use.
4480     * @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.
4481     * @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.
4482     * @return The joined String, {@code null} if null list input.
4483     * @since 3.8
4484     */
4485    public static String join(final List<?> list, final char separator, final int startIndex, final int endIndex) {
4486        if (list == null) {
4487            return null;
4488        }
4489        final int noOfItems = endIndex - startIndex;
4490        if (noOfItems <= 0) {
4491            return EMPTY;
4492        }
4493        final List<?> subList = list.subList(startIndex, endIndex);
4494        return join(subList.iterator(), separator);
4495    }
4496
4497    /**
4498     * Joins the elements of the provided {@link List} into a single String containing the provided list of elements.
4499     *
4500     * <p>
4501     * No delimiter is added before or after the list. Null objects or empty strings within the array are represented by empty strings.
4502     * </p>
4503     *
4504     * <pre>
4505     * StringUtils.join(null, *)               = null
4506     * StringUtils.join([], *)                 = ""
4507     * StringUtils.join([null], *)             = ""
4508     * StringUtils.join(["a", "b", "c"], ';')  = "a;b;c"
4509     * StringUtils.join(["a", "b", "c"], null) = "abc"
4510     * StringUtils.join([null, "", "a"], ';')  = ";;a"
4511     * </pre>
4512     *
4513     * @param list       The {@link List} of values to join together, may be null.
4514     * @param separator  The separator character to use.
4515     * @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.
4516     * @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.
4517     * @return The joined String, {@code null} if null list input.
4518     * @since 3.8
4519     */
4520    public static String join(final List<?> list, final String separator, final int startIndex, final int endIndex) {
4521        if (list == null) {
4522            return null;
4523        }
4524        final int noOfItems = endIndex - startIndex;
4525        if (noOfItems <= 0) {
4526            return EMPTY;
4527        }
4528        final List<?> subList = list.subList(startIndex, endIndex);
4529        return join(subList.iterator(), separator);
4530    }
4531
4532    /**
4533     * Joins the elements of the provided array into a single String containing the provided list of elements.
4534     *
4535     * <p>
4536     * No delimiter is added before or after the list. Null objects or empty strings within the array are represented
4537     * by empty strings.
4538     * </p>
4539     *
4540     * <pre>
4541     * StringUtils.join(null, *)               = null
4542     * StringUtils.join([], *)                 = ""
4543     * StringUtils.join([null], *)             = ""
4544     * StringUtils.join([1, 2, 3], ';')  = "1;2;3"
4545     * StringUtils.join([1, 2, 3], null) = "123"
4546     * </pre>
4547     *
4548     * @param array
4549     *            the array of values to join together, may be null.
4550     * @param separator
4551     *            the separator character to use.
4552     * @return The joined String, {@code null} if null array input.
4553     * @since 3.2
4554     */
4555    public static String join(final long[] array, final char separator) {
4556        if (array == null) {
4557            return null;
4558        }
4559        return join(array, separator, 0, array.length);
4560    }
4561
4562    /**
4563     * Joins the elements of the provided array into a single String containing the provided list of elements.
4564     *
4565     * <p>
4566     * No delimiter is added before or after the list. Null objects or empty strings within the array are represented
4567     * by empty strings.
4568     * </p>
4569     *
4570     * <pre>
4571     * StringUtils.join(null, *)               = null
4572     * StringUtils.join([], *)                 = ""
4573     * StringUtils.join([null], *)             = ""
4574     * StringUtils.join([1, 2, 3], ';')  = "1;2;3"
4575     * StringUtils.join([1, 2, 3], null) = "123"
4576     * </pre>
4577     *
4578     * @param array
4579     *            the array of values to join together, may be null.
4580     * @param delimiter
4581     *            the separator character to use.
4582     * @param startIndex
4583     *            the first index to start joining from. It is an error to pass in a start index past the end of the
4584     *            array.
4585     * @param endIndex
4586     *            the index to stop joining from (exclusive). It is an error to pass in an end index past the end of
4587     *            the array.
4588     * @return The joined String, {@code null} if null array input.
4589     * @since 3.2
4590     */
4591    public static String join(final long[] array, final char delimiter, final int startIndex, final int endIndex) {
4592        // See StringUtilsJoinBenchmark
4593        if (array == null) {
4594            return null;
4595        }
4596        checkFromToIndex(startIndex, endIndex, array.length);
4597        final int count = endIndex - startIndex;
4598        if (count <= 0) {
4599            return EMPTY;
4600        }
4601        final byte maxElementChars = 20; // "-9223372036854775808"
4602        final StringBuilder stringBuilder = capacity(count, maxElementChars);
4603        stringBuilder.append(array[startIndex]);
4604        for (int i = startIndex + 1; i < endIndex; i++) {
4605            stringBuilder.append(delimiter).append(array[i]);
4606        }
4607        return stringBuilder.toString();
4608    }
4609
4610    /**
4611     * Joins the elements of the provided array into a single String containing the provided list of elements.
4612     *
4613     * <p>
4614     * No delimiter is added before or after the list. Null objects or empty strings within the array are represented by empty strings.
4615     * </p>
4616     *
4617     * <pre>
4618     * StringUtils.join(null, *)               = null
4619     * StringUtils.join([], *)                 = ""
4620     * StringUtils.join([null], *)             = ""
4621     * StringUtils.join(["a", "b", "c"], ';')  = "a;b;c"
4622     * StringUtils.join(["a", "b", "c"], null) = "abc"
4623     * StringUtils.join([null, "", "a"], ';')  = ";;a"
4624     * </pre>
4625     *
4626     * @param array     The array of values to join together, may be null.
4627     * @param delimiter The separator character to use.
4628     * @return The joined String, {@code null} if null array input.
4629     * @since 2.0
4630     */
4631    public static String join(final Object[] array, final char delimiter) {
4632        if (array == null) {
4633            return null;
4634        }
4635        return join(array, delimiter, 0, array.length);
4636    }
4637
4638    /**
4639     * Joins the elements of the provided array into a single String containing the provided list of elements.
4640     *
4641     * <p>
4642     * No delimiter is added before or after the list. Null objects or empty strings within the array are represented by empty strings.
4643     * </p>
4644     *
4645     * <pre>
4646     * StringUtils.join(null, *)               = null
4647     * StringUtils.join([], *)                 = ""
4648     * StringUtils.join([null], *)             = ""
4649     * StringUtils.join(["a", "b", "c"], ';')  = "a;b;c"
4650     * StringUtils.join(["a", "b", "c"], null) = "abc"
4651     * StringUtils.join([null, "", "a"], ';')  = ";;a"
4652     * </pre>
4653     *
4654     * @param array      The array of values to join together, may be null.
4655     * @param delimiter  The separator character to use.
4656     * @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.
4657     * @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.
4658     * @return The joined String, {@code null} if null array input.
4659     * @since 2.0
4660     */
4661    public static String join(final Object[] array, final char delimiter, final int startIndex, final int endIndex) {
4662        return join(array, String.valueOf(delimiter), startIndex, endIndex);
4663    }
4664
4665    /**
4666     * Joins the elements of the provided array into a single String containing the provided list of elements.
4667     *
4668     * <p>
4669     * 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
4670     * array are represented by empty strings.
4671     * </p>
4672     *
4673     * <pre>
4674     * StringUtils.join(null, *)                = null
4675     * StringUtils.join([], *)                  = ""
4676     * StringUtils.join([null], *)              = ""
4677     * StringUtils.join(["a", "b", "c"], "--")  = "a--b--c"
4678     * StringUtils.join(["a", "b", "c"], null)  = "abc"
4679     * StringUtils.join(["a", "b", "c"], "")    = "abc"
4680     * StringUtils.join([null, "", "a"], ',')   = ",,a"
4681     * </pre>
4682     *
4683     * @param array     The array of values to join together, may be null.
4684     * @param delimiter The separator character to use, null treated as "".
4685     * @return The joined String, {@code null} if null array input.
4686     */
4687    public static String join(final Object[] array, final String delimiter) {
4688        return array != null ? join(array, ObjectUtils.toString(delimiter), 0, array.length) : null;
4689    }
4690
4691    /**
4692     * Joins the elements of the provided array into a single String containing the provided list of elements.
4693     *
4694     * <p>
4695     * 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
4696     * array are represented by empty strings.
4697     * </p>
4698     *
4699     * <pre>
4700     * StringUtils.join(null, *, *, *)                = null
4701     * StringUtils.join([], *, *, *)                  = ""
4702     * StringUtils.join([null], *, *, *)              = ""
4703     * StringUtils.join(["a", "b", "c"], "--", 0, 3)  = "a--b--c"
4704     * StringUtils.join(["a", "b", "c"], "--", 1, 3)  = "b--c"
4705     * StringUtils.join(["a", "b", "c"], "--", 2, 3)  = "c"
4706     * StringUtils.join(["a", "b", "c"], "--", 2, 2)  = ""
4707     * StringUtils.join(["a", "b", "c"], null, 0, 3)  = "abc"
4708     * StringUtils.join(["a", "b", "c"], "", 0, 3)    = "abc"
4709     * StringUtils.join([null, "", "a"], ',', 0, 3)   = ",,a"
4710     * </pre>
4711     *
4712     * @param array      The array of values to join together, may be null.
4713     * @param delimiter  The separator character to use, null treated as "".
4714     * @param startIndex The first index to start joining from.
4715     * @param endIndex   The index to stop joining from (exclusive).
4716     * @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
4717     *         given by {@code endIndex - startIndex}.
4718     * @throws ArrayIndexOutOfBoundsException Thrown if<br> {@code startIndex < 0} or <br> {@code startIndex >= array.length()} or <br> {@code endIndex < 0} or
4719     *         <br> {@code endIndex > array.length()}.
4720     */
4721    public static String join(final Object[] array, final String delimiter, final int startIndex, final int endIndex) {
4722        return array != null ? Streams.of(array).skip(startIndex).limit(Math.max(0, endIndex - startIndex))
4723                .collect(LangCollectors.joining(delimiter, EMPTY, EMPTY, ObjectUtils::toString)) : null;
4724    }
4725
4726    /**
4727     * Joins the elements of the provided array into a single String containing the provided list of elements.
4728     *
4729     * <p>
4730     * No delimiter is added before or after the list. Null objects or empty strings within the array are represented
4731     * by empty strings.
4732     * </p>
4733     *
4734     * <pre>
4735     * StringUtils.join(null, *)          = null
4736     * StringUtils.join([], *)            = ""
4737     * StringUtils.join([null], *)        = ""
4738     * StringUtils.join([1, 2, 3], ';')   = "1;2;3"
4739     * StringUtils.join([1, 2, 3], null)  = "123"
4740     * </pre>
4741     *
4742     * @param array
4743     *            the array of values to join together, may be null.
4744     * @param delimiter
4745     *            the separator character to use.
4746     * @return The joined String, {@code null} if null array input.
4747     * @since 3.2
4748     */
4749    public static String join(final short[] array, final char delimiter) {
4750        if (array == null) {
4751            return null;
4752        }
4753        return join(array, delimiter, 0, array.length);
4754    }
4755
4756    /**
4757     * Joins the elements of the provided array into a single String containing the provided list of elements.
4758     *
4759     * <p>
4760     * No delimiter is added before or after the list. Null objects or empty strings within the array are represented
4761     * by empty strings.
4762     * </p>
4763     *
4764     * <pre>
4765     * StringUtils.join(null, *)          = null
4766     * StringUtils.join([], *)            = ""
4767     * StringUtils.join([null], *)        = ""
4768     * StringUtils.join([1, 2, 3], ';')   = "1;2;3"
4769     * StringUtils.join([1, 2, 3], null)  = "123"
4770     * </pre>
4771     *
4772     * @param array
4773     *            the array of values to join together, may be null.
4774     * @param delimiter
4775     *            the separator character to use.
4776     * @param startIndex
4777     *            the first index to start joining from. It is an error to pass in a start index past the end of the
4778     *            array.
4779     * @param endIndex
4780     *            the index to stop joining from (exclusive). It is an error to pass in an end index past the end of
4781     *            the array.
4782     * @return The joined String, {@code null} if null array input.
4783     * @since 3.2
4784     */
4785    public static String join(final short[] array, final char delimiter, final int startIndex, final int endIndex) {
4786        // See StringUtilsJoinBenchmark
4787        if (array == null) {
4788            return null;
4789        }
4790        checkFromToIndex(startIndex, endIndex, array.length);
4791        final int count = endIndex - startIndex;
4792        if (count <= 0) {
4793            return EMPTY;
4794        }
4795        final byte maxElementChars = 6; // "-32768"
4796        final StringBuilder stringBuilder = capacity(count, maxElementChars);
4797        stringBuilder.append(array[startIndex]);
4798        for (int i = startIndex + 1; i < endIndex; i++) {
4799            stringBuilder.append(delimiter).append(array[i]);
4800        }
4801        return stringBuilder.toString();
4802    }
4803
4804    /**
4805     * Joins the elements of the provided array into a single String containing the provided list of elements.
4806     *
4807     * <p>
4808     * No separator is added to the joined String. Null objects or empty strings within the array are represented by empty strings.
4809     * </p>
4810     *
4811     * <pre>
4812     * StringUtils.join(null)            = null
4813     * StringUtils.join([])              = ""
4814     * StringUtils.join([null])          = ""
4815     * StringUtils.join("a", "b", "c")   = "abc"
4816     * StringUtils.join(null, "", "a")   = "a"
4817     * </pre>
4818     *
4819     * @param <T>      the specific type of values to join together.
4820     * @param elements The values to join together, may be null.
4821     * @return The joined String, {@code null} if null array input.
4822     * @since 2.0
4823     * @since 3.0 Changed signature to use varargs
4824     */
4825    @SafeVarargs
4826    public static <T> String join(final T... elements) {
4827        return join(elements, null);
4828    }
4829
4830    /**
4831     * Joins the elements of the provided varargs into a single String containing the provided elements.
4832     *
4833     * <p>
4834     * No delimiter is added before or after the list. {@code null} elements and separator are treated as empty Strings ("").
4835     * </p>
4836     *
4837     * <pre>
4838     * StringUtils.joinWith(",", "a", "b")        = "a,b"
4839     * StringUtils.joinWith(",", "a", "b","")     = "a,b,"
4840     * StringUtils.joinWith(",", "a", null, "b")  = "a,,b"
4841     * StringUtils.joinWith(null, "a", "b")       = "ab"
4842     * </pre>
4843     *
4844     * @param delimiter The separator character to use, null treated as "".
4845     * @param array     The varargs providing the values to join together. {@code null} elements are treated as "".
4846     * @return The joined String.
4847     * @throws IllegalArgumentException Thrown if a null varargs is provided.
4848     * @since 3.5
4849     */
4850    public static String joinWith(final String delimiter, final Object... array) {
4851        if (array == null) {
4852            throw new IllegalArgumentException("Object varargs must not be null");
4853        }
4854        return join(array, delimiter);
4855    }
4856
4857    /**
4858     * Finds the last index within a CharSequence, handling {@code null}. This method uses {@link String#lastIndexOf(String)} if possible.
4859     *
4860     * <p>
4861     * A {@code null} CharSequence will return {@code -1}.
4862     * </p>
4863     *
4864     * <pre>
4865     * StringUtils.lastIndexOf(null, *)          = -1
4866     * StringUtils.lastIndexOf(*, null)          = -1
4867     * StringUtils.lastIndexOf("", "")           = 0
4868     * StringUtils.lastIndexOf("aabaabaa", "a")  = 7
4869     * StringUtils.lastIndexOf("aabaabaa", "b")  = 5
4870     * StringUtils.lastIndexOf("aabaabaa", "ab") = 4
4871     * StringUtils.lastIndexOf("aabaabaa", "")   = 8
4872     * </pre>
4873     *
4874     * @param seq       The CharSequence to check, may be null.
4875     * @param searchSeq The CharSequence to find, may be null.
4876     * @return The last index of the search String, -1 if no match or {@code null} string input.
4877     * @since 2.0
4878     * @since 3.0 Changed signature from lastIndexOf(String, String) to lastIndexOf(CharSequence, CharSequence)
4879     * @deprecated Use {@link Strings#lastIndexOf(CharSequence, CharSequence) Strings.CS.lastIndexOf(CharSequence, CharSequence)}.
4880     */
4881    @Deprecated
4882    public static int lastIndexOf(final CharSequence seq, final CharSequence searchSeq) {
4883        return Strings.CS.lastIndexOf(seq, searchSeq);
4884    }
4885
4886    /**
4887     * Finds the last index within a CharSequence, handling {@code null}. This method uses {@link String#lastIndexOf(String, int)} if possible.
4888     *
4889     * <p>
4890     * A {@code null} CharSequence will return {@code -1}. A negative start position returns {@code -1}. An empty ("") search CharSequence always matches unless
4891     * 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
4892     * backwards; matches starting after the start position are ignored.
4893     * </p>
4894     *
4895     * <pre>
4896     * StringUtils.lastIndexOf(null, *, *)          = -1
4897     * StringUtils.lastIndexOf(*, null, *)          = -1
4898     * StringUtils.lastIndexOf("aabaabaa", "a", 8)  = 7
4899     * StringUtils.lastIndexOf("aabaabaa", "b", 8)  = 5
4900     * StringUtils.lastIndexOf("aabaabaa", "ab", 8) = 4
4901     * StringUtils.lastIndexOf("aabaabaa", "b", 9)  = 5
4902     * StringUtils.lastIndexOf("aabaabaa", "b", -1) = -1
4903     * StringUtils.lastIndexOf("aabaabaa", "a", 0)  = 0
4904     * StringUtils.lastIndexOf("aabaabaa", "b", 0)  = -1
4905     * StringUtils.lastIndexOf("aabaabaa", "b", 1)  = -1
4906     * StringUtils.lastIndexOf("aabaabaa", "b", 2)  = 2
4907     * StringUtils.lastIndexOf("aabaabaa", "ba", 2)  = 2
4908     * </pre>
4909     *
4910     * @param seq       The CharSequence to check, may be null.
4911     * @param searchSeq The CharSequence to find, may be null.
4912     * @param startPos  The start position, negative treated as zero.
4913     * @return The last index of the search CharSequence (always &le; startPos), -1 if no match or {@code null} string input.
4914     * @since 2.0
4915     * @since 3.0 Changed signature from lastIndexOf(String, String, int) to lastIndexOf(CharSequence, CharSequence, int)
4916     * @deprecated Use {@link Strings#lastIndexOf(CharSequence, CharSequence, int) Strings.CS.lastIndexOf(CharSequence, CharSequence, int)}.
4917     */
4918    @Deprecated
4919    public static int lastIndexOf(final CharSequence seq, final CharSequence searchSeq, final int startPos) {
4920        return Strings.CS.lastIndexOf(seq, searchSeq, startPos);
4921    }
4922
4923    /**
4924     * 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
4925     * (inclusive), the index (in Unicode code units) returned is the largest value <em>k</em> such that:
4926     *
4927     * <pre>
4928     * this.charAt(<em>k</em>) == searchChar
4929     * </pre>
4930     *
4931     * <p>
4932     * is true. For other values of {@code searchChar}, it is the largest value <em>k</em> such that:
4933     * </p>
4934     *
4935     * <pre>
4936     * this.codePointAt(<em>k</em>) == searchChar
4937     * </pre>
4938     *
4939     * <p>
4940     * is true. In either case, if no such character occurs in this string, then {@code -1} is returned. Furthermore, a {@code null} or empty ("")
4941     * {@link CharSequence} will return {@code -1}. The {@code seq} {@link CharSequence} object is searched backwards starting at the last character.
4942     * </p>
4943     *
4944     * <pre>
4945     * StringUtils.lastIndexOf(null, *)         = -1
4946     * StringUtils.lastIndexOf("", *)           = -1
4947     * StringUtils.lastIndexOf("aabaabaa", 'a') = 7
4948     * StringUtils.lastIndexOf("aabaabaa", 'b') = 5
4949     * </pre>
4950     *
4951     * @param seq        The {@link CharSequence} to check, may be null.
4952     * @param searchChar The character to find.
4953     * @return The last index of the search character, -1 if no match or {@code null} string input.
4954     * @since 2.0
4955     * @since 3.0 Changed signature from lastIndexOf(String, int) to lastIndexOf(CharSequence, int)
4956     * @since 3.6 Updated {@link CharSequenceUtils} call to behave more like {@link String}
4957     */
4958    public static int lastIndexOf(final CharSequence seq, final int searchChar) {
4959        if (isEmpty(seq)) {
4960            return INDEX_NOT_FOUND;
4961        }
4962        return CharSequenceUtils.lastIndexOf(seq, searchChar, seq.length());
4963    }
4964
4965    /**
4966     * Returns the index within {@code seq} of the last occurrence of the specified character, searching backward starting at the specified index. For values of
4967     * {@code searchChar} in the range from 0 to 0xFFFF (inclusive), the index returned is the largest value <em>k</em> such that:
4968     *
4969     * <pre>
4970     * (this.charAt(<em>k</em>) == searchChar) &amp;&amp; (<em>k</em> &lt;= startPos)
4971     * </pre>
4972     *
4973     * <p>
4974     * is true. For other values of {@code searchChar}, it is the largest value <em>k</em> such that:
4975     * </p>
4976     *
4977     * <pre>
4978     * (this.codePointAt(<em>k</em>) == searchChar) &amp;&amp; (<em>k</em> &lt;= startPos)
4979     * </pre>
4980     *
4981     * <p>
4982     * 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
4983     * {@code null} or empty ("") {@link CharSequence} will return {@code -1}. A start position greater than the string length searches the whole string. The
4984     * search starts at the {@code startPos} and works backwards; matches starting after the start position are ignored.
4985     * </p>
4986     *
4987     * <p>
4988     * All indices are specified in {@code char} values (Unicode code units).
4989     * </p>
4990     *
4991     * <pre>
4992     * StringUtils.lastIndexOf(null, *, *)          = -1
4993     * StringUtils.lastIndexOf("", *,  *)           = -1
4994     * StringUtils.lastIndexOf("aabaabaa", 'b', 8)  = 5
4995     * StringUtils.lastIndexOf("aabaabaa", 'b', 4)  = 2
4996     * StringUtils.lastIndexOf("aabaabaa", 'b', 0)  = -1
4997     * StringUtils.lastIndexOf("aabaabaa", 'b', 9)  = 5
4998     * StringUtils.lastIndexOf("aabaabaa", 'b', -1) = -1
4999     * StringUtils.lastIndexOf("aabaabaa", 'a', 0)  = 0
5000     * </pre>
5001     *
5002     * @param seq        The CharSequence to check, may be null.
5003     * @param searchChar The character to find.
5004     * @param startPos   The start position.
5005     * @return The last index of the search character (always &le; startPos), -1 if no match or {@code null} string input.
5006     * @since 2.0
5007     * @since 3.0 Changed signature from lastIndexOf(String, int, int) to lastIndexOf(CharSequence, int, int)
5008     */
5009    public static int lastIndexOf(final CharSequence seq, final int searchChar, final int startPos) {
5010        if (isEmpty(seq)) {
5011            return INDEX_NOT_FOUND;
5012        }
5013        return CharSequenceUtils.lastIndexOf(seq, searchChar, startPos);
5014    }
5015
5016    /**
5017     * Finds the latest index of any substring in a set of potential substrings.
5018     *
5019     * <p>
5020     * 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
5021     * will be ignored, but a search array containing "" will return the length of {@code str} if {@code str} is not null. This method uses
5022     * {@link String#indexOf(String)} if possible
5023     * </p>
5024     *
5025     * <pre>
5026     * StringUtils.lastIndexOfAny(null, *)                    = -1
5027     * StringUtils.lastIndexOfAny(*, null)                    = -1
5028     * StringUtils.lastIndexOfAny(*, [])                      = -1
5029     * StringUtils.lastIndexOfAny(*, [null])                  = -1
5030     * StringUtils.lastIndexOfAny("zzabyycdxx", ["ab", "cd"]) = 6
5031     * StringUtils.lastIndexOfAny("zzabyycdxx", ["cd", "ab"]) = 6
5032     * StringUtils.lastIndexOfAny("zzabyycdxx", ["mn", "op"]) = -1
5033     * StringUtils.lastIndexOfAny("zzabyycdxx", ["mn", "op"]) = -1
5034     * StringUtils.lastIndexOfAny("zzabyycdxx", ["mn", ""])   = 10
5035     * </pre>
5036     *
5037     * @param str        The CharSequence to check, may be null.
5038     * @param searchStrs The CharSequences to search for, may be null.
5039     * @return The last index of any of the CharSequences, -1 if no match.
5040     * @since 3.0 Changed signature from lastIndexOfAny(String, String[]) to lastIndexOfAny(CharSequence, CharSequence)
5041     */
5042    public static int lastIndexOfAny(final CharSequence str, final CharSequence... searchStrs) {
5043        if (str == null || searchStrs == null) {
5044            return INDEX_NOT_FOUND;
5045        }
5046        int ret = INDEX_NOT_FOUND;
5047        int tmp;
5048        for (final CharSequence search : searchStrs) {
5049            if (search == null) {
5050                continue;
5051            }
5052            tmp = CharSequenceUtils.lastIndexOf(str, search, str.length());
5053            if (tmp > ret) {
5054                ret = tmp;
5055            }
5056        }
5057        return ret;
5058    }
5059
5060    /**
5061     * Case insensitive find of the last index within a CharSequence.
5062     *
5063     * <p>
5064     * A {@code null} CharSequence will return {@code -1}. A negative start position returns {@code -1}. An empty ("") search CharSequence always matches unless
5065     * the start position is negative. A start position greater than the string length searches the whole string.
5066     * </p>
5067     *
5068     * <pre>
5069     * StringUtils.lastIndexOfIgnoreCase(null, *)          = -1
5070     * StringUtils.lastIndexOfIgnoreCase(*, null)          = -1
5071     * StringUtils.lastIndexOfIgnoreCase("aabaabaa", "A")  = 7
5072     * StringUtils.lastIndexOfIgnoreCase("aabaabaa", "B")  = 5
5073     * StringUtils.lastIndexOfIgnoreCase("aabaabaa", "AB") = 4
5074     * </pre>
5075     *
5076     * @param str       The CharSequence to check, may be null.
5077     * @param searchStr The CharSequence to find, may be null.
5078     * @return The first index of the search CharSequence, -1 if no match or {@code null} string input.
5079     * @since 2.5
5080     * @since 3.0 Changed signature from lastIndexOfIgnoreCase(String, String) to lastIndexOfIgnoreCase(CharSequence, CharSequence)
5081     * @deprecated Use {@link Strings#lastIndexOf(CharSequence, CharSequence) Strings.CI.lastIndexOf(CharSequence, CharSequence)}.
5082     */
5083    @Deprecated
5084    public static int lastIndexOfIgnoreCase(final CharSequence str, final CharSequence searchStr) {
5085        return Strings.CI.lastIndexOf(str, searchStr);
5086    }
5087
5088    /**
5089     * Case insensitive find of the last index within a CharSequence from the specified position.
5090     *
5091     * <p>
5092     * A {@code null} CharSequence will return {@code -1}. A negative start position returns {@code -1}. An empty ("") search CharSequence always matches unless
5093     * 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
5094     * backwards; matches starting after the start position are ignored.
5095     * </p>
5096     *
5097     * <pre>
5098     * StringUtils.lastIndexOfIgnoreCase(null, *, *)          = -1
5099     * StringUtils.lastIndexOfIgnoreCase(*, null, *)          = -1
5100     * StringUtils.lastIndexOfIgnoreCase("aabaabaa", "A", 8)  = 7
5101     * StringUtils.lastIndexOfIgnoreCase("aabaabaa", "B", 8)  = 5
5102     * StringUtils.lastIndexOfIgnoreCase("aabaabaa", "AB", 8) = 4
5103     * StringUtils.lastIndexOfIgnoreCase("aabaabaa", "B", 9)  = 5
5104     * StringUtils.lastIndexOfIgnoreCase("aabaabaa", "B", -1) = -1
5105     * StringUtils.lastIndexOfIgnoreCase("aabaabaa", "A", 0)  = 0
5106     * StringUtils.lastIndexOfIgnoreCase("aabaabaa", "B", 0)  = -1
5107     * </pre>
5108     *
5109     * @param str       The CharSequence to check, may be null.
5110     * @param searchStr The CharSequence to find, may be null.
5111     * @param startPos  The start position.
5112     * @return The last index of the search CharSequence (always &le; startPos), -1 if no match or {@code null} input.
5113     * @since 2.5
5114     * @since 3.0 Changed signature from lastIndexOfIgnoreCase(String, String, int) to lastIndexOfIgnoreCase(CharSequence, CharSequence, int)
5115     * @deprecated Use {@link Strings#lastIndexOf(CharSequence, CharSequence, int) Strings.CI.lastIndexOf(CharSequence, CharSequence, int)}.
5116     */
5117    @Deprecated
5118    public static int lastIndexOfIgnoreCase(final CharSequence str, final CharSequence searchStr, final int startPos) {
5119        return Strings.CI.lastIndexOf(str, searchStr, startPos);
5120    }
5121
5122    /**
5123     * Finds the n-th last index within a String, handling {@code null}. This method uses {@link String#lastIndexOf(String)}.
5124     *
5125     * <p>
5126     * A {@code null} String will return {@code -1}.
5127     * </p>
5128     *
5129     * <pre>
5130     * StringUtils.lastOrdinalIndexOf(null, *, *)          = -1
5131     * StringUtils.lastOrdinalIndexOf(*, null, *)          = -1
5132     * StringUtils.lastOrdinalIndexOf("", "", *)           = 0
5133     * StringUtils.lastOrdinalIndexOf("aabaabaa", "a", 1)  = 7
5134     * StringUtils.lastOrdinalIndexOf("aabaabaa", "a", 2)  = 6
5135     * StringUtils.lastOrdinalIndexOf("aabaabaa", "b", 1)  = 5
5136     * StringUtils.lastOrdinalIndexOf("aabaabaa", "b", 2)  = 2
5137     * StringUtils.lastOrdinalIndexOf("aabaabaa", "ab", 1) = 4
5138     * StringUtils.lastOrdinalIndexOf("aabaabaa", "ab", 2) = 1
5139     * StringUtils.lastOrdinalIndexOf("aabaabaa", "", 1)   = 8
5140     * StringUtils.lastOrdinalIndexOf("aabaabaa", "", 2)   = 8
5141     * </pre>
5142     *
5143     * <p>
5144     * Note that 'tail(CharSequence str, int n)' may be implemented as:
5145     * </p>
5146     *
5147     * <pre>
5148     * str.substring(lastOrdinalIndexOf(str, "\n", n) + 1)
5149     * </pre>
5150     *
5151     * @param str       The CharSequence to check, may be null.
5152     * @param searchStr The CharSequence to find, may be null.
5153     * @param ordinal   The n-th last {@code searchStr} to find.
5154     * @return The n-th last index of the search CharSequence, {@code -1} ({@code INDEX_NOT_FOUND}) if no match or {@code null} string input.
5155     * @since 2.5
5156     * @since 3.0 Changed signature from lastOrdinalIndexOf(String, String, int) to lastOrdinalIndexOf(CharSequence, CharSequence, int)
5157     */
5158    public static int lastOrdinalIndexOf(final CharSequence str, final CharSequence searchStr, final int ordinal) {
5159        return ordinalIndexOf(str, searchStr, ordinal, true);
5160    }
5161
5162    /**
5163     * Gets the leftmost {@code len} characters of a String.
5164     *
5165     * <p>
5166     * 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
5167     * if len is negative.
5168     * </p>
5169     *
5170     * <pre>
5171     * StringUtils.left(null, *)    = null
5172     * StringUtils.left(*, -ve)     = ""
5173     * StringUtils.left("", *)      = ""
5174     * StringUtils.left("abc", 0)   = ""
5175     * StringUtils.left("abc", 2)   = "ab"
5176     * StringUtils.left("abc", 4)   = "abc"
5177     * </pre>
5178     *
5179     * @param str The String to get the leftmost characters from, may be null.
5180     * @param len The length of the required String.
5181     * @return The leftmost characters, {@code null} if null String input.
5182     */
5183    public static String left(final String str, final int len) {
5184        if (str == null) {
5185            return null;
5186        }
5187        if (len < 0) {
5188            return EMPTY;
5189        }
5190        if (str.length() <= len) {
5191            return str;
5192        }
5193        int cut = len;
5194        // keep the cut off the middle of a surrogate pair so the result is never left holding a lone surrogate
5195        if (splitsSurrogatePair(str, cut)) {
5196            cut--;
5197        }
5198        return str.substring(0, cut);
5199    }
5200
5201    /**
5202     * Left pad a String with spaces (' ').
5203     *
5204     * <p>
5205     * The String is padded to the size of {@code size}.
5206     * </p>
5207     *
5208     * <pre>
5209     * StringUtils.leftPad(null, *)   = null
5210     * StringUtils.leftPad("", 3)     = "   "
5211     * StringUtils.leftPad("bat", 3)  = "bat"
5212     * StringUtils.leftPad("bat", 5)  = "  bat"
5213     * StringUtils.leftPad("bat", 1)  = "bat"
5214     * StringUtils.leftPad("bat", -1) = "bat"
5215     * </pre>
5216     *
5217     * @param str  The String to pad out, may be null.
5218     * @param size The size to pad to.
5219     * @return left padded String or original String if no padding is necessary, {@code null} if null String input.
5220     */
5221    public static String leftPad(final String str, final int size) {
5222        return leftPad(str, size, ' ');
5223    }
5224
5225    /**
5226     * Left pad a String with a specified character.
5227     *
5228     * <p>
5229     * Pad to a size of {@code size}.
5230     * </p>
5231     *
5232     * <pre>
5233     * StringUtils.leftPad(null, *, *)     = null
5234     * StringUtils.leftPad("", 3, 'z')     = "zzz"
5235     * StringUtils.leftPad("bat", 3, 'z')  = "bat"
5236     * StringUtils.leftPad("bat", 5, 'z')  = "zzbat"
5237     * StringUtils.leftPad("bat", 1, 'z')  = "bat"
5238     * StringUtils.leftPad("bat", -1, 'z') = "bat"
5239     * </pre>
5240     *
5241     * @param str     The String to pad out, may be null.
5242     * @param size    The size to pad to.
5243     * @param padChar The character to pad with.
5244     * @return left padded String or original String if no padding is necessary, {@code null} if null String input.
5245     * @since 2.0
5246     */
5247    public static String leftPad(final String str, final int size, final char padChar) {
5248        if (str == null || size <= str.length()) {
5249            return str;
5250        }
5251        final int pads = size - str.length();
5252        if (pads <= 0) {
5253            return str; // returns original String when possible
5254        }
5255        if (pads > PAD_LIMIT) {
5256            return leftPad(str, size, String.valueOf(padChar));
5257        }
5258        return repeat(padChar, pads).concat(str);
5259    }
5260
5261    /**
5262     * Left pad a String with a specified String.
5263     *
5264     * <p>
5265     * Pad to a size of {@code size}. If the requested padding length would split a Unicode surrogate pair in {@code padStr},
5266     * the padding is shortened by one {@code char} to avoid introducing an unpaired surrogate by splitting the pair. In that case, the
5267     * returned String has a length of {@code size - 1}.
5268     * </p>
5269     *
5270     * <pre>
5271     * StringUtils.leftPad(null, *, *)      = null
5272     * StringUtils.leftPad("", 3, "z")      = "zzz"
5273     * StringUtils.leftPad("bat", 3, "yz")  = "bat"
5274     * StringUtils.leftPad("bat", 5, "yz")  = "yzbat"
5275     * StringUtils.leftPad("bat", 8, "yz")  = "yzyzybat"
5276     * StringUtils.leftPad("bat", 1, "yz")  = "bat"
5277     * StringUtils.leftPad("bat", -1, "yz") = "bat"
5278     * StringUtils.leftPad("bat", 5, null)  = "  bat"
5279     * StringUtils.leftPad("bat", 5, "")    = "  bat"
5280     * StringUtils.leftPad("a", 2, "\uD83D\uDE00")    = "a"
5281     * StringUtils.leftPad("a", 3, "\uD83D\uDE00")    = "\uD83D\uDE00a"
5282     * </pre>
5283     *
5284     * @param str    The String to pad out, may be null.
5285     * @param size   The size to pad to.
5286     * @param padStr The String to pad with, null or empty treated as single space.
5287     * @return left padded String or original String if no padding is necessary, {@code null} if null String input.
5288     */
5289    public static String leftPad(final String str, final int size, String padStr) {
5290        if (str == null || size <= str.length()) {
5291            return str;
5292        }
5293        if (isEmpty(padStr)) {
5294            padStr = SPACE;
5295        }
5296        final int padLen = padStr.length();
5297        final int strLen = str.length();
5298        int pads = size - strLen;
5299        if (pads <= 0) {
5300            return str; // returns original String when possible
5301        }
5302        if (padLen == 1 && pads <= PAD_LIMIT) {
5303            return leftPad(str, size, padStr.charAt(0));
5304        }
5305        // Keep the padding boundary off the middle of a surrogate pair to avoid introducing a lone surrogate.
5306        if (splitsSurrogatePair(padStr, pads % padLen)) {
5307            pads--;
5308        }
5309        if (pads <= 0) {
5310            return str;
5311        }
5312        if (pads == padLen) {
5313            return padStr.concat(str);
5314        }
5315        if (pads < padLen) {
5316            return padStr.substring(0, pads).concat(str);
5317        }
5318        final char[] padding = new char[pads];
5319        final char[] padChars = padStr.toCharArray();
5320        for (int i = 0; i < pads; i++) {
5321            padding[i] = padChars[i % padLen];
5322        }
5323        return new String(padding).concat(str);
5324    }
5325
5326    /**
5327     * Gets a CharSequence length or {@code 0} if the CharSequence is {@code null}.
5328     *
5329     * @param cs A CharSequence or {@code null}.
5330     * @return CharSequence length or {@code 0} if the CharSequence is {@code null}.
5331     * @since 2.4
5332     * @since 3.0 Changed signature from length(String) to length(CharSequence)
5333     */
5334    public static int length(final CharSequence cs) {
5335        return cs == null ? 0 : cs.length();
5336    }
5337
5338    /**
5339     * Converts a String to lower case as per {@link String#toLowerCase()}.
5340     *
5341     * <p>
5342     * A {@code null} input String returns {@code null}.
5343     * </p>
5344     *
5345     * <pre>
5346     * StringUtils.lowerCase(null)  = null
5347     * StringUtils.lowerCase("")    = ""
5348     * StringUtils.lowerCase("aBc") = "abc"
5349     * </pre>
5350     *
5351     * <p>
5352     * <strong>Note:</strong> As described in the documentation for {@link String#toLowerCase()}, the result of this method is affected by the current locale.
5353     * For platform-independent case transformations, the method {@link #lowerCase(String, Locale)} should be used with a specific locale (e.g.
5354     * {@link Locale#ENGLISH}).
5355     * </p>
5356     *
5357     * @param str The String to lower case, may be null.
5358     * @return The lower cased String, {@code null} if null String input.
5359     */
5360    public static String lowerCase(final String str) {
5361        if (str == null) {
5362            return null;
5363        }
5364        return str.toLowerCase();
5365    }
5366
5367    /**
5368     * Converts a String to lower case as per {@link String#toLowerCase(Locale)}.
5369     *
5370     * <p>
5371     * A {@code null} input String returns {@code null}.
5372     * </p>
5373     *
5374     * <pre>
5375     * StringUtils.lowerCase(null, Locale.ENGLISH)  = null
5376     * StringUtils.lowerCase("", Locale.ENGLISH)    = ""
5377     * StringUtils.lowerCase("aBc", Locale.ENGLISH) = "abc"
5378     * </pre>
5379     *
5380     * @param str    The String to lower case, may be null.
5381     * @param locale The locale that defines the case transformation rules, must not be null.
5382     * @return The lower cased String, {@code null} if null String input.
5383     * @since 2.5
5384     */
5385    public static String lowerCase(final String str, final Locale locale) {
5386        if (str == null) {
5387            return null;
5388        }
5389        return str.toLowerCase(LocaleUtils.toLocale(locale));
5390    }
5391
5392    private static int[] matches(final CharSequence first, final CharSequence second) {
5393        final CharSequence max;
5394        final CharSequence min;
5395        if (first.length() > second.length()) {
5396            max = first;
5397            min = second;
5398        } else {
5399            max = second;
5400            min = first;
5401        }
5402        final int range = Math.max(max.length() / 2 - 1, 0);
5403        final int[] matchIndexes = ArrayFill.fill(new int[min.length()], -1);
5404        final boolean[] matchFlags = new boolean[max.length()];
5405        int matches = 0;
5406        for (int mi = 0; mi < min.length(); mi++) {
5407            final char c1 = min.charAt(mi);
5408            for (int xi = Math.max(mi - range, 0), xn = Math.min(mi + range + 1, max.length()); xi < xn; xi++) {
5409                if (!matchFlags[xi] && c1 == max.charAt(xi)) {
5410                    matchIndexes[mi] = xi;
5411                    matchFlags[xi] = true;
5412                    matches++;
5413                    break;
5414                }
5415            }
5416        }
5417        final char[] ms1 = new char[matches];
5418        final char[] ms2 = new char[matches];
5419        for (int i = 0, si = 0; i < min.length(); i++) {
5420            if (matchIndexes[i] != -1) {
5421                ms1[si] = min.charAt(i);
5422                si++;
5423            }
5424        }
5425        for (int i = 0, si = 0; i < max.length(); i++) {
5426            if (matchFlags[i]) {
5427                ms2[si] = max.charAt(i);
5428                si++;
5429            }
5430        }
5431        int transpositions = 0;
5432        for (int mi = 0; mi < ms1.length; mi++) {
5433            if (ms1[mi] != ms2[mi]) {
5434                transpositions++;
5435            }
5436        }
5437        int prefix = 0;
5438        for (int mi = 0; mi < min.length(); mi++) {
5439            if (first.charAt(mi) != second.charAt(mi)) {
5440                break;
5441            }
5442            prefix++;
5443        }
5444        return new int[] { matches, transpositions / 2, prefix, max.length() };
5445    }
5446
5447    /**
5448     * Gets {@code len} characters from the middle of a String.
5449     *
5450     * <p>
5451     * If {@code len} characters are not available, the remainder of the String will be returned without an exception. If the String is {@code null},
5452     * {@code null} will be returned. An empty String is returned if len is negative or exceeds the length of {@code str}.
5453     * </p>
5454     *
5455     * <pre>
5456     * StringUtils.mid(null, *, *)    = null
5457     * StringUtils.mid(*, *, -ve)     = ""
5458     * StringUtils.mid("", 0, *)      = ""
5459     * StringUtils.mid("abc", 0, 2)   = "ab"
5460     * StringUtils.mid("abc", 0, 4)   = "abc"
5461     * StringUtils.mid("abc", 2, 4)   = "c"
5462     * StringUtils.mid("abc", 4, 2)   = ""
5463     * StringUtils.mid("abc", -2, 2)  = "ab"
5464     * </pre>
5465     *
5466     * @param str The String to get the characters from, may be null.
5467     * @param pos The position to start from, negative treated as zero.
5468     * @param len The length of the required String.
5469     * @return The middle characters, {@code null} if null String input.
5470     */
5471    public static String mid(final String str, int pos, final int len) {
5472        if (str == null) {
5473            return null;
5474        }
5475        if (len < 0 || pos > str.length()) {
5476            return EMPTY;
5477        }
5478        if (pos < 0) {
5479            pos = 0;
5480        }
5481        int start = pos;
5482        // keep the start off the middle of a surrogate pair so the result is never left holding a lone surrogate
5483        if (splitsSurrogatePair(str, start)) {
5484            start++;
5485        }
5486        if (str.length() - pos <= len) {
5487            return str.substring(start);
5488        }
5489        int end = pos + len;
5490        // keep both cuts off the middle of a surrogate pair so the result is never left holding a lone surrogate
5491        if (splitsSurrogatePair(str, end)) {
5492            end--;
5493        }
5494        return str.substring(start, Math.max(start, end));
5495    }
5496
5497    /**
5498     * Normalizes whitespace in a String.
5499     *
5500     * <p>Removes leading and trailing whitespace and replaces each remaining sequence of characters recognized by {@link Character#isWhitespace(char)}
5501     * with a single ordinary space ({@code U+0020}). This includes Unicode whitespace beyond the characters matched by the default regular expression
5502     * {@code \s}, such as EM SPACE ({@code U+2003}).</p>
5503     *
5504     * <p>Additionally, converts each non-breaking space ({@code U+00A0}) to an ordinary space, even though {@link Character#isWhitespace(char)} excludes it.
5505     * These conversions do not collapse adjacent spaces: for example, <code>"a&#92;u00A0&#92;u00A0b"</code> becomes {@code "a  b"}. Finally,
5506     * {@link String#trim()} removes
5507     * leading and trailing characters whose values are at most {@code U+0020}, including converted non-breaking spaces. Other non-breaking spaces, such as
5508     * FIGURE SPACE ({@code U+2007}) and NARROW NO-BREAK SPACE ({@code U+202F}), are preserved.</p>
5509     *
5510     * <p>This method was inspired by XPath's
5511     * <a href="https://www.w3.org/TR/xpath/#function-normalize-space">normalize-space</a> function, but does not reproduce its behavior.
5512     * XPath normalizes only XML
5513     * whitespace ({@code U+0020}, {@code U+0009}, {@code U+000D}, and {@code U+000A}) and preserves non-breaking spaces. This method additionally normalizes
5514     * Java whitespace, converts {@code U+00A0}, and trims leading and trailing control characters as described above.</p>
5515     *
5516     * @param str The source String to normalize whitespaces from, may be null.
5517     * @return The modified string with whitespace normalized, {@code null} if null String input.
5518     * @see Character#isWhitespace(char)
5519     * @see #trim(String)
5520     * @see <a href="https://www.w3.org/TR/xpath/#function-normalize-space">https://www.w3.org/TR/xpath/#function-normalize-space</a>
5521     * @since 3.0
5522     */
5523    public static String normalizeSpace(final String str) {
5524        // LANG-1020: Improved performance significantly by normalizing manually instead of using regex
5525        // See https://github.com/librucha/commons-lang-normalizespaces-benchmark for performance test
5526        if (isEmpty(str)) {
5527            return str;
5528        }
5529        final int size = str.length();
5530        final char[] newChars = new char[size];
5531        int count = 0;
5532        int whitespacesCount = 0;
5533        boolean startWhitespaces = true;
5534        for (int i = 0; i < size; i++) {
5535            final char actualChar = str.charAt(i);
5536            final boolean isWhitespace = Character.isWhitespace(actualChar);
5537            if (isWhitespace) {
5538                if (whitespacesCount == 0 && !startWhitespaces) {
5539                    newChars[count++] = SPACE.charAt(0);
5540                }
5541                whitespacesCount++;
5542            } else {
5543                startWhitespaces = false;
5544                newChars[count++] = actualChar == 160 ? 32 : actualChar;
5545                whitespacesCount = 0;
5546            }
5547        }
5548        if (startWhitespaces) {
5549            return EMPTY;
5550        }
5551        return new String(newChars, 0, count - (whitespacesCount > 0 ? 1 : 0)).trim();
5552    }
5553
5554    /**
5555     * Finds the n-th index within a CharSequence, handling {@code null}. This method uses {@link String#indexOf(String)} if possible.
5556     * <p>
5557     * <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
5558     * (unless {@code searchStr} is an empty string, in which case the position is never incremented and {@code 0} is returned immediately). This means that
5559     * matches may overlap.
5560     * </p>
5561     * <p>
5562     * A {@code null} CharSequence will return {@code -1}.
5563     * </p>
5564     *
5565     * <pre>
5566     * StringUtils.ordinalIndexOf(null, *, *)          = -1
5567     * StringUtils.ordinalIndexOf(*, null, *)          = -1
5568     * StringUtils.ordinalIndexOf("", "", *)           = 0
5569     * StringUtils.ordinalIndexOf("aabaabaa", "a", 1)  = 0
5570     * StringUtils.ordinalIndexOf("aabaabaa", "a", 2)  = 1
5571     * StringUtils.ordinalIndexOf("aabaabaa", "b", 1)  = 2
5572     * StringUtils.ordinalIndexOf("aabaabaa", "b", 2)  = 5
5573     * StringUtils.ordinalIndexOf("aabaabaa", "ab", 1) = 1
5574     * StringUtils.ordinalIndexOf("aabaabaa", "ab", 2) = 4
5575     * StringUtils.ordinalIndexOf("aabaabaa", "", 1)   = 0
5576     * StringUtils.ordinalIndexOf("aabaabaa", "", 2)   = 0
5577     * </pre>
5578     *
5579     * <p>
5580     * Matches may overlap:
5581     * </p>
5582     *
5583     * <pre>
5584     * StringUtils.ordinalIndexOf("ababab", "aba", 1)   = 0
5585     * StringUtils.ordinalIndexOf("ababab", "aba", 2)   = 2
5586     * StringUtils.ordinalIndexOf("ababab", "aba", 3)   = -1
5587     *
5588     * StringUtils.ordinalIndexOf("abababab", "abab", 1) = 0
5589     * StringUtils.ordinalIndexOf("abababab", "abab", 2) = 2
5590     * StringUtils.ordinalIndexOf("abababab", "abab", 3) = 4
5591     * StringUtils.ordinalIndexOf("abababab", "abab", 4) = -1
5592     * </pre>
5593     *
5594     * <p>
5595     * Note that 'head(CharSequence str, int n)' may be implemented as:
5596     * </p>
5597     *
5598     * <pre>
5599     * str.substring(0, lastOrdinalIndexOf(str, "\n", n))
5600     * </pre>
5601     *
5602     * @param str       The CharSequence to check, may be null.
5603     * @param searchStr The CharSequence to find, may be null.
5604     * @param ordinal   The n-th {@code searchStr} to find.
5605     * @return The n-th index of the search CharSequence, {@code -1} ({@code INDEX_NOT_FOUND}) if no match or {@code null} string input.
5606     * @since 2.1
5607     * @since 3.0 Changed signature from ordinalIndexOf(String, String, int) to ordinalIndexOf(CharSequence, CharSequence, int)
5608     */
5609    public static int ordinalIndexOf(final CharSequence str, final CharSequence searchStr, final int ordinal) {
5610        return ordinalIndexOf(str, searchStr, ordinal, false);
5611    }
5612
5613    /**
5614     * Finds the n-th index within a String, handling {@code null}. This method uses {@link String#indexOf(String)} if possible.
5615     * <p>
5616     * Note that matches may overlap.
5617     * <p>
5618     *
5619     * <p>
5620     * A {@code null} CharSequence will return {@code -1}.
5621     * </p>
5622     *
5623     * @param str       The CharSequence to check, may be null.
5624     * @param searchStr The CharSequence to find, may be null.
5625     * @param ordinal   The n-th {@code searchStr} to find, overlapping matches are allowed.
5626     * @param lastIndex true if lastOrdinalIndexOf() otherwise false if ordinalIndexOf().
5627     * @return The n-th index of the search CharSequence, {@code -1} ({@code INDEX_NOT_FOUND}) if no match or {@code null} string input.
5628     */
5629    // Shared code between ordinalIndexOf(String, String, int) and lastOrdinalIndexOf(String, String, int)
5630    private static int ordinalIndexOf(final CharSequence str, final CharSequence searchStr, final int ordinal, final boolean lastIndex) {
5631        if (str == null || searchStr == null || ordinal <= 0) {
5632            return INDEX_NOT_FOUND;
5633        }
5634        if (isEmpty(searchStr)) {
5635            return lastIndex ? str.length() : 0;
5636        }
5637        int found = 0;
5638        // set the initial index beyond the end of the string
5639        // this is to allow for the initial index decrement/increment
5640        int index = lastIndex ? str.length() : INDEX_NOT_FOUND;
5641        do {
5642            if (lastIndex) {
5643                index = CharSequenceUtils.lastIndexOf(str, searchStr, index - 1); // step backwards through string
5644            } else {
5645                index = CharSequenceUtils.indexOf(str, searchStr, index + 1); // step forwards through string
5646            }
5647            if (index < 0) {
5648                return index;
5649            }
5650            found++;
5651        } while (found < ordinal);
5652        return index;
5653    }
5654
5655    /**
5656     * Overlays part of a String with another String.
5657     *
5658     * <p>
5659     * 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
5660     * length. The start index is always the smaller of the two indices.
5661     * </p>
5662     *
5663     * <pre>
5664     * StringUtils.overlay(null, *, *, *)            = null
5665     * StringUtils.overlay("", "abc", 0, 0)          = "abc"
5666     * StringUtils.overlay("abcdef", null, 2, 4)     = "abef"
5667     * StringUtils.overlay("abcdef", "", 2, 4)       = "abef"
5668     * StringUtils.overlay("abcdef", "", 4, 2)       = "abef"
5669     * StringUtils.overlay("abcdef", "zzzz", 2, 4)   = "abzzzzef"
5670     * StringUtils.overlay("abcdef", "zzzz", 4, 2)   = "abzzzzef"
5671     * StringUtils.overlay("abcdef", "zzzz", -1, 4)  = "zzzzef"
5672     * StringUtils.overlay("abcdef", "zzzz", 2, 8)   = "abzzzz"
5673     * StringUtils.overlay("abcdef", "zzzz", -2, -3) = "zzzzabcdef"
5674     * StringUtils.overlay("abcdef", "zzzz", 8, 10)  = "abcdefzzzz"
5675     * </pre>
5676     *
5677     * @param str     The String to do overlaying in, may be null.
5678     * @param overlay The String to overlay, may be null.
5679     * @param start   The position to start overlaying at.
5680     * @param end     The position to stop overlaying before.
5681     * @return overlaid String, {@code null} if null String input.
5682     * @since 2.0
5683     */
5684    public static String overlay(final String str, String overlay, int start, int end) {
5685        if (str == null) {
5686            return null;
5687        }
5688        if (overlay == null) {
5689            overlay = EMPTY;
5690        }
5691        final int len = str.length();
5692        if (start < 0) {
5693            start = 0;
5694        }
5695        if (start > len) {
5696            start = len;
5697        }
5698        if (end < 0) {
5699            end = 0;
5700        }
5701        if (end > len) {
5702            end = len;
5703        }
5704        if (start > end) {
5705            final int temp = start;
5706            start = end;
5707            end = temp;
5708        }
5709        // keep both cuts off the middle of a surrogate pair so the result is never left holding a lone surrogate
5710        if (splitsSurrogatePair(str, start)) {
5711            start--;
5712        }
5713        if (splitsSurrogatePair(str, end)) {
5714            end++;
5715        }
5716        return str.substring(0, start) + overlay + str.substring(end);
5717    }
5718
5719    /**
5720     * Prepends the prefix to the start of the string if the string does not already start with any of the prefixes.
5721     *
5722     * <pre>
5723     * StringUtils.prependIfMissing(null, null) = null
5724     * StringUtils.prependIfMissing("abc", null) = "abc"
5725     * StringUtils.prependIfMissing("", "xyz") = "xyz"
5726     * StringUtils.prependIfMissing("abc", "xyz") = "xyzabc"
5727     * StringUtils.prependIfMissing("xyzabc", "xyz") = "xyzabc"
5728     * StringUtils.prependIfMissing("XYZabc", "xyz") = "xyzXYZabc"
5729     * </pre>
5730     * <p>
5731     * With additional prefixes,
5732     * </p>
5733     *
5734     * <pre>
5735     * StringUtils.prependIfMissing(null, null, null) = null
5736     * StringUtils.prependIfMissing("abc", null, null) = "abc"
5737     * StringUtils.prependIfMissing("", "xyz", null) = "xyz"
5738     * StringUtils.prependIfMissing("abc", "xyz", new CharSequence[]{null}) = "xyzabc"
5739     * StringUtils.prependIfMissing("abc", "xyz", "") = "abc"
5740     * StringUtils.prependIfMissing("abc", "xyz", "mno") = "xyzabc"
5741     * StringUtils.prependIfMissing("xyzabc", "xyz", "mno") = "xyzabc"
5742     * StringUtils.prependIfMissing("mnoabc", "xyz", "mno") = "mnoabc"
5743     * StringUtils.prependIfMissing("XYZabc", "xyz", "mno") = "xyzXYZabc"
5744     * StringUtils.prependIfMissing("MNOabc", "xyz", "mno") = "xyzMNOabc"
5745     * </pre>
5746     *
5747     * @param str      The string.
5748     * @param prefix   The prefix to prepend to the start of the string.
5749     * @param prefixes Additional prefixes that are valid.
5750     * @return A new String if prefix was prepended, the same string otherwise.
5751     * @since 3.2
5752     * @deprecated Use {@link Strings#prependIfMissing(String, CharSequence, CharSequence...) Strings.CS.prependIfMissing(String, CharSequence,
5753     *             CharSequence...)}.
5754     */
5755    @Deprecated
5756    public static String prependIfMissing(final String str, final CharSequence prefix, final CharSequence... prefixes) {
5757        return Strings.CS.prependIfMissing(str, prefix, prefixes);
5758    }
5759
5760    /**
5761     * Prepends the prefix to the start of the string if the string does not already start, case-insensitive, with any of the prefixes.
5762     *
5763     * <pre>
5764     * StringUtils.prependIfMissingIgnoreCase(null, null) = null
5765     * StringUtils.prependIfMissingIgnoreCase("abc", null) = "abc"
5766     * StringUtils.prependIfMissingIgnoreCase("", "xyz") = "xyz"
5767     * StringUtils.prependIfMissingIgnoreCase("abc", "xyz") = "xyzabc"
5768     * StringUtils.prependIfMissingIgnoreCase("xyzabc", "xyz") = "xyzabc"
5769     * StringUtils.prependIfMissingIgnoreCase("XYZabc", "xyz") = "XYZabc"
5770     * </pre>
5771     * <p>
5772     * With additional prefixes,
5773     * </p>
5774     *
5775     * <pre>
5776     * StringUtils.prependIfMissingIgnoreCase(null, null, null) = null
5777     * StringUtils.prependIfMissingIgnoreCase("abc", null, null) = "abc"
5778     * StringUtils.prependIfMissingIgnoreCase("", "xyz", null) = "xyz"
5779     * StringUtils.prependIfMissingIgnoreCase("abc", "xyz", new CharSequence[]{null}) = "xyzabc"
5780     * StringUtils.prependIfMissingIgnoreCase("abc", "xyz", "") = "abc"
5781     * StringUtils.prependIfMissingIgnoreCase("abc", "xyz", "mno") = "xyzabc"
5782     * StringUtils.prependIfMissingIgnoreCase("xyzabc", "xyz", "mno") = "xyzabc"
5783     * StringUtils.prependIfMissingIgnoreCase("mnoabc", "xyz", "mno") = "mnoabc"
5784     * StringUtils.prependIfMissingIgnoreCase("XYZabc", "xyz", "mno") = "XYZabc"
5785     * StringUtils.prependIfMissingIgnoreCase("MNOabc", "xyz", "mno") = "MNOabc"
5786     * </pre>
5787     *
5788     * @param str      The string.
5789     * @param prefix   The prefix to prepend to the start of the string.
5790     * @param prefixes Additional prefixes that are valid (optional).
5791     * @return A new String if prefix was prepended, the same string otherwise.
5792     * @since 3.2
5793     * @deprecated Use {@link Strings#prependIfMissing(String, CharSequence, CharSequence...) Strings.CI.prependIfMissing(String, CharSequence,
5794     *             CharSequence...)}.
5795     */
5796    @Deprecated
5797    public static String prependIfMissingIgnoreCase(final String str, final CharSequence prefix, final CharSequence... prefixes) {
5798        return Strings.CI.prependIfMissing(str, prefix, prefixes);
5799    }
5800
5801    /**
5802     * Removes all occurrences of a character from within the source string.
5803     *
5804     * <p>
5805     * A {@code null} source string will return {@code null}. An empty ("") source string will return the empty string.
5806     * </p>
5807     *
5808     * <pre>
5809     * StringUtils.remove(null, *)       = null
5810     * StringUtils.remove("", *)         = ""
5811     * StringUtils.remove("queued", 'u') = "qeed"
5812     * StringUtils.remove("queued", 'z') = "queued"
5813     * </pre>
5814     *
5815     * @param str    The source String to search, may be null.
5816     * @param remove The char to search for and remove, may be null.
5817     * @return The substring with the char removed if found, {@code null} if null String input.
5818     * @since 2.1
5819     */
5820    public static String remove(final String str, final char remove) {
5821        if (isEmpty(str) || str.indexOf(remove) == INDEX_NOT_FOUND) {
5822            return str;
5823        }
5824        final char[] chars = str.toCharArray();
5825        int pos = 0;
5826        for (int i = 0; i < chars.length; i++) {
5827            if (chars[i] != remove) {
5828                chars[pos++] = chars[i];
5829            }
5830        }
5831        return new String(chars, 0, pos);
5832    }
5833
5834    /**
5835     * Removes all occurrences of a substring from within the source string.
5836     *
5837     * <p>
5838     * 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
5839     * the source string. An empty ("") remove string will return the source string.
5840     * </p>
5841     *
5842     * <pre>
5843     * StringUtils.remove(null, *)        = null
5844     * StringUtils.remove("", *)          = ""
5845     * StringUtils.remove(*, null)        = *
5846     * StringUtils.remove(*, "")          = *
5847     * StringUtils.remove("queued", "ue") = "qd"
5848     * StringUtils.remove("queued", "zz") = "queued"
5849     * </pre>
5850     *
5851     * @param str    The source String to search, may be null.
5852     * @param remove The String to search for and remove, may be null.
5853     * @return The substring with the string removed if found, {@code null} if null String input.
5854     * @since 2.1
5855     * @deprecated Use {@link Strings#remove(String, String) Strings.CS.remove(String, String)}.
5856     */
5857    @Deprecated
5858    public static String remove(final String str, final String remove) {
5859        return Strings.CS.remove(str, remove);
5860    }
5861
5862    /**
5863     * Removes each substring of the text String that matches the given regular expression.
5864     *
5865     * This method is a {@code null} safe equivalent to:
5866     * <ul>
5867     * <li>{@code text.replaceAll(regex, StringUtils.EMPTY)}</li>
5868     * <li>{@code Pattern.compile(regex).matcher(text).replaceAll(StringUtils.EMPTY)}</li>
5869     * </ul>
5870     *
5871     * <p>
5872     * A {@code null} reference passed to this method is a no-op.
5873     * </p>
5874     *
5875     * <p>
5876     * Unlike in the {@link #removePattern(String, String)} method, the {@link Pattern#DOTALL} option is NOT automatically added. To use the DOTALL option
5877     * prepend {@code "(?s)"} to the regex. DOTALL is also known as single-line mode in Perl.
5878     * </p>
5879     *
5880     * <pre>{@code
5881     * StringUtils.removeAll(null, *)      = null
5882     * StringUtils.removeAll("any", (String) null)  = "any"
5883     * StringUtils.removeAll("any", "")    = "any"
5884     * StringUtils.removeAll("any", ".*")  = ""
5885     * StringUtils.removeAll("any", ".+")  = ""
5886     * StringUtils.removeAll("abc", ".?")  = ""
5887     * StringUtils.removeAll("A<__>\n<__>B", "<.*>")      = "A\nB"
5888     * StringUtils.removeAll("A<__>\n<__>B", "(?s)<.*>")  = "AB"
5889     * StringUtils.removeAll("ABCabc123abc", "[a-z]")     = "ABC123"
5890     * }</pre>
5891     *
5892     * @param text  text to remove from, may be null.
5893     * @param regex The regular expression to which this string is to be matched.
5894     * @return The text with any removes processed, {@code null} if null String input.
5895     * @throws java.util.regex.PatternSyntaxException Thrown if the regular expression's syntax is invalid.
5896     * @see #replaceAll(String, String, String)
5897     * @see #removePattern(String, String)
5898     * @see String#replaceAll(String, String)
5899     * @see java.util.regex.Pattern
5900     * @see java.util.regex.Pattern#DOTALL
5901     * @since 3.5
5902     * @deprecated Use {@link RegExUtils#removeAll(String, String)}.
5903     */
5904    @Deprecated
5905    public static String removeAll(final String text, final String regex) {
5906        return RegExUtils.removeAll(text, regex);
5907    }
5908
5909    /**
5910     * Removes a substring only if it is at the end of a source string, otherwise returns the source string.
5911     *
5912     * <p>
5913     * 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
5914     * the source string.
5915     * </p>
5916     *
5917     * <pre>
5918     * StringUtils.removeEnd(null, *)      = null
5919     * StringUtils.removeEnd("", *)        = ""
5920     * StringUtils.removeEnd(*, null)      = *
5921     * StringUtils.removeEnd("www.domain.com", ".com.")  = "www.domain.com"
5922     * StringUtils.removeEnd("www.domain.com", ".com")   = "www.domain"
5923     * StringUtils.removeEnd("www.domain.com", "domain") = "www.domain.com"
5924     * StringUtils.removeEnd("abc", "")    = "abc"
5925     * </pre>
5926     *
5927     * @param str    The source String to search, may be null.
5928     * @param remove The String to search for and remove, may be null.
5929     * @return The substring with the string removed if found, {@code null} if null String input.
5930     * @since 2.1
5931     * @deprecated Use {@link Strings#removeEnd(String, CharSequence) Strings.CS.removeEnd(String, CharSequence)}.
5932     */
5933    @Deprecated
5934    public static String removeEnd(final String str, final String remove) {
5935        return Strings.CS.removeEnd(str, remove);
5936    }
5937
5938    /**
5939     * Case-insensitive removal of a substring if it is at the end of a source string, otherwise returns the source string.
5940     *
5941     * <p>
5942     * 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
5943     * the source string.
5944     * </p>
5945     *
5946     * <pre>
5947     * StringUtils.removeEndIgnoreCase(null, *)      = null
5948     * StringUtils.removeEndIgnoreCase("", *)        = ""
5949     * StringUtils.removeEndIgnoreCase(*, null)      = *
5950     * StringUtils.removeEndIgnoreCase("www.domain.com", ".com.")  = "www.domain.com"
5951     * StringUtils.removeEndIgnoreCase("www.domain.com", ".com")   = "www.domain"
5952     * StringUtils.removeEndIgnoreCase("www.domain.com", "domain") = "www.domain.com"
5953     * StringUtils.removeEndIgnoreCase("abc", "")    = "abc"
5954     * StringUtils.removeEndIgnoreCase("www.domain.com", ".COM") = "www.domain"
5955     * StringUtils.removeEndIgnoreCase("www.domain.COM", ".com") = "www.domain"
5956     * </pre>
5957     *
5958     * @param str    The source String to search, may be null.
5959     * @param remove The String to search for (case-insensitive) and remove, may be null.
5960     * @return The substring with the string removed if found, {@code null} if null String input.
5961     * @since 2.4
5962     * @deprecated Use {@link Strings#removeEnd(String, CharSequence) Strings.CI.removeEnd(String, CharSequence)}.
5963     */
5964    @Deprecated
5965    public static String removeEndIgnoreCase(final String str, final String remove) {
5966        return Strings.CI.removeEnd(str, remove);
5967    }
5968
5969    /**
5970     * Removes the first substring of the text string that matches the given regular expression.
5971     *
5972     * This method is a {@code null} safe equivalent to:
5973     * <ul>
5974     * <li>{@code text.replaceFirst(regex, StringUtils.EMPTY)}</li>
5975     * <li>{@code Pattern.compile(regex).matcher(text).replaceFirst(StringUtils.EMPTY)}</li>
5976     * </ul>
5977     *
5978     * <p>
5979     * A {@code null} reference passed to this method is a no-op.
5980     * </p>
5981     *
5982     * <p>
5983     * 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
5984     * single-line mode in Perl.
5985     * </p>
5986     *
5987     * <pre>{@code
5988     * StringUtils.removeFirst(null, *)      = null
5989     * StringUtils.removeFirst("any", (String) null)  = "any"
5990     * StringUtils.removeFirst("any", "")    = "any"
5991     * StringUtils.removeFirst("any", ".*")  = ""
5992     * StringUtils.removeFirst("any", ".+")  = ""
5993     * StringUtils.removeFirst("abc", ".?")  = "bc"
5994     * StringUtils.removeFirst("A<__>\n<__>B", "<.*>")      = "A\n<__>B"
5995     * StringUtils.removeFirst("A<__>\n<__>B", "(?s)<.*>")  = "AB"
5996     * StringUtils.removeFirst("ABCabc123", "[a-z]")          = "ABCbc123"
5997     * StringUtils.removeFirst("ABCabc123abc", "[a-z]+")      = "ABC123abc"
5998     * }</pre>
5999     *
6000     * @param text  text to remove from, may be null.
6001     * @param regex The regular expression to which this string is to be matched.
6002     * @return The text with the first replacement processed, {@code null} if null String input.
6003     * @throws java.util.regex.PatternSyntaxException Thrown if the regular expression's syntax is invalid.
6004     * @see #replaceFirst(String, String, String)
6005     * @see String#replaceFirst(String, String)
6006     * @see java.util.regex.Pattern
6007     * @see java.util.regex.Pattern#DOTALL
6008     * @since 3.5
6009     * @deprecated Use {@link RegExUtils#replaceFirst(String, String, String) RegExUtils.replaceFirst(String, String, EMPTY)}.
6010     */
6011    @Deprecated
6012    public static String removeFirst(final String text, final String regex) {
6013        return replaceFirst(text, regex, EMPTY);
6014    }
6015
6016    /**
6017     * Case-insensitive removal of all occurrences of a substring from within the source string.
6018     *
6019     * <p>
6020     * 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
6021     * the source string. An empty ("") remove string will return the source string.
6022     * </p>
6023     *
6024     * <pre>
6025     * StringUtils.removeIgnoreCase(null, *)        = null
6026     * StringUtils.removeIgnoreCase("", *)          = ""
6027     * StringUtils.removeIgnoreCase(*, null)        = *
6028     * StringUtils.removeIgnoreCase(*, "")          = *
6029     * StringUtils.removeIgnoreCase("queued", "ue") = "qd"
6030     * StringUtils.removeIgnoreCase("queued", "zz") = "queued"
6031     * StringUtils.removeIgnoreCase("quEUed", "UE") = "qd"
6032     * StringUtils.removeIgnoreCase("queued", "zZ") = "queued"
6033     * </pre>
6034     *
6035     * @param str    The source String to search, may be null.
6036     * @param remove The String to search for (case-insensitive) and remove, may be null.
6037     * @return The substring with the string removed if found, {@code null} if null String input.
6038     * @since 3.5
6039     * @deprecated Use {@link Strings#remove(String, String) Strings.CI.remove(String, String)}.
6040     */
6041    @Deprecated
6042    public static String removeIgnoreCase(final String str, final String remove) {
6043        return Strings.CI.remove(str, remove);
6044    }
6045
6046    /**
6047     * Removes each substring of the source String that matches the given regular expression using the DOTALL option.
6048     *
6049     * This call is a {@code null} safe equivalent to:
6050     * <ul>
6051     * <li>{@code source.replaceAll(&quot;(?s)&quot; + regex, StringUtils.EMPTY)}</li>
6052     * <li>{@code Pattern.compile(regex, Pattern.DOTALL).matcher(source).replaceAll(StringUtils.EMPTY)}</li>
6053     * </ul>
6054     *
6055     * <p>
6056     * A {@code null} reference passed to this method is a no-op.
6057     * </p>
6058     *
6059     * <pre>{@code
6060     * StringUtils.removePattern(null, *)       = null
6061     * StringUtils.removePattern("any", (String) null)   = "any"
6062     * StringUtils.removePattern("A<__>\n<__>B", "<.*>")  = "AB"
6063     * StringUtils.removePattern("ABCabc123", "[a-z]")    = "ABC123"
6064     * }</pre>
6065     *
6066     * @param source The source string.
6067     * @param regex  The regular expression to which this string is to be matched.
6068     * @return The resulting {@link String}.
6069     * @see #replacePattern(String, String, String)
6070     * @see String#replaceAll(String, String)
6071     * @see Pattern#DOTALL
6072     * @since 3.2
6073     * @since 3.5 Changed {@code null} reference passed to this method is a no-op.
6074     * @deprecated Use {@link RegExUtils#removePattern(CharSequence, String)}.
6075     */
6076    @Deprecated
6077    public static String removePattern(final String source, final String regex) {
6078        return RegExUtils.removePattern(source, regex);
6079    }
6080
6081    /**
6082     * Removes a char only if it is at the beginning of a source string, otherwise returns the source string.
6083     *
6084     * <p>
6085     * A {@code null} source string will return {@code null}. An empty ("") source string will return the empty string.
6086     * </p>
6087     *
6088     * <pre>
6089     * StringUtils.removeStart(null, *)      = null
6090     * StringUtils.removeStart("", *)        = ""
6091     * StringUtils.removeStart("/path", '/') = "path"
6092     * StringUtils.removeStart("path", '/')  = "path"
6093     * StringUtils.removeStart("path", '\0') = "path"
6094     * </pre>
6095     *
6096     * @param str    The source String to search, may be null.
6097     * @param remove The char to search for and remove.
6098     * @return The substring with the char removed if found, {@code null} if null String input.
6099     * @since 3.13.0
6100     */
6101    public static String removeStart(final String str, final char remove) {
6102        if (isEmpty(str)) {
6103            return str;
6104        }
6105        return str.charAt(0) == remove ? str.substring(1) : str;
6106    }
6107
6108    /**
6109     * Removes a substring only if it is at the beginning of a source string, otherwise returns the source string.
6110     *
6111     * <p>
6112     * 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
6113     * the source string.
6114     * </p>
6115     *
6116     * <pre>
6117     * StringUtils.removeStart(null, *)                    = null
6118     * StringUtils.removeStart("", *)                      = ""
6119     * StringUtils.removeStart(*, null)                    = *
6120     * StringUtils.removeStart("www.domain.com", "www.")   = "domain.com"
6121     * StringUtils.removeStart("domain.com", "www.")       = "domain.com"
6122     * StringUtils.removeStart("www.domain.com", "domain") = "www.domain.com"
6123     * StringUtils.removeStart("abc", "")                  = "abc"
6124     * </pre>
6125     *
6126     * @param str    The source String to search, may be null.
6127     * @param remove The String to search for and remove, may be null.
6128     * @return The substring with the string removed if found, {@code null} if null String input.
6129     * @since 2.1
6130     * @deprecated Use {@link Strings#removeStart(String, CharSequence) Strings.CS.removeStart(String, CharSequence)}.
6131     */
6132    @Deprecated
6133    public static String removeStart(final String str, final String remove) {
6134        return Strings.CS.removeStart(str, remove);
6135    }
6136
6137    /**
6138     * Case-insensitive removal of a substring if it is at the beginning of a source string, otherwise returns the source string.
6139     *
6140     * <p>
6141     * 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
6142     * the source string.
6143     * </p>
6144     *
6145     * <pre>
6146     * StringUtils.removeStartIgnoreCase(null, *)                    = null
6147     * StringUtils.removeStartIgnoreCase("", *)                      = ""
6148     * StringUtils.removeStartIgnoreCase(*, null)                    = *
6149     * StringUtils.removeStartIgnoreCase("www.domain.com", "www.")   = "domain.com"
6150     * StringUtils.removeStartIgnoreCase("www.domain.com", "WWW.")   = "domain.com"
6151     * StringUtils.removeStartIgnoreCase("domain.com", "www.")       = "domain.com"
6152     * StringUtils.removeStartIgnoreCase("www.domain.com", "domain") = "www.domain.com"
6153     * StringUtils.removeStartIgnoreCase("abc", "")                  = "abc"
6154     * </pre>
6155     *
6156     * @param str    The source String to search, may be null.
6157     * @param remove The String to search for (case-insensitive) and remove, may be null.
6158     * @return The substring with the string removed if found, {@code null} if null String input.
6159     * @since 2.4
6160     * @deprecated Use {@link Strings#removeStart(String, CharSequence) Strings.CI.removeStart(String, CharSequence)}.
6161     */
6162    @Deprecated
6163    public static String removeStartIgnoreCase(final String str, final String remove) {
6164        return Strings.CI.removeStart(str, remove);
6165    }
6166
6167    /**
6168     * Returns padding using the specified delimiter repeated to a given length.
6169     *
6170     * <pre>
6171     * StringUtils.repeat('e', 0)  = ""
6172     * StringUtils.repeat('e', 3)  = "eee"
6173     * StringUtils.repeat('e', -2) = ""
6174     * </pre>
6175     *
6176     * <p>
6177     * Note: this method does not support padding with <a href="https://www.unicode.org/glossary/#supplementary_character">Unicode Supplementary Characters</a>
6178     * 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
6179     * {@link #repeat(String, int)} instead.
6180     * </p>
6181     *
6182     * @param repeat character to repeat.
6183     * @param count  number of times to repeat char, negative treated as zero.
6184     * @return String with repeated character.
6185     * @see #repeat(String, int)
6186     */
6187    public static String repeat(final char repeat, final int count) {
6188        if (count <= 0) {
6189            return EMPTY;
6190        }
6191        return new String(ArrayFill.fill(new char[count], repeat));
6192    }
6193
6194    /**
6195     * Repeats a String {@code repeat} times to form a new String.
6196     *
6197     * <pre>
6198     * StringUtils.repeat(null, 2) = null
6199     * StringUtils.repeat("", 0)   = ""
6200     * StringUtils.repeat("", 2)   = ""
6201     * StringUtils.repeat("a", 3)  = "aaa"
6202     * StringUtils.repeat("ab", 2) = "abab"
6203     * StringUtils.repeat("a", -2) = ""
6204     * </pre>
6205     *
6206     * @param repeat The String to repeat, may be null.
6207     * @param count  number of times to repeat str, negative treated as zero.
6208     * @return A new String consisting of the original String repeated, {@code null} if null String input.
6209     */
6210    public static String repeat(final String repeat, final int count) {
6211        // Performance tuned for 2.0 (JDK1.4)
6212        if (repeat == null) {
6213            return null;
6214        }
6215        if (count <= 0) {
6216            return EMPTY;
6217        }
6218        final int inputLength = repeat.length();
6219        if (count == 1 || inputLength == 0) {
6220            return repeat;
6221        }
6222        if (inputLength == 1 && count <= PAD_LIMIT) {
6223            return repeat(repeat.charAt(0), count);
6224        }
6225        final int outputLength;
6226        try {
6227            outputLength = Math.multiplyExact(inputLength, count);
6228        } catch (final Exception e) {
6229            throw new IllegalArgumentException("The requested result is too large for a String.");
6230        }
6231        switch (inputLength) {
6232        case 1:
6233            return repeat(repeat.charAt(0), count);
6234        case 2:
6235            final char ch0 = repeat.charAt(0);
6236            final char ch1 = repeat.charAt(1);
6237            final char[] output2 = new char[outputLength];
6238            for (int i = count * 2 - 2; i >= 0; i--, i--) {
6239                output2[i] = ch0;
6240                output2[i + 1] = ch1;
6241            }
6242            return new String(output2);
6243        default:
6244            final StringBuilder buf = new StringBuilder(outputLength);
6245            for (int i = 0; i < count; i++) {
6246                buf.append(repeat);
6247            }
6248            return buf.toString();
6249        }
6250    }
6251
6252    /**
6253     * Repeats a String {@code repeat} times to form a new String, with a String separator injected each time.
6254     *
6255     * <pre>
6256     * StringUtils.repeat(null, null, 2) = null
6257     * StringUtils.repeat(null, "x", 2)  = null
6258     * StringUtils.repeat("", null, 0)   = ""
6259     * StringUtils.repeat("", "", 2)     = ""
6260     * StringUtils.repeat("", "x", 3)    = "xx"
6261     * StringUtils.repeat("?", ", ", 3)  = "?, ?, ?"
6262     * </pre>
6263     *
6264     * @param repeat    The String to repeat, may be null.
6265     * @param separator The String to inject, may be null.
6266     * @param count     number of times to repeat str, negative treated as zero.
6267     * @return A new String consisting of the original String repeated, {@code null} if null String input.
6268     * @since 2.5
6269     */
6270    public static String repeat(final String repeat, final String separator, final int count) {
6271        if (repeat == null || separator == null) {
6272            return repeat(repeat, count);
6273        }
6274        // given that repeat(String, int) is quite optimized, better to rely on it than try and splice this into it
6275        final String result = repeat(repeat + separator, count);
6276        return Strings.CS.removeEnd(result, separator);
6277    }
6278
6279    /**
6280     * Replaces all occurrences of a String within another String.
6281     *
6282     * <p>
6283     * A {@code null} reference passed to this method is a no-op.
6284     * </p>
6285     *
6286     * <pre>
6287     * StringUtils.replace(null, *, *)        = null
6288     * StringUtils.replace("", *, *)          = ""
6289     * StringUtils.replace("any", null, *)    = "any"
6290     * StringUtils.replace("any", *, null)    = "any"
6291     * StringUtils.replace("any", "", *)      = "any"
6292     * StringUtils.replace("aba", "a", null)  = "aba"
6293     * StringUtils.replace("aba", "a", "")    = "b"
6294     * StringUtils.replace("aba", "a", "z")   = "zbz"
6295     * </pre>
6296     *
6297     * @param text         text to search and replace in, may be null.
6298     * @param searchString The String to search for, may be null.
6299     * @param replacement  The String to replace it with, may be null.
6300     * @return The text with any replacements processed, {@code null} if null String input.
6301     * @see #replace(String text, String searchString, String replacement, int max)
6302     * @deprecated Use {@link Strings#replace(String, String, String) Strings.CS.replace(String, String, String)}.
6303     */
6304    @Deprecated
6305    public static String replace(final String text, final String searchString, final String replacement) {
6306        return Strings.CS.replace(text, searchString, replacement);
6307    }
6308
6309    /**
6310     * Replaces a String with another String inside a larger String, for the first {@code max} values of the search String.
6311     *
6312     * <p>
6313     * A {@code null} reference passed to this method is a no-op.
6314     * </p>
6315     *
6316     * <pre>
6317     * StringUtils.replace(null, *, *, *)         = null
6318     * StringUtils.replace("", *, *, *)           = ""
6319     * StringUtils.replace("any", null, *, *)     = "any"
6320     * StringUtils.replace("any", *, null, *)     = "any"
6321     * StringUtils.replace("any", "", *, *)       = "any"
6322     * StringUtils.replace("any", *, *, 0)        = "any"
6323     * StringUtils.replace("abaa", "a", null, -1) = "abaa"
6324     * StringUtils.replace("abaa", "a", "", -1)   = "b"
6325     * StringUtils.replace("abaa", "a", "z", 0)   = "abaa"
6326     * StringUtils.replace("abaa", "a", "z", 1)   = "zbaa"
6327     * StringUtils.replace("abaa", "a", "z", 2)   = "zbza"
6328     * StringUtils.replace("abaa", "a", "z", -1)  = "zbzz"
6329     * </pre>
6330     *
6331     * @param text         text to search and replace in, may be null.
6332     * @param searchString The String to search for, may be null.
6333     * @param replacement  The String to replace it with, may be null.
6334     * @param max          maximum number of values to replace, or {@code -1} if no maximum.
6335     * @return The text with any replacements processed, {@code null} if null String input.
6336     * @deprecated Use {@link Strings#replace(String, String, String, int) Strings.CS.replace(String, String, String, int)}.
6337     */
6338    @Deprecated
6339    public static String replace(final String text, final String searchString, final String replacement, final int max) {
6340        return Strings.CS.replace(text, searchString, replacement, max);
6341    }
6342
6343    /**
6344     * Replaces each substring of the text String that matches the given regular expression with the given replacement.
6345     *
6346     * This method is a {@code null} safe equivalent to:
6347     * <ul>
6348     * <li>{@code text.replaceAll(regex, replacement)}</li>
6349     * <li>{@code Pattern.compile(regex).matcher(text).replaceAll(replacement)}</li>
6350     * </ul>
6351     *
6352     * <p>
6353     * A {@code null} reference passed to this method is a no-op.
6354     * </p>
6355     *
6356     * <p>
6357     * Unlike in the {@link #replacePattern(String, String, String)} method, the {@link Pattern#DOTALL} option is NOT automatically added. To use the DOTALL
6358     * option prepend {@code "(?s)"} to the regex. DOTALL is also known as single-line mode in Perl.
6359     * </p>
6360     *
6361     * <pre>{@code
6362     * StringUtils.replaceAll(null, *, *)                                         = null
6363     * StringUtils.replaceAll("any", (String) null, *)                            = "any"
6364     * StringUtils.replaceAll("any", *, null)                                     = "any"
6365     * StringUtils.replaceAll("", "", "zzz")                                      = "zzz"
6366     * StringUtils.replaceAll("", ".*", "zzz")                                    = "zzz"
6367     * StringUtils.replaceAll("", ".+", "zzz")                                    = ""
6368     * StringUtils.replaceAll("abc", "", "ZZ")                                    = "ZZaZZbZZcZZ"
6369     * StringUtils.replaceAll("<__>\n<__>", "<.*>", "z")                          = "z\nz"
6370     * StringUtils.replaceAll("<__>\n<__>", "(?s)<.*>", "z")                      = "z"
6371     * StringUtils.replaceAll("ABCabc123", "[a-z]", "_")                          = "ABC___123"
6372     * StringUtils.replaceAll("ABCabc123", "[^A-Z0-9]+", "_")                     = "ABC_123"
6373     * StringUtils.replaceAll("ABCabc123", "[^A-Z0-9]+", "")                      = "ABC123"
6374     * StringUtils.replaceAll("Lorem ipsum  dolor   sit", "( +)([a-z]+)", "_$2")  = "Lorem_ipsum_dolor_sit"
6375     * }</pre>
6376     *
6377     * @param text        text to search and replace in, may be null.
6378     * @param regex       The regular expression to which this string is to be matched.
6379     * @param replacement The string to be substituted for each match.
6380     * @return The text with any replacements processed, {@code null} if null String input.
6381     * @throws java.util.regex.PatternSyntaxException Thrown if the regular expression's syntax is invalid.
6382     * @see #replacePattern(String, String, String)
6383     * @see String#replaceAll(String, String)
6384     * @see java.util.regex.Pattern
6385     * @see java.util.regex.Pattern#DOTALL
6386     * @since 3.5
6387     * @deprecated Use {@link RegExUtils#replaceAll(String, String, String)}.
6388     */
6389    @Deprecated
6390    public static String replaceAll(final String text, final String regex, final String replacement) {
6391        return RegExUtils.replaceAll(text, regex, replacement);
6392    }
6393
6394    /**
6395     * Replaces all occurrences of a character in a String with another. This is a null-safe version of {@link String#replace(char, char)}.
6396     *
6397     * <p>
6398     * A {@code null} string input returns {@code null}. An empty ("") string input returns an empty string.
6399     * </p>
6400     *
6401     * <pre>
6402     * StringUtils.replaceChars(null, *, *)        = null
6403     * StringUtils.replaceChars("", *, *)          = ""
6404     * StringUtils.replaceChars("abcba", 'b', 'y') = "aycya"
6405     * StringUtils.replaceChars("abcba", 'z', 'y') = "abcba"
6406     * </pre>
6407     *
6408     * @param str         String to replace characters in, may be null.
6409     * @param searchChar  The character to search for, may be null.
6410     * @param replaceChar The character to replace, may be null.
6411     * @return modified String, {@code null} if null string input.
6412     * @since 2.0
6413     */
6414    public static String replaceChars(final String str, final char searchChar, final char replaceChar) {
6415        if (str == null) {
6416            return null;
6417        }
6418        return str.replace(searchChar, replaceChar);
6419    }
6420
6421    /**
6422     * Replaces multiple characters in a String in one go. This method can also be used to delete characters.
6423     *
6424     * <p>
6425     * For example:
6426     * </p>
6427     * <pre>
6428     * replaceChars(&quot;hello&quot;, &quot;ho&quot;, &quot;jy&quot;) = jelly.
6429     * </pre>
6430     *
6431     * <p>
6432     * 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
6433     * the input string.
6434     * </p>
6435     *
6436     * <p>
6437     * 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
6438     * characters are deleted. If the search characters is shorter, then the extra replace characters are ignored.
6439     * </p>
6440     *
6441     * <pre>
6442     * StringUtils.replaceChars(null, *, *)           = null
6443     * StringUtils.replaceChars("", *, *)             = ""
6444     * StringUtils.replaceChars("abc", null, *)       = "abc"
6445     * StringUtils.replaceChars("abc", "", *)         = "abc"
6446     * StringUtils.replaceChars("abc", "b", null)     = "ac"
6447     * StringUtils.replaceChars("abc", "b", "")       = "ac"
6448     * StringUtils.replaceChars("abcba", "bc", "yz")  = "ayzya"
6449     * StringUtils.replaceChars("abcba", "bc", "y")   = "ayya"
6450     * StringUtils.replaceChars("abcba", "bc", "yzx") = "ayzya"
6451     * </pre>
6452     *
6453     * @param str          String to replace characters in, may be null.
6454     * @param searchChars  A set of characters to search for, may be null.
6455     * @param replaceChars A set of characters to replace, may be null.
6456     * @return modified String, {@code null} if null string input.
6457     * @since 2.0
6458     */
6459    public static String replaceChars(final String str, final String searchChars, String replaceChars) {
6460        if (isEmpty(str) || isEmpty(searchChars)) {
6461            return str;
6462        }
6463        replaceChars = ObjectUtils.toString(replaceChars);
6464        boolean modified = false;
6465        final int replaceCharsLength = replaceChars.length();
6466        final int strLength = str.length();
6467        final StringBuilder buf = new StringBuilder(strLength);
6468        for (int i = 0; i < strLength; i++) {
6469            final char ch = str.charAt(i);
6470            final int index = searchChars.indexOf(ch);
6471            if (index >= 0) {
6472                modified = true;
6473                if (index < replaceCharsLength) {
6474                    buf.append(replaceChars.charAt(index));
6475                }
6476            } else {
6477                buf.append(ch);
6478            }
6479        }
6480        if (modified) {
6481            return buf.toString();
6482        }
6483        return str;
6484    }
6485
6486    /**
6487     * Replaces all occurrences of Strings within another String.
6488     *
6489     * <p>
6490     * 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
6491     * will not repeat. For repeating replaces, call the overloaded method.
6492     * </p>
6493     *
6494     * <pre>
6495     *  StringUtils.replaceEach(null, *, *)                                                = null
6496     *  StringUtils.replaceEach("", *, *)                                                  = ""
6497     *  StringUtils.replaceEach("aba", null, null)                                         = "aba"
6498     *  StringUtils.replaceEach("aba", new String[0], null)                                = "aba"
6499     *  StringUtils.replaceEach("aba", null, new String[0])                                = "aba"
6500     *  StringUtils.replaceEach("aba", new String[]{"a"}, null)                            = "aba"
6501     *  StringUtils.replaceEach("aba", new String[]{"a"}, new String[]{""})                = "b"
6502     *  StringUtils.replaceEach("aba", new String[]{null}, new String[]{"a"})              = "aba"
6503     *  StringUtils.replaceEach("abcde", new String[]{"ab", "d"}, new String[]{"w", "t"})  = "wcte"
6504     *  (example of how it does not repeat)
6505     *  StringUtils.replaceEach("abcde", new String[]{"ab", "d"}, new String[]{"d", "t"})  = "dcte"
6506     * </pre>
6507     *
6508     * @param text            text to search and replace in, no-op if null.
6509     * @param searchList      The Strings to search for, no-op if null.
6510     * @param replacementList The Strings to replace them with, no-op if null.
6511     * @return The text with any replacements processed, {@code null} if null String input.
6512     * @throws IllegalArgumentException Thrown if the lengths of the arrays are not the same (null is ok, and/or size 0).
6513     * @since 2.4
6514     */
6515    public static String replaceEach(final String text, final String[] searchList, final String[] replacementList) {
6516        return replaceEachOnce(text, searchList, replacementList);
6517    }
6518
6519    /**
6520     * Replace all occurrences of Strings within another String, in a single pass. This is a private helper method for
6521     * {@link #replaceEachRepeatedly(String, String[], String[])} and {@link #replaceEach(String, String[], String[])}
6522     *
6523     * <p>
6524     * 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.
6525     * </p>
6526     *
6527     * <pre>
6528     *  StringUtils.replaceEachOnce(null, *, *)                                                = null
6529     *  StringUtils.replaceEachOnce("", *, *)                                                  = ""
6530     *  StringUtils.replaceEachOnce("aba", null, null)                                         = "aba"
6531     *  StringUtils.replaceEachOnce("aba", new String[0], null)                                = "aba"
6532     *  StringUtils.replaceEachOnce("aba", null, new String[0])                                = "aba"
6533     *  StringUtils.replaceEachOnce("aba", new String[]{"a"}, null)                            = "aba"
6534     *  StringUtils.replaceEachOnce("aba", new String[]{"a"}, new String[]{""})                = "b"
6535     *  StringUtils.replaceEachOnce("aba", new String[]{null}, new String[]{"a"})              = "aba"
6536     *  StringUtils.replaceEachOnce("abcde", new String[]{"ab", "d"}, new String[]{"w", "t"})  = "wcte"
6537     *  StringUtils.replaceEachOnce("abcde", new String[]{"ab", "d"}, new String[]{"d", "t"})  = "dcte"
6538     * </pre>
6539     *
6540     * <p>
6541     * When no replacement is performed, the {@code text} argument is returned unchanged (same reference); callers rely on this to detect convergence.
6542     * </p>
6543     *
6544     * @param text            text to search and replace in, no-op if null.
6545     * @param searchList      The Strings to search for, no-op if null.
6546     * @param replacementList The Strings to replace them with, no-op if null.
6547     * @return The text with any replacements processed, {@code null} if null String input.
6548     * @throws IllegalArgumentException Thrown if the lengths of the arrays are not the same (null is ok, and/or size 0).
6549     * @since 2.4
6550     */
6551    private static String replaceEachOnce(final String text, final String[] searchList, final String[] replacementList) {
6552
6553        // Performance note: This creates very few new objects (one major goal)
6554        // let me know if there are performance requests, we can create a harness to measure
6555        if (isEmpty(text) || ArrayUtils.isEmpty(searchList) || ArrayUtils.isEmpty(replacementList)) {
6556            return text;
6557        }
6558
6559        final int searchLength = searchList.length;
6560        final int replacementLength = replacementList.length;
6561
6562        // make sure lengths are ok, these need to be equal
6563        if (searchLength != replacementLength) {
6564            throw new IllegalArgumentException("Search and Replace array lengths don't match: "
6565                + searchLength
6566                + " vs "
6567                + replacementLength);
6568        }
6569
6570        // keep track of which still have matches
6571        final boolean[] noMoreMatchesForReplIndex = new boolean[searchLength];
6572
6573        // index on index that the match was found
6574        int textIndex = -1;
6575        int replaceIndex = -1;
6576        int tempIndex;
6577
6578        // index of replace array that will replace the search string found
6579        // NOTE: logic duplicated below START
6580        for (int i = 0; i < searchLength; i++) {
6581            if (noMoreMatchesForReplIndex[i] || isEmpty(searchList[i]) || replacementList[i] == null) {
6582                continue;
6583            }
6584            tempIndex = text.indexOf(searchList[i]);
6585
6586            // see if we need to keep searching for this
6587            if (tempIndex == -1) {
6588                noMoreMatchesForReplIndex[i] = true;
6589            } else if (textIndex == -1 || tempIndex < textIndex) {
6590                textIndex = tempIndex;
6591                replaceIndex = i;
6592            }
6593        }
6594        // NOTE: logic mostly below END
6595
6596        // no search strings found, we are done
6597        if (textIndex == -1) {
6598            return text;
6599        }
6600
6601        int start = 0;
6602
6603        // get a good guess on the size of the result buffer so it doesn't have to double if it goes over a bit
6604        int increase = 0;
6605
6606        // count the replacement text elements that are larger than their corresponding text being replaced
6607        for (int i = 0; i < searchList.length; i++) {
6608            if (searchList[i] == null || replacementList[i] == null) {
6609                continue;
6610            }
6611            final int greater = replacementList[i].length() - searchList[i].length();
6612            if (greater > 0) {
6613                increase += 3 * greater; // assume 3 matches
6614            }
6615        }
6616        // have upper-bound at 20% increase, then let Java take over
6617        increase = Math.min(increase, text.length() / 5);
6618
6619        final StringBuilder buf = new StringBuilder(text.length() + increase);
6620
6621        while (textIndex != -1) {
6622
6623            for (int i = start; i < textIndex; i++) {
6624                buf.append(text.charAt(i));
6625            }
6626            buf.append(replacementList[replaceIndex]);
6627
6628            start = textIndex + searchList[replaceIndex].length();
6629
6630            textIndex = -1;
6631            replaceIndex = -1;
6632            // find the next earliest match
6633            // NOTE: logic mostly duplicated above START
6634            for (int i = 0; i < searchLength; i++) {
6635                if (noMoreMatchesForReplIndex[i] || isEmpty(searchList[i]) || replacementList[i] == null) {
6636                    continue;
6637                }
6638                tempIndex = text.indexOf(searchList[i], start);
6639
6640                // see if we need to keep searching for this
6641                if (tempIndex == -1) {
6642                    noMoreMatchesForReplIndex[i] = true;
6643                } else if (textIndex == -1 || tempIndex < textIndex) {
6644                    textIndex = tempIndex;
6645                    replaceIndex = i;
6646                }
6647            }
6648            // NOTE: logic duplicated above END
6649
6650        }
6651        final int textLength = text.length();
6652        for (int i = start; i < textLength; i++) {
6653            buf.append(text.charAt(i));
6654        }
6655        return buf.toString();
6656    }
6657
6658    /**
6659     * Replaces all occurrences of Strings within another String.
6660     *
6661     * <p>
6662     * 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.
6663     * </p>
6664     *
6665     * <pre>
6666     *  StringUtils.replaceEachRepeatedly(null, *, *)                                                = null
6667     *  StringUtils.replaceEachRepeatedly("", *, *)                                                  = ""
6668     *  StringUtils.replaceEachRepeatedly("aba", null, null)                                         = "aba"
6669     *  StringUtils.replaceEachRepeatedly("aba", new String[0], null)                                = "aba"
6670     *  StringUtils.replaceEachRepeatedly("aba", null, new String[0])                                = "aba"
6671     *  StringUtils.replaceEachRepeatedly("aba", new String[]{"a"}, null)                            = "aba"
6672     *  StringUtils.replaceEachRepeatedly("aba", new String[]{"a"}, new String[]{""})                = "b"
6673     *  StringUtils.replaceEachRepeatedly("aba", new String[]{null}, new String[]{"a"})              = "aba"
6674     *  StringUtils.replaceEachRepeatedly("abcde", new String[]{"ab", "d"}, new String[]{"w", "t"})  = "wcte"
6675     *  (example of how it repeats)
6676     *  StringUtils.replaceEachRepeatedly("abcde", new String[]{"ab", "d"}, new String[]{"d", "t"})  = "tcte"
6677     *  StringUtils.replaceEachRepeatedly("abcde", new String[]{"ab", "d"}, new String[]{"d", "ab"}) = Throws {@link IllegalStateException}
6678     * </pre>
6679     *
6680     * @param text            text to search and replace in, no-op if null.
6681     * @param searchList      The Strings to search for, no-op if null.
6682     * @param replacementList The Strings to replace them with, no-op if null.
6683     * @return The text with any replacements processed, {@code null} if null String input.
6684     * @throws IllegalStateException    Thrown if the search is repeating and there is an endless loop due to outputs of one being inputs to another.
6685     * @throws IllegalArgumentException Thrown if the lengths of the arrays are not the same (null is ok, and/or size 0).
6686     * @since 2.4
6687     */
6688    public static String replaceEachRepeatedly(final String text, final String[] searchList, final String[] replacementList) {
6689        // The iteration budget is a fixed constant, deliberately independent of the caller-supplied
6690        // searchList length: deriving the budget from the input would let the input size choose the
6691        // recursion depth/amplification (formerly a real StackOverflowError on large search lists).
6692        String result = text;
6693        for (int timeToLive = DEFAULT_TTL; timeToLive >= 0; timeToLive--) {
6694            final String next = replaceEachOnce(result, searchList, replacementList);
6695            if (next == result) {
6696                // No replacement was performed; converged.
6697                return result;
6698            }
6699            result = next;
6700        }
6701        throw new IllegalStateException("Aborting to protect against StackOverflowError - " +
6702            "output of one loop is the input of another");
6703    }
6704
6705    /**
6706     * Replaces the first substring of the text string that matches the given regular expression with the given replacement.
6707     *
6708     * This method is a {@code null} safe equivalent to:
6709     * <ul>
6710     * <li>{@code text.replaceFirst(regex, replacement)}</li>
6711     * <li>{@code Pattern.compile(regex).matcher(text).replaceFirst(replacement)}</li>
6712     * </ul>
6713     *
6714     * <p>
6715     * A {@code null} reference passed to this method is a no-op.
6716     * </p>
6717     *
6718     * <p>
6719     * 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
6720     * single-line mode in Perl.
6721     * </p>
6722     *
6723     * <pre>{@code
6724     * StringUtils.replaceFirst(null, *, *)       = null
6725     * StringUtils.replaceFirst("any", (String) null, *)   = "any"
6726     * StringUtils.replaceFirst("any", *, null)   = "any"
6727     * StringUtils.replaceFirst("", "", "zzz")    = "zzz"
6728     * StringUtils.replaceFirst("", ".*", "zzz")  = "zzz"
6729     * StringUtils.replaceFirst("", ".+", "zzz")  = ""
6730     * StringUtils.replaceFirst("abc", "", "ZZ")  = "ZZabc"
6731     * StringUtils.replaceFirst("<__>\n<__>", "<.*>", "z")      = "z\n<__>"
6732     * StringUtils.replaceFirst("<__>\n<__>", "(?s)<.*>", "z")  = "z"
6733     * StringUtils.replaceFirst("ABCabc123", "[a-z]", "_")          = "ABC_bc123"
6734     * StringUtils.replaceFirst("ABCabc123abc", "[^A-Z0-9]+", "_")  = "ABC_123abc"
6735     * StringUtils.replaceFirst("ABCabc123abc", "[^A-Z0-9]+", "")   = "ABC123abc"
6736     * StringUtils.replaceFirst("Lorem ipsum  dolor   sit", "( +)([a-z]+)", "_$2")  = "Lorem_ipsum  dolor   sit"
6737     * }</pre>
6738     *
6739     * @param text        text to search and replace in, may be null.
6740     * @param regex       The regular expression to which this string is to be matched.
6741     * @param replacement The string to be substituted for the first match.
6742     * @return The text with the first replacement processed, {@code null} if null String input.
6743     * @throws java.util.regex.PatternSyntaxException Thrown if the regular expression's syntax is invalid.
6744     * @see String#replaceFirst(String, String)
6745     * @see java.util.regex.Pattern
6746     * @see java.util.regex.Pattern#DOTALL
6747     * @since 3.5
6748     * @deprecated Use {@link RegExUtils#replaceFirst(String, String, String)}.
6749     */
6750    @Deprecated
6751    public static String replaceFirst(final String text, final String regex, final String replacement) {
6752        return RegExUtils.replaceFirst(text, regex, replacement);
6753    }
6754
6755    /**
6756     * Case insensitively replaces all occurrences of a String within another String.
6757     *
6758     * <p>
6759     * A {@code null} reference passed to this method is a no-op.
6760     * </p>
6761     *
6762     * <pre>
6763     * StringUtils.replaceIgnoreCase(null, *, *)        = null
6764     * StringUtils.replaceIgnoreCase("", *, *)          = ""
6765     * StringUtils.replaceIgnoreCase("any", null, *)    = "any"
6766     * StringUtils.replaceIgnoreCase("any", *, null)    = "any"
6767     * StringUtils.replaceIgnoreCase("any", "", *)      = "any"
6768     * StringUtils.replaceIgnoreCase("aba", "a", null)  = "aba"
6769     * StringUtils.replaceIgnoreCase("abA", "A", "")    = "b"
6770     * StringUtils.replaceIgnoreCase("aba", "A", "z")   = "zbz"
6771     * </pre>
6772     *
6773     * @param text         text to search and replace in, may be null.
6774     * @param searchString The String to search for (case-insensitive), may be null.
6775     * @param replacement  The String to replace it with, may be null.
6776     * @return The text with any replacements processed, {@code null} if null String input.
6777     * @see #replaceIgnoreCase(String text, String searchString, String replacement, int max)
6778     * @since 3.5
6779     * @deprecated Use {@link Strings#replace(String, String, String) Strings.CI.replace(String, String, String)}.
6780     */
6781    @Deprecated
6782    public static String replaceIgnoreCase(final String text, final String searchString, final String replacement) {
6783        return Strings.CI.replace(text, searchString, replacement);
6784    }
6785
6786    /**
6787     * Case insensitively replaces a String with another String inside a larger String, for the first {@code max} values of the search String.
6788     *
6789     * <p>
6790     * A {@code null} reference passed to this method is a no-op.
6791     * </p>
6792     *
6793     * <pre>
6794     * StringUtils.replaceIgnoreCase(null, *, *, *)         = null
6795     * StringUtils.replaceIgnoreCase("", *, *, *)           = ""
6796     * StringUtils.replaceIgnoreCase("any", null, *, *)     = "any"
6797     * StringUtils.replaceIgnoreCase("any", *, null, *)     = "any"
6798     * StringUtils.replaceIgnoreCase("any", "", *, *)       = "any"
6799     * StringUtils.replaceIgnoreCase("any", *, *, 0)        = "any"
6800     * StringUtils.replaceIgnoreCase("abaa", "a", null, -1) = "abaa"
6801     * StringUtils.replaceIgnoreCase("abaa", "a", "", -1)   = "b"
6802     * StringUtils.replaceIgnoreCase("abaa", "a", "z", 0)   = "abaa"
6803     * StringUtils.replaceIgnoreCase("abaa", "A", "z", 1)   = "zbaa"
6804     * StringUtils.replaceIgnoreCase("abAa", "a", "z", 2)   = "zbza"
6805     * StringUtils.replaceIgnoreCase("abAa", "a", "z", -1)  = "zbzz"
6806     * </pre>
6807     *
6808     * @param text         text to search and replace in, may be null.
6809     * @param searchString The String to search for (case-insensitive), may be null.
6810     * @param replacement  The String to replace it with, may be null.
6811     * @param max          maximum number of values to replace, or {@code -1} if no maximum.
6812     * @return The text with any replacements processed, {@code null} if null String input.
6813     * @since 3.5
6814     * @deprecated Use {@link Strings#replace(String, String, String, int) Strings.CI.replace(String, String, String, int)}.
6815     */
6816    @Deprecated
6817    public static String replaceIgnoreCase(final String text, final String searchString, final String replacement, final int max) {
6818        return Strings.CI.replace(text, searchString, replacement, max);
6819    }
6820
6821    /**
6822     * Replaces a String with another String inside a larger String, once.
6823     *
6824     * <p>
6825     * A {@code null} reference passed to this method is a no-op.
6826     * </p>
6827     *
6828     * <pre>
6829     * StringUtils.replaceOnce(null, *, *)        = null
6830     * StringUtils.replaceOnce("", *, *)          = ""
6831     * StringUtils.replaceOnce("any", null, *)    = "any"
6832     * StringUtils.replaceOnce("any", *, null)    = "any"
6833     * StringUtils.replaceOnce("any", "", *)      = "any"
6834     * StringUtils.replaceOnce("aba", "a", null)  = "aba"
6835     * StringUtils.replaceOnce("aba", "a", "")    = "ba"
6836     * StringUtils.replaceOnce("aba", "a", "z")   = "zba"
6837     * </pre>
6838     *
6839     * @param text         text to search and replace in, may be null.
6840     * @param searchString The String to search for, may be null.
6841     * @param replacement  The String to replace with, may be null.
6842     * @return The text with any replacements processed, {@code null} if null String input.
6843     * @see #replace(String text, String searchString, String replacement, int max)
6844     * @deprecated Use {@link Strings#replaceOnce(String, String, String) Strings.CS.replaceOnce(String, String, String)}.
6845     */
6846    @Deprecated
6847    public static String replaceOnce(final String text, final String searchString, final String replacement) {
6848        return Strings.CS.replaceOnce(text, searchString, replacement);
6849    }
6850
6851    /**
6852     * Case insensitively replaces a String with another String inside a larger String, once.
6853     *
6854     * <p>
6855     * A {@code null} reference passed to this method is a no-op.
6856     * </p>
6857     *
6858     * <pre>
6859     * StringUtils.replaceOnceIgnoreCase(null, *, *)        = null
6860     * StringUtils.replaceOnceIgnoreCase("", *, *)          = ""
6861     * StringUtils.replaceOnceIgnoreCase("any", null, *)    = "any"
6862     * StringUtils.replaceOnceIgnoreCase("any", *, null)    = "any"
6863     * StringUtils.replaceOnceIgnoreCase("any", "", *)      = "any"
6864     * StringUtils.replaceOnceIgnoreCase("aba", "a", null)  = "aba"
6865     * StringUtils.replaceOnceIgnoreCase("aba", "a", "")    = "ba"
6866     * StringUtils.replaceOnceIgnoreCase("aba", "a", "z")   = "zba"
6867     * StringUtils.replaceOnceIgnoreCase("FoOFoofoo", "foo", "") = "Foofoo"
6868     * </pre>
6869     *
6870     * @param text         text to search and replace in, may be null.
6871     * @param searchString The String to search for (case-insensitive), may be null.
6872     * @param replacement  The String to replace with, may be null.
6873     * @return The text with any replacements processed, {@code null} if null String input.
6874     * @see #replaceIgnoreCase(String text, String searchString, String replacement, int max)
6875     * @since 3.5
6876     * @deprecated Use {@link Strings#replaceOnce(String, String, String) Strings.CI.replaceOnce(String, String, String)}.
6877     */
6878    @Deprecated
6879    public static String replaceOnceIgnoreCase(final String text, final String searchString, final String replacement) {
6880        return Strings.CI.replaceOnce(text, searchString, replacement);
6881    }
6882
6883    /**
6884     * Replaces each substring of the source String that matches the given regular expression with the given replacement using the {@link Pattern#DOTALL}
6885     * option. DOTALL is also known as single-line mode in Perl.
6886     *
6887     * This call is a {@code null} safe equivalent to:
6888     * <ul>
6889     * <li>{@code source.replaceAll(&quot;(?s)&quot; + regex, replacement)}</li>
6890     * <li>{@code Pattern.compile(regex, Pattern.DOTALL).matcher(source).replaceAll(replacement)}</li>
6891     * </ul>
6892     *
6893     * <p>
6894     * A {@code null} reference passed to this method is a no-op.
6895     * </p>
6896     *
6897     * <pre>{@code
6898     * StringUtils.replacePattern(null, *, *)                                         = null
6899     * StringUtils.replacePattern("any", (String) null, *)                            = "any"
6900     * StringUtils.replacePattern("any", *, null)                                     = "any"
6901     * StringUtils.replacePattern("", "", "zzz")                                      = "zzz"
6902     * StringUtils.replacePattern("", ".*", "zzz")                                    = "zzz"
6903     * StringUtils.replacePattern("", ".+", "zzz")                                    = ""
6904     * StringUtils.replacePattern("<__>\n<__>", "<.*>", "z")                          = "z"
6905     * StringUtils.replacePattern("ABCabc123", "[a-z]", "_")                          = "ABC___123"
6906     * StringUtils.replacePattern("ABCabc123", "[^A-Z0-9]+", "_")                     = "ABC_123"
6907     * StringUtils.replacePattern("ABCabc123", "[^A-Z0-9]+", "")                      = "ABC123"
6908     * StringUtils.replacePattern("Lorem ipsum  dolor   sit", "( +)([a-z]+)", "_$2")  = "Lorem_ipsum_dolor_sit"
6909     * }</pre>
6910     *
6911     * @param source      The source string.
6912     * @param regex       The regular expression to which this string is to be matched.
6913     * @param replacement The string to be substituted for each match.
6914     * @return The resulting {@link String}.
6915     * @see #replaceAll(String, String, String)
6916     * @see String#replaceAll(String, String)
6917     * @see Pattern#DOTALL
6918     * @since 3.2
6919     * @since 3.5 Changed {@code null} reference passed to this method is a no-op.
6920     * @deprecated Use {@link RegExUtils#replacePattern(CharSequence, String, String)}.
6921     */
6922    @Deprecated
6923    public static String replacePattern(final String source, final String regex, final String replacement) {
6924        return RegExUtils.replacePattern(source, regex, replacement);
6925    }
6926
6927    /**
6928     * Reverses a String as per {@link StringBuilder#reverse()}.
6929     *
6930     * <p>
6931     * A {@code null} String returns {@code null}.
6932     * </p>
6933     *
6934     * <pre>
6935     * StringUtils.reverse(null)  = null
6936     * StringUtils.reverse("")    = ""
6937     * StringUtils.reverse("bat") = "tab"
6938     * </pre>
6939     *
6940     * @param str The String to reverse, may be null.
6941     * @return The reversed String, {@code null} if null String input.
6942     */
6943    public static String reverse(final String str) {
6944        if (str == null) {
6945            return null;
6946        }
6947        return new StringBuilder(str).reverse().toString();
6948    }
6949
6950    /**
6951     * Reverses a String that is delimited by a specific character.
6952     *
6953     * <p>
6954     * The Strings between the delimiters are not reversed. Thus java.lang.String becomes String.lang.java (if the delimiter is {@code '.'}).
6955     * </p>
6956     *
6957     * <pre>
6958     * StringUtils.reverseDelimited(null, *)      = null
6959     * StringUtils.reverseDelimited("", *)        = ""
6960     * StringUtils.reverseDelimited("a.b.c", 'x') = "a.b.c"
6961     * StringUtils.reverseDelimited("a.b.c", '.') = "c.b.a"
6962     * </pre>
6963     *
6964     * @param str           The String to reverse, may be null.
6965     * @param separatorChar The separator character to use.
6966     * @return The reversed String, {@code null} if null String input.
6967     * @since 2.0
6968     */
6969    public static String reverseDelimited(final String str, final char separatorChar) {
6970        final String[] strs = split(str, separatorChar);
6971        ArrayUtils.reverse(strs);
6972        return join(strs, separatorChar);
6973    }
6974
6975    /**
6976     * Gets the rightmost {@code len} characters of a String.
6977     *
6978     * <p>
6979     * 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
6980     * returned if len is negative.
6981     * </p>
6982     *
6983     * <pre>
6984     * StringUtils.right(null, *)    = null
6985     * StringUtils.right(*, -ve)     = ""
6986     * StringUtils.right("", *)      = ""
6987     * StringUtils.right("abc", 0)   = ""
6988     * StringUtils.right("abc", 2)   = "bc"
6989     * StringUtils.right("abc", 4)   = "abc"
6990     * </pre>
6991     *
6992     * @param str The String to get the rightmost characters from, may be null.
6993     * @param len The length of the required String.
6994     * @return The rightmost characters, {@code null} if null String input.
6995     */
6996    public static String right(final String str, final int len) {
6997        if (str == null) {
6998            return null;
6999        }
7000        if (len < 0) {
7001            return EMPTY;
7002        }
7003        if (str.length() <= len) {
7004            return str;
7005        }
7006        int start = str.length() - len;
7007        // keep the cut off the middle of a surrogate pair so the result is never left holding a lone surrogate
7008        if (splitsSurrogatePair(str, start)) {
7009            start++;
7010        }
7011        return str.substring(start);
7012    }
7013
7014    /**
7015     * Right pad a String with spaces (' ').
7016     *
7017     * <p>
7018     * The String is padded to the size of {@code size}.
7019     * </p>
7020     *
7021     * <pre>
7022     * StringUtils.rightPad(null, *)   = null
7023     * StringUtils.rightPad("", 3)     = "   "
7024     * StringUtils.rightPad("bat", 3)  = "bat"
7025     * StringUtils.rightPad("bat", 5)  = "bat  "
7026     * StringUtils.rightPad("bat", 1)  = "bat"
7027     * StringUtils.rightPad("bat", -1) = "bat"
7028     * </pre>
7029     *
7030     * @param str  The String to pad out, may be null.
7031     * @param size The size to pad to.
7032     * @return right padded String or original String if no padding is necessary, {@code null} if null String input.
7033     */
7034    public static String rightPad(final String str, final int size) {
7035        return rightPad(str, size, ' ');
7036    }
7037
7038    /**
7039     * Right pad a String with a specified character.
7040     *
7041     * <p>
7042     * The String is padded to the size of {@code size}.
7043     * </p>
7044     *
7045     * <pre>
7046     * StringUtils.rightPad(null, *, *)     = null
7047     * StringUtils.rightPad("", 3, 'z')     = "zzz"
7048     * StringUtils.rightPad("bat", 3, 'z')  = "bat"
7049     * StringUtils.rightPad("bat", 5, 'z')  = "batzz"
7050     * StringUtils.rightPad("bat", 1, 'z')  = "bat"
7051     * StringUtils.rightPad("bat", -1, 'z') = "bat"
7052     * </pre>
7053     *
7054     * @param str     The String to pad out, may be null.
7055     * @param size    The size to pad to.
7056     * @param padChar The character to pad with.
7057     * @return right padded String or original String if no padding is necessary, {@code null} if null String input.
7058     * @since 2.0
7059     */
7060    public static String rightPad(final String str, final int size, final char padChar) {
7061        if (str == null || size <= str.length()) {
7062            return str;
7063        }
7064        final int pads = size - str.length();
7065        if (pads <= 0) {
7066            return str; // returns original String when possible
7067        }
7068        if (pads > PAD_LIMIT) {
7069            return rightPad(str, size, String.valueOf(padChar));
7070        }
7071        return str.concat(repeat(padChar, pads));
7072    }
7073
7074    /**
7075     * Right pad a String with a specified String.
7076     *
7077     * <p>
7078     * The String is padded to the size of {@code size}. If the requested padding length would split a Unicode surrogate pair
7079     * in {@code padStr}, the padding is shortened by one {@code char} to avoid introducing an unpaired surrogate by splitting the pair.
7080     * In that case, the returned String has a length of {@code size - 1}.
7081     * </p>
7082     *
7083     * <pre>
7084     * StringUtils.rightPad(null, *, *)      = null
7085     * StringUtils.rightPad("", 3, "z")      = "zzz"
7086     * StringUtils.rightPad("bat", 3, "yz")  = "bat"
7087     * StringUtils.rightPad("bat", 5, "yz")  = "batyz"
7088     * StringUtils.rightPad("bat", 8, "yz")  = "batyzyzy"
7089     * StringUtils.rightPad("bat", 1, "yz")  = "bat"
7090     * StringUtils.rightPad("bat", -1, "yz") = "bat"
7091     * StringUtils.rightPad("bat", 5, null)  = "bat  "
7092     * StringUtils.rightPad("bat", 5, "")    = "bat  "
7093     * StringUtils.rightPad("a", 2, "\uD83D\uDE00")    = "a"
7094     * StringUtils.rightPad("a", 3, "\uD83D\uDE00")    = "a\uD83D\uDE00"
7095     * </pre>
7096     *
7097     * @param str    The String to pad out, may be null.
7098     * @param size   The size to pad to.
7099     * @param padStr The String to pad with, null or empty treated as single space.
7100     * @return right padded String or original String if no padding is necessary, {@code null} if null String input.
7101     */
7102    public static String rightPad(final String str, final int size, String padStr) {
7103        if (str == null || size <= str.length()) {
7104            return str;
7105        }
7106        if (isEmpty(padStr)) {
7107            padStr = SPACE;
7108        }
7109        final int padLen = padStr.length();
7110        final int strLen = str.length();
7111        int pads = size - strLen;
7112        if (pads <= 0) {
7113            return str; // returns original String when possible
7114        }
7115        if (padLen == 1 && pads <= PAD_LIMIT) {
7116            return rightPad(str, size, padStr.charAt(0));
7117        }
7118        // Keep the padding boundary off the middle of a surrogate pair to avoid introducing a lone surrogate.
7119        if (splitsSurrogatePair(padStr, pads % padLen)) {
7120            pads--;
7121        }
7122        if (pads <= 0) {
7123            return str;
7124        }
7125        if (pads == padLen) {
7126            return str.concat(padStr);
7127        }
7128        if (pads < padLen) {
7129            return str.concat(padStr.substring(0, pads));
7130        }
7131        final char[] padding = new char[pads];
7132        final char[] padChars = padStr.toCharArray();
7133        for (int i = 0; i < pads; i++) {
7134            padding[i] = padChars[i % padLen];
7135        }
7136        return str.concat(new String(padding));
7137    }
7138
7139    /**
7140     * Rotate (circular shift) a String of {@code shift} characters.
7141     * <ul>
7142     * <li>If {@code shift > 0}, right circular shift (ex : ABCDEF =&gt; FABCDE)</li>
7143     * <li>If {@code shift < 0}, left circular shift (ex : ABCDEF =&gt; BCDEFA)</li>
7144     * </ul>
7145     *
7146     * <pre>
7147     * StringUtils.rotate(null, *)        = null
7148     * StringUtils.rotate("", *)          = ""
7149     * StringUtils.rotate("abcdefg", 0)   = "abcdefg"
7150     * StringUtils.rotate("abcdefg", 2)   = "fgabcde"
7151     * StringUtils.rotate("abcdefg", -2)  = "cdefgab"
7152     * StringUtils.rotate("abcdefg", 7)   = "abcdefg"
7153     * StringUtils.rotate("abcdefg", -7)  = "abcdefg"
7154     * StringUtils.rotate("abcdefg", 9)   = "fgabcde"
7155     * StringUtils.rotate("abcdefg", -9)  = "cdefgab"
7156     * </pre>
7157     *
7158     * @param str   The String to rotate, may be null.
7159     * @param shift number of time to shift (positive : right shift, negative : left shift).
7160     * @return The rotated String, or the original String if {@code shift == 0}, or {@code null} if null String input.
7161     * @since 3.5
7162     */
7163    public static String rotate(final String str, final int shift) {
7164        if (str == null) {
7165            return null;
7166        }
7167        final int strLen = str.length();
7168        if (shift == 0 || strLen == 0 || shift % strLen == 0) {
7169            return str;
7170        }
7171        final StringBuilder builder = new StringBuilder(strLen);
7172        final int offset = -(shift % strLen);
7173        builder.append(substring(str, offset));
7174        builder.append(substring(str, 0, offset));
7175        return builder.toString();
7176    }
7177
7178    /**
7179     * Splits the provided text into an array, using whitespace as the separator. Whitespace is defined by {@link Character#isWhitespace(char)}.
7180     *
7181     * <p>
7182     * 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
7183     * StrTokenizer class.
7184     * </p>
7185     *
7186     * <p>
7187     * A {@code null} input String returns {@code null}.
7188     * </p>
7189     *
7190     * <pre>
7191     * StringUtils.split(null)       = null
7192     * StringUtils.split("")         = []
7193     * StringUtils.split("abc def")  = ["abc", "def"]
7194     * StringUtils.split("abc  def") = ["abc", "def"]
7195     * StringUtils.split(" abc ")    = ["abc"]
7196     * </pre>
7197     *
7198     * @param str The String to parse, may be null.
7199     * @return An array of parsed Strings, {@code null} if null String input.
7200     */
7201    public static String[] split(final String str) {
7202        return split(str, null, -1);
7203    }
7204
7205    /**
7206     * Splits the provided text into an array, separator specified. This is an alternative to using StringTokenizer.
7207     *
7208     * <p>
7209     * 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
7210     * StrTokenizer class.
7211     * </p>
7212     *
7213     * <p>
7214     * A {@code null} input String returns {@code null}.
7215     * </p>
7216     *
7217     * <pre>
7218     * StringUtils.split(null, *)         = null
7219     * StringUtils.split("", *)           = []
7220     * StringUtils.split("a.b.c", '.')    = ["a", "b", "c"]
7221     * StringUtils.split("a..b.c", '.')   = ["a", "b", "c"]
7222     * StringUtils.split("a:b:c", '.')    = ["a:b:c"]
7223     * StringUtils.split("a b c", ' ')    = ["a", "b", "c"]
7224     * </pre>
7225     *
7226     * @param str           The String to parse, may be null.
7227     * @param separatorChar The character used as the delimiter.
7228     * @return An array of parsed Strings, {@code null} if null String input.
7229     * @since 2.0
7230     */
7231    public static String[] split(final String str, final char separatorChar) {
7232        return splitWorker(str, separatorChar, false);
7233    }
7234
7235    /**
7236     * Splits the provided text into an array, separators specified. This is an alternative to using StringTokenizer.
7237     *
7238     * <p>
7239     * 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
7240     * StrTokenizer class.
7241     * </p>
7242     *
7243     * <p>
7244     * A {@code null} input String returns {@code null}. A {@code null} separatorChars splits on whitespace.
7245     * </p>
7246     *
7247     * <pre>
7248     * StringUtils.split(null, *)         = null
7249     * StringUtils.split("", *)           = []
7250     * StringUtils.split("abc def", null) = ["abc", "def"]
7251     * StringUtils.split("abc def", " ")  = ["abc", "def"]
7252     * StringUtils.split("abc  def", " ") = ["abc", "def"]
7253     * StringUtils.split("ab:cd:ef", ":") = ["ab", "cd", "ef"]
7254     * </pre>
7255     *
7256     * @param str            The String to parse, may be null.
7257     * @param separatorChars The characters used as the delimiters, {@code null} splits on whitespace.
7258     * @return An array of parsed Strings, {@code null} if null String input.
7259     */
7260    public static String[] split(final String str, final String separatorChars) {
7261        return splitWorker(str, separatorChars, -1, false);
7262    }
7263
7264    /**
7265     * Splits the provided text into an array with a maximum length, separators specified.
7266     *
7267     * <p>
7268     * The separator is not included in the returned String array. Adjacent separators are treated as one separator.
7269     * </p>
7270     *
7271     * <p>
7272     * A {@code null} input String returns {@code null}. A {@code null} separatorChars splits on whitespace.
7273     * </p>
7274     *
7275     * <p>
7276     * If more than {@code max} delimited substrings are found, the last returned string includes all characters after the first {@code max - 1} returned
7277     * strings (including separator characters).
7278     * </p>
7279     *
7280     * <pre>
7281     * StringUtils.split(null, *, *)            = null
7282     * StringUtils.split("", *, *)              = []
7283     * StringUtils.split("ab cd ef", null, 0)   = ["ab", "cd", "ef"]
7284     * StringUtils.split("ab   cd ef", null, 0) = ["ab", "cd", "ef"]
7285     * StringUtils.split("ab:cd:ef", ":", 0)    = ["ab", "cd", "ef"]
7286     * StringUtils.split("ab:cd:ef", ":", 2)    = ["ab", "cd:ef"]
7287     * </pre>
7288     *
7289     * @param str            The String to parse, may be null.
7290     * @param separatorChars The characters used as the delimiters, {@code null} splits on whitespace.
7291     * @param max            The maximum number of elements to include in the array. A zero or negative value implies no limit.
7292     * @return An array of parsed Strings, {@code null} if null String input.
7293     */
7294    public static String[] split(final String str, final String separatorChars, final int max) {
7295        return splitWorker(str, separatorChars, max, false);
7296    }
7297
7298    /**
7299     * Splits a String by Character type as returned by {@link Character#getType(int)}. Groups of contiguous characters of the same type are returned
7300     * as complete tokens.
7301     *
7302     * <pre>
7303     * StringUtils.splitByCharacterType(null)         = null
7304     * StringUtils.splitByCharacterType("")           = []
7305     * StringUtils.splitByCharacterType("ab de fg")   = ["ab", " ", "de", " ", "fg"]
7306     * StringUtils.splitByCharacterType("ab   de fg") = ["ab", "   ", "de", " ", "fg"]
7307     * StringUtils.splitByCharacterType("ab:cd:ef")   = ["ab", ":", "cd", ":", "ef"]
7308     * StringUtils.splitByCharacterType("number5")    = ["number", "5"]
7309     * StringUtils.splitByCharacterType("fooBar")     = ["foo", "B", "ar"]
7310     * StringUtils.splitByCharacterType("foo200Bar")  = ["foo", "200", "B", "ar"]
7311     * StringUtils.splitByCharacterType("ASFRules")   = ["ASFR", "ules"]
7312     * </pre>
7313     *
7314     * @param str The String to split, may be {@code null}.
7315     * @return An array of parsed Strings, {@code null} if null String input.
7316     * @see Character#getType(int)
7317     * @since 2.4
7318     */
7319    public static String[] splitByCharacterType(final String str) {
7320        return splitByCharacterType(str, false);
7321    }
7322
7323    /**
7324     * 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
7325     * as complete tokens, with the following exception: if {@code camelCase} is {@code true}, the character of type {@link Character#UPPERCASE_LETTER}, if any,
7326     * immediately preceding a token of type {@link Character#LOWERCASE_LETTER} will belong to the following token rather than to the preceding, if any,
7327     * {@link Character#UPPERCASE_LETTER} token.
7328     *
7329     * @param str       The String to split, may be {@code null}.
7330     * @param camelCase whether to use so-called "camel-case" for letter types.
7331     * @return An array of parsed Strings, {@code null} if null String input.
7332     * @since 2.4
7333     */
7334    private static String[] splitByCharacterType(final String str, final boolean camelCase) {
7335        if (str == null) {
7336            return null;
7337        }
7338        if (str.isEmpty()) {
7339            return ArrayUtils.EMPTY_STRING_ARRAY;
7340        }
7341        final char[] c = str.toCharArray();
7342        final List<String> list = new ArrayList<>();
7343        int tokenStart = 0;
7344        int currentType = Character.getType(Character.codePointAt(c, tokenStart));
7345        for (int pos = tokenStart + Character.charCount(Character.codePointAt(c, tokenStart)); pos < c.length;) {
7346            final int codePoint = Character.codePointAt(c, pos);
7347            final int type = Character.getType(codePoint);
7348            final int count = Character.charCount(codePoint);
7349            if (type == currentType) {
7350                pos += count;
7351                continue;
7352            }
7353            if (camelCase && type == Character.LOWERCASE_LETTER && currentType == Character.UPPERCASE_LETTER) {
7354                final int newTokenStart = pos - Character.charCount(Character.codePointBefore(c, pos));
7355                if (newTokenStart != tokenStart) {
7356                    list.add(new String(c, tokenStart, newTokenStart - tokenStart));
7357                    tokenStart = newTokenStart;
7358                }
7359            } else {
7360                list.add(new String(c, tokenStart, pos - tokenStart));
7361                tokenStart = pos;
7362            }
7363            currentType = type;
7364            pos += count;
7365        }
7366        list.add(new String(c, tokenStart, c.length - tokenStart));
7367        return list.toArray(ArrayUtils.EMPTY_STRING_ARRAY);
7368    }
7369
7370    /**
7371     * Splits a String by Character type as returned by {@link Character#getType(int)}. Groups of contiguous characters of the same type are returned
7372     * as complete tokens, with the following exception: the character of type {@link Character#UPPERCASE_LETTER}, if any, immediately preceding a token of type
7373     * {@link Character#LOWERCASE_LETTER} will belong to the following token rather than to the preceding, if any, {@link Character#UPPERCASE_LETTER} token.
7374     *
7375     * <pre>
7376     * StringUtils.splitByCharacterTypeCamelCase(null)         = null
7377     * StringUtils.splitByCharacterTypeCamelCase("")           = []
7378     * StringUtils.splitByCharacterTypeCamelCase("ab de fg")   = ["ab", " ", "de", " ", "fg"]
7379     * StringUtils.splitByCharacterTypeCamelCase("ab   de fg") = ["ab", "   ", "de", " ", "fg"]
7380     * StringUtils.splitByCharacterTypeCamelCase("ab:cd:ef")   = ["ab", ":", "cd", ":", "ef"]
7381     * StringUtils.splitByCharacterTypeCamelCase("number5")    = ["number", "5"]
7382     * StringUtils.splitByCharacterTypeCamelCase("fooBar")     = ["foo", "Bar"]
7383     * StringUtils.splitByCharacterTypeCamelCase("foo200Bar")  = ["foo", "200", "Bar"]
7384     * StringUtils.splitByCharacterTypeCamelCase("ASFRules")   = ["ASF", "Rules"]
7385     * </pre>
7386     *
7387     * @param str The String to split, may be {@code null}.
7388     * @return An array of parsed Strings, {@code null} if null String input.
7389     * @see Character#getType(int)
7390     * @since 2.4
7391     */
7392    public static String[] splitByCharacterTypeCamelCase(final String str) {
7393        return splitByCharacterType(str, true);
7394    }
7395
7396    /**
7397     * Splits the provided text into an array, separator string specified.
7398     *
7399     * <p>
7400     * The separator(s) will not be included in the returned String array. Adjacent separators are treated as one separator.
7401     * </p>
7402     *
7403     * <p>
7404     * A {@code null} input String returns {@code null}. A {@code null} separator splits on whitespace.
7405     * </p>
7406     *
7407     * <pre>
7408     * StringUtils.splitByWholeSeparator(null, *)               = null
7409     * StringUtils.splitByWholeSeparator("", *)                 = []
7410     * StringUtils.splitByWholeSeparator("ab de fg", null)      = ["ab", "de", "fg"]
7411     * StringUtils.splitByWholeSeparator("ab   de fg", null)    = ["ab", "de", "fg"]
7412     * StringUtils.splitByWholeSeparator("ab:cd:ef", ":")       = ["ab", "cd", "ef"]
7413     * StringUtils.splitByWholeSeparator("ab-!-cd-!-ef", "-!-") = ["ab", "cd", "ef"]
7414     * </pre>
7415     *
7416     * @param str       The String to parse, may be null.
7417     * @param separator String containing the String to be used as a delimiter, {@code null} splits on whitespace.
7418     * @return An array of parsed Strings, {@code null} if null String was input.
7419     */
7420    public static String[] splitByWholeSeparator(final String str, final String separator) {
7421        return splitByWholeSeparatorWorker(str, separator, -1, false);
7422    }
7423
7424    /**
7425     * Splits the provided text into an array, separator string specified. Returns a maximum of {@code max} substrings.
7426     *
7427     * <p>
7428     * The separator(s) will not be included in the returned String array. Adjacent separators are treated as one separator.
7429     * </p>
7430     *
7431     * <p>
7432     * A {@code null} input String returns {@code null}. A {@code null} separator splits on whitespace.
7433     * </p>
7434     *
7435     * <pre>
7436     * StringUtils.splitByWholeSeparator(null, *, *)               = null
7437     * StringUtils.splitByWholeSeparator("", *, *)                 = []
7438     * StringUtils.splitByWholeSeparator("ab de fg", null, 0)      = ["ab", "de", "fg"]
7439     * StringUtils.splitByWholeSeparator("ab   de fg", null, 0)    = ["ab", "de", "fg"]
7440     * StringUtils.splitByWholeSeparator("ab:cd:ef", ":", 2)       = ["ab", "cd:ef"]
7441     * StringUtils.splitByWholeSeparator("ab-!-cd-!-ef", "-!-", 5) = ["ab", "cd", "ef"]
7442     * StringUtils.splitByWholeSeparator("ab-!-cd-!-ef", "-!-", 2) = ["ab", "cd-!-ef"]
7443     * </pre>
7444     *
7445     * @param str       The String to parse, may be null.
7446     * @param separator String containing the String to be used as a delimiter, {@code null} splits on whitespace.
7447     * @param max       The maximum number of elements to include in the returned array. A zero or negative value implies no limit.
7448     * @return An array of parsed Strings, {@code null} if null String was input.
7449     */
7450    public static String[] splitByWholeSeparator(final String str, final String separator, final int max) {
7451        return splitByWholeSeparatorWorker(str, separator, max, false);
7452    }
7453
7454    /**
7455     * Splits the provided text into an array, separator string specified.
7456     *
7457     * <p>
7458     * The separator is not included in the returned String array. Adjacent separators are treated as separators for empty tokens. For more control over the
7459     * split use the StrTokenizer class.
7460     * </p>
7461     *
7462     * <p>
7463     * A {@code null} input String returns {@code null}. A {@code null} separator splits on whitespace.
7464     * </p>
7465     *
7466     * <pre>
7467     * StringUtils.splitByWholeSeparatorPreserveAllTokens(null, *)               = null
7468     * StringUtils.splitByWholeSeparatorPreserveAllTokens("", *)                 = []
7469     * StringUtils.splitByWholeSeparatorPreserveAllTokens("ab de fg", null)      = ["ab", "de", "fg"]
7470     * StringUtils.splitByWholeSeparatorPreserveAllTokens("ab   de fg", null)    = ["ab", "", "", "de", "fg"]
7471     * StringUtils.splitByWholeSeparatorPreserveAllTokens("ab:cd:ef", ":")       = ["ab", "cd", "ef"]
7472     * StringUtils.splitByWholeSeparatorPreserveAllTokens("ab-!-cd-!-ef", "-!-") = ["ab", "cd", "ef"]
7473     * </pre>
7474     *
7475     * @param str       The String to parse, may be null.
7476     * @param separator String containing the String to be used as a delimiter, {@code null} splits on whitespace.
7477     * @return An array of parsed Strings, {@code null} if null String was input.
7478     * @since 2.4
7479     */
7480    public static String[] splitByWholeSeparatorPreserveAllTokens(final String str, final String separator) {
7481        return splitByWholeSeparatorWorker(str, separator, -1, true);
7482    }
7483
7484    /**
7485     * Splits the provided text into an array, separator string specified. Returns a maximum of {@code max} substrings.
7486     *
7487     * <p>
7488     * The separator is not included in the returned String array. Adjacent separators are treated as separators for empty tokens. For more control over the
7489     * split use the StrTokenizer class.
7490     * </p>
7491     *
7492     * <p>
7493     * A {@code null} input String returns {@code null}. A {@code null} separator splits on whitespace.
7494     * </p>
7495     *
7496     * <pre>
7497     * StringUtils.splitByWholeSeparatorPreserveAllTokens(null, *, *)               = null
7498     * StringUtils.splitByWholeSeparatorPreserveAllTokens("", *, *)                 = []
7499     * StringUtils.splitByWholeSeparatorPreserveAllTokens("ab de fg", null, 0)      = ["ab", "de", "fg"]
7500     * StringUtils.splitByWholeSeparatorPreserveAllTokens("ab   de fg", null, 0)    = ["ab", "", "", "de", "fg"]
7501     * StringUtils.splitByWholeSeparatorPreserveAllTokens("ab:cd:ef", ":", 2)       = ["ab", "cd:ef"]
7502     * StringUtils.splitByWholeSeparatorPreserveAllTokens("ab-!-cd-!-ef", "-!-", 5) = ["ab", "cd", "ef"]
7503     * StringUtils.splitByWholeSeparatorPreserveAllTokens("ab-!-cd-!-ef", "-!-", 2) = ["ab", "cd-!-ef"]
7504     * </pre>
7505     *
7506     * @param str       The String to parse, may be null.
7507     * @param separator String containing the String to be used as a delimiter, {@code null} splits on whitespace.
7508     * @param max       The maximum number of elements to include in the returned array. A zero or negative value implies no limit.
7509     * @return An array of parsed Strings, {@code null} if null String was input.
7510     * @since 2.4
7511     */
7512    public static String[] splitByWholeSeparatorPreserveAllTokens(final String str, final String separator, final int max) {
7513        return splitByWholeSeparatorWorker(str, separator, max, true);
7514    }
7515
7516    /**
7517     * Performs the logic for the {@code splitByWholeSeparatorPreserveAllTokens} methods.
7518     *
7519     * @param str               The String to parse, may be {@code null}.
7520     * @param separator         String containing the String to be used as a delimiter, {@code null} splits on whitespace.
7521     * @param max               The maximum number of elements to include in the returned array. A zero or negative value implies no limit.
7522     * @param preserveAllTokens if {@code true}, adjacent separators are treated as empty token separators; if {@code false}, adjacent separators are treated as
7523     *                          one separator.
7524     * @return An array of parsed Strings, {@code null} if null String input.
7525     * @since 2.4
7526     */
7527    private static String[] splitByWholeSeparatorWorker(final String str, final String separator, final int max, final boolean preserveAllTokens) {
7528        if (str == null) {
7529            return null;
7530        }
7531        final int len = str.length();
7532        if (len == 0) {
7533            return ArrayUtils.EMPTY_STRING_ARRAY;
7534        }
7535        if (separator == null || EMPTY.equals(separator)) {
7536            // Split on whitespace.
7537            return splitWorker(str, null, max, preserveAllTokens);
7538        }
7539        final int separatorLength = separator.length();
7540        final ArrayList<String> substrings = new ArrayList<>();
7541        int numberOfSubstrings = 0;
7542        int beg = 0;
7543        int end = 0;
7544        while (end < len) {
7545            end = str.indexOf(separator, beg);
7546            if (end > -1) {
7547                if (end > beg) {
7548                    numberOfSubstrings += 1;
7549                    if (numberOfSubstrings == max) {
7550                        end = len;
7551                        substrings.add(str.substring(beg));
7552                    } else {
7553                        // The following is OK, because String.substring( beg, end ) excludes
7554                        // the character at the position 'end'.
7555                        substrings.add(str.substring(beg, end));
7556                        // Set the starting point for the next search.
7557                        // The following is equivalent to beg = end + (separatorLength - 1) + 1,
7558                        // which is the right calculation:
7559                        beg = end + separatorLength;
7560                    }
7561                } else {
7562                    // We found a consecutive occurrence of the separator, so skip it.
7563                    if (preserveAllTokens) {
7564                        numberOfSubstrings += 1;
7565                        if (numberOfSubstrings == max) {
7566                            end = len;
7567                            substrings.add(str.substring(beg));
7568                        } else {
7569                            substrings.add(EMPTY);
7570                        }
7571                    }
7572                    beg = end + separatorLength;
7573                }
7574            } else {
7575                // String.substring( beg ) goes from 'beg' to the end of the String.
7576                // beg == len means the String ended on a separator, so the trailing
7577                // token is empty and must be dropped unless empty tokens are preserved.
7578                if (preserveAllTokens || beg < len) {
7579                    substrings.add(str.substring(beg));
7580                }
7581                end = len;
7582            }
7583        }
7584        return substrings.toArray(ArrayUtils.EMPTY_STRING_ARRAY);
7585    }
7586
7587    /**
7588     * Splits the provided text into an array, using whitespace as the separator, preserving all tokens, including empty tokens created by adjacent separators.
7589     * This is an alternative to using StringTokenizer. Whitespace is defined by {@link Character#isWhitespace(char)}.
7590     *
7591     * <p>
7592     * The separator is not included in the returned String array. Adjacent separators are treated as separators for empty tokens. For more control over the
7593     * split use the StrTokenizer class.
7594     * </p>
7595     *
7596     * <p>
7597     * A {@code null} input String returns {@code null}.
7598     * </p>
7599     *
7600     * <pre>
7601     * StringUtils.splitPreserveAllTokens(null)       = null
7602     * StringUtils.splitPreserveAllTokens("")         = []
7603     * StringUtils.splitPreserveAllTokens("abc def")  = ["abc", "def"]
7604     * StringUtils.splitPreserveAllTokens("abc  def") = ["abc", "", "def"]
7605     * StringUtils.splitPreserveAllTokens(" abc ")    = ["", "abc", ""]
7606     * </pre>
7607     *
7608     * @param str The String to parse, may be {@code null}.
7609     * @return An array of parsed Strings, {@code null} if null String input.
7610     * @since 2.1
7611     */
7612    public static String[] splitPreserveAllTokens(final String str) {
7613        return splitWorker(str, null, -1, true);
7614    }
7615
7616    /**
7617     * Splits the provided text into an array, separator specified, preserving all tokens, including empty tokens created by adjacent separators. This is an
7618     * alternative to using StringTokenizer.
7619     *
7620     * <p>
7621     * The separator is not included in the returned String array. Adjacent separators are treated as separators for empty tokens. For more control over the
7622     * split use the StrTokenizer class.
7623     * </p>
7624     *
7625     * <p>
7626     * A {@code null} input String returns {@code null}.
7627     * </p>
7628     *
7629     * <pre>
7630     * StringUtils.splitPreserveAllTokens(null, *)         = null
7631     * StringUtils.splitPreserveAllTokens("", *)           = []
7632     * StringUtils.splitPreserveAllTokens("a.b.c", '.')    = ["a", "b", "c"]
7633     * StringUtils.splitPreserveAllTokens("a..b.c", '.')   = ["a", "", "b", "c"]
7634     * StringUtils.splitPreserveAllTokens("a:b:c", '.')    = ["a:b:c"]
7635     * StringUtils.splitPreserveAllTokens("a\tb\nc", null) = ["a", "b", "c"]
7636     * StringUtils.splitPreserveAllTokens("a b c", ' ')    = ["a", "b", "c"]
7637     * StringUtils.splitPreserveAllTokens("a b c ", ' ')   = ["a", "b", "c", ""]
7638     * StringUtils.splitPreserveAllTokens("a b c  ", ' ')  = ["a", "b", "c", "", ""]
7639     * StringUtils.splitPreserveAllTokens(" a b c", ' ')   = ["", "a", "b", "c"]
7640     * StringUtils.splitPreserveAllTokens("  a b c", ' ')  = ["", "", "a", "b", "c"]
7641     * StringUtils.splitPreserveAllTokens(" a b c ", ' ')  = ["", "a", "b", "c", ""]
7642     * </pre>
7643     *
7644     * @param str           The String to parse, may be {@code null}.
7645     * @param separatorChar The character used as the delimiter, {@code null} splits on whitespace.
7646     * @return An array of parsed Strings, {@code null} if null String input.
7647     * @since 2.1
7648     */
7649    public static String[] splitPreserveAllTokens(final String str, final char separatorChar) {
7650        return splitWorker(str, separatorChar, true);
7651    }
7652
7653    /**
7654     * Splits the provided text into an array, separators specified, preserving all tokens, including empty tokens created by adjacent separators. This is an
7655     * alternative to using StringTokenizer.
7656     *
7657     * <p>
7658     * The separator is not included in the returned String array. Adjacent separators are treated as separators for empty tokens. For more control over the
7659     * split use the StrTokenizer class.
7660     * </p>
7661     *
7662     * <p>
7663     * A {@code null} input String returns {@code null}. A {@code null} separatorChars splits on whitespace.
7664     * </p>
7665     *
7666     * <pre>
7667     * StringUtils.splitPreserveAllTokens(null, *)           = null
7668     * StringUtils.splitPreserveAllTokens("", *)             = []
7669     * StringUtils.splitPreserveAllTokens("abc def", null)   = ["abc", "def"]
7670     * StringUtils.splitPreserveAllTokens("abc def", " ")    = ["abc", "def"]
7671     * StringUtils.splitPreserveAllTokens("abc  def", " ")   = ["abc", "", "def"]
7672     * StringUtils.splitPreserveAllTokens("ab:cd:ef", ":")   = ["ab", "cd", "ef"]
7673     * StringUtils.splitPreserveAllTokens("ab:cd:ef:", ":")  = ["ab", "cd", "ef", ""]
7674     * StringUtils.splitPreserveAllTokens("ab:cd:ef::", ":") = ["ab", "cd", "ef", "", ""]
7675     * StringUtils.splitPreserveAllTokens("ab::cd:ef", ":")  = ["ab", "", "cd", "ef"]
7676     * StringUtils.splitPreserveAllTokens(":cd:ef", ":")     = ["", "cd", "ef"]
7677     * StringUtils.splitPreserveAllTokens("::cd:ef", ":")    = ["", "", "cd", "ef"]
7678     * StringUtils.splitPreserveAllTokens(":cd:ef:", ":")    = ["", "cd", "ef", ""]
7679     * </pre>
7680     *
7681     * @param str            The String to parse, may be {@code null}.
7682     * @param separatorChars The characters used as the delimiters, {@code null} splits on whitespace.
7683     * @return An array of parsed Strings, {@code null} if null String input.
7684     * @since 2.1
7685     */
7686    public static String[] splitPreserveAllTokens(final String str, final String separatorChars) {
7687        return splitWorker(str, separatorChars, -1, true);
7688    }
7689
7690    /**
7691     * Splits the provided text into an array with a maximum length, separators specified, preserving all tokens, including empty tokens created by adjacent
7692     * separators.
7693     *
7694     * <p>
7695     * The separator is not included in the returned String array. Adjacent separators are treated as separators for empty tokens. Adjacent separators are
7696     * treated as one separator.
7697     * </p>
7698     *
7699     * <p>
7700     * A {@code null} input String returns {@code null}. A {@code null} separatorChars splits on whitespace.
7701     * </p>
7702     *
7703     * <p>
7704     * If more than {@code max} delimited substrings are found, the last returned string includes all characters after the first {@code max - 1} returned
7705     * strings (including separator characters).
7706     * </p>
7707     *
7708     * <pre>
7709     * StringUtils.splitPreserveAllTokens(null, *, *)            = null
7710     * StringUtils.splitPreserveAllTokens("", *, *)              = []
7711     * StringUtils.splitPreserveAllTokens("ab de fg", null, 0)   = ["ab", "de", "fg"]
7712     * StringUtils.splitPreserveAllTokens("ab   de fg", null, 0) = ["ab", "", "", "de", "fg"]
7713     * StringUtils.splitPreserveAllTokens("ab:cd:ef", ":", 0)    = ["ab", "cd", "ef"]
7714     * StringUtils.splitPreserveAllTokens("ab:cd:ef", ":", 2)    = ["ab", "cd:ef"]
7715     * StringUtils.splitPreserveAllTokens("ab   de fg", null, 2) = ["ab", "  de fg"]
7716     * StringUtils.splitPreserveAllTokens("ab   de fg", null, 3) = ["ab", "", " de fg"]
7717     * StringUtils.splitPreserveAllTokens("ab   de fg", null, 4) = ["ab", "", "", "de fg"]
7718     * </pre>
7719     *
7720     * @param str            The String to parse, may be {@code null}.
7721     * @param separatorChars The characters used as the delimiters, {@code null} splits on whitespace.
7722     * @param max            The maximum number of elements to include in the array. A zero or negative value implies no limit.
7723     * @return An array of parsed Strings, {@code null} if null String input.
7724     * @since 2.1
7725     */
7726    public static String[] splitPreserveAllTokens(final String str, final String separatorChars, final int max) {
7727        return splitWorker(str, separatorChars, max, true);
7728    }
7729
7730    /**
7731     * 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
7732     * {@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.
7733     *
7734     * @param str   The String being sliced.
7735     * @param index A candidate substring boundary, in {@code char} units.
7736     * @return whether slicing at {@code index} would split a surrogate pair.
7737     */
7738    private static boolean splitsSurrogatePair(final String str, final int index) {
7739        return index > 0 && index < str.length() && Character.isHighSurrogate(str.charAt(index - 1)) && Character.isLowSurrogate(str.charAt(index));
7740    }
7741
7742    /**
7743     * Performs the logic for the {@code split} and {@code splitPreserveAllTokens} methods that do not return a maximum array length.
7744     *
7745     * @param str               The String to parse, may be {@code null}.
7746     * @param separatorChar     The separate character.
7747     * @param preserveAllTokens if {@code true}, adjacent separators are treated as empty token separators; if {@code false}, adjacent separators are treated as
7748     *                          one separator.
7749     * @return An array of parsed Strings, {@code null} if null String input.
7750     */
7751    private static String[] splitWorker(final String str, final char separatorChar, final boolean preserveAllTokens) {
7752        // Performance tuned for 2.0 (JDK1.4)
7753        if (str == null) {
7754            return null;
7755        }
7756        final int len = str.length();
7757        if (len == 0) {
7758            return ArrayUtils.EMPTY_STRING_ARRAY;
7759        }
7760        final List<String> list = new ArrayList<>();
7761        int i = 0;
7762        int start = 0;
7763        boolean match = false;
7764        boolean lastMatch = false;
7765        while (i < len) {
7766            if (str.charAt(i) == separatorChar) {
7767                if (match || preserveAllTokens) {
7768                    list.add(str.substring(start, i));
7769                    match = false;
7770                    lastMatch = true;
7771                }
7772                start = ++i;
7773                continue;
7774            }
7775            lastMatch = false;
7776            match = true;
7777            i++;
7778        }
7779        if (match || preserveAllTokens && lastMatch) {
7780            list.add(str.substring(start, i));
7781        }
7782        return list.toArray(ArrayUtils.EMPTY_STRING_ARRAY);
7783    }
7784
7785    /**
7786     * Performs the logic for the {@code split} and {@code splitPreserveAllTokens} methods that return a maximum array length.
7787     *
7788     * @param str               The String to parse, may be {@code null}.
7789     * @param separatorChars    The separate character.
7790     * @param max               The maximum number of elements to include in the array. A zero or negative value implies no limit.
7791     * @param preserveAllTokens if {@code true}, adjacent separators are treated as empty token separators; if {@code false}, adjacent separators are treated as
7792     *                          one separator.
7793     * @return An array of parsed Strings, {@code null} if null String input.
7794     */
7795    private static String[] splitWorker(final String str, final String separatorChars, final int max, final boolean preserveAllTokens) {
7796        // Performance tuned for 2.0 (JDK1.4)
7797        // Direct code is quicker than StringTokenizer.
7798        // Also, StringTokenizer uses isSpace() not isWhitespace()
7799        if (str == null) {
7800            return null;
7801        }
7802        final int len = str.length();
7803        if (len == 0) {
7804            return ArrayUtils.EMPTY_STRING_ARRAY;
7805        }
7806        final List<String> list = new ArrayList<>();
7807        int sizePlus1 = 1;
7808        int i = 0;
7809        int start = 0;
7810        boolean match = false;
7811        boolean lastMatch = false;
7812        if (separatorChars == null) {
7813            // Null separator means use whitespace
7814            while (i < len) {
7815                if (Character.isWhitespace(str.charAt(i))) {
7816                    if (match || preserveAllTokens) {
7817                        lastMatch = true;
7818                        if (sizePlus1++ == max) {
7819                            i = len;
7820                            lastMatch = false;
7821                        }
7822                        list.add(str.substring(start, i));
7823                        match = false;
7824                    }
7825                    start = ++i;
7826                    continue;
7827                }
7828                lastMatch = false;
7829                match = true;
7830                i++;
7831            }
7832        } else if (separatorChars.length() == 1) {
7833            // Optimize 1 character case
7834            final char sep = separatorChars.charAt(0);
7835            while (i < len) {
7836                if (str.charAt(i) == sep) {
7837                    if (match || preserveAllTokens) {
7838                        lastMatch = true;
7839                        if (sizePlus1++ == max) {
7840                            i = len;
7841                            lastMatch = false;
7842                        }
7843                        list.add(str.substring(start, i));
7844                        match = false;
7845                    }
7846                    start = ++i;
7847                    continue;
7848                }
7849                lastMatch = false;
7850                match = true;
7851                i++;
7852            }
7853        } else {
7854            // standard case
7855            while (i < len) {
7856                if (separatorChars.indexOf(str.charAt(i)) >= 0) {
7857                    if (match || preserveAllTokens) {
7858                        lastMatch = true;
7859                        if (sizePlus1++ == max) {
7860                            i = len;
7861                            lastMatch = false;
7862                        }
7863                        list.add(str.substring(start, i));
7864                        match = false;
7865                    }
7866                    start = ++i;
7867                    continue;
7868                }
7869                lastMatch = false;
7870                match = true;
7871                i++;
7872            }
7873        }
7874        if (match || preserveAllTokens && lastMatch) {
7875            list.add(str.substring(start, i));
7876        }
7877        return list.toArray(ArrayUtils.EMPTY_STRING_ARRAY);
7878    }
7879
7880    /**
7881     * Tests if a CharSequence starts with a specified prefix.
7882     *
7883     * <p>
7884     * {@code null}s are handled without exceptions. Two {@code null} references are considered to be equal. The comparison is case-sensitive.
7885     * </p>
7886     *
7887     * <pre>
7888     * StringUtils.startsWith(null, null)      = true
7889     * StringUtils.startsWith(null, "abc")     = false
7890     * StringUtils.startsWith("abcdef", null)  = false
7891     * StringUtils.startsWith("abcdef", "abc") = true
7892     * StringUtils.startsWith("ABCDEF", "abc") = false
7893     * </pre>
7894     *
7895     * @param str    The CharSequence to check, may be null.
7896     * @param prefix The prefix to find, may be null.
7897     * @return {@code true} if the CharSequence starts with the prefix, case-sensitive, or both {@code null}.
7898     * @see String#startsWith(String)
7899     * @since 2.4
7900     * @since 3.0 Changed signature from startsWith(String, String) to startsWith(CharSequence, CharSequence)
7901     * @deprecated Use {@link Strings#startsWith(CharSequence, CharSequence) Strings.CS.startsWith(CharSequence, CharSequence)}.
7902     */
7903    @Deprecated
7904    public static boolean startsWith(final CharSequence str, final CharSequence prefix) {
7905        return Strings.CS.startsWith(str, prefix);
7906    }
7907
7908    /**
7909     * Tests if a CharSequence starts with any of the provided case-sensitive prefixes.
7910     *
7911     * <pre>
7912     * StringUtils.startsWithAny(null, null)      = false
7913     * StringUtils.startsWithAny(null, new String[] {"abc"})  = false
7914     * StringUtils.startsWithAny("abcxyz", null)     = false
7915     * StringUtils.startsWithAny("abcxyz", new String[] {""}) = true
7916     * StringUtils.startsWithAny("abcxyz", new String[] {"abc"}) = true
7917     * StringUtils.startsWithAny("abcxyz", new String[] {null, "xyz", "abc"}) = true
7918     * StringUtils.startsWithAny("abcxyz", null, "xyz", "ABCX") = false
7919     * StringUtils.startsWithAny("ABCXYZ", null, "xyz", "abc") = false
7920     * </pre>
7921     *
7922     * @param sequence      The CharSequence to check, may be null.
7923     * @param searchStrings The case-sensitive CharSequence prefixes, may be empty or contain {@code null}.
7924     * @return {@code true} if the input {@code sequence} is {@code null} AND no {@code searchStrings} are provided, or the input {@code sequence} begins with
7925     *         any of the provided case-sensitive {@code searchStrings}.
7926     * @see StringUtils#startsWith(CharSequence, CharSequence)
7927     * @since 2.5
7928     * @since 3.0 Changed signature from startsWithAny(String, String[]) to startsWithAny(CharSequence, CharSequence...)
7929     * @deprecated Use {@link Strings#startsWithAny(CharSequence, CharSequence...) Strings.CS.startsWithAny(CharSequence, CharSequence...)}.
7930     */
7931    @Deprecated
7932    public static boolean startsWithAny(final CharSequence sequence, final CharSequence... searchStrings) {
7933        return Strings.CS.startsWithAny(sequence, searchStrings);
7934    }
7935
7936    /**
7937     * Case-insensitive check if a CharSequence starts with a specified prefix.
7938     *
7939     * <p>
7940     * {@code null}s are handled without exceptions. Two {@code null} references are considered to be equal. The comparison is case insensitive.
7941     * </p>
7942     *
7943     * <pre>
7944     * StringUtils.startsWithIgnoreCase(null, null)      = true
7945     * StringUtils.startsWithIgnoreCase(null, "abc")     = false
7946     * StringUtils.startsWithIgnoreCase("abcdef", null)  = false
7947     * StringUtils.startsWithIgnoreCase("abcdef", "abc") = true
7948     * StringUtils.startsWithIgnoreCase("ABCDEF", "abc") = true
7949     * </pre>
7950     *
7951     * @param str    The CharSequence to check, may be null.
7952     * @param prefix The prefix to find, may be null.
7953     * @return {@code true} if the CharSequence starts with the prefix, case-insensitive, or both {@code null}.
7954     * @see String#startsWith(String)
7955     * @since 2.4
7956     * @since 3.0 Changed signature from startsWithIgnoreCase(String, String) to startsWithIgnoreCase(CharSequence, CharSequence)
7957     * @deprecated Use {@link Strings#startsWith(CharSequence, CharSequence) Strings.CI.startsWith(CharSequence, CharSequence)}.
7958     */
7959    @Deprecated
7960    public static boolean startsWithIgnoreCase(final CharSequence str, final CharSequence prefix) {
7961        return Strings.CI.startsWith(str, prefix);
7962    }
7963
7964    /**
7965     * Strips whitespace from the start and end of a String.
7966     *
7967     * <p>
7968     * This is similar to {@link #trim(String)} but removes whitespace. Whitespace is defined by {@link Character#isWhitespace(char)}.
7969     * </p>
7970     *
7971     * <p>
7972     * A {@code null} input String returns {@code null}.
7973     * </p>
7974     *
7975     * <pre>
7976     * StringUtils.strip(null)     = null
7977     * StringUtils.strip("")       = ""
7978     * StringUtils.strip("   ")    = ""
7979     * StringUtils.strip("abc")    = "abc"
7980     * StringUtils.strip("  abc")  = "abc"
7981     * StringUtils.strip("abc  ")  = "abc"
7982     * StringUtils.strip(" abc ")  = "abc"
7983     * StringUtils.strip(" ab c ") = "ab c"
7984     * </pre>
7985     *
7986     * @param str The String to remove whitespace from, may be null.
7987     * @return The stripped String, {@code null} if null String input.
7988     */
7989    public static String strip(final String str) {
7990        return strip(str, null);
7991    }
7992
7993    /**
7994     * 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
7995     * to be controlled.
7996     *
7997     * <p>
7998     * A {@code null} input String returns {@code null}. An empty string ("") input returns the empty string.
7999     * </p>
8000     *
8001     * <p>
8002     * If the stripChars String is {@code null}, whitespace is stripped as defined by {@link Character#isWhitespace(char)}. Alternatively use
8003     * {@link #strip(String)}.
8004     * </p>
8005     *
8006     * <pre>
8007     * StringUtils.strip(null, *)          = null
8008     * StringUtils.strip("", *)            = ""
8009     * StringUtils.strip("abc", null)      = "abc"
8010     * StringUtils.strip("  abc", null)    = "abc"
8011     * StringUtils.strip("abc  ", null)    = "abc"
8012     * StringUtils.strip(" abc ", null)    = "abc"
8013     * StringUtils.strip("  abcyx", "xyz") = "  abc"
8014     * </pre>
8015     *
8016     * @param str        The String to remove characters from, may be null.
8017     * @param stripChars The characters to remove, null treated as whitespace.
8018     * @return The stripped String, {@code null} if null String input.
8019     */
8020    public static String strip(String str, final String stripChars) {
8021        str = stripStart(str, stripChars);
8022        return stripEnd(str, stripChars);
8023    }
8024
8025    /**
8026     * Removes diacritics (~= accents) from a string. The case will not be altered.
8027     * <p>
8028     * For instance, '&agrave;' will be replaced by 'a'.
8029     * </p>
8030     * <p>
8031     * Decomposes ligatures and digraphs per the KD column in the <a href = "https://www.unicode.org/charts/normalization/">Unicode Normalization Chart.</a>
8032     * </p>
8033     * <p>
8034     * Be aware that this NFKD compatibility decomposition can map non-letter compatibility forms (fullwidth, small-form, math-symbol variants of {@code <},
8035     * {@code >}, {@code /}, and so on) to their ASCII counterparts.
8036     * </p>
8037     *
8038     * <pre>
8039     * StringUtils.stripAccents(null)         = null
8040     * StringUtils.stripAccents("")           = ""
8041     * StringUtils.stripAccents("control")    = "control"
8042     * StringUtils.stripAccents("&eacute;clair")     = "eclair"
8043     * StringUtils.stripAccents("\u1d43\u1d47\u1d9c\u00b9\u00b2\u00b3")     = "abc123"
8044     * StringUtils.stripAccents("\u00BC \u00BD \u00BE")      = "1⁄4 1⁄2 3⁄4"
8045     * </pre>
8046     * <p>
8047     * See also <a href="https://www.unicode.org/unicode/reports/tr15/tr15-23.html">Unicode Standard Annex #15 Unicode Normalization Forms</a>.
8048     * </p>
8049     *
8050     * @param input String to be stripped.
8051     * @return input text with diacritics removed.
8052     * @since 3.0
8053     */
8054    // See also Lucene's ASCIIFoldingFilter (Lucene 2.9) that replaces accented characters by their unaccented equivalent (and uncommitted bug fix:
8055    // https://issues.apache.org/jira/browse/LUCENE-1343?focusedCommentId=12858907&page=com.atlassian.jira.plugin.system.issuetabpanels%3Acomment-tabpanel#action_12858907).
8056    public static String stripAccents(final String input) {
8057        if (isEmpty(input)) {
8058            return input;
8059        }
8060        final StringBuilder decomposed = new StringBuilder(Normalizer.normalize(input, Normalizer.Form.NFKD));
8061        convertRemainingAccentCharacters(decomposed);
8062        final String stripped = STRIP_ACCENTS_PATTERN.matcher(decomposed).replaceAll(EMPTY);
8063        return Normalizer.normalize(stripped, Normalizer.Form.NFC);
8064    }
8065
8066    /**
8067     * Strips whitespace from the start and end of every String in an array. Whitespace is defined by {@link Character#isWhitespace(char)}.
8068     *
8069     * <p>
8070     * 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
8071     * {@code null} array entry will be ignored.
8072     * </p>
8073     *
8074     * <pre>
8075     * StringUtils.stripAll(null)             = null
8076     * StringUtils.stripAll([])               = []
8077     * StringUtils.stripAll(["abc", "  abc"]) = ["abc", "abc"]
8078     * StringUtils.stripAll(["abc  ", null])  = ["abc", null]
8079     * </pre>
8080     *
8081     * @param strs The array to remove whitespace from, may be null.
8082     * @return The stripped Strings, {@code null} if null array input.
8083     */
8084    public static String[] stripAll(final String... strs) {
8085        return stripAll(strs, null);
8086    }
8087
8088    /**
8089     * Strips any of a set of characters from the start and end of every String in an array.
8090     * <p>
8091     * Whitespace is defined by {@link Character#isWhitespace(char)}.
8092     * </p>
8093     *
8094     * <p>
8095     * 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
8096     * {@code null} array entry will be ignored. A {@code null} stripChars will strip whitespace as defined by {@link Character#isWhitespace(char)}.
8097     * </p>
8098     *
8099     * <pre>
8100     * StringUtils.stripAll(null, *)                = null
8101     * StringUtils.stripAll([], *)                  = []
8102     * StringUtils.stripAll(["abc", "  abc"], null) = ["abc", "abc"]
8103     * StringUtils.stripAll(["abc  ", null], null)  = ["abc", null]
8104     * StringUtils.stripAll(["abc  ", null], "yz")  = ["abc  ", null]
8105     * StringUtils.stripAll(["yabcz", null], "yz")  = ["abc", null]
8106     * </pre>
8107     *
8108     * @param strs       The array to remove characters from, may be null.
8109     * @param stripChars The characters to remove, null treated as whitespace.
8110     * @return The stripped Strings, {@code null} if null array input.
8111     */
8112    public static String[] stripAll(final String[] strs, final String stripChars) {
8113        final int strsLen = ArrayUtils.getLength(strs);
8114        if (strsLen == 0) {
8115            return strs;
8116        }
8117        return ArrayUtils.setAll(new String[strsLen], i -> strip(strs[i], stripChars));
8118    }
8119
8120    /**
8121     * Strips any of a set of characters from the end of a String.
8122     *
8123     * <p>
8124     * A {@code null} input String returns {@code null}. An empty string ("") input returns the empty string.
8125     * </p>
8126     *
8127     * <p>
8128     * If the stripChars String is {@code null}, whitespace is stripped as defined by {@link Character#isWhitespace(char)}.
8129     * </p>
8130     *
8131     * <p>
8132     * The characters in {@code stripChars} are treated individually, not as a suffix. To remove a suffix as a whole,
8133     * use {@link Strings#removeEnd(String, CharSequence)} on {@link Strings#CS} instead.
8134     * </p>
8135     *
8136     * <pre>
8137     * StringUtils.stripEnd(null, *)          = null
8138     * StringUtils.stripEnd("", *)            = ""
8139     * StringUtils.stripEnd("abc", "")        = "abc"
8140     * StringUtils.stripEnd("abc", null)      = "abc"
8141     * StringUtils.stripEnd("  abc", null)    = "  abc"
8142     * StringUtils.stripEnd("abc  ", null)    = "abc"
8143     * StringUtils.stripEnd(" abc ", null)    = " abc"
8144     * StringUtils.stripEnd("  abcyx", "xyz") = "  abc"
8145     * StringUtils.stripEnd("120.00", ".0")   = "12"
8146     * StringUtils.stripEnd("85123116", "16") = "85123"
8147     * </pre>
8148     *
8149     * @param str        The String to remove characters from, may be null.
8150     * @param stripChars The set of characters to remove, null treated as whitespace.
8151     * @return The stripped String, {@code null} if null String input.
8152     */
8153    public static String stripEnd(final String str, final String stripChars) {
8154        int end = length(str);
8155        if (end == 0) {
8156            return str;
8157        }
8158        if (stripChars == null) {
8159            while (end != 0 && Character.isWhitespace(str.charAt(end - 1))) {
8160                end--;
8161            }
8162        } else if (stripChars.isEmpty()) {
8163            return str;
8164        } else {
8165            while (end != 0) {
8166                final int codePoint = str.codePointBefore(end);
8167                if (stripChars.indexOf(codePoint) == INDEX_NOT_FOUND) {
8168                    break;
8169                }
8170                end -= Character.charCount(codePoint);
8171            }
8172        }
8173        return str.substring(0, end);
8174    }
8175
8176    /**
8177     * Strips any of a set of characters from the start of a String.
8178     *
8179     * <p>
8180     * A {@code null} input String returns {@code null}. An empty string ("") input returns the empty string.
8181     * </p>
8182     *
8183     * <p>
8184     * If the stripChars String is {@code null}, whitespace is stripped as defined by {@link Character#isWhitespace(char)}.
8185     * </p>
8186     *
8187     * <pre>
8188     * StringUtils.stripStart(null, *)          = null
8189     * StringUtils.stripStart("", *)            = ""
8190     * StringUtils.stripStart("abc", "")        = "abc"
8191     * StringUtils.stripStart("abc", null)      = "abc"
8192     * StringUtils.stripStart("  abc", null)    = "abc"
8193     * StringUtils.stripStart("abc  ", null)    = "abc  "
8194     * StringUtils.stripStart(" abc ", null)    = "abc "
8195     * StringUtils.stripStart("yxabc  ", "xyz") = "abc  "
8196     * </pre>
8197     *
8198     * @param str        The String to remove characters from, may be null.
8199     * @param stripChars The characters to remove, null treated as whitespace.
8200     * @return The stripped String, {@code null} if null String input.
8201     */
8202    public static String stripStart(final String str, final String stripChars) {
8203        final int strLen = length(str);
8204        if (strLen == 0) {
8205            return str;
8206        }
8207        int start = 0;
8208        if (stripChars == null) {
8209            while (start != strLen && Character.isWhitespace(str.charAt(start))) {
8210                start++;
8211            }
8212        } else if (stripChars.isEmpty()) {
8213            return str;
8214        } else {
8215            while (start != strLen) {
8216                final int codePoint = str.codePointAt(start);
8217                if (stripChars.indexOf(codePoint) == INDEX_NOT_FOUND) {
8218                    break;
8219                }
8220                start += Character.charCount(codePoint);
8221            }
8222        }
8223        return str.substring(start);
8224    }
8225
8226    /**
8227     * Strips whitespace from the start and end of a String returning an empty String if {@code null} input.
8228     *
8229     * <p>
8230     * This is similar to {@link #trimToEmpty(String)} but removes whitespace. Whitespace is defined by {@link Character#isWhitespace(char)}.
8231     * </p>
8232     *
8233     * <pre>
8234     * StringUtils.stripToEmpty(null)     = ""
8235     * StringUtils.stripToEmpty("")       = ""
8236     * StringUtils.stripToEmpty("   ")    = ""
8237     * StringUtils.stripToEmpty("abc")    = "abc"
8238     * StringUtils.stripToEmpty("  abc")  = "abc"
8239     * StringUtils.stripToEmpty("abc  ")  = "abc"
8240     * StringUtils.stripToEmpty(" abc ")  = "abc"
8241     * StringUtils.stripToEmpty(" ab c ") = "ab c"
8242     * </pre>
8243     *
8244     * @param str The String to be stripped, may be null.
8245     * @return The trimmed String, or an empty String if {@code null} input.
8246     * @since 2.0
8247     */
8248    public static String stripToEmpty(final String str) {
8249        return str == null ? EMPTY : strip(str, null);
8250    }
8251
8252    /**
8253     * Strips whitespace from the start and end of a String returning {@code null} if the String is empty ("") after the strip.
8254     *
8255     * <p>
8256     * This is similar to {@link #trimToNull(String)} but removes whitespace. Whitespace is defined by {@link Character#isWhitespace(char)}.
8257     * </p>
8258     *
8259     * <pre>
8260     * StringUtils.stripToNull(null)     = null
8261     * StringUtils.stripToNull("")       = null
8262     * StringUtils.stripToNull("   ")    = null
8263     * StringUtils.stripToNull("abc")    = "abc"
8264     * StringUtils.stripToNull("  abc")  = "abc"
8265     * StringUtils.stripToNull("abc  ")  = "abc"
8266     * StringUtils.stripToNull(" abc ")  = "abc"
8267     * StringUtils.stripToNull(" ab c ") = "ab c"
8268     * </pre>
8269     *
8270     * @param str The String to be stripped, may be null.
8271     * @return The stripped String, {@code null} if whitespace, empty or null String input.
8272     * @since 2.0
8273     */
8274    public static String stripToNull(String str) {
8275        if (str == null) {
8276            return null;
8277        }
8278        str = strip(str, null);
8279        return str.isEmpty() ? null : str; // NOSONARLINT str cannot be null here
8280    }
8281
8282    /**
8283     * Gets a substring from the specified String avoiding exceptions.
8284     *
8285     * <p>
8286     * A negative start position can be used to start {@code n} characters from the end of the String.
8287     * </p>
8288     *
8289     * <p>
8290     * A {@code null} String will return {@code null}. An empty ("") String will return "".
8291     * </p>
8292     *
8293     * <pre>
8294     * StringUtils.substring(null, *)   = null
8295     * StringUtils.substring("", *)     = ""
8296     * StringUtils.substring("abc", 0)  = "abc"
8297     * StringUtils.substring("abc", 2)  = "c"
8298     * StringUtils.substring("abc", 4)  = ""
8299     * StringUtils.substring("abc", -2) = "bc"
8300     * StringUtils.substring("abc", -4) = "abc"
8301     * </pre>
8302     *
8303     * @param str   The String to get the substring from, may be null.
8304     * @param start The position to start from, negative means count back from the end of the String by this many characters.
8305     * @return substring from start position, {@code null} if null String input.
8306     */
8307    public static String substring(final String str, int start) {
8308        if (str == null) {
8309            return null;
8310        }
8311        // handle negatives, which means last n characters
8312        if (start < 0) {
8313            start = str.length() + start; // remember start is negative
8314        }
8315        if (start < 0) {
8316            start = 0;
8317        }
8318        if (start > str.length()) {
8319            return EMPTY;
8320        }
8321        return str.substring(start);
8322    }
8323
8324    /**
8325     * Gets a substring from the specified String avoiding exceptions.
8326     *
8327     * <p>
8328     * A negative start position can be used to start/end {@code n} characters from the end of the String.
8329     * </p>
8330     *
8331     * <p>
8332     * The returned substring starts with the character in the {@code start} position and ends before the {@code end} position. All position counting is
8333     * 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
8334     * relative to the end of the String.
8335     * </p>
8336     *
8337     * <p>
8338     * If {@code start} is not strictly to the left of {@code end}, "" is returned.
8339     * </p>
8340     *
8341     * <pre>
8342     * StringUtils.substring(null, *, *)    = null
8343     * StringUtils.substring("", * ,  *)    = "";
8344     * StringUtils.substring("abc", 0, 2)   = "ab"
8345     * StringUtils.substring("abc", 2, 0)   = ""
8346     * StringUtils.substring("abc", 2, 4)   = "c"
8347     * StringUtils.substring("abc", 4, 6)   = ""
8348     * StringUtils.substring("abc", 2, 2)   = ""
8349     * StringUtils.substring("abc", -2, -1) = "b"
8350     * StringUtils.substring("abc", -4, 2)  = "ab"
8351     * </pre>
8352     *
8353     * @param str   The String to get the substring from, may be null.
8354     * @param start The position to start from, negative means count back from the end of the String by this many characters.
8355     * @param end   The position to end at (exclusive), negative means count back from the end of the String by this many characters.
8356     * @return substring from start position to end position, {@code null} if null String input.
8357     */
8358    public static String substring(final String str, int start, int end) {
8359        if (str == null) {
8360            return null;
8361        }
8362        // handle negatives
8363        if (end < 0) {
8364            end = str.length() + end; // remember end is negative
8365        }
8366        if (start < 0) {
8367            start = str.length() + start; // remember start is negative
8368        }
8369        // check length next
8370        if (end > str.length()) {
8371            end = str.length();
8372        }
8373        // if start is greater than end, return ""
8374        if (start > end) {
8375            return EMPTY;
8376        }
8377        if (start < 0) {
8378            start = 0;
8379        }
8380        if (end < 0) {
8381            end = 0;
8382        }
8383        return str.substring(start, end);
8384    }
8385
8386    /**
8387     * Gets the substring after the first occurrence of a separator. The separator is not returned.
8388     *
8389     * <p>
8390     * A {@code null} string input will return {@code null}. An empty ("") string input will return the empty string.
8391     * </p>
8392     *
8393     * <p>
8394     * If nothing is found, the empty string is returned.
8395     * </p>
8396     *
8397     * <pre>
8398     * StringUtils.substringAfter(null, *)      = null
8399     * StringUtils.substringAfter("", *)        = ""
8400     * StringUtils.substringAfter("abc", 'a')   = "bc"
8401     * StringUtils.substringAfter("abcba", 'b') = "cba"
8402     * StringUtils.substringAfter("abc", 'c')   = ""
8403     * StringUtils.substringAfter("abc", 'd')   = ""
8404     * StringUtils.substringAfter(" abc", 32)   = "abc"
8405     * </pre>
8406     *
8407     * @param str       The String to get a substring from, may be null.
8408     * @param find The character (Unicode code point) to find.
8409     * @return The substring after the first occurrence of the specified character, {@code null} if null String input.
8410     * @since 3.11
8411     */
8412    public static String substringAfter(final String str, final int find) {
8413        if (isEmpty(str)) {
8414            return str;
8415        }
8416        final int pos = str.indexOf(find);
8417        if (pos == INDEX_NOT_FOUND) {
8418            return EMPTY;
8419        }
8420        return str.substring(pos + Character.charCount(find));
8421    }
8422
8423    /**
8424     * Gets the substring after the first occurrence of a separator. The separator is not returned.
8425     *
8426     * <p>
8427     * 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
8428     * empty string if the input string is not {@code null}.
8429     * </p>
8430     *
8431     * <p>
8432     * If nothing is found, the empty string is returned.
8433     * </p>
8434     *
8435     * <pre>
8436     * StringUtils.substringAfter(null, *)      = null
8437     * StringUtils.substringAfter("", *)        = ""
8438     * StringUtils.substringAfter(*, null)      = ""
8439     * StringUtils.substringAfter("abc", "a")   = "bc"
8440     * StringUtils.substringAfter("abcba", "b") = "cba"
8441     * StringUtils.substringAfter("abc", "c")   = ""
8442     * StringUtils.substringAfter("abc", "d")   = ""
8443     * StringUtils.substringAfter("abc", "")    = "abc"
8444     * </pre>
8445     *
8446     * @param str       The String to get a substring from, may be null.
8447     * @param find The String to find, may be null.
8448     * @return The substring after the first occurrence of the specified string, {@code null} if null String input.
8449     * @since 2.0
8450     */
8451    public static String substringAfter(final String str, final String find) {
8452        if (isEmpty(str)) {
8453            return str;
8454        }
8455        if (find == null) {
8456            return EMPTY;
8457        }
8458        final int pos = str.indexOf(find);
8459        if (pos == INDEX_NOT_FOUND) {
8460            return EMPTY;
8461        }
8462        return str.substring(pos + find.length());
8463    }
8464
8465    /**
8466     * Gets the substring after the last occurrence of a separator. The separator is not returned.
8467     *
8468     * <p>
8469     * A {@code null} string input will return {@code null}. An empty ("") string input will return the empty string.
8470     * </p>
8471     *
8472     * <p>
8473     * If nothing is found, the empty string is returned.
8474     * </p>
8475     *
8476     * <pre>
8477     * StringUtils.substringAfterLast(null, *)      = null
8478     * StringUtils.substringAfterLast("", *)        = ""
8479     * StringUtils.substringAfterLast("abc", 'a')   = "bc"
8480     * StringUtils.substringAfterLast(" bc", 32)    = "bc"
8481     * StringUtils.substringAfterLast("abcba", 'b') = "a"
8482     * StringUtils.substringAfterLast("abc", 'c')   = ""
8483     * StringUtils.substringAfterLast("a", 'a')     = ""
8484     * StringUtils.substringAfterLast("a", 'z')     = ""
8485     * </pre>
8486     *
8487     * @param str       The String to get a substring from, may be null.
8488     * @param find The character (Unicode code point) to find.
8489     * @return The substring after the last occurrence of the specified character, {@code null} if null String input.
8490     * @since 3.11
8491     */
8492    public static String substringAfterLast(final String str, final int find) {
8493        if (isEmpty(str)) {
8494            return str;
8495        }
8496        final int pos = str.lastIndexOf(find);
8497        if (pos == INDEX_NOT_FOUND || pos == str.length() - Character.charCount(find)) {
8498            return EMPTY;
8499        }
8500        return str.substring(pos + Character.charCount(find));
8501    }
8502
8503    /**
8504     * Gets the substring after the last occurrence of a separator. The separator is not returned.
8505     *
8506     * <p>
8507     * 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
8508     * return the empty string if the input string is not {@code null}.
8509     * </p>
8510     *
8511     * <p>
8512     * If nothing is found, the empty string is returned.
8513     * </p>
8514     *
8515     * <pre>
8516     * StringUtils.substringAfterLast(null, *)      = null
8517     * StringUtils.substringAfterLast("", *)        = ""
8518     * StringUtils.substringAfterLast(*, "")        = ""
8519     * StringUtils.substringAfterLast(*, null)      = ""
8520     * StringUtils.substringAfterLast("abc", "a")   = "bc"
8521     * StringUtils.substringAfterLast("abcba", "b") = "a"
8522     * StringUtils.substringAfterLast("abc", "c")   = ""
8523     * StringUtils.substringAfterLast("a", "a")     = ""
8524     * StringUtils.substringAfterLast("a", "z")     = ""
8525     * </pre>
8526     *
8527     * @param str       The String to get a substring from, may be null.
8528     * @param find The String to find, may be null.
8529     * @return The substring after the last occurrence of the specified string, {@code null} if null String input.
8530     * @since 2.0
8531     */
8532    public static String substringAfterLast(final String str, final String find) {
8533        if (isEmpty(str)) {
8534            return str;
8535        }
8536        if (isEmpty(find)) {
8537            return EMPTY;
8538        }
8539        final int pos = str.lastIndexOf(find);
8540        if (pos == INDEX_NOT_FOUND || pos == str.length() - find.length()) {
8541            return EMPTY;
8542        }
8543        return str.substring(pos + find.length());
8544    }
8545
8546    /**
8547     * Gets the substring before the first occurrence of a separator. The separator is not returned.
8548     *
8549     * <p>
8550     * A {@code null} string input will return {@code null}. An empty ("") string input will return the empty string.
8551     * </p>
8552     *
8553     * <p>
8554     * If nothing is found, the string input is returned.
8555     * </p>
8556     *
8557     * <pre>
8558     * StringUtils.substringBefore(null, *)      = null
8559     * StringUtils.substringBefore("", *)        = ""
8560     * StringUtils.substringBefore("abc", 'a')   = ""
8561     * StringUtils.substringBefore("abcba", 'b') = "a"
8562     * StringUtils.substringBefore("abc", 'c')   = "ab"
8563     * StringUtils.substringBefore("abc", 'd')   = "abc"
8564     * </pre>
8565     *
8566     * @param str       The String to get a substring from, may be null.
8567     * @param find The character (Unicode code point) to find.
8568     * @return The substring before the first occurrence of the specified character, {@code null} if null String input.
8569     * @since 3.12.0
8570     */
8571    public static String substringBefore(final String str, final int find) {
8572        if (isEmpty(str)) {
8573            return str;
8574        }
8575        final int pos = str.indexOf(find);
8576        if (pos == INDEX_NOT_FOUND) {
8577            return str;
8578        }
8579        return str.substring(0, pos);
8580    }
8581
8582    /**
8583     * Gets the substring before the first occurrence of a separator. The separator is not returned.
8584     *
8585     * <p>
8586     * 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
8587     * input string.
8588     * </p>
8589     *
8590     * <p>
8591     * If nothing is found, the string input is returned.
8592     * </p>
8593     *
8594     * <pre>
8595     * StringUtils.substringBefore(null, *)      = null
8596     * StringUtils.substringBefore("", *)        = ""
8597     * StringUtils.substringBefore("abc", "a")   = ""
8598     * StringUtils.substringBefore("abcba", "b") = "a"
8599     * StringUtils.substringBefore("abc", "c")   = "ab"
8600     * StringUtils.substringBefore("abc", "d")   = "abc"
8601     * StringUtils.substringBefore("abc", "")    = ""
8602     * StringUtils.substringBefore("abc", null)  = "abc"
8603     * </pre>
8604     *
8605     * @param str       The String to get a substring from, may be null.
8606     * @param find The String to find, may be null.
8607     * @return The substring before the first occurrence of the specified string, {@code null} if null String input.
8608     * @since 2.0
8609     */
8610    public static String substringBefore(final String str, final String find) {
8611        if (isEmpty(str) || find == null) {
8612            return str;
8613        }
8614        if (find.isEmpty()) {
8615            return EMPTY;
8616        }
8617        final int pos = str.indexOf(find);
8618        if (pos == INDEX_NOT_FOUND) {
8619            return str;
8620        }
8621        return str.substring(0, pos);
8622    }
8623
8624    /**
8625     * Gets the substring before the last occurrence of a separator. The separator is not returned.
8626     *
8627     * <p>
8628     * 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
8629     * return the input string.
8630     * </p>
8631     *
8632     * <p>
8633     * If nothing is found, the string input is returned.
8634     * </p>
8635     *
8636     * <pre>
8637     * StringUtils.substringBeforeLast(null, *)      = null
8638     * StringUtils.substringBeforeLast("", *)        = ""
8639     * StringUtils.substringBeforeLast("abcba", "b") = "abc"
8640     * StringUtils.substringBeforeLast("abc", "c")   = "ab"
8641     * StringUtils.substringBeforeLast("a", "a")     = ""
8642     * StringUtils.substringBeforeLast("a", "z")     = "a"
8643     * StringUtils.substringBeforeLast("a", null)    = "a"
8644     * StringUtils.substringBeforeLast("a", "")      = "a"
8645     * </pre>
8646     *
8647     * @param str       The String to get a substring from, may be null.
8648     * @param find The String to find, may be null.
8649     * @return The substring before the last occurrence of the specified string, {@code null} if null String input.
8650     * @since 2.0
8651     */
8652    public static String substringBeforeLast(final String str, final String find) {
8653        if (isEmpty(str) || isEmpty(find)) {
8654            return str;
8655        }
8656        final int pos = str.lastIndexOf(find);
8657        if (pos == INDEX_NOT_FOUND) {
8658            return str;
8659        }
8660        return str.substring(0, pos);
8661    }
8662
8663    /**
8664     * Gets the String that is nested in between two instances of the same String.
8665     *
8666     * <p>
8667     * A {@code null} input String returns {@code null}. A {@code null} tag returns {@code null}.
8668     * </p>
8669     *
8670     * <pre>
8671     * StringUtils.substringBetween(null, *)            = null
8672     * StringUtils.substringBetween("", "")             = ""
8673     * StringUtils.substringBetween("", "tag")          = null
8674     * StringUtils.substringBetween("tagabctag", null)  = null
8675     * StringUtils.substringBetween("tagabctag", "")    = ""
8676     * StringUtils.substringBetween("tagabctag", "tag") = "abc"
8677     * </pre>
8678     *
8679     * @param str The String containing the substring, may be null.
8680     * @param tag The String before and after the substring, may be null.
8681     * @return The substring, {@code null} if no match.
8682     * @since 2.0
8683     */
8684    public static String substringBetween(final String str, final String tag) {
8685        return substringBetween(str, tag, tag);
8686    }
8687
8688    /**
8689     * Gets the String that is nested in between two Strings. Only the first match is returned.
8690     *
8691     * <p>
8692     * 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
8693     * empty string.
8694     * </p>
8695     *
8696     * <pre>
8697     * StringUtils.substringBetween("wx[b]yz", "[", "]") = "b"
8698     * StringUtils.substringBetween(null, *, *)          = null
8699     * StringUtils.substringBetween(*, null, *)          = null
8700     * StringUtils.substringBetween(*, *, null)          = null
8701     * StringUtils.substringBetween("", "", "")          = ""
8702     * StringUtils.substringBetween("", "", "]")         = null
8703     * StringUtils.substringBetween("", "[", "]")        = null
8704     * StringUtils.substringBetween("yabcz", "", "")     = ""
8705     * StringUtils.substringBetween("yabcz", "y", "z")   = "abc"
8706     * StringUtils.substringBetween("yabczyabcz", "y", "z")   = "abc"
8707     * </pre>
8708     *
8709     * @param str   The String containing the substring, may be null.
8710     * @param open  The String before the substring, may be null.
8711     * @param close The String after the substring, may be null.
8712     * @return The substring, {@code null} if no match.
8713     * @since 2.0
8714     */
8715    public static String substringBetween(final String str, final String open, final String close) {
8716        if (!ObjectUtils.allNotNull(str, open, close)) {
8717            return null;
8718        }
8719        final int start = str.indexOf(open);
8720        if (start != INDEX_NOT_FOUND) {
8721            final int end = str.indexOf(close, start + open.length());
8722            if (end != INDEX_NOT_FOUND) {
8723                return str.substring(start + open.length(), end);
8724            }
8725        }
8726        return null;
8727    }
8728
8729    /**
8730     * Searches a String for substrings delimited by a start and end tag, returning all matching substrings in an array.
8731     *
8732     * <p>
8733     * A {@code null} input String returns {@code null}. A {@code null} open/close returns {@code null} (no match). An empty ("") open/close returns
8734     * {@code null} (no match).
8735     * </p>
8736     *
8737     * <pre>
8738     * StringUtils.substringsBetween("[a][b][c]", "[", "]") = ["a","b","c"]
8739     * StringUtils.substringsBetween(null, *, *)            = null
8740     * StringUtils.substringsBetween(*, null, *)            = null
8741     * StringUtils.substringsBetween(*, *, null)            = null
8742     * StringUtils.substringsBetween("", "[", "]")          = []
8743     * </pre>
8744     *
8745     * @param str   The String containing the substrings, null returns null, empty returns empty.
8746     * @param open  The String identifying the start of the substring, empty returns null.
8747     * @param close The String identifying the end of the substring, empty returns null.
8748     * @return A String Array of substrings, or {@code null} if no match.
8749     * @since 2.3
8750     */
8751    public static String[] substringsBetween(final String str, final String open, final String close) {
8752        if (str == null || isEmpty(open) || isEmpty(close)) {
8753            return null;
8754        }
8755        final int strLen = str.length();
8756        if (strLen == 0) {
8757            return ArrayUtils.EMPTY_STRING_ARRAY;
8758        }
8759        final int closeLen = close.length();
8760        final int openLen = open.length();
8761        final List<String> list = new ArrayList<>();
8762        int pos = 0;
8763        while (pos < strLen - closeLen) {
8764            int start = str.indexOf(open, pos);
8765            if (start < 0) {
8766                break;
8767            }
8768            start += openLen;
8769            final int end = str.indexOf(close, start);
8770            if (end < 0) {
8771                break;
8772            }
8773            list.add(str.substring(start, end));
8774            pos = end + closeLen;
8775        }
8776        if (list.isEmpty()) {
8777            return null;
8778        }
8779        return list.toArray(ArrayUtils.EMPTY_STRING_ARRAY);
8780    }
8781
8782    /**
8783     * Swaps the case of a String changing upper and title case to lower case, and lower case to upper case.
8784     *
8785     * <ul>
8786     * <li>Upper case character converts to Lower case</li>
8787     * <li>Title case character converts to Lower case</li>
8788     * <li>Lower case character converts to Upper case</li>
8789     * </ul>
8790     *
8791     * <p>
8792     * For a word based algorithm, see {@link org.apache.commons.text.WordUtils#swapCase(String)}. A {@code null} input String returns {@code null}.
8793     * </p>
8794     *
8795     * <pre>
8796     * StringUtils.swapCase(null)                 = null
8797     * StringUtils.swapCase("")                   = ""
8798     * StringUtils.swapCase("The dog has a BONE") = "tHE DOG HAS A bone"
8799     * </pre>
8800     *
8801     * <p>
8802     * 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
8803     * functionality is available in org.apache.commons.lang3.text.WordUtils.
8804     * </p>
8805     *
8806     * @param str The String to swap case, may be null.
8807     * @return The changed String, {@code null} if null String input.
8808     */
8809    public static String swapCase(final String str) {
8810        if (isEmpty(str)) {
8811            return str;
8812        }
8813        final int strLen = str.length();
8814        final int[] newCodePoints = new int[strLen]; // cannot be longer than the char array
8815        int outOffset = 0;
8816        for (int i = 0; i < strLen;) {
8817            final int oldCodepoint = str.codePointAt(i);
8818            final int newCodePoint;
8819            if (Character.isUpperCase(oldCodepoint) || Character.isTitleCase(oldCodepoint)) {
8820                newCodePoint = Character.toLowerCase(oldCodepoint);
8821            } else if (Character.isLowerCase(oldCodepoint)) {
8822                newCodePoint = Character.toUpperCase(oldCodepoint);
8823            } else {
8824                newCodePoint = oldCodepoint;
8825            }
8826            newCodePoints[outOffset++] = newCodePoint;
8827            i += Character.charCount(newCodePoint);
8828        }
8829        return new String(newCodePoints, 0, outOffset);
8830    }
8831
8832    /**
8833     * Converts a {@link CharSequence} into an array of code points.
8834     *
8835     * <p>
8836     * 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
8837     * followed by a low surrogate or a low surrogate not preceded by a high surrogate) will be returned as-is.
8838     * </p>
8839     *
8840     * <pre>
8841     * StringUtils.toCodePoints(null)   =  null
8842     * StringUtils.toCodePoints("")     =  []  // empty array
8843     * </pre>
8844     *
8845     * @param cs The character sequence to convert.
8846     * @return An array of code points.
8847     * @since 3.6
8848     */
8849    public static int[] toCodePoints(final CharSequence cs) {
8850        if (cs == null) {
8851            return null;
8852        }
8853        if (isEmpty(cs)) {
8854            return ArrayUtils.EMPTY_INT_ARRAY;
8855        }
8856        return cs.toString().codePoints().toArray();
8857    }
8858
8859    /**
8860     * Converts a {@code byte[]} to a String using the specified character encoding.
8861     *
8862     * @param bytes   The byte array to read from.
8863     * @param charset The encoding to use, if null then use the platform default.
8864     * @return A new String.
8865     * @throws NullPointerException Thrown if {@code bytes} is null.
8866     * @since 3.2
8867     * @since 3.3 No longer throws {@link UnsupportedEncodingException}.
8868     */
8869    public static String toEncodedString(final byte[] bytes, final Charset charset) {
8870        return new String(bytes, Charsets.toCharset(charset));
8871    }
8872
8873    /**
8874     * Converts the given source String as a lower-case using the {@link Locale#ROOT} locale in a null-safe manner.
8875     *
8876     * @param source A source String or null.
8877     * @return The given source String as a lower-case using the {@link Locale#ROOT} locale or null.
8878     * @since 3.10
8879     */
8880    public static String toRootLowerCase(final String source) {
8881        return source == null ? null : source.toLowerCase(Locale.ROOT);
8882    }
8883
8884    /**
8885     * Converts the given source String as an upper-case using the {@link Locale#ROOT} locale in a null-safe manner.
8886     *
8887     * @param source A source String or null.
8888     * @return The given source String as an upper-case using the {@link Locale#ROOT} locale or null.
8889     * @since 3.10
8890     */
8891    public static String toRootUpperCase(final String source) {
8892        return source == null ? null : source.toUpperCase(Locale.ROOT);
8893    }
8894
8895    /**
8896     * Converts a {@code byte[]} to a String using the specified character encoding.
8897     *
8898     * @param bytes       The byte array to read from.
8899     * @param charsetName The encoding to use, if null then use the platform default.
8900     * @return A new String.
8901     * @throws NullPointerException Thrown if the input is null.
8902     * @since 3.1
8903     * @deprecated Use {@link StringUtils#toEncodedString(byte[], Charset)} instead of String constants in your code.
8904     */
8905    @Deprecated
8906    public static String toString(final byte[] bytes, final String charsetName) {
8907        return new String(bytes, Charsets.toCharset(charsetName));
8908    }
8909
8910    /**
8911     * Removes control characters plus space (char &lt;= 32) from both ends of this String, handling {@code null} by returning {@code null}.
8912     *
8913     * <p>
8914     * The String is trimmed using {@link String#trim()}. Trim removes start and end characters &lt;= 32. To strip whitespace use {@link #strip(String)}.
8915     * </p>
8916     *
8917     * <p>
8918     * To trim your choice of characters, use the {@link #strip(String, String)} methods.
8919     * </p>
8920     *
8921     * <pre>
8922     * StringUtils.trim(null)          = null
8923     * StringUtils.trim("")            = ""
8924     * StringUtils.trim("     ")       = ""
8925     * StringUtils.trim("abc")         = "abc"
8926     * StringUtils.trim("    abc    ") = "abc"
8927     * </pre>
8928     *
8929     * @param str The String to be trimmed, may be null.
8930     * @return The trimmed string, {@code null} if null String input.
8931     */
8932    public static String trim(final String str) {
8933        return str == null ? null : str.trim();
8934    }
8935
8936    /**
8937     * Removes {@link CharUtils#isAsciiControl(char) ASCII control characters} (char &lt;= 31 or char == 127) from both ends of this String, handling
8938     * {@code null} by returning {@code null}.
8939     *
8940     * <p>
8941     * To trim your choice of characters, use the {@link #strip(String, String)} methods.
8942     * </p>
8943     *
8944     * <pre>{@code
8945     * StringUtils.trimAsciiControl(null)          = null
8946     * StringUtils.trimAsciiControl("")            = ""
8947     * StringUtils.trimAsciiControl("abc\u0000")   = "abc"
8948     * StringUtils.trimAsciiControl("abc")         = "abc"
8949     * StringUtils.trimAsciiControl(" abc ")       = " abc "
8950     * }</pre>
8951     *
8952     * @param str The String to be trimmed, may be null.
8953     * @return The trimmed string, {@code null} if null String input.
8954     * @since 3.21.0
8955     */
8956    public static String trimAsciiControl(final String str) {
8957        if (str == null) {
8958            return null;
8959        }
8960        int len = str.length();
8961        int st = 0;
8962        while (st < len && CharUtils.isAsciiControl(str.charAt(st))) {
8963            st++;
8964        }
8965        while (st < len && CharUtils.isAsciiControl(str.charAt(len - 1))) {
8966            len--;
8967        }
8968        return st > 0 || len < str.length() ? str.substring(st, len) : str;
8969    }
8970
8971    /**
8972     * 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
8973     * it is {@code null}.
8974     *
8975     * <p>
8976     * The String is trimmed using {@link String#trim()}. Trim removes start and end characters &lt;= 32. To strip whitespace use {@link #stripToEmpty(String)}.
8977     * </p>
8978     *
8979     * <pre>
8980     * StringUtils.trimToEmpty(null)          = ""
8981     * StringUtils.trimToEmpty("")            = ""
8982     * StringUtils.trimToEmpty("     ")       = ""
8983     * StringUtils.trimToEmpty("abc")         = "abc"
8984     * StringUtils.trimToEmpty("    abc    ") = "abc"
8985     * </pre>
8986     *
8987     * @param str The String to be trimmed, may be null.
8988     * @return The trimmed String, or an empty String if {@code null} input.
8989     * @since 2.0
8990     */
8991    public static String trimToEmpty(final String str) {
8992        return str == null ? EMPTY : str.trim();
8993    }
8994
8995    /**
8996     * 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
8997     * {@code null}.
8998     *
8999     * <p>
9000     * The String is trimmed using {@link String#trim()}. Trim removes start and end characters &lt;= 32. To strip whitespace use {@link #stripToNull(String)}.
9001     * </p>
9002     *
9003     * <pre>
9004     * StringUtils.trimToNull(null)          = null
9005     * StringUtils.trimToNull("")            = null
9006     * StringUtils.trimToNull("     ")       = null
9007     * StringUtils.trimToNull("abc")         = "abc"
9008     * StringUtils.trimToNull("    abc    ") = "abc"
9009     * </pre>
9010     *
9011     * @param str The String to be trimmed, may be null.
9012     * @return The trimmed String, {@code null} if only chars &lt;= 32, empty or null String input.
9013     * @since 2.0
9014     */
9015    public static String trimToNull(final String str) {
9016        final String ts = trim(str);
9017        return isEmpty(ts) ? null : ts;
9018    }
9019
9020    /**
9021     * Truncates a String. This will turn "Now is the time for all good men" into "Now is the time for".
9022     *
9023     * <p>
9024     * Specifically:
9025     * </p>
9026     * <ul>
9027     * <li>If {@code str} is less than {@code maxWidth} characters long, return it.</li>
9028     * <li>Else truncate it to {@code substring(str, 0, maxWidth)}.</li>
9029     * <li>If {@code maxWidth} is less than {@code 0}, throw an {@link IllegalArgumentException}.</li>
9030     * <li>In no case will it return a String of length greater than {@code maxWidth}.</li>
9031     * </ul>
9032     *
9033     * <pre>
9034     * StringUtils.truncate(null, 0)       = null
9035     * StringUtils.truncate(null, 2)       = null
9036     * StringUtils.truncate("", 4)         = ""
9037     * StringUtils.truncate("abcdefg", 4)  = "abcd"
9038     * StringUtils.truncate("abcdefg", 6)  = "abcdef"
9039     * StringUtils.truncate("abcdefg", 7)  = "abcdefg"
9040     * StringUtils.truncate("abcdefg", 8)  = "abcdefg"
9041     * StringUtils.truncate("abcdefg", -1) = throws an IllegalArgumentException
9042     * </pre>
9043     *
9044     * @param str      The String to truncate, may be null.
9045     * @param maxWidth maximum length of result String, must be non-negative.
9046     * @return truncated String, {@code null} if null String input.
9047     * @throws IllegalArgumentException Thrown if {@code maxWidth} is less than {@code 0}.
9048     * @since 3.5
9049     */
9050    public static String truncate(final String str, final int maxWidth) {
9051        return truncate(str, 0, maxWidth);
9052    }
9053
9054    /**
9055     * Truncates a String. This will turn "Now is the time for all good men" into "is the time for all".
9056     *
9057     * <p>
9058     * Works like {@code truncate(String, int)}, but allows you to specify a "left edge" offset.
9059     * </p>
9060     *
9061     * <p>
9062     * Specifically:
9063     * </p>
9064     * <ul>
9065     * <li>If {@code str} is less than {@code maxWidth} characters long, return it.</li>
9066     * <li>Else truncate it to {@code substring(str, offset, maxWidth)}.</li>
9067     * <li>If {@code maxWidth} is less than {@code 0}, throw an {@link IllegalArgumentException}.</li>
9068     * <li>If {@code offset} is less than {@code 0}, throw an {@link IllegalArgumentException}.</li>
9069     * <li>In no case will it return a String of length greater than {@code maxWidth}.</li>
9070     * </ul>
9071     *
9072     * <pre>
9073     * StringUtils.truncate(null, 0, 0) = null
9074     * StringUtils.truncate(null, 2, 4) = null
9075     * StringUtils.truncate("", 0, 10) = ""
9076     * StringUtils.truncate("", 2, 10) = ""
9077     * StringUtils.truncate("abcdefghij", 0, 3) = "abc"
9078     * StringUtils.truncate("abcdefghij", 5, 6) = "fghij"
9079     * StringUtils.truncate("raspberry peach", 10, 15) = "peach"
9080     * StringUtils.truncate("abcdefghijklmno", 0, 10) = "abcdefghij"
9081     * StringUtils.truncate("abcdefghijklmno", -1, 10) = throws an IllegalArgumentException
9082     * StringUtils.truncate("abcdefghijklmno", Integer.MIN_VALUE, 10) = throws an IllegalArgumentException
9083     * StringUtils.truncate("abcdefghijklmno", Integer.MIN_VALUE, Integer.MAX_VALUE) = throws an IllegalArgumentException
9084     * StringUtils.truncate("abcdefghijklmno", 0, Integer.MAX_VALUE) = "abcdefghijklmno"
9085     * StringUtils.truncate("abcdefghijklmno", 1, 10) = "bcdefghijk"
9086     * StringUtils.truncate("abcdefghijklmno", 2, 10) = "cdefghijkl"
9087     * StringUtils.truncate("abcdefghijklmno", 3, 10) = "defghijklm"
9088     * StringUtils.truncate("abcdefghijklmno", 4, 10) = "efghijklmn"
9089     * StringUtils.truncate("abcdefghijklmno", 5, 10) = "fghijklmno"
9090     * StringUtils.truncate("abcdefghijklmno", 5, 5) = "fghij"
9091     * StringUtils.truncate("abcdefghijklmno", 5, 3) = "fgh"
9092     * StringUtils.truncate("abcdefghijklmno", 10, 3) = "klm"
9093     * StringUtils.truncate("abcdefghijklmno", 10, Integer.MAX_VALUE) = "klmno"
9094     * StringUtils.truncate("abcdefghijklmno", 13, 1) = "n"
9095     * StringUtils.truncate("abcdefghijklmno", 13, Integer.MAX_VALUE) = "no"
9096     * StringUtils.truncate("abcdefghijklmno", 14, 1) = "o"
9097     * StringUtils.truncate("abcdefghijklmno", 14, Integer.MAX_VALUE) = "o"
9098     * StringUtils.truncate("abcdefghijklmno", 15, 1) = ""
9099     * StringUtils.truncate("abcdefghijklmno", 15, Integer.MAX_VALUE) = ""
9100     * StringUtils.truncate("abcdefghijklmno", Integer.MAX_VALUE, Integer.MAX_VALUE) = ""
9101     * StringUtils.truncate("abcdefghij", 3, -1) = throws an IllegalArgumentException
9102     * StringUtils.truncate("abcdefghij", -2, 4) = throws an IllegalArgumentException
9103     * </pre>
9104     *
9105     * @param str      The String to truncate, may be null.
9106     * @param offset   left edge of source String.
9107     * @param maxWidth maximum length of result String, must be non-negative.
9108     * @return truncated String, {@code null} if null String input.
9109     * @throws IllegalArgumentException Thrown if {@code offset} or {@code maxWidth} is less than {@code 0}.
9110     * @since 3.5
9111     */
9112    public static String truncate(final String str, final int offset, final int maxWidth) {
9113        if (offset < 0) {
9114            throw new IllegalArgumentException("offset cannot be negative");
9115        }
9116        if (maxWidth < 0) {
9117            throw new IllegalArgumentException("maxWidth cannot be negative");
9118        }
9119        if (str == null) {
9120            return null;
9121        }
9122        final int len = str.length();
9123        int start = Math.min(offset, len);
9124        int end = Math.min(offset > len - maxWidth ? len : offset + maxWidth, len);
9125        // keep both edges off the middle of a surrogate pair so the result is never left holding a lone surrogate
9126        if (splitsSurrogatePair(str, start)) {
9127            start++;
9128        }
9129        if (splitsSurrogatePair(str, end)) {
9130            end--;
9131        }
9132        return str.substring(start, Math.max(start, end));
9133    }
9134
9135    /**
9136     * Uncapitalizes a String, changing the first character to lower case as per {@link Character#toLowerCase(int)}. No other characters are changed.
9137     *
9138     * <p>
9139     * For a word based algorithm, see {@link org.apache.commons.text.WordUtils#uncapitalize(String)}. A {@code null} input String returns {@code null}.
9140     * </p>
9141     *
9142     * <pre>
9143     * StringUtils.uncapitalize(null)  = null
9144     * StringUtils.uncapitalize("")    = ""
9145     * StringUtils.uncapitalize("cat") = "cat"
9146     * StringUtils.uncapitalize("Cat") = "cat"
9147     * StringUtils.uncapitalize("CAT") = "cAT"
9148     * </pre>
9149     *
9150     * @param str The String to uncapitalize, may be null.
9151     * @return The uncapitalized String, {@code null} if null String input.
9152     * @see org.apache.commons.text.WordUtils#uncapitalize(String)
9153     * @see #capitalize(String)
9154     * @since 2.0
9155     */
9156    public static String uncapitalize(final String str) {
9157        final int strLen = length(str);
9158        if (strLen == 0) {
9159            return str;
9160        }
9161        final int firstCodePoint = str.codePointAt(0);
9162        final int newCodePoint = Character.toLowerCase(firstCodePoint);
9163        if (firstCodePoint == newCodePoint) {
9164            // already uncapitalized
9165            return str;
9166        }
9167        final int[] newCodePoints = str.codePoints().toArray();
9168        newCodePoints[0] = newCodePoint; // copy the first code point
9169        return new String(newCodePoints, 0, newCodePoints.length);
9170    }
9171
9172    /**
9173     * Unwraps a given string from a character.
9174     *
9175     * <pre>
9176     * StringUtils.unwrap(null, null)         = null
9177     * StringUtils.unwrap(null, '\0')         = 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("AABabcBAA", 'A')   = "ABabcBA"
9183     * StringUtils.unwrap("A", '#')           = "A"
9184     * StringUtils.unwrap("#A", '#')          = "#A"
9185     * StringUtils.unwrap("A#", '#')          = "A#"
9186     * </pre>
9187     *
9188     * @param str      The String to be unwrapped, can be null.
9189     * @param wrapChar The character used to unwrap.
9190     * @return unwrapped String or the original string if it is not quoted properly with the wrapChar.
9191     * @since 3.6
9192     */
9193    public static String unwrap(final String str, final char wrapChar) {
9194        if (isEmpty(str) || wrapChar == CharUtils.NUL || str.length() == 1) {
9195            return str;
9196        }
9197        if (str.charAt(0) == wrapChar && str.charAt(str.length() - 1) == wrapChar) {
9198            final int startIndex = 0;
9199            final int endIndex = str.length() - 1;
9200            return str.substring(startIndex + 1, endIndex);
9201        }
9202        return str;
9203    }
9204
9205    /**
9206     * Unwraps a given string from another string.
9207     *
9208     * <pre>
9209     * StringUtils.unwrap(null, null)         = null
9210     * StringUtils.unwrap(null, "")           = null
9211     * StringUtils.unwrap(null, "1")          = null
9212     * StringUtils.unwrap("a", "a")           = "a"
9213     * StringUtils.unwrap("aa", "a")          = ""
9214     * StringUtils.unwrap("\'abc\'", "\'")    = "abc"
9215     * StringUtils.unwrap("\"abc\"", "\"")    = "abc"
9216     * StringUtils.unwrap("AABabcBAA", "AA")  = "BabcB"
9217     * StringUtils.unwrap("A", "#")           = "A"
9218     * StringUtils.unwrap("#A", "#")          = "#A"
9219     * StringUtils.unwrap("A#", "#")          = "A#"
9220     * </pre>
9221     *
9222     * @param str       The String to be unwrapped, can be null.
9223     * @param wrapToken The String used to unwrap.
9224     * @return unwrapped String or the original string if it is not quoted properly with the wrapToken.
9225     * @since 3.6
9226     */
9227    public static String unwrap(final String str, final String wrapToken) {
9228        if (isEmpty(str) || isEmpty(wrapToken) || str.length() < 2 * wrapToken.length()) {
9229            return str;
9230        }
9231        if (Strings.CS.startsWith(str, wrapToken) && Strings.CS.endsWith(str, wrapToken)) {
9232            return str.substring(wrapToken.length(), str.lastIndexOf(wrapToken));
9233        }
9234        return str;
9235    }
9236
9237    /**
9238     * Converts a String to upper case as per {@link String#toUpperCase()}.
9239     *
9240     * <p>
9241     * A {@code null} input String returns {@code null}.
9242     * </p>
9243     *
9244     * <pre>
9245     * StringUtils.upperCase(null)  = null
9246     * StringUtils.upperCase("")    = ""
9247     * StringUtils.upperCase("aBc") = "ABC"
9248     * </pre>
9249     *
9250     * <p>
9251     * <strong>Note:</strong> As described in the documentation for {@link String#toUpperCase()}, the result of this method is affected by the current locale.
9252     * For platform-independent case transformations, the method {@link #upperCase(String, Locale)} should be used with a specific locale (e.g.
9253     * {@link Locale#ENGLISH}).
9254     * </p>
9255     *
9256     * @param str The String to upper case, may be null.
9257     * @return The upper-cased String, {@code null} if null String input.
9258     */
9259    public static String upperCase(final String str) {
9260        if (str == null) {
9261            return null;
9262        }
9263        return str.toUpperCase();
9264    }
9265
9266    /**
9267     * Converts a String to upper case as per {@link String#toUpperCase(Locale)}.
9268     *
9269     * <p>
9270     * A {@code null} input String returns {@code null}.
9271     * </p>
9272     *
9273     * <pre>
9274     * StringUtils.upperCase(null, Locale.ENGLISH)  = null
9275     * StringUtils.upperCase("", Locale.ENGLISH)    = ""
9276     * StringUtils.upperCase("aBc", Locale.ENGLISH) = "ABC"
9277     * </pre>
9278     *
9279     * @param str    The String to upper case, may be null.
9280     * @param locale The locale that defines the case transformation rules, must not be null.
9281     * @return The upper-cased String, {@code null} if null String input.
9282     * @since 2.5
9283     */
9284    public static String upperCase(final String str, final Locale locale) {
9285        if (str == null) {
9286            return null;
9287        }
9288        return str.toUpperCase(LocaleUtils.toLocale(locale));
9289    }
9290
9291    /**
9292     * Returns the string representation of the {@code char} array or null.
9293     *
9294     * @param value The character array.
9295     * @return A String or null.
9296     * @see String#valueOf(char[])
9297     * @since 3.9
9298     */
9299    public static String valueOf(final char[] value) {
9300        return value == null ? null : String.valueOf(value);
9301    }
9302
9303    /**
9304     * Wraps a string with a char.
9305     *
9306     * <pre>
9307     * StringUtils.wrap(null, *)        = null
9308     * StringUtils.wrap("", *)          = ""
9309     * StringUtils.wrap("ab", '\0')     = "ab"
9310     * StringUtils.wrap("ab", 'x')      = "xabx"
9311     * StringUtils.wrap("ab", '\'')     = "'ab'"
9312     * StringUtils.wrap("\"ab\"", '\"') = "\"\"ab\"\""
9313     * </pre>
9314     *
9315     * @param str      The string to be wrapped, may be {@code null}.
9316     * @param wrapWith The char that will wrap {@code str}.
9317     * @return The wrapped string, or {@code null} if {@code str == null}.
9318     * @since 3.4
9319     */
9320    public static String wrap(final String str, final char wrapWith) {
9321        if (isEmpty(str) || wrapWith == CharUtils.NUL) {
9322            return str;
9323        }
9324        return wrapWith + str + wrapWith;
9325    }
9326
9327    /**
9328     * Wraps a String with another String.
9329     *
9330     * <p>
9331     * A {@code null} input String returns {@code null}.
9332     * </p>
9333     *
9334     * <pre>
9335     * StringUtils.wrap(null, *)         = null
9336     * StringUtils.wrap("", *)           = ""
9337     * StringUtils.wrap("ab", null)      = "ab"
9338     * StringUtils.wrap("ab", "x")       = "xabx"
9339     * StringUtils.wrap("ab", "\"")      = "\"ab\""
9340     * StringUtils.wrap("\"ab\"", "\"")  = "\"\"ab\"\""
9341     * StringUtils.wrap("ab", "'")       = "'ab'"
9342     * StringUtils.wrap("'abcd'", "'")   = "''abcd''"
9343     * StringUtils.wrap("\"abcd\"", "'") = "'\"abcd\"'"
9344     * StringUtils.wrap("'abcd'", "\"")  = "\"'abcd'\""
9345     * </pre>
9346     *
9347     * @param str      The String to be wrapper, may be null.
9348     * @param wrapWith The String that will wrap str.
9349     * @return wrapped String, {@code null} if null String input.
9350     * @since 3.4
9351     */
9352    public static String wrap(final String str, final String wrapWith) {
9353        if (isEmpty(str) || isEmpty(wrapWith)) {
9354            return str;
9355        }
9356        return wrapWith.concat(str).concat(wrapWith);
9357    }
9358
9359    /**
9360     * Wraps a string with a char if that char is missing from the start or end of the given string.
9361     *
9362     * <p>
9363     * A new {@link String} will not be created if {@code str} is already wrapped.
9364     * </p>
9365     *
9366     * <pre>
9367     * StringUtils.wrapIfMissing(null, *)        = null
9368     * StringUtils.wrapIfMissing("", *)          = ""
9369     * StringUtils.wrapIfMissing("ab", '\0')     = "ab"
9370     * StringUtils.wrapIfMissing("ab", 'x')      = "xabx"
9371     * StringUtils.wrapIfMissing("ab", '\'')     = "'ab'"
9372     * StringUtils.wrapIfMissing("\"ab\"", '\"') = "\"ab\""
9373     * StringUtils.wrapIfMissing("/", '/')  = "/"
9374     * StringUtils.wrapIfMissing("a/b/c", '/')  = "/a/b/c/"
9375     * StringUtils.wrapIfMissing("/a/b/c", '/')  = "/a/b/c/"
9376     * StringUtils.wrapIfMissing("a/b/c/", '/')  = "/a/b/c/"
9377     * </pre>
9378     *
9379     * @param str      The string to be wrapped, may be {@code null}.
9380     * @param wrapWith The char that will wrap {@code str}.
9381     * @return The wrapped string, or {@code null} if {@code str == null}.
9382     * @since 3.5
9383     */
9384    public static String wrapIfMissing(final String str, final char wrapWith) {
9385        if (isEmpty(str) || wrapWith == CharUtils.NUL) {
9386            return str;
9387        }
9388        final boolean wrapStart = str.charAt(0) != wrapWith;
9389        final boolean wrapEnd = str.charAt(str.length() - 1) != wrapWith;
9390        if (!wrapStart && !wrapEnd) {
9391            return str;
9392        }
9393        final StringBuilder builder = new StringBuilder(str.length() + 2);
9394        if (wrapStart) {
9395            builder.append(wrapWith);
9396        }
9397        builder.append(str);
9398        if (wrapEnd) {
9399            builder.append(wrapWith);
9400        }
9401        return builder.toString();
9402    }
9403
9404    /**
9405     * Wraps a string with a string if that string is missing from the start or end of the given string.
9406     *
9407     * <p>
9408     * A new {@link String} will not be created if {@code str} is already wrapped.
9409     * </p>
9410     *
9411     * <pre>
9412     * StringUtils.wrapIfMissing(null, *)         = null
9413     * StringUtils.wrapIfMissing("", *)           = ""
9414     * StringUtils.wrapIfMissing("ab", null)      = "ab"
9415     * StringUtils.wrapIfMissing("ab", "x")       = "xabx"
9416     * StringUtils.wrapIfMissing("ab", "\"")      = "\"ab\""
9417     * StringUtils.wrapIfMissing("\"ab\"", "\"")  = "\"ab\""
9418     * StringUtils.wrapIfMissing("ab", "'")       = "'ab'"
9419     * StringUtils.wrapIfMissing("'abcd'", "'")   = "'abcd'"
9420     * StringUtils.wrapIfMissing("\"abcd\"", "'") = "'\"abcd\"'"
9421     * StringUtils.wrapIfMissing("'abcd'", "\"")  = "\"'abcd'\""
9422     * StringUtils.wrapIfMissing("/", "/")  = "/"
9423     * StringUtils.wrapIfMissing("a/b/c", "/")  = "/a/b/c/"
9424     * StringUtils.wrapIfMissing("/a/b/c", "/")  = "/a/b/c/"
9425     * StringUtils.wrapIfMissing("a/b/c/", "/")  = "/a/b/c/"
9426     * </pre>
9427     *
9428     * @param str      The string to be wrapped, may be {@code null}.
9429     * @param wrapWith The string that will wrap {@code str}.
9430     * @return The wrapped string, or {@code null} if {@code str == null}.
9431     * @since 3.5
9432     */
9433    public static String wrapIfMissing(final String str, final String wrapWith) {
9434        if (isEmpty(str) || isEmpty(wrapWith)) {
9435            return str;
9436        }
9437        final boolean wrapStart = !str.startsWith(wrapWith);
9438        final boolean wrapEnd = !str.endsWith(wrapWith);
9439        if (!wrapStart && !wrapEnd) {
9440            return str;
9441        }
9442        final StringBuilder builder = new StringBuilder(str.length() + wrapWith.length() + wrapWith.length());
9443        if (wrapStart) {
9444            builder.append(wrapWith);
9445        }
9446        builder.append(str);
9447        if (wrapEnd) {
9448            builder.append(wrapWith);
9449        }
9450        return builder.toString();
9451    }
9452
9453    /**
9454     * {@link StringUtils} instances should NOT be constructed in standard programming. Instead, the class should be used as {@code StringUtils.trim(" foo ");}.
9455     *
9456     * <p>
9457     * This constructor is public to permit tools that require a JavaBean instance to operate.
9458     * </p>
9459     *
9460     * @deprecated TODO Make private in 4.0.
9461     */
9462    @Deprecated
9463    public StringUtils() {
9464        // empty
9465    }
9466
9467}