001/*
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements.  See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License.  You may obtain a copy of the License at
008 *
009 *      https://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017package org.apache.commons.lang3;
018
019import java.io.UnsupportedEncodingException;
020import java.nio.CharBuffer;
021import java.nio.charset.Charset;
022import java.text.Normalizer;
023import java.util.ArrayList;
024import java.util.Arrays;
025import java.util.Iterator;
026import java.util.List;
027import java.util.Locale;
028import java.util.Objects;
029import java.util.Set;
030import java.util.function.Supplier;
031import java.util.regex.Pattern;
032import java.util.stream.Collectors;
033
034import org.apache.commons.lang3.function.Suppliers;
035import org.apache.commons.lang3.stream.LangCollectors;
036import org.apache.commons.lang3.stream.Streams;
037
038/**
039 * Operations on {@link String} that are
040 * {@code null} safe.
041 *
042 * <ul>
043 *  <li><strong>IsEmpty/IsBlank</strong>
044 *      - checks if a String contains text</li>
045 *  <li><strong>Trim/Strip</strong>
046 *      - removes leading and trailing whitespace</li>
047 *  <li><strong>Equals/Compare</strong>
048 *      - compares two strings in a null-safe manner</li>
049 *  <li><strong>startsWith</strong>
050 *      - check if a String starts with a prefix in a null-safe manner</li>
051 *  <li><strong>endsWith</strong>
052 *      - check if a String ends with a suffix in a null-safe manner</li>
053 *  <li><strong>IndexOf/LastIndexOf/Contains</strong>
054 *      - null-safe index-of checks
055 *  <li><strong>IndexOfAny/LastIndexOfAny/IndexOfAnyBut/LastIndexOfAnyBut</strong>
056 *      - index-of any of a set of Strings</li>
057 *  <li><strong>ContainsOnly/ContainsNone/ContainsAny</strong>
058 *      - checks if String contains only/none/any of these characters</li>
059 *  <li><strong>Substring/Left/Right/Mid</strong>
060 *      - null-safe substring extractions</li>
061 *  <li><strong>SubstringBefore/SubstringAfter/SubstringBetween</strong>
062 *      - substring extraction relative to other strings</li>
063 *  <li><strong>Split/Join</strong>
064 *      - splits a String into an array of substrings and vice versa</li>
065 *  <li><strong>Remove/Delete</strong>
066 *      - removes part of a String</li>
067 *  <li><strong>Replace/Overlay</strong>
068 *      - Searches a String and replaces one String with another</li>
069 *  <li><strong>Chomp/Chop</strong>
070 *      - removes the last part of a String</li>
071 *  <li><strong>AppendIfMissing</strong>
072 *      - appends a suffix to the end of the String if not present</li>
073 *  <li><strong>PrependIfMissing</strong>
074 *      - prepends a prefix to the start of the String if not present</li>
075 *  <li><strong>LeftPad/RightPad/Center/Repeat</strong>
076 *      - pads a String</li>
077 *  <li><strong>UpperCase/LowerCase/SwapCase/Capitalize/Uncapitalize</strong>
078 *      - changes the case of a String</li>
079 *  <li><strong>CountMatches</strong>
080 *      - counts the number of occurrences of one String in another</li>
081 *  <li><strong>IsAlpha/IsNumeric/IsWhitespace/IsAsciiPrintable</strong>
082 *      - checks the characters in a String</li>
083 *  <li><strong>DefaultString</strong>
084 *      - protects against a null input String</li>
085 *  <li><strong>Rotate</strong>
086 *      - rotate (circular shift) a String</li>
087 *  <li><strong>Reverse/ReverseDelimited</strong>
088 *      - reverses a String</li>
089 *  <li><strong>Abbreviate</strong>
090 *      - abbreviates a string using ellipses or another given String</li>
091 *  <li><strong>Difference</strong>
092 *      - compares Strings and reports on their differences</li>
093 *  <li><strong>LevenshteinDistance</strong>
094 *      - the number of changes needed to change one String into another</li>
095 * </ul>
096 *
097 * <p>The {@link StringUtils} class defines certain words related to
098 * String handling.</p>
099 *
100 * <ul>
101 *  <li>null - {@code null}</li>
102 *  <li>empty - a zero-length string ({@code ""})</li>
103 *  <li>space - the space character ({@code ' '}, char 32)</li>
104 *  <li>whitespace - the characters defined by {@link Character#isWhitespace(char)}</li>
105 *  <li>trim - the characters &lt;= 32 as in {@link String#trim()}</li>
106 * </ul>
107 *
108 * <p>{@link StringUtils} handles {@code null} input Strings quietly.
109 * That is to say that a {@code null} input will return {@code null}.
110 * Where a {@code boolean} or {@code int} is being returned
111 * details vary by method.</p>
112 *
113 * <p>A side effect of the {@code null} handling is that a
114 * {@link NullPointerException} should be considered a bug in
115 * {@link StringUtils}.</p>
116 *
117 * <p>Methods in this class include sample code in their Javadoc comments to explain their operation.
118 * The symbol {@code *} is used to indicate any input including {@code null}.</p>
119 *
120 * <p>#ThreadSafe#</p>
121 * @see String
122 * @since 1.0
123 */
124//@Immutable
125public class StringUtils {
126
127    // Performance testing notes (JDK 1.4, Jul03, scolebourne)
128    // Whitespace:
129    // Character.isWhitespace() is faster than WHITESPACE.indexOf()
130    // where WHITESPACE is a string of all whitespace characters
131    //
132    // Character access:
133    // String.charAt(n) versus toCharArray(), then array[n]
134    // String.charAt(n) is about 15% worse for a 10K string
135    // They are about equal for a length 50 string
136    // String.charAt(n) is about 4 times better for a length 3 string
137    // String.charAt(n) is best bet overall
138    //
139    // Append:
140    // String.concat about twice as fast as StringBuffer.append
141    // (not sure who tested this)
142
143    /**
144     * A String for a space character.
145     *
146     * @since 3.2
147     */
148    public static final String SPACE = " ";
149
150    /**
151     * The empty String {@code ""}.
152     * @since 2.0
153     */
154    public static final String EMPTY = "";
155
156    /**
157     * A String for linefeed LF ("\n").
158     *
159     * @see <a href="https://docs.oracle.com/javase/specs/jls/se8/html/jls-3.html#jls-3.10.6">JLF: Escape Sequences
160     *      for Character and String Literals</a>
161     * @since 3.2
162     */
163    public static final String LF = "\n";
164
165    /**
166     * A String for carriage return CR ("\r").
167     *
168     * @see <a href="https://docs.oracle.com/javase/specs/jls/se8/html/jls-3.html#jls-3.10.6">JLF: Escape Sequences
169     *      for Character and String Literals</a>
170     * @since 3.2
171     */
172    public static final String CR = "\r";
173
174    /**
175     * Represents a failed index search.
176     * @since 2.1
177     */
178    public static final int INDEX_NOT_FOUND = -1;
179
180    /**
181     * The maximum size to which the padding constant(s) can expand.
182     */
183    private static final int PAD_LIMIT = 8192;
184
185    /**
186     * The default maximum depth at which recursive replacement will continue until no further search replacements are possible.
187     */
188    private static final int DEFAULT_TTL = 5;
189
190    /**
191     * Pattern used in {@link #stripAccents(String)}.
192     */
193    private static final Pattern STRIP_ACCENTS_PATTERN = Pattern.compile("\\p{InCombiningDiacriticalMarks}+"); //$NON-NLS-1$
194
195    /**
196     * Abbreviates a String using ellipses. This will turn
197     * "Now is the time for all good men" into "Now is the time for..."
198     *
199     * <p>Specifically:</p>
200     * <ul>
201     *   <li>If the number of characters in {@code str} is less than or equal to
202     *       {@code maxWidth}, return {@code str}.</li>
203     *   <li>Else abbreviate it to {@code (substring(str, 0, max-3) + "...")}.</li>
204     *   <li>If {@code maxWidth} is less than {@code 4}, throw an
205     *       {@link IllegalArgumentException}.</li>
206     *   <li>In no case will it return a String of length greater than
207     *       {@code maxWidth}.</li>
208     * </ul>
209     *
210     * <pre>
211     * StringUtils.abbreviate(null, *)      = null
212     * StringUtils.abbreviate("", 4)        = ""
213     * StringUtils.abbreviate("abcdefg", 6) = "abc..."
214     * StringUtils.abbreviate("abcdefg", 7) = "abcdefg"
215     * StringUtils.abbreviate("abcdefg", 8) = "abcdefg"
216     * StringUtils.abbreviate("abcdefg", 4) = "a..."
217     * StringUtils.abbreviate("abcdefg", 3) = IllegalArgumentException
218     * </pre>
219     *
220     * @param str  the String to check, may be null
221     * @param maxWidth  maximum length of result String, must be at least 4
222     * @return abbreviated String, {@code null} if null String input
223     * @throws IllegalArgumentException if the width is too small
224     * @since 2.0
225     */
226    public static String abbreviate(final String str, final int maxWidth) {
227        return abbreviate(str, "...", 0, maxWidth);
228    }
229
230    /**
231     * Abbreviates a String using ellipses. This will turn
232     * "Now is the time for all good men" into "...is the time for..."
233     *
234     * <p>Works like {@code abbreviate(String, int)}, but allows you to specify
235     * a "left edge" offset.  Note that this left edge is not necessarily going to
236     * be the leftmost character in the result, or the first character following the
237     * ellipses, but it will appear somewhere in the result.
238     *
239     * <p>In no case will it return a String of length greater than
240     * {@code maxWidth}.</p>
241     *
242     * <pre>
243     * StringUtils.abbreviate(null, *, *)                = null
244     * StringUtils.abbreviate("", 0, 4)                  = ""
245     * StringUtils.abbreviate("abcdefghijklmno", -1, 10) = "abcdefg..."
246     * StringUtils.abbreviate("abcdefghijklmno", 0, 10)  = "abcdefg..."
247     * StringUtils.abbreviate("abcdefghijklmno", 1, 10)  = "abcdefg..."
248     * StringUtils.abbreviate("abcdefghijklmno", 4, 10)  = "abcdefg..."
249     * StringUtils.abbreviate("abcdefghijklmno", 5, 10)  = "...fghi..."
250     * StringUtils.abbreviate("abcdefghijklmno", 6, 10)  = "...ghij..."
251     * StringUtils.abbreviate("abcdefghijklmno", 8, 10)  = "...ijklmno"
252     * StringUtils.abbreviate("abcdefghijklmno", 10, 10) = "...ijklmno"
253     * StringUtils.abbreviate("abcdefghijklmno", 12, 10) = "...ijklmno"
254     * StringUtils.abbreviate("abcdefghij", 0, 3)        = IllegalArgumentException
255     * StringUtils.abbreviate("abcdefghij", 5, 6)        = IllegalArgumentException
256     * </pre>
257     *
258     * @param str  the String to check, may be null
259     * @param offset  left edge of source String
260     * @param maxWidth  maximum length of result String, must be at least 4
261     * @return abbreviated String, {@code null} if null String input
262     * @throws IllegalArgumentException if the width is too small
263     * @since 2.0
264     */
265    public static String abbreviate(final String str, final int offset, final int maxWidth) {
266        return abbreviate(str, "...", offset, maxWidth);
267    }
268
269    /**
270     * Abbreviates a String using another given String as replacement marker. This will turn
271     * "Now is the time for all good men" into "Now is the time for..." if "..." was defined
272     * as the replacement marker.
273     *
274     * <p>Specifically:</p>
275     * <ul>
276     *   <li>If the number of characters in {@code str} is less than or equal to
277     *       {@code maxWidth}, return {@code str}.</li>
278     *   <li>Else abbreviate it to {@code (substring(str, 0, max-abbrevMarker.length) + abbrevMarker)}.</li>
279     *   <li>If {@code maxWidth} is less than {@code abbrevMarker.length + 1}, throw an
280     *       {@link IllegalArgumentException}.</li>
281     *   <li>In no case will it return a String of length greater than
282     *       {@code maxWidth}.</li>
283     * </ul>
284     *
285     * <pre>
286     * StringUtils.abbreviate(null, "...", *)      = null
287     * StringUtils.abbreviate("abcdefg", null, *)  = "abcdefg"
288     * StringUtils.abbreviate("", "...", 4)        = ""
289     * StringUtils.abbreviate("abcdefg", ".", 5)   = "abcd."
290     * StringUtils.abbreviate("abcdefg", ".", 7)   = "abcdefg"
291     * StringUtils.abbreviate("abcdefg", ".", 8)   = "abcdefg"
292     * StringUtils.abbreviate("abcdefg", "..", 4)  = "ab.."
293     * StringUtils.abbreviate("abcdefg", "..", 3)  = "a.."
294     * StringUtils.abbreviate("abcdefg", "..", 2)  = IllegalArgumentException
295     * StringUtils.abbreviate("abcdefg", "...", 3) = IllegalArgumentException
296     * </pre>
297     *
298     * @param str  the String to check, may be null
299     * @param abbrevMarker  the String used as replacement marker
300     * @param maxWidth  maximum length of result String, must be at least {@code abbrevMarker.length + 1}
301     * @return abbreviated String, {@code null} if null String input
302     * @throws IllegalArgumentException if the width is too small
303     * @since 3.6
304     */
305    public static String abbreviate(final String str, final String abbrevMarker, final int maxWidth) {
306        return abbreviate(str, abbrevMarker, 0, maxWidth);
307    }
308    /**
309     * Abbreviates a String using a given replacement marker. This will turn
310     * "Now is the time for all good men" into "...is the time for..." if "..." was defined
311     * as the replacement marker.
312     *
313     * <p>Works like {@code abbreviate(String, String, int)}, but allows you to specify
314     * a "left edge" offset.  Note that this left edge is not necessarily going to
315     * be the leftmost character in the result, or the first character following the
316     * replacement marker, but it will appear somewhere in the result.
317     *
318     * <p>In no case will it return a String of length greater than {@code maxWidth}.</p>
319     *
320     * <pre>
321     * StringUtils.abbreviate(null, null, *, *)                 = null
322     * StringUtils.abbreviate("abcdefghijklmno", null, *, *)    = "abcdefghijklmno"
323     * StringUtils.abbreviate("", "...", 0, 4)                  = ""
324     * StringUtils.abbreviate("abcdefghijklmno", "---", -1, 10) = "abcdefg---"
325     * StringUtils.abbreviate("abcdefghijklmno", ",", 0, 10)    = "abcdefghi,"
326     * StringUtils.abbreviate("abcdefghijklmno", ",", 1, 10)    = "abcdefghi,"
327     * StringUtils.abbreviate("abcdefghijklmno", ",", 2, 10)    = "abcdefghi,"
328     * StringUtils.abbreviate("abcdefghijklmno", "::", 4, 10)   = "::efghij::"
329     * StringUtils.abbreviate("abcdefghijklmno", "...", 6, 10)  = "...ghij..."
330     * StringUtils.abbreviate("abcdefghijklmno", "*", 9, 10)    = "*ghijklmno"
331     * StringUtils.abbreviate("abcdefghijklmno", "'", 10, 10)   = "'ghijklmno"
332     * StringUtils.abbreviate("abcdefghijklmno", "!", 12, 10)   = "!ghijklmno"
333     * StringUtils.abbreviate("abcdefghij", "abra", 0, 4)       = IllegalArgumentException
334     * StringUtils.abbreviate("abcdefghij", "...", 5, 6)        = IllegalArgumentException
335     * </pre>
336     *
337     * @param str  the String to check, may be null
338     * @param abbrevMarker  the String used as replacement marker
339     * @param offset  left edge of source String
340     * @param maxWidth  maximum length of result String, must be at least 4
341     * @return abbreviated String, {@code null} if null String input
342     * @throws IllegalArgumentException if the width is too small
343     * @since 3.6
344     */
345    public static String abbreviate(final String str, final String abbrevMarker, int offset, final int maxWidth) {
346        if (isNotEmpty(str) && EMPTY.equals(abbrevMarker) && maxWidth > 0) {
347            return substring(str, 0, maxWidth);
348        }
349        if (isAnyEmpty(str, abbrevMarker)) {
350            return str;
351        }
352        final int abbrevMarkerLength = abbrevMarker.length();
353        final int minAbbrevWidth = abbrevMarkerLength + 1;
354        final int minAbbrevWidthOffset = abbrevMarkerLength + abbrevMarkerLength + 1;
355
356        if (maxWidth < minAbbrevWidth) {
357            throw new IllegalArgumentException(String.format("Minimum abbreviation width is %d", minAbbrevWidth));
358        }
359        final int strLen = str.length();
360        if (strLen <= maxWidth) {
361            return str;
362        }
363        if (offset > strLen) {
364            offset = strLen;
365        }
366        if (strLen - offset < maxWidth - abbrevMarkerLength) {
367            offset = strLen - (maxWidth - abbrevMarkerLength);
368        }
369        if (offset <= abbrevMarkerLength + 1) {
370            return str.substring(0, maxWidth - abbrevMarkerLength) + abbrevMarker;
371        }
372        if (maxWidth < minAbbrevWidthOffset) {
373            throw new IllegalArgumentException(String.format("Minimum abbreviation width with offset is %d", minAbbrevWidthOffset));
374        }
375        if (offset + maxWidth - abbrevMarkerLength < strLen) {
376            return abbrevMarker + abbreviate(str.substring(offset), abbrevMarker, maxWidth - abbrevMarkerLength);
377        }
378        return abbrevMarker + str.substring(strLen - (maxWidth - abbrevMarkerLength));
379    }
380
381    /**
382     * Abbreviates a String to the length passed, replacing the middle characters with the supplied
383     * replacement String.
384     *
385     * <p>This abbreviation only occurs if the following criteria is met:</p>
386     * <ul>
387     * <li>Neither the String for abbreviation nor the replacement String are null or empty </li>
388     * <li>The length to truncate to is less than the length of the supplied String</li>
389     * <li>The length to truncate to is greater than 0</li>
390     * <li>The abbreviated String will have enough room for the length supplied replacement String
391     * and the first and last characters of the supplied String for abbreviation</li>
392     * </ul>
393     * <p>Otherwise, the returned String will be the same as the supplied String for abbreviation.
394     * </p>
395     *
396     * <pre>
397     * StringUtils.abbreviateMiddle(null, null, 0)    = null
398     * StringUtils.abbreviateMiddle("abc", null, 0)   = "abc"
399     * StringUtils.abbreviateMiddle("abc", ".", 0)    = "abc"
400     * StringUtils.abbreviateMiddle("abc", ".", 3)    = "abc"
401     * StringUtils.abbreviateMiddle("abcdef", ".", 4) = "ab.f"
402     * </pre>
403     *
404     * @param str  the String to abbreviate, may be null
405     * @param middle the String to replace the middle characters with, may be null
406     * @param length the length to abbreviate {@code str} to.
407     * @return the abbreviated String if the above criteria is met, or the original String supplied for abbreviation.
408     * @since 2.5
409     */
410    public static String abbreviateMiddle(final String str, final String middle, final int length) {
411        if (isAnyEmpty(str, middle) || length >= str.length() || length < middle.length() + 2) {
412            return str;
413        }
414        final int targetSting = length - middle.length();
415        final int startOffset = targetSting / 2 + targetSting % 2;
416        final int endOffset = str.length() - targetSting / 2;
417        return str.substring(0, startOffset) + middle + str.substring(endOffset);
418    }
419
420    /**
421     * Appends the suffix to the end of the string if the string does not already end with any of the suffixes.
422     *
423     * <pre>
424     * StringUtils.appendIfMissing(null, null)      = null
425     * StringUtils.appendIfMissing("abc", null)     = "abc"
426     * StringUtils.appendIfMissing("", "xyz"        = "xyz"
427     * StringUtils.appendIfMissing("abc", "xyz")    = "abcxyz"
428     * StringUtils.appendIfMissing("abcxyz", "xyz") = "abcxyz"
429     * StringUtils.appendIfMissing("abcXYZ", "xyz") = "abcXYZxyz"
430     * </pre>
431     * <p>
432     * With additional suffixes,
433     * </p>
434     *
435     * <pre>
436     * StringUtils.appendIfMissing(null, null, null)       = null
437     * StringUtils.appendIfMissing("abc", null, null)      = "abc"
438     * StringUtils.appendIfMissing("", "xyz", null)        = "xyz"
439     * StringUtils.appendIfMissing("abc", "xyz", new CharSequence[]{null}) = "abcxyz"
440     * StringUtils.appendIfMissing("abc", "xyz", "")       = "abc"
441     * StringUtils.appendIfMissing("abc", "xyz", "mno")    = "abcxyz"
442     * StringUtils.appendIfMissing("abcxyz", "xyz", "mno") = "abcxyz"
443     * StringUtils.appendIfMissing("abcmno", "xyz", "mno") = "abcmno"
444     * StringUtils.appendIfMissing("abcXYZ", "xyz", "mno") = "abcXYZxyz"
445     * StringUtils.appendIfMissing("abcMNO", "xyz", "mno") = "abcMNOxyz"
446     * </pre>
447     *
448     * @param str      The string.
449     * @param suffix   The suffix to append to the end of the string.
450     * @param suffixes Additional suffixes that are valid terminators.
451     * @return A new String if suffix was appended, the same string otherwise.
452     * @since 3.2
453     * @deprecated Use {@link Strings#appendIfMissing(String, CharSequence, CharSequence...) Strings.CS.appendIfMissing(String, CharSequence, CharSequence...)}
454     */
455    @Deprecated
456    public static String appendIfMissing(final String str, final CharSequence suffix, final CharSequence... suffixes) {
457        return Strings.CS.appendIfMissing(str, suffix, suffixes);
458    }
459
460    /**
461     * Appends the suffix to the end of the string if the string does not
462     * already end, case-insensitive, with any of the suffixes.
463     *
464     * <pre>
465     * StringUtils.appendIfMissingIgnoreCase(null, null)      = null
466     * StringUtils.appendIfMissingIgnoreCase("abc", null)     = "abc"
467     * StringUtils.appendIfMissingIgnoreCase("", "xyz")       = "xyz"
468     * StringUtils.appendIfMissingIgnoreCase("abc", "xyz")    = "abcxyz"
469     * StringUtils.appendIfMissingIgnoreCase("abcxyz", "xyz") = "abcxyz"
470     * StringUtils.appendIfMissingIgnoreCase("abcXYZ", "xyz") = "abcXYZ"
471     * </pre>
472     * <p>With additional suffixes,</p>
473     * <pre>
474     * StringUtils.appendIfMissingIgnoreCase(null, null, null)       = null
475     * StringUtils.appendIfMissingIgnoreCase("abc", null, null)      = "abc"
476     * StringUtils.appendIfMissingIgnoreCase("", "xyz", null)        = "xyz"
477     * StringUtils.appendIfMissingIgnoreCase("abc", "xyz", new CharSequence[]{null}) = "abcxyz"
478     * StringUtils.appendIfMissingIgnoreCase("abc", "xyz", "")       = "abc"
479     * StringUtils.appendIfMissingIgnoreCase("abc", "xyz", "mno")    = "abcxyz"
480     * StringUtils.appendIfMissingIgnoreCase("abcxyz", "xyz", "mno") = "abcxyz"
481     * StringUtils.appendIfMissingIgnoreCase("abcmno", "xyz", "mno") = "abcmno"
482     * StringUtils.appendIfMissingIgnoreCase("abcXYZ", "xyz", "mno") = "abcXYZ"
483     * StringUtils.appendIfMissingIgnoreCase("abcMNO", "xyz", "mno") = "abcMNO"
484     * </pre>
485     *
486     * @param str The string.
487     * @param suffix The suffix to append to the end of the string.
488     * @param suffixes Additional suffixes that are valid terminators.
489     * @return A new String if suffix was appended, the same string otherwise.
490     * @since 3.2
491     * @deprecated Use {@link Strings#appendIfMissing(String, CharSequence, CharSequence...) Strings.CI.appendIfMissing(String, CharSequence, CharSequence...)}
492     */
493    @Deprecated
494    public static String appendIfMissingIgnoreCase(final String str, final CharSequence suffix, final CharSequence... suffixes) {
495        return Strings.CI.appendIfMissing(str, suffix, suffixes);
496    }
497
498    /**
499     * Capitalizes a String changing the first character to title case as
500     * per {@link Character#toTitleCase(int)}. No other characters are changed.
501     *
502     * <p>For a word based algorithm, see {@link org.apache.commons.text.WordUtils#capitalize(String)}.
503     * A {@code null} input String returns {@code null}.</p>
504     *
505     * <pre>
506     * StringUtils.capitalize(null)    = null
507     * StringUtils.capitalize("")      = ""
508     * StringUtils.capitalize("cat")   = "Cat"
509     * StringUtils.capitalize("cAt")   = "CAt"
510     * StringUtils.capitalize("'cat'") = "'cat'"
511     * </pre>
512     *
513     * @param str the String to capitalize, may be null
514     * @return the capitalized String, {@code null} if null String input
515     * @see org.apache.commons.text.WordUtils#capitalize(String)
516     * @see #uncapitalize(String)
517     * @since 2.0
518     */
519    public static String capitalize(final String str) {
520        if (isEmpty(str)) {
521            return str;
522        }
523        final int firstCodepoint = str.codePointAt(0);
524        final int newCodePoint = Character.toTitleCase(firstCodepoint);
525        if (firstCodepoint == newCodePoint) {
526            // already capitalized
527            return str;
528        }
529        final int[] newCodePoints = str.codePoints().toArray();
530        newCodePoints[0] = newCodePoint; // copy the first code point
531        return new String(newCodePoints, 0, newCodePoints.length);
532    }
533
534    /**
535     * Centers a String in a larger String of size {@code size}
536     * using the space character (' ').
537     *
538     * <p>If the size is less than the String length, the original String is returned.
539     * A {@code null} String returns {@code null}.
540     * A negative size is treated as zero.</p>
541     *
542     * <p>Equivalent to {@code center(str, size, " ")}.</p>
543     *
544     * <pre>
545     * StringUtils.center(null, *)   = null
546     * StringUtils.center("", 4)     = "    "
547     * StringUtils.center("ab", -1)  = "ab"
548     * StringUtils.center("ab", 4)   = " ab "
549     * StringUtils.center("abcd", 2) = "abcd"
550     * StringUtils.center("a", 4)    = " a  "
551     * </pre>
552     *
553     * @param str  the String to center, may be null
554     * @param size  the int size of new String, negative treated as zero
555     * @return centered String, {@code null} if null String input
556     */
557    public static String center(final String str, final int size) {
558        return center(str, size, ' ');
559    }
560
561    /**
562     * Centers a String in a larger String of size {@code size}.
563     * Uses a supplied character as the value to pad the String with.
564     *
565     * <p>If the size is less than the String length, the String is returned.
566     * A {@code null} String returns {@code null}.
567     * A negative size is treated as zero.</p>
568     *
569     * <pre>
570     * StringUtils.center(null, *, *)     = null
571     * StringUtils.center("", 4, ' ')     = "    "
572     * StringUtils.center("ab", -1, ' ')  = "ab"
573     * StringUtils.center("ab", 4, ' ')   = " ab "
574     * StringUtils.center("abcd", 2, ' ') = "abcd"
575     * StringUtils.center("a", 4, ' ')    = " a  "
576     * StringUtils.center("a", 4, 'y')    = "yayy"
577     * </pre>
578     *
579     * @param str  the String to center, may be null
580     * @param size  the int size of new String, negative treated as zero
581     * @param padChar  the character to pad the new String with
582     * @return centered String, {@code null} if null String input
583     * @since 2.0
584     */
585    public static String center(String str, final int size, final char padChar) {
586        if (str == null || size <= 0) {
587            return str;
588        }
589        final int strLen = str.length();
590        final int pads = size - strLen;
591        if (pads <= 0) {
592            return str;
593        }
594        str = leftPad(str, strLen + pads / 2, padChar);
595        return rightPad(str, size, padChar);
596    }
597
598    /**
599     * Centers a String in a larger String of size {@code size}.
600     * Uses a supplied String as the value to pad the String with.
601     *
602     * <p>If the size is less than the String length, the String is returned.
603     * A {@code null} String returns {@code null}.
604     * A negative size is treated as zero.</p>
605     *
606     * <pre>
607     * StringUtils.center(null, *, *)     = null
608     * StringUtils.center("", 4, " ")     = "    "
609     * StringUtils.center("ab", -1, " ")  = "ab"
610     * StringUtils.center("ab", 4, " ")   = " ab "
611     * StringUtils.center("abcd", 2, " ") = "abcd"
612     * StringUtils.center("a", 4, " ")    = " a  "
613     * StringUtils.center("a", 4, "yz")   = "yayz"
614     * StringUtils.center("abc", 7, null) = "  abc  "
615     * StringUtils.center("abc", 7, "")   = "  abc  "
616     * </pre>
617     *
618     * @param str  the String to center, may be null
619     * @param size  the int size of new String, negative treated as zero
620     * @param padStr  the String to pad the new String with, must not be null or empty
621     * @return centered String, {@code null} if null String input
622     * @throws IllegalArgumentException if padStr is {@code null} or empty
623     */
624    public static String center(String str, final int size, String padStr) {
625        if (str == null || size <= 0) {
626            return str;
627        }
628        if (isEmpty(padStr)) {
629            padStr = SPACE;
630        }
631        final int strLen = str.length();
632        final int pads = size - strLen;
633        if (pads <= 0) {
634            return str;
635        }
636        str = leftPad(str, strLen + pads / 2, padStr);
637        return rightPad(str, size, padStr);
638    }
639
640    /**
641     * Removes one newline from end of a String if it's there,
642     * otherwise leave it alone.  A newline is &quot;{@code \n}&quot;,
643     * &quot;{@code \r}&quot;, or &quot;{@code \r\n}&quot;.
644     *
645     * <p>NOTE: This method changed in 2.0.
646     * It now more closely matches Perl chomp.</p>
647     *
648     * <pre>
649     * StringUtils.chomp(null)          = null
650     * StringUtils.chomp("")            = ""
651     * StringUtils.chomp("abc \r")      = "abc "
652     * StringUtils.chomp("abc\n")       = "abc"
653     * StringUtils.chomp("abc\r\n")     = "abc"
654     * StringUtils.chomp("abc\r\n\r\n") = "abc\r\n"
655     * StringUtils.chomp("abc\n\r")     = "abc\n"
656     * StringUtils.chomp("abc\n\rabc")  = "abc\n\rabc"
657     * StringUtils.chomp("\r")          = ""
658     * StringUtils.chomp("\n")          = ""
659     * StringUtils.chomp("\r\n")        = ""
660     * </pre>
661     *
662     * @param str  the String to chomp a newline from, may be null
663     * @return String without newline, {@code null} if null String input
664     */
665    public static String chomp(final String str) {
666        if (isEmpty(str)) {
667            return str;
668        }
669
670        if (str.length() == 1) {
671            final char ch = str.charAt(0);
672            if (ch == CharUtils.CR || ch == CharUtils.LF) {
673                return EMPTY;
674            }
675            return str;
676        }
677
678        int lastIdx = str.length() - 1;
679        final char last = str.charAt(lastIdx);
680
681        if (last == CharUtils.LF) {
682            if (str.charAt(lastIdx - 1) == CharUtils.CR) {
683                lastIdx--;
684            }
685        } else if (last != CharUtils.CR) {
686            lastIdx++;
687        }
688        return str.substring(0, lastIdx);
689    }
690
691    /**
692     * Removes {@code separator} from the end of
693     * {@code str} if it's there, otherwise leave it alone.
694     *
695     * <p>NOTE: This method changed in version 2.0.
696     * It now more closely matches Perl chomp.
697     * For the previous behavior, use {@link #substringBeforeLast(String, String)}.
698     * This method uses {@link String#endsWith(String)}.</p>
699     *
700     * <pre>
701     * StringUtils.chomp(null, *)         = null
702     * StringUtils.chomp("", *)           = ""
703     * StringUtils.chomp("foobar", "bar") = "foo"
704     * StringUtils.chomp("foobar", "baz") = "foobar"
705     * StringUtils.chomp("foo", "foo")    = ""
706     * StringUtils.chomp("foo ", "foo")   = "foo "
707     * StringUtils.chomp(" foo", "foo")   = " "
708     * StringUtils.chomp("foo", "foooo")  = "foo"
709     * StringUtils.chomp("foo", "")       = "foo"
710     * StringUtils.chomp("foo", null)     = "foo"
711     * </pre>
712     *
713     * @param str  the String to chomp from, may be null
714     * @param separator  separator String, may be null
715     * @return String without trailing separator, {@code null} if null String input
716     * @deprecated This feature will be removed in Lang 4, use {@link StringUtils#removeEnd(String, String)} instead
717     */
718    @Deprecated
719    public static String chomp(final String str, final String separator) {
720        return Strings.CS.removeEnd(str, separator);
721    }
722
723    /**
724     * Remove the last character from a String.
725     *
726     * <p>If the String ends in {@code \r\n}, then remove both
727     * of them.</p>
728     *
729     * <pre>
730     * StringUtils.chop(null)          = null
731     * StringUtils.chop("")            = ""
732     * StringUtils.chop("abc \r")      = "abc "
733     * StringUtils.chop("abc\n")       = "abc"
734     * StringUtils.chop("abc\r\n")     = "abc"
735     * StringUtils.chop("abc")         = "ab"
736     * StringUtils.chop("abc\nabc")    = "abc\nab"
737     * StringUtils.chop("a")           = ""
738     * StringUtils.chop("\r")          = ""
739     * StringUtils.chop("\n")          = ""
740     * StringUtils.chop("\r\n")        = ""
741     * </pre>
742     *
743     * @param str  the String to chop last character from, may be null
744     * @return String without last character, {@code null} if null String input
745     */
746    public static String chop(final String str) {
747        if (str == null) {
748            return null;
749        }
750        final int strLen = str.length();
751        if (strLen < 2) {
752            return EMPTY;
753        }
754        final int lastIdx = strLen - 1;
755        final String ret = str.substring(0, lastIdx);
756        final char last = str.charAt(lastIdx);
757        if (last == CharUtils.LF && ret.charAt(lastIdx - 1) == CharUtils.CR) {
758            return ret.substring(0, lastIdx - 1);
759        }
760        return ret;
761    }
762
763    /**
764     * Compare two Strings lexicographically, as per {@link String#compareTo(String)}, returning :
765     * <ul>
766     *  <li>{@code int = 0}, if {@code str1} is equal to {@code str2} (or both {@code null})</li>
767     *  <li>{@code int < 0}, if {@code str1} is less than {@code str2}</li>
768     *  <li>{@code int > 0}, if {@code str1} is greater than {@code str2}</li>
769     * </ul>
770     *
771     * <p>This is a {@code null} safe version of :</p>
772     * <blockquote><pre>str1.compareTo(str2)</pre></blockquote>
773     *
774     * <p>{@code null} value is considered less than non-{@code null} value.
775     * Two {@code null} references are considered equal.</p>
776     *
777     * <pre>{@code
778     * StringUtils.compare(null, null)   = 0
779     * StringUtils.compare(null , "a")   < 0
780     * StringUtils.compare("a", null)   > 0
781     * StringUtils.compare("abc", "abc") = 0
782     * StringUtils.compare("a", "b")     < 0
783     * StringUtils.compare("b", "a")     > 0
784     * StringUtils.compare("a", "B")     > 0
785     * StringUtils.compare("ab", "abc")  < 0
786     * }</pre>
787     *
788     * @see #compare(String, String, boolean)
789     * @see String#compareTo(String)
790     * @param str1  the String to compare from
791     * @param str2  the String to compare to
792     * @return &lt; 0, 0, &gt; 0, if {@code str1} is respectively less, equal or greater than {@code str2}
793     * @since 3.5
794     * @deprecated Use {@link Strings#compare(String, String) Strings.CS.compare(String, String)}
795     */
796    @Deprecated
797    public static int compare(final String str1, final String str2) {
798        return Strings.CS.compare(str1, str2);
799    }
800
801    /**
802     * Compare two Strings lexicographically, as per {@link String#compareTo(String)}, returning :
803     * <ul>
804     *  <li>{@code int = 0}, if {@code str1} is equal to {@code str2} (or both {@code null})</li>
805     *  <li>{@code int < 0}, if {@code str1} is less than {@code str2}</li>
806     *  <li>{@code int > 0}, if {@code str1} is greater than {@code str2}</li>
807     * </ul>
808     *
809     * <p>This is a {@code null} safe version of :</p>
810     * <blockquote><pre>str1.compareTo(str2)</pre></blockquote>
811     *
812     * <p>{@code null} inputs are handled according to the {@code nullIsLess} parameter.
813     * Two {@code null} references are considered equal.</p>
814     *
815     * <pre>{@code
816     * StringUtils.compare(null, null, *)     = 0
817     * StringUtils.compare(null , "a", true)  < 0
818     * StringUtils.compare(null , "a", false) > 0
819     * StringUtils.compare("a", null, true)   > 0
820     * StringUtils.compare("a", null, false)  < 0
821     * StringUtils.compare("abc", "abc", *)   = 0
822     * StringUtils.compare("a", "b", *)       < 0
823     * StringUtils.compare("b", "a", *)       > 0
824     * StringUtils.compare("a", "B", *)       > 0
825     * StringUtils.compare("ab", "abc", *)    < 0
826     * }</pre>
827     *
828     * @see String#compareTo(String)
829     * @param str1  the String to compare from
830     * @param str2  the String to compare to
831     * @param nullIsLess  whether consider {@code null} value less than non-{@code null} value
832     * @return &lt; 0, 0, &gt; 0, if {@code str1} is respectively less, equal ou greater than {@code str2}
833     * @since 3.5
834     */
835    public static int compare(final String str1, final String str2, final boolean nullIsLess) {
836        if (str1 == str2) { // NOSONARLINT this intentionally uses == to allow for both null
837            return 0;
838        }
839        if (str1 == null) {
840            return nullIsLess ? -1 : 1;
841        }
842        if (str2 == null) {
843            return nullIsLess ? 1 : - 1;
844        }
845        return str1.compareTo(str2);
846    }
847
848    /**
849     * Compare two Strings lexicographically, ignoring case differences,
850     * as per {@link String#compareToIgnoreCase(String)}, returning :
851     * <ul>
852     *  <li>{@code int = 0}, if {@code str1} is equal to {@code str2} (or both {@code null})</li>
853     *  <li>{@code int < 0}, if {@code str1} is less than {@code str2}</li>
854     *  <li>{@code int > 0}, if {@code str1} is greater than {@code str2}</li>
855     * </ul>
856     *
857     * <p>This is a {@code null} safe version of :</p>
858     * <blockquote><pre>str1.compareToIgnoreCase(str2)</pre></blockquote>
859     *
860     * <p>{@code null} value is considered less than non-{@code null} value.
861     * Two {@code null} references are considered equal.
862     * Comparison is case insensitive.</p>
863     *
864     * <pre>{@code
865     * StringUtils.compareIgnoreCase(null, null)   = 0
866     * StringUtils.compareIgnoreCase(null , "a")   < 0
867     * StringUtils.compareIgnoreCase("a", null)    > 0
868     * StringUtils.compareIgnoreCase("abc", "abc") = 0
869     * StringUtils.compareIgnoreCase("abc", "ABC") = 0
870     * StringUtils.compareIgnoreCase("a", "b")     < 0
871     * StringUtils.compareIgnoreCase("b", "a")     > 0
872     * StringUtils.compareIgnoreCase("a", "B")     < 0
873     * StringUtils.compareIgnoreCase("A", "b")     < 0
874     * StringUtils.compareIgnoreCase("ab", "ABC")  < 0
875     * }</pre>
876     *
877     * @see #compareIgnoreCase(String, String, boolean)
878     * @see String#compareToIgnoreCase(String)
879     * @param str1  the String to compare from
880     * @param str2  the String to compare to
881     * @return &lt; 0, 0, &gt; 0, if {@code str1} is respectively less, equal ou greater than {@code str2},
882     *          ignoring case differences.
883     * @since 3.5
884     * @deprecated Use {@link Strings#compare(String, String) Strings.CI.compare(String, String)}
885     */
886    @Deprecated
887    public static int compareIgnoreCase(final String str1, final String str2) {
888        return Strings.CI.compare(str1, str2);
889    }
890
891    /**
892     * Compare two Strings lexicographically, ignoring case differences,
893     * as per {@link String#compareToIgnoreCase(String)}, returning :
894     * <ul>
895     *  <li>{@code int = 0}, if {@code str1} is equal to {@code str2} (or both {@code null})</li>
896     *  <li>{@code int < 0}, if {@code str1} is less than {@code str2}</li>
897     *  <li>{@code int > 0}, if {@code str1} is greater than {@code str2}</li>
898     * </ul>
899     *
900     * <p>This is a {@code null} safe version of :</p>
901     * <blockquote><pre>str1.compareToIgnoreCase(str2)</pre></blockquote>
902     *
903     * <p>{@code null} inputs are handled according to the {@code nullIsLess} parameter.
904     * Two {@code null} references are considered equal.
905     * Comparison is case insensitive.</p>
906     *
907     * <pre>{@code
908     * StringUtils.compareIgnoreCase(null, null, *)     = 0
909     * StringUtils.compareIgnoreCase(null , "a", true)  < 0
910     * StringUtils.compareIgnoreCase(null , "a", false) > 0
911     * StringUtils.compareIgnoreCase("a", null, true)   > 0
912     * StringUtils.compareIgnoreCase("a", null, false)  < 0
913     * StringUtils.compareIgnoreCase("abc", "abc", *)   = 0
914     * StringUtils.compareIgnoreCase("abc", "ABC", *)   = 0
915     * StringUtils.compareIgnoreCase("a", "b", *)       < 0
916     * StringUtils.compareIgnoreCase("b", "a", *)       > 0
917     * StringUtils.compareIgnoreCase("a", "B", *)       < 0
918     * StringUtils.compareIgnoreCase("A", "b", *)       < 0
919     * StringUtils.compareIgnoreCase("ab", "abc", *)    < 0
920     * }</pre>
921     *
922     * @see String#compareToIgnoreCase(String)
923     * @param str1  the String to compare from
924     * @param str2  the String to compare to
925     * @param nullIsLess  whether consider {@code null} value less than non-{@code null} value
926     * @return &lt; 0, 0, &gt; 0, if {@code str1} is respectively less, equal ou greater than {@code str2},
927     *          ignoring case differences.
928     * @since 3.5
929     */
930    public static int compareIgnoreCase(final String str1, final String str2, final boolean nullIsLess) {
931        if (str1 == str2) { // NOSONARLINT this intentionally uses == to allow for both null
932            return 0;
933        }
934        if (str1 == null) {
935            return nullIsLess ? -1 : 1;
936        }
937        if (str2 == null) {
938            return nullIsLess ? 1 : - 1;
939        }
940        return str1.compareToIgnoreCase(str2);
941    }
942
943    /**
944     * Tests if CharSequence contains a search CharSequence, handling {@code null}.
945     * This method uses {@link String#indexOf(String)} if possible.
946     *
947     * <p>A {@code null} CharSequence will return {@code false}.</p>
948     *
949     * <pre>
950     * StringUtils.contains(null, *)     = false
951     * StringUtils.contains(*, null)     = false
952     * StringUtils.contains("", "")      = true
953     * StringUtils.contains("abc", "")   = true
954     * StringUtils.contains("abc", "a")  = true
955     * StringUtils.contains("abc", "z")  = false
956     * </pre>
957     *
958     * @param seq  the CharSequence to check, may be null
959     * @param searchSeq  the CharSequence to find, may be null
960     * @return true if the CharSequence contains the search CharSequence,
961     *  false if not or {@code null} string input
962     * @since 2.0
963     * @since 3.0 Changed signature from contains(String, String) to contains(CharSequence, CharSequence)
964     * @deprecated Use {@link Strings#contains(CharSequence, CharSequence) Strings.CS.contains(CharSequence, CharSequence)}
965     */
966    @Deprecated
967    public static boolean contains(final CharSequence seq, final CharSequence searchSeq) {
968        return Strings.CS.contains(seq, searchSeq);
969    }
970
971    /**
972     * Tests if CharSequence contains a search character, handling {@code null}.
973     * This method uses {@link String#indexOf(int)} if possible.
974     *
975     * <p>A {@code null} or empty ("") CharSequence will return {@code false}.</p>
976     *
977     * <pre>
978     * StringUtils.contains(null, *)    = false
979     * StringUtils.contains("", *)      = false
980     * StringUtils.contains("abc", 'a') = true
981     * StringUtils.contains("abc", 'z') = false
982     * </pre>
983     *
984     * @param seq  the CharSequence to check, may be null
985     * @param searchChar  the character to find
986     * @return true if the CharSequence contains the search character,
987     *  false if not or {@code null} string input
988     * @since 2.0
989     * @since 3.0 Changed signature from contains(String, int) to contains(CharSequence, int)
990     */
991    public static boolean contains(final CharSequence seq, final int searchChar) {
992        if (isEmpty(seq)) {
993            return false;
994        }
995        return CharSequenceUtils.indexOf(seq, searchChar, 0) >= 0;
996    }
997
998    /**
999     * Tests if the CharSequence contains any character in the given
1000     * set of characters.
1001     *
1002     * <p>A {@code null} CharSequence will return {@code false}.
1003     * A {@code null} or zero length search array will return {@code false}.</p>
1004     *
1005     * <pre>
1006     * StringUtils.containsAny(null, *)                  = false
1007     * StringUtils.containsAny("", *)                    = false
1008     * StringUtils.containsAny(*, null)                  = false
1009     * StringUtils.containsAny(*, [])                    = false
1010     * StringUtils.containsAny("zzabyycdxx", ['z', 'a']) = true
1011     * StringUtils.containsAny("zzabyycdxx", ['b', 'y']) = true
1012     * StringUtils.containsAny("zzabyycdxx", ['z', 'y']) = true
1013     * StringUtils.containsAny("aba", ['z'])             = false
1014     * </pre>
1015     *
1016     * @param cs  the CharSequence to check, may be null
1017     * @param searchChars  the chars to search for, may be null
1018     * @return the {@code true} if any of the chars are found,
1019     * {@code false} if no match or null input
1020     * @since 2.4
1021     * @since 3.0 Changed signature from containsAny(String, char[]) to containsAny(CharSequence, char...)
1022     */
1023    public static boolean containsAny(final CharSequence cs, final char... searchChars) {
1024        if (isEmpty(cs) || ArrayUtils.isEmpty(searchChars)) {
1025            return false;
1026        }
1027        final int csLength = cs.length();
1028        final int searchLength = searchChars.length;
1029        final int csLast = csLength - 1;
1030        final int searchLast = searchLength - 1;
1031        for (int i = 0; i < csLength; i++) {
1032            final char ch = cs.charAt(i);
1033            for (int j = 0; j < searchLength; j++) {
1034                if (searchChars[j] == ch) {
1035                    if (!Character.isHighSurrogate(ch) || j == searchLast || i < csLast && searchChars[j + 1] == cs.charAt(i + 1)) {
1036                        return true;
1037                    }
1038                }
1039            }
1040        }
1041        return false;
1042    }
1043
1044    /**
1045     * Tests if the CharSequence contains any character in the given set of characters.
1046     *
1047     * <p>
1048     * A {@code null} CharSequence will return {@code false}. A {@code null} search CharSequence will return
1049     * {@code false}.
1050     * </p>
1051     *
1052     * <pre>
1053     * StringUtils.containsAny(null, *)               = false
1054     * StringUtils.containsAny("", *)                 = false
1055     * StringUtils.containsAny(*, null)               = false
1056     * StringUtils.containsAny(*, "")                 = false
1057     * StringUtils.containsAny("zzabyycdxx", "za")    = true
1058     * StringUtils.containsAny("zzabyycdxx", "by")    = true
1059     * StringUtils.containsAny("zzabyycdxx", "zy")    = true
1060     * StringUtils.containsAny("zzabyycdxx", "\tx")   = true
1061     * StringUtils.containsAny("zzabyycdxx", "$.#yF") = true
1062     * StringUtils.containsAny("aba", "z")            = false
1063     * </pre>
1064     *
1065     * @param cs
1066     *            the CharSequence to check, may be null
1067     * @param searchChars
1068     *            the chars to search for, may be null
1069     * @return the {@code true} if any of the chars are found, {@code false} if no match or null input
1070     * @since 2.4
1071     * @since 3.0 Changed signature from containsAny(String, String) to containsAny(CharSequence, CharSequence)
1072     */
1073    public static boolean containsAny(final CharSequence cs, final CharSequence searchChars) {
1074        if (searchChars == null) {
1075            return false;
1076        }
1077        return containsAny(cs, CharSequenceUtils.toCharArray(searchChars));
1078    }
1079
1080    /**
1081     * Tests if the CharSequence contains any of the CharSequences in the given array.
1082     *
1083     * <p>
1084     * A {@code null} {@code cs} CharSequence will return {@code false}. A {@code null} or zero length search array will
1085     * return {@code false}.
1086     * </p>
1087     *
1088     * <pre>
1089     * StringUtils.containsAny(null, *)            = false
1090     * StringUtils.containsAny("", *)              = false
1091     * StringUtils.containsAny(*, null)            = false
1092     * StringUtils.containsAny(*, [])              = false
1093     * StringUtils.containsAny("abcd", "ab", null) = true
1094     * StringUtils.containsAny("abcd", "ab", "cd") = true
1095     * StringUtils.containsAny("abc", "d", "abc")  = true
1096     * </pre>
1097     *
1098     * @param cs The CharSequence to check, may be null
1099     * @param searchCharSequences The array of CharSequences to search for, may be null. Individual CharSequences may be
1100     *        null as well.
1101     * @return {@code true} if any of the search CharSequences are found, {@code false} otherwise
1102     * @since 3.4
1103     * @deprecated Use {@link Strings#containsAny(CharSequence, CharSequence...) Strings.CS.containsAny(CharSequence, CharSequence...)}
1104     */
1105    @Deprecated
1106    public static boolean containsAny(final CharSequence cs, final CharSequence... searchCharSequences) {
1107        return Strings.CS.containsAny(cs, searchCharSequences);
1108    }
1109
1110    /**
1111     * Tests if the CharSequence contains any of the CharSequences in the given array, ignoring case.
1112     *
1113     * <p>
1114     * A {@code null} {@code cs} CharSequence will return {@code false}. A {@code null} or zero length search array will
1115     * return {@code false}.
1116     * </p>
1117     *
1118     * <pre>
1119     * StringUtils.containsAny(null, *)            = false
1120     * StringUtils.containsAny("", *)              = false
1121     * StringUtils.containsAny(*, null)            = false
1122     * StringUtils.containsAny(*, [])              = false
1123     * StringUtils.containsAny("abcd", "ab", null) = true
1124     * StringUtils.containsAny("abcd", "ab", "cd") = true
1125     * StringUtils.containsAny("abc", "d", "abc")  = true
1126     * StringUtils.containsAny("abc", "D", "ABC")  = true
1127     * StringUtils.containsAny("ABC", "d", "abc")  = true
1128     * </pre>
1129     *
1130     * @param cs The CharSequence to check, may be null
1131     * @param searchCharSequences The array of CharSequences to search for, may be null. Individual CharSequences may be
1132     *        null as well.
1133     * @return {@code true} if any of the search CharSequences are found, {@code false} otherwise
1134     * @since 3.12.0
1135     * @deprecated Use {@link Strings#containsAny(CharSequence, CharSequence...) Strings.CI.containsAny(CharSequence, CharSequence...)}
1136     */
1137    @Deprecated
1138    public static boolean containsAnyIgnoreCase(final CharSequence cs, final CharSequence... searchCharSequences) {
1139        return Strings.CI.containsAny(cs, searchCharSequences);
1140    }
1141
1142    /**
1143     * Tests if CharSequence contains a search CharSequence irrespective of case,
1144     * handling {@code null}. Case-insensitivity is defined as by
1145     * {@link String#equalsIgnoreCase(String)}.
1146     *
1147     * <p>A {@code null} CharSequence will return {@code false}.
1148     *
1149     * <pre>
1150     * StringUtils.containsIgnoreCase(null, *)    = false
1151     * StringUtils.containsIgnoreCase(*, null)    = false
1152     * StringUtils.containsIgnoreCase("", "")     = true
1153     * StringUtils.containsIgnoreCase("abc", "")  = true
1154     * StringUtils.containsIgnoreCase("abc", "a") = true
1155     * StringUtils.containsIgnoreCase("abc", "z") = false
1156     * StringUtils.containsIgnoreCase("abc", "A") = true
1157     * StringUtils.containsIgnoreCase("abc", "Z") = false
1158     * </pre>
1159     *
1160     * @param str  the CharSequence to check, may be null
1161     * @param searchStr  the CharSequence to find, may be null
1162     * @return true if the CharSequence contains the search CharSequence irrespective of
1163     * case or false if not or {@code null} string input
1164     * @since 3.0 Changed signature from containsIgnoreCase(String, String) to containsIgnoreCase(CharSequence, CharSequence)
1165     * @deprecated Use {@link Strings#contains(CharSequence, CharSequence) Strings.CI.contains(CharSequence, CharSequence)}
1166     */
1167    @Deprecated
1168    public static boolean containsIgnoreCase(final CharSequence str, final CharSequence searchStr) {
1169        return Strings.CI.contains(str, searchStr);
1170    }
1171
1172    /**
1173     * Tests that the CharSequence does not contain certain characters.
1174     *
1175     * <p>A {@code null} CharSequence will return {@code true}.
1176     * A {@code null} invalid character array will return {@code true}.
1177     * An empty CharSequence (length()=0) always returns true.</p>
1178     *
1179     * <pre>
1180     * StringUtils.containsNone(null, *)       = true
1181     * StringUtils.containsNone(*, null)       = true
1182     * StringUtils.containsNone("", *)         = true
1183     * StringUtils.containsNone("ab", '')      = true
1184     * StringUtils.containsNone("abab", 'xyz') = true
1185     * StringUtils.containsNone("ab1", 'xyz')  = true
1186     * StringUtils.containsNone("abz", 'xyz')  = false
1187     * </pre>
1188     *
1189     * @param cs  the CharSequence to check, may be null
1190     * @param searchChars  an array of invalid chars, may be null
1191     * @return true if it contains none of the invalid chars, or is null
1192     * @since 2.0
1193     * @since 3.0 Changed signature from containsNone(String, char[]) to containsNone(CharSequence, char...)
1194     */
1195    public static boolean containsNone(final CharSequence cs, final char... searchChars) {
1196        if (cs == null || searchChars == null) {
1197            return true;
1198        }
1199        final int csLen = cs.length();
1200        final int csLast = csLen - 1;
1201        final int searchLen = searchChars.length;
1202        final int searchLast = searchLen - 1;
1203        for (int i = 0; i < csLen; i++) {
1204            final char ch = cs.charAt(i);
1205            for (int j = 0; j < searchLen; j++) {
1206                if (searchChars[j] == ch) {
1207                    if (!Character.isHighSurrogate(ch) || j == searchLast || i < csLast && searchChars[j + 1] == cs.charAt(i + 1)) {
1208                        return false;
1209                    }
1210                }
1211            }
1212        }
1213        return true;
1214    }
1215
1216    /**
1217     * Tests that the CharSequence does not contain certain characters.
1218     *
1219     * <p>A {@code null} CharSequence will return {@code true}.
1220     * A {@code null} invalid character array will return {@code true}.
1221     * An empty String ("") always returns true.</p>
1222     *
1223     * <pre>
1224     * StringUtils.containsNone(null, *)       = true
1225     * StringUtils.containsNone(*, null)       = true
1226     * StringUtils.containsNone("", *)         = true
1227     * StringUtils.containsNone("ab", "")      = true
1228     * StringUtils.containsNone("abab", "xyz") = true
1229     * StringUtils.containsNone("ab1", "xyz")  = true
1230     * StringUtils.containsNone("abz", "xyz")  = false
1231     * </pre>
1232     *
1233     * @param cs  the CharSequence to check, may be null
1234     * @param invalidChars  a String of invalid chars, may be null
1235     * @return true if it contains none of the invalid chars, or is null
1236     * @since 2.0
1237     * @since 3.0 Changed signature from containsNone(String, String) to containsNone(CharSequence, String)
1238     */
1239    public static boolean containsNone(final CharSequence cs, final String invalidChars) {
1240        if (invalidChars == null) {
1241            return true;
1242        }
1243        return containsNone(cs, invalidChars.toCharArray());
1244    }
1245
1246    /**
1247     * Tests if the CharSequence contains only certain characters.
1248     *
1249     * <p>A {@code null} CharSequence will return {@code false}.
1250     * A {@code null} valid character array will return {@code false}.
1251     * An empty CharSequence (length()=0) always returns {@code true}.</p>
1252     *
1253     * <pre>
1254     * StringUtils.containsOnly(null, *)       = false
1255     * StringUtils.containsOnly(*, null)       = false
1256     * StringUtils.containsOnly("", *)         = true
1257     * StringUtils.containsOnly("ab", '')      = false
1258     * StringUtils.containsOnly("abab", 'abc') = true
1259     * StringUtils.containsOnly("ab1", 'abc')  = false
1260     * StringUtils.containsOnly("abz", 'abc')  = false
1261     * </pre>
1262     *
1263     * @param cs  the String to check, may be null
1264     * @param valid  an array of valid chars, may be null
1265     * @return true if it only contains valid chars and is non-null
1266     * @since 3.0 Changed signature from containsOnly(String, char[]) to containsOnly(CharSequence, char...)
1267     */
1268    public static boolean containsOnly(final CharSequence cs, final char... valid) {
1269        // All these pre-checks are to maintain API with an older version
1270        if (valid == null || cs == null) {
1271            return false;
1272        }
1273        if (cs.length() == 0) {
1274            return true;
1275        }
1276        if (valid.length == 0) {
1277            return false;
1278        }
1279        return indexOfAnyBut(cs, valid) == INDEX_NOT_FOUND;
1280    }
1281
1282    /**
1283     * Tests if the CharSequence contains only certain characters.
1284     *
1285     * <p>A {@code null} CharSequence will return {@code false}.
1286     * A {@code null} valid character String will return {@code false}.
1287     * An empty String (length()=0) always returns {@code true}.</p>
1288     *
1289     * <pre>
1290     * StringUtils.containsOnly(null, *)       = false
1291     * StringUtils.containsOnly(*, null)       = false
1292     * StringUtils.containsOnly("", *)         = true
1293     * StringUtils.containsOnly("ab", "")      = false
1294     * StringUtils.containsOnly("abab", "abc") = true
1295     * StringUtils.containsOnly("ab1", "abc")  = false
1296     * StringUtils.containsOnly("abz", "abc")  = false
1297     * </pre>
1298     *
1299     * @param cs  the CharSequence to check, may be null
1300     * @param validChars  a String of valid chars, may be null
1301     * @return true if it only contains valid chars and is non-null
1302     * @since 2.0
1303     * @since 3.0 Changed signature from containsOnly(String, String) to containsOnly(CharSequence, String)
1304     */
1305    public static boolean containsOnly(final CharSequence cs, final String validChars) {
1306        if (cs == null || validChars == null) {
1307            return false;
1308        }
1309        return containsOnly(cs, validChars.toCharArray());
1310    }
1311
1312    /**
1313     * Tests whether the given CharSequence contains any whitespace characters.
1314     *
1315     * <p>Whitespace is defined by {@link Character#isWhitespace(char)}.</p>
1316     *
1317     * <pre>
1318     * StringUtils.containsWhitespace(null)       = false
1319     * StringUtils.containsWhitespace("")         = false
1320     * StringUtils.containsWhitespace("ab")       = false
1321     * StringUtils.containsWhitespace(" ab")      = true
1322     * StringUtils.containsWhitespace("a b")      = true
1323     * StringUtils.containsWhitespace("ab ")      = true
1324     * </pre>
1325     *
1326     * @param seq the CharSequence to check (may be {@code null})
1327     * @return {@code true} if the CharSequence is not empty and
1328     * contains at least 1 (breaking) whitespace character
1329     * @since 3.0
1330     */
1331    // From org.springframework.util.StringUtils, under Apache License 2.0
1332    public static boolean containsWhitespace(final CharSequence seq) {
1333        if (isEmpty(seq)) {
1334            return false;
1335        }
1336        final int strLen = seq.length();
1337        for (int i = 0; i < strLen; i++) {
1338            if (Character.isWhitespace(seq.charAt(i))) {
1339                return true;
1340            }
1341        }
1342        return false;
1343    }
1344
1345    private static void convertRemainingAccentCharacters(final StringBuilder decomposed) {
1346        for (int i = 0; i < decomposed.length(); i++) {
1347            final char charAt = decomposed.charAt(i);
1348            switch (charAt) {
1349            case '\u0141':
1350                decomposed.setCharAt(i, 'L');
1351                break;
1352            case '\u0142':
1353                decomposed.setCharAt(i, 'l');
1354                break;
1355            // D with stroke
1356            case '\u0110':
1357                // LATIN CAPITAL LETTER D WITH STROKE
1358                decomposed.setCharAt(i, 'D');
1359                break;
1360            case '\u0111':
1361                // LATIN SMALL LETTER D WITH STROKE
1362                decomposed.setCharAt(i, 'd');
1363                break;
1364            // I with bar
1365            case '\u0197':
1366                decomposed.setCharAt(i, 'I');
1367                break;
1368            case '\u0268':
1369                decomposed.setCharAt(i, 'i');
1370                break;
1371            case '\u1D7B':
1372                decomposed.setCharAt(i, 'I');
1373                break;
1374            case '\u1DA4':
1375                decomposed.setCharAt(i, 'i');
1376                break;
1377            case '\u1DA7':
1378                decomposed.setCharAt(i, 'I');
1379                break;
1380            // U with bar
1381            case '\u0244':
1382                // LATIN CAPITAL LETTER U BAR
1383                decomposed.setCharAt(i, 'U');
1384                break;
1385            case '\u0289':
1386                // LATIN SMALL LETTER U BAR
1387                decomposed.setCharAt(i, 'u');
1388                break;
1389            case '\u1D7E':
1390                // LATIN SMALL CAPITAL LETTER U WITH STROKE
1391                decomposed.setCharAt(i, 'U');
1392                break;
1393            case '\u1DB6':
1394                // MODIFIER LETTER SMALL U BAR
1395                decomposed.setCharAt(i, 'u');
1396                break;
1397            // T with stroke
1398            case '\u0166':
1399                // LATIN CAPITAL LETTER T WITH STROKE
1400                decomposed.setCharAt(i, 'T');
1401                break;
1402            case '\u0167':
1403                // LATIN SMALL LETTER T WITH STROKE
1404                decomposed.setCharAt(i, 't');
1405                break;
1406            default:
1407                break;
1408            }
1409        }
1410    }
1411
1412    /**
1413     * Counts how many times the char appears in the given string.
1414     *
1415     * <p>A {@code null} or empty ("") String input returns {@code 0}.</p>
1416     *
1417     * <pre>
1418     * StringUtils.countMatches(null, *)     = 0
1419     * StringUtils.countMatches("", *)       = 0
1420     * StringUtils.countMatches("abba", 0)   = 0
1421     * StringUtils.countMatches("abba", 'a') = 2
1422     * StringUtils.countMatches("abba", 'b') = 2
1423     * StringUtils.countMatches("abba", 'x') = 0
1424     * </pre>
1425     *
1426     * @param str  the CharSequence to check, may be null
1427     * @param ch  the char to count
1428     * @return the number of occurrences, 0 if the CharSequence is {@code null}
1429     * @since 3.4
1430     */
1431    public static int countMatches(final CharSequence str, final char ch) {
1432        if (isEmpty(str)) {
1433            return 0;
1434        }
1435        int count = 0;
1436        // We could also call str.toCharArray() for faster lookups but that would generate more garbage.
1437        for (int i = 0; i < str.length(); i++) {
1438            if (ch == str.charAt(i)) {
1439                count++;
1440            }
1441        }
1442        return count;
1443    }
1444
1445    /**
1446     * Counts how many times the substring appears in the larger string.
1447     * Note that the code only counts non-overlapping matches.
1448     *
1449     * <p>A {@code null} or empty ("") String input returns {@code 0}.</p>
1450     *
1451     * <pre>
1452     * StringUtils.countMatches(null, *)        = 0
1453     * StringUtils.countMatches("", *)          = 0
1454     * StringUtils.countMatches("abba", null)   = 0
1455     * StringUtils.countMatches("abba", "")     = 0
1456     * StringUtils.countMatches("abba", "a")    = 2
1457     * StringUtils.countMatches("abba", "ab")   = 1
1458     * StringUtils.countMatches("abba", "xxx")  = 0
1459     * StringUtils.countMatches("ababa", "aba") = 1
1460     * </pre>
1461     *
1462     * @param str  the CharSequence to check, may be null
1463     * @param sub  the substring to count, may be null
1464     * @return the number of occurrences, 0 if either CharSequence is {@code null}
1465     * @since 3.0 Changed signature from countMatches(String, String) to countMatches(CharSequence, CharSequence)
1466     */
1467    public static int countMatches(final CharSequence str, final CharSequence sub) {
1468        if (isEmpty(str) || isEmpty(sub)) {
1469            return 0;
1470        }
1471        int count = 0;
1472        int idx = 0;
1473        while ((idx = CharSequenceUtils.indexOf(str, sub, idx)) != INDEX_NOT_FOUND) {
1474            count++;
1475            idx += sub.length();
1476        }
1477        return count;
1478    }
1479
1480    /**
1481     * Returns either the passed in CharSequence, or if the CharSequence is {@link #isBlank(CharSequence) blank} (whitespaces, empty ({@code ""}) or
1482     * {@code null}), the value of {@code defaultStr}.
1483     *
1484     * <p>
1485     * Whitespace is defined by {@link Character#isWhitespace(char)}.
1486     * </p>
1487     *
1488     * <pre>
1489     * StringUtils.defaultIfBlank(null, "NULL")  = "NULL"
1490     * StringUtils.defaultIfBlank("", "NULL")    = "NULL"
1491     * StringUtils.defaultIfBlank(" ", "NULL")   = "NULL"
1492     * StringUtils.defaultIfBlank("bat", "NULL") = "bat"
1493     * StringUtils.defaultIfBlank("", null)      = null
1494     * </pre>
1495     *
1496     * @param <T>        the specific kind of CharSequence
1497     * @param str        the CharSequence to check, may be null
1498     * @param defaultStr the default CharSequence to return if {@code str} is {@link #isBlank(CharSequence) blank} (whitespaces, empty ({@code""}) or
1499     *                   {@code null}); may be null
1500     * @return the passed in CharSequence, or the default
1501     * @see StringUtils#defaultString(String, String)
1502     * @see #isBlank(CharSequence)
1503     */
1504    public static <T extends CharSequence> T defaultIfBlank(final T str, final T defaultStr) {
1505        return isBlank(str) ? defaultStr : str;
1506    }
1507
1508    /**
1509     * Returns either the passed in CharSequence, or if the CharSequence is
1510     * empty or {@code null}, the value of {@code defaultStr}.
1511     *
1512     * <pre>
1513     * StringUtils.defaultIfEmpty(null, "NULL")  = "NULL"
1514     * StringUtils.defaultIfEmpty("", "NULL")    = "NULL"
1515     * StringUtils.defaultIfEmpty(" ", "NULL")   = " "
1516     * StringUtils.defaultIfEmpty("bat", "NULL") = "bat"
1517     * StringUtils.defaultIfEmpty("", null)      = null
1518     * </pre>
1519     * @param <T> the specific kind of CharSequence
1520     * @param str  the CharSequence to check, may be null
1521     * @param defaultStr  the default CharSequence to return
1522     *  if the input is empty ("") or {@code null}, may be null
1523     * @return the passed in CharSequence, or the default
1524     * @see StringUtils#defaultString(String, String)
1525     */
1526    public static <T extends CharSequence> T defaultIfEmpty(final T str, final T defaultStr) {
1527        return isEmpty(str) ? defaultStr : str;
1528    }
1529
1530    /**
1531     * Returns either the passed in String,
1532     * or if the String is {@code null}, an empty String ("").
1533     *
1534     * <pre>
1535     * StringUtils.defaultString(null)  = ""
1536     * StringUtils.defaultString("")    = ""
1537     * StringUtils.defaultString("bat") = "bat"
1538     * </pre>
1539     *
1540     * @see Objects#toString(Object, String)
1541     * @see String#valueOf(Object)
1542     * @param str  the String to check, may be null
1543     * @return the passed in String, or the empty String if it
1544     *  was {@code null}
1545     */
1546    public static String defaultString(final String str) {
1547        return Objects.toString(str, EMPTY);
1548    }
1549
1550    /**
1551     * Returns either the given String, or if the String is
1552     * {@code null}, {@code nullDefault}.
1553     *
1554     * <pre>
1555     * StringUtils.defaultString(null, "NULL")  = "NULL"
1556     * StringUtils.defaultString("", "NULL")    = ""
1557     * StringUtils.defaultString("bat", "NULL") = "bat"
1558     * </pre>
1559     * <p>
1560     * Since this is now provided by Java, instead call {@link Objects#toString(Object, String)}:
1561     * </p>
1562     * <pre>
1563     * Objects.toString(null, "NULL")  = "NULL"
1564     * Objects.toString("", "NULL")    = ""
1565     * Objects.toString("bat", "NULL") = "bat"
1566     * </pre>
1567     *
1568     * @see Objects#toString(Object, String)
1569     * @see String#valueOf(Object)
1570     * @param str  the String to check, may be null
1571     * @param nullDefault  the default String to return
1572     *  if the input is {@code null}, may be null
1573     * @return the passed in String, or the default if it was {@code null}
1574     * @deprecated Use {@link Objects#toString(Object, String)}
1575     */
1576    @Deprecated
1577    public static String defaultString(final String str, final String nullDefault) {
1578        return Objects.toString(str, nullDefault);
1579    }
1580
1581    /**
1582     * Deletes all whitespaces from a String as defined by
1583     * {@link Character#isWhitespace(char)}.
1584     *
1585     * <pre>
1586     * StringUtils.deleteWhitespace(null)         = null
1587     * StringUtils.deleteWhitespace("")           = ""
1588     * StringUtils.deleteWhitespace("abc")        = "abc"
1589     * StringUtils.deleteWhitespace("   ab  c  ") = "abc"
1590     * </pre>
1591     *
1592     * @param str  the String to delete whitespace from, may be null
1593     * @return the String without whitespaces, {@code null} if null String input
1594     */
1595    public static String deleteWhitespace(final String str) {
1596        if (isEmpty(str)) {
1597            return str;
1598        }
1599        final int sz = str.length();
1600        final char[] chs = new char[sz];
1601        int count = 0;
1602        for (int i = 0; i < sz; i++) {
1603            if (!Character.isWhitespace(str.charAt(i))) {
1604                chs[count++] = str.charAt(i);
1605            }
1606        }
1607        if (count == sz) {
1608            return str;
1609        }
1610        if (count == 0) {
1611            return EMPTY;
1612        }
1613        return new String(chs, 0, count);
1614    }
1615
1616    /**
1617     * Compares two Strings, and returns the portion where they differ.
1618     * More precisely, return the remainder of the second String,
1619     * starting from where it's different from the first. This means that
1620     * the difference between "abc" and "ab" is the empty String and not "c".
1621     *
1622     * <p>For example,
1623     * {@code difference("i am a machine", "i am a robot") -> "robot"}.</p>
1624     *
1625     * <pre>
1626     * StringUtils.difference(null, null)       = null
1627     * StringUtils.difference("", "")           = ""
1628     * StringUtils.difference("", "abc")        = "abc"
1629     * StringUtils.difference("abc", "")        = ""
1630     * StringUtils.difference("abc", "abc")     = ""
1631     * StringUtils.difference("abc", "ab")      = ""
1632     * StringUtils.difference("ab", "abxyz")    = "xyz"
1633     * StringUtils.difference("abcde", "abxyz") = "xyz"
1634     * StringUtils.difference("abcde", "xyz")   = "xyz"
1635     * </pre>
1636     *
1637     * @param str1  the first String, may be null
1638     * @param str2  the second String, may be null
1639     * @return the portion of str2 where it differs from str1; returns the
1640     * empty String if they are equal
1641     * @see #indexOfDifference(CharSequence,CharSequence)
1642     * @since 2.0
1643     */
1644    public static String difference(final String str1, final String str2) {
1645        if (str1 == null) {
1646            return str2;
1647        }
1648        if (str2 == null) {
1649            return str1;
1650        }
1651        final int at = indexOfDifference(str1, str2);
1652        if (at == INDEX_NOT_FOUND) {
1653            return EMPTY;
1654        }
1655        return str2.substring(at);
1656    }
1657
1658    /**
1659     * Tests if a CharSequence ends with a specified suffix.
1660     *
1661     * <p>{@code null}s are handled without exceptions. Two {@code null}
1662     * references are considered to be equal. The comparison is case-sensitive.</p>
1663     *
1664     * <pre>
1665     * StringUtils.endsWith(null, null)      = true
1666     * StringUtils.endsWith(null, "def")     = false
1667     * StringUtils.endsWith("abcdef", null)  = false
1668     * StringUtils.endsWith("abcdef", "def") = true
1669     * StringUtils.endsWith("ABCDEF", "def") = false
1670     * StringUtils.endsWith("ABCDEF", "cde") = false
1671     * StringUtils.endsWith("ABCDEF", "")    = true
1672     * </pre>
1673     *
1674     * @see String#endsWith(String)
1675     * @param str  the CharSequence to check, may be null
1676     * @param suffix the suffix to find, may be null
1677     * @return {@code true} if the CharSequence ends with the suffix, case-sensitive, or
1678     *  both {@code null}
1679     * @since 2.4
1680     * @since 3.0 Changed signature from endsWith(String, String) to endsWith(CharSequence, CharSequence)
1681     * @deprecated Use {@link Strings#endsWith(CharSequence, CharSequence) Strings.CS.endsWith(CharSequence, CharSequence)}
1682     */
1683    @Deprecated
1684    public static boolean endsWith(final CharSequence str, final CharSequence suffix) {
1685        return Strings.CS.endsWith(str, suffix);
1686    }
1687
1688    /**
1689     * Tests if a CharSequence ends with any of the provided case-sensitive suffixes.
1690     *
1691     * <pre>
1692     * StringUtils.endsWithAny(null, null)                  = false
1693     * StringUtils.endsWithAny(null, new String[] {"abc"})  = false
1694     * StringUtils.endsWithAny("abcxyz", null)              = false
1695     * StringUtils.endsWithAny("abcxyz", new String[] {""}) = true
1696     * StringUtils.endsWithAny("abcxyz", new String[] {"xyz"}) = true
1697     * StringUtils.endsWithAny("abcxyz", new String[] {null, "xyz", "abc"}) = true
1698     * StringUtils.endsWithAny("abcXYZ", "def", "XYZ")      = true
1699     * StringUtils.endsWithAny("abcXYZ", "def", "xyz")      = false
1700     * </pre>
1701     *
1702     * @param sequence  the CharSequence to check, may be null
1703     * @param searchStrings the case-sensitive CharSequences to find, may be empty or contain {@code null}
1704     * @see StringUtils#endsWith(CharSequence, CharSequence)
1705     * @return {@code true} if the input {@code sequence} is {@code null} AND no {@code searchStrings} are provided, or
1706     *   the input {@code sequence} ends in any of the provided case-sensitive {@code searchStrings}.
1707     * @since 3.0
1708     * @deprecated Use {@link Strings#endsWithAny(CharSequence, CharSequence...) Strings.CS.endsWithAny(CharSequence, CharSequence...)}
1709     */
1710    @Deprecated
1711    public static boolean endsWithAny(final CharSequence sequence, final CharSequence... searchStrings) {
1712        return Strings.CS.endsWithAny(sequence, searchStrings);
1713    }
1714
1715    /**
1716     * Case-insensitive check if a CharSequence ends with a specified suffix.
1717     *
1718     * <p>{@code null}s are handled without exceptions. Two {@code null}
1719     * references are considered to be equal. The comparison is case insensitive.</p>
1720     *
1721     * <pre>
1722     * StringUtils.endsWithIgnoreCase(null, null)      = true
1723     * StringUtils.endsWithIgnoreCase(null, "def")     = false
1724     * StringUtils.endsWithIgnoreCase("abcdef", null)  = false
1725     * StringUtils.endsWithIgnoreCase("abcdef", "def") = true
1726     * StringUtils.endsWithIgnoreCase("ABCDEF", "def") = true
1727     * StringUtils.endsWithIgnoreCase("ABCDEF", "cde") = false
1728     * </pre>
1729     *
1730     * @see String#endsWith(String)
1731     * @param str  the CharSequence to check, may be null
1732     * @param suffix the suffix to find, may be null
1733     * @return {@code true} if the CharSequence ends with the suffix, case-insensitive, or
1734     *  both {@code null}
1735     * @since 2.4
1736     * @since 3.0 Changed signature from endsWithIgnoreCase(String, String) to endsWithIgnoreCase(CharSequence, CharSequence)
1737     * @deprecated Use {@link Strings#endsWith(CharSequence, CharSequence) Strings.CS.endsWith(CharSequence, CharSequence)}
1738     */
1739    @Deprecated
1740    public static boolean endsWithIgnoreCase(final CharSequence str, final CharSequence suffix) {
1741        return Strings.CI.endsWith(str, suffix);
1742    }
1743
1744    /**
1745     * Compares two CharSequences, returning {@code true} if they represent
1746     * equal sequences of characters.
1747     *
1748     * <p>{@code null}s are handled without exceptions. Two {@code null}
1749     * references are considered to be equal. The comparison is <strong>case-sensitive</strong>.</p>
1750     *
1751     * <pre>
1752     * StringUtils.equals(null, null)   = true
1753     * StringUtils.equals(null, "abc")  = false
1754     * StringUtils.equals("abc", null)  = false
1755     * StringUtils.equals("abc", "abc") = true
1756     * StringUtils.equals("abc", "ABC") = false
1757     * </pre>
1758     *
1759     * @param cs1  the first CharSequence, may be {@code null}
1760     * @param cs2  the second CharSequence, may be {@code null}
1761     * @return {@code true} if the CharSequences are equal (case-sensitive), or both {@code null}
1762     * @since 3.0 Changed signature from equals(String, String) to equals(CharSequence, CharSequence)
1763     * @see Object#equals(Object)
1764     * @see #equalsIgnoreCase(CharSequence, CharSequence)
1765     * @deprecated Use {@link Strings#equals(CharSequence, CharSequence) Strings.CS.equals(CharSequence, CharSequence)}
1766     */
1767    @Deprecated
1768    public static boolean equals(final CharSequence cs1, final CharSequence cs2) {
1769        return Strings.CS.equals(cs1, cs2);
1770    }
1771
1772    /**
1773     * Compares given {@code string} to a CharSequences vararg of {@code searchStrings},
1774     * returning {@code true} if the {@code string} is equal to any of the {@code searchStrings}.
1775     *
1776     * <pre>
1777     * StringUtils.equalsAny(null, (CharSequence[]) null) = false
1778     * StringUtils.equalsAny(null, null, null)    = true
1779     * StringUtils.equalsAny(null, "abc", "def")  = false
1780     * StringUtils.equalsAny("abc", null, "def")  = false
1781     * StringUtils.equalsAny("abc", "abc", "def") = true
1782     * StringUtils.equalsAny("abc", "ABC", "DEF") = false
1783     * </pre>
1784     *
1785     * @param string to compare, may be {@code null}.
1786     * @param searchStrings a vararg of strings, may be {@code null}.
1787     * @return {@code true} if the string is equal (case-sensitive) to any other element of {@code searchStrings};
1788     * {@code false} if {@code searchStrings} is null or contains no matches.
1789     * @since 3.5
1790     * @deprecated Use {@link Strings#equalsAny(CharSequence, CharSequence...) Strings.CS.equalsAny(CharSequence, CharSequence...)}
1791     */
1792    @Deprecated
1793    public static boolean equalsAny(final CharSequence string, final CharSequence... searchStrings) {
1794        return Strings.CS.equalsAny(string, searchStrings);
1795    }
1796
1797    /**
1798     * Compares given {@code string} to a CharSequences vararg of {@code searchStrings},
1799     * returning {@code true} if the {@code string} is equal to any of the {@code searchStrings}, ignoring case.
1800     *
1801     * <pre>
1802     * StringUtils.equalsAnyIgnoreCase(null, (CharSequence[]) null) = false
1803     * StringUtils.equalsAnyIgnoreCase(null, null, null)    = true
1804     * StringUtils.equalsAnyIgnoreCase(null, "abc", "def")  = false
1805     * StringUtils.equalsAnyIgnoreCase("abc", null, "def")  = false
1806     * StringUtils.equalsAnyIgnoreCase("abc", "abc", "def") = true
1807     * StringUtils.equalsAnyIgnoreCase("abc", "ABC", "DEF") = true
1808     * </pre>
1809     *
1810     * @param string to compare, may be {@code null}.
1811     * @param searchStrings a vararg of strings, may be {@code null}.
1812     * @return {@code true} if the string is equal (case-insensitive) to any other element of {@code searchStrings};
1813     * {@code false} if {@code searchStrings} is null or contains no matches.
1814     * @since 3.5
1815     * @deprecated Use {@link Strings#equalsAny(CharSequence, CharSequence...) Strings.CI-.equalsAny(CharSequence, CharSequence...)}
1816     */
1817    @Deprecated
1818    public static boolean equalsAnyIgnoreCase(final CharSequence string, final CharSequence... searchStrings) {
1819        return Strings.CI.equalsAny(string, searchStrings);
1820    }
1821
1822    /**
1823     * Compares two CharSequences, returning {@code true} if they represent
1824     * equal sequences of characters, ignoring case.
1825     *
1826     * <p>{@code null}s are handled without exceptions. Two {@code null}
1827     * references are considered equal. The comparison is <strong>case insensitive</strong>.</p>
1828     *
1829     * <pre>
1830     * StringUtils.equalsIgnoreCase(null, null)   = true
1831     * StringUtils.equalsIgnoreCase(null, "abc")  = false
1832     * StringUtils.equalsIgnoreCase("abc", null)  = false
1833     * StringUtils.equalsIgnoreCase("abc", "abc") = true
1834     * StringUtils.equalsIgnoreCase("abc", "ABC") = true
1835     * </pre>
1836     *
1837     * @param cs1  the first CharSequence, may be {@code null}
1838     * @param cs2  the second CharSequence, may be {@code null}
1839     * @return {@code true} if the CharSequences are equal (case-insensitive), or both {@code null}
1840     * @since 3.0 Changed signature from equalsIgnoreCase(String, String) to equalsIgnoreCase(CharSequence, CharSequence)
1841     * @see #equals(CharSequence, CharSequence)
1842     * @deprecated Use {@link Strings#equals(CharSequence, CharSequence) Strings.CI.equals(CharSequence, CharSequence)}
1843     */
1844    @Deprecated
1845    public static boolean equalsIgnoreCase(final CharSequence cs1, final CharSequence cs2) {
1846        return Strings.CI.equals(cs1, cs2);
1847    }
1848
1849    /**
1850     * Returns the first value in the array which is not empty (""),
1851     * {@code null} or whitespace only.
1852     *
1853     * <p>Whitespace is defined by {@link Character#isWhitespace(char)}.</p>
1854     *
1855     * <p>If all values are blank or the array is {@code null}
1856     * or empty then {@code null} is returned.</p>
1857     *
1858     * <pre>
1859     * StringUtils.firstNonBlank(null, null, null)     = null
1860     * StringUtils.firstNonBlank(null, "", " ")        = null
1861     * StringUtils.firstNonBlank("abc")                = "abc"
1862     * StringUtils.firstNonBlank(null, "xyz")          = "xyz"
1863     * StringUtils.firstNonBlank(null, "", " ", "xyz") = "xyz"
1864     * StringUtils.firstNonBlank(null, "xyz", "abc")   = "xyz"
1865     * StringUtils.firstNonBlank()                     = null
1866     * </pre>
1867     *
1868     * @param <T> the specific kind of CharSequence
1869     * @param values  the values to test, may be {@code null} or empty
1870     * @return the first value from {@code values} which is not blank,
1871     *  or {@code null} if there are no non-blank values
1872     * @since 3.8
1873     */
1874    @SafeVarargs
1875    public static <T extends CharSequence> T firstNonBlank(final T... values) {
1876        if (values != null) {
1877            for (final T val : values) {
1878                if (isNotBlank(val)) {
1879                    return val;
1880                }
1881            }
1882        }
1883        return null;
1884    }
1885
1886    /**
1887     * Returns the first value in the array which is not empty.
1888     *
1889     * <p>If all values are empty or the array is {@code null}
1890     * or empty then {@code null} is returned.</p>
1891     *
1892     * <pre>
1893     * StringUtils.firstNonEmpty(null, null, null)   = null
1894     * StringUtils.firstNonEmpty(null, null, "")     = null
1895     * StringUtils.firstNonEmpty(null, "", " ")      = " "
1896     * StringUtils.firstNonEmpty("abc")              = "abc"
1897     * StringUtils.firstNonEmpty(null, "xyz")        = "xyz"
1898     * StringUtils.firstNonEmpty("", "xyz")          = "xyz"
1899     * StringUtils.firstNonEmpty(null, "xyz", "abc") = "xyz"
1900     * StringUtils.firstNonEmpty()                   = null
1901     * </pre>
1902     *
1903     * @param <T> the specific kind of CharSequence
1904     * @param values  the values to test, may be {@code null} or empty
1905     * @return the first value from {@code values} which is not empty,
1906     *  or {@code null} if there are no non-empty values
1907     * @since 3.8
1908     */
1909    @SafeVarargs
1910    public static <T extends CharSequence> T firstNonEmpty(final T... values) {
1911        if (values != null) {
1912            for (final T val : values) {
1913                if (isNotEmpty(val)) {
1914                    return val;
1915                }
1916            }
1917        }
1918        return null;
1919    }
1920
1921    /**
1922     * Calls {@link String#getBytes(Charset)} in a null-safe manner.
1923     *
1924     * @param string input string
1925     * @param charset The {@link Charset} to encode the {@link String}. If null, then use the default Charset.
1926     * @return The empty byte[] if {@code string} is null, the result of {@link String#getBytes(Charset)} otherwise.
1927     * @see String#getBytes(Charset)
1928     * @since 3.10
1929     */
1930    public static byte[] getBytes(final String string, final Charset charset) {
1931        return string == null ? ArrayUtils.EMPTY_BYTE_ARRAY : string.getBytes(Charsets.toCharset(charset));
1932    }
1933
1934    /**
1935     * Calls {@link String#getBytes(String)} in a null-safe manner.
1936     *
1937     * @param string input string
1938     * @param charset The {@link Charset} name to encode the {@link String}. If null, then use the default Charset.
1939     * @return The empty byte[] if {@code string} is null, the result of {@link String#getBytes(String)} otherwise.
1940     * @throws UnsupportedEncodingException Thrown when the named charset is not supported.
1941     * @see String#getBytes(String)
1942     * @since 3.10
1943     */
1944    public static byte[] getBytes(final String string, final String charset) throws UnsupportedEncodingException {
1945        return string == null ? ArrayUtils.EMPTY_BYTE_ARRAY : string.getBytes(Charsets.toCharsetName(charset));
1946    }
1947
1948    /**
1949     * Compares all Strings in an array and returns the initial sequence of
1950     * characters that is common to all of them.
1951     *
1952     * <p>For example,
1953     * {@code getCommonPrefix(new String[] {"i am a machine", "i am a robot"}) -&gt; "i am a "}</p>
1954     *
1955     * <pre>
1956     * StringUtils.getCommonPrefix(null)                             = ""
1957     * StringUtils.getCommonPrefix(new String[] {})                  = ""
1958     * StringUtils.getCommonPrefix(new String[] {"abc"})             = "abc"
1959     * StringUtils.getCommonPrefix(new String[] {null, null})        = ""
1960     * StringUtils.getCommonPrefix(new String[] {"", ""})            = ""
1961     * StringUtils.getCommonPrefix(new String[] {"", null})          = ""
1962     * StringUtils.getCommonPrefix(new String[] {"abc", null, null}) = ""
1963     * StringUtils.getCommonPrefix(new String[] {null, null, "abc"}) = ""
1964     * StringUtils.getCommonPrefix(new String[] {"", "abc"})         = ""
1965     * StringUtils.getCommonPrefix(new String[] {"abc", ""})         = ""
1966     * StringUtils.getCommonPrefix(new String[] {"abc", "abc"})      = "abc"
1967     * StringUtils.getCommonPrefix(new String[] {"abc", "a"})        = "a"
1968     * StringUtils.getCommonPrefix(new String[] {"ab", "abxyz"})     = "ab"
1969     * StringUtils.getCommonPrefix(new String[] {"abcde", "abxyz"})  = "ab"
1970     * StringUtils.getCommonPrefix(new String[] {"abcde", "xyz"})    = ""
1971     * StringUtils.getCommonPrefix(new String[] {"xyz", "abcde"})    = ""
1972     * StringUtils.getCommonPrefix(new String[] {"i am a machine", "i am a robot"}) = "i am a "
1973     * </pre>
1974     *
1975     * @param strs  array of String objects, entries may be null
1976     * @return the initial sequence of characters that are common to all Strings
1977     * in the array; empty String if the array is null, the elements are all null
1978     * or if there is no common prefix.
1979     * @since 2.4
1980     */
1981    public static String getCommonPrefix(final String... strs) {
1982        if (ArrayUtils.isEmpty(strs)) {
1983            return EMPTY;
1984        }
1985        final int smallestIndexOfDiff = indexOfDifference(strs);
1986        if (smallestIndexOfDiff == INDEX_NOT_FOUND) {
1987            // all strings were identical
1988            if (strs[0] == null) {
1989                return EMPTY;
1990            }
1991            return strs[0];
1992        }
1993        if (smallestIndexOfDiff == 0) {
1994            // there were no common initial characters
1995            return EMPTY;
1996        }
1997        // we found a common initial character sequence
1998        return strs[0].substring(0, smallestIndexOfDiff);
1999    }
2000
2001    /**
2002     * Checks if a String {@code str} contains Unicode digits,
2003     * if yes then concatenate all the digits in {@code str} and return it as a String.
2004     *
2005     * <p>An empty ("") String will be returned if no digits found in {@code str}.</p>
2006     *
2007     * <pre>
2008     * StringUtils.getDigits(null)                 = null
2009     * StringUtils.getDigits("")                   = ""
2010     * StringUtils.getDigits("abc")                = ""
2011     * StringUtils.getDigits("1000$")              = "1000"
2012     * StringUtils.getDigits("1123~45")            = "112345"
2013     * StringUtils.getDigits("(541) 754-3010")     = "5417543010"
2014     * StringUtils.getDigits("\u0967\u0968\u0969") = "\u0967\u0968\u0969"
2015     * </pre>
2016     *
2017     * @param str the String to extract digits from, may be null
2018     * @return String with only digits,
2019     *           or an empty ("") String if no digits found,
2020     *           or {@code null} String if {@code str} is null
2021     * @since 3.6
2022     */
2023    public static String getDigits(final String str) {
2024        if (isEmpty(str)) {
2025            return str;
2026        }
2027        final int sz = str.length();
2028        final StringBuilder strDigits = new StringBuilder(sz);
2029        for (int i = 0; i < sz; i++) {
2030            final char tempChar = str.charAt(i);
2031            if (Character.isDigit(tempChar)) {
2032                strDigits.append(tempChar);
2033            }
2034        }
2035        return strDigits.toString();
2036    }
2037
2038    /**
2039     * Find the Fuzzy Distance which indicates the similarity score between two Strings.
2040     *
2041     * <p>This string matching algorithm is similar to the algorithms of editors such as Sublime Text,
2042     * TextMate, Atom and others. One point is given for every matched character. Subsequent
2043     * matches yield two bonus points. A higher score indicates a higher similarity.</p>
2044     *
2045     * <pre>
2046     * StringUtils.getFuzzyDistance(null, null, null)                                    = IllegalArgumentException
2047     * StringUtils.getFuzzyDistance("", "", Locale.ENGLISH)                              = 0
2048     * StringUtils.getFuzzyDistance("Workshop", "b", Locale.ENGLISH)                     = 0
2049     * StringUtils.getFuzzyDistance("Room", "o", Locale.ENGLISH)                         = 1
2050     * StringUtils.getFuzzyDistance("Workshop", "w", Locale.ENGLISH)                     = 1
2051     * StringUtils.getFuzzyDistance("Workshop", "ws", Locale.ENGLISH)                    = 2
2052     * StringUtils.getFuzzyDistance("Workshop", "wo", Locale.ENGLISH)                    = 4
2053     * StringUtils.getFuzzyDistance("Apache Software Foundation", "asf", Locale.ENGLISH) = 3
2054     * </pre>
2055     *
2056     * @param term a full term that should be matched against, must not be null
2057     * @param query the query that will be matched against a term, must not be null
2058     * @param locale This string matching logic is case-insensitive. A locale is necessary to normalize
2059     *  both Strings to lower case.
2060     * @return result score
2061     * @throws IllegalArgumentException if either String input {@code null} or Locale input {@code null}
2062     * @since 3.4
2063     * @deprecated As of 3.6, use Apache Commons Text
2064     * <a href="https://commons.apache.org/proper/commons-text/javadocs/api-release/org/apache/commons/text/similarity/FuzzyScore.html">
2065     * FuzzyScore</a> instead
2066     */
2067    @Deprecated
2068    public static int getFuzzyDistance(final CharSequence term, final CharSequence query, final Locale locale) {
2069        if (term == null || query == null) {
2070            throw new IllegalArgumentException("Strings must not be null");
2071        }
2072        if (locale == null) {
2073            throw new IllegalArgumentException("Locale must not be null");
2074        }
2075
2076        // fuzzy logic is case-insensitive. We normalize the Strings to lower
2077        // case right from the start. Turning characters to lower case
2078        // via Character.toLowerCase(char) is unfortunately insufficient
2079        // as it does not accept a locale.
2080        final String termLowerCase = term.toString().toLowerCase(locale);
2081        final String queryLowerCase = query.toString().toLowerCase(locale);
2082
2083        // the resulting score
2084        int score = 0;
2085
2086        // the position in the term which will be scanned next for potential
2087        // query character matches
2088        int termIndex = 0;
2089
2090        // index of the previously matched character in the term
2091        int previousMatchingCharacterIndex = Integer.MIN_VALUE;
2092
2093        for (int queryIndex = 0; queryIndex < queryLowerCase.length(); queryIndex++) {
2094            final char queryChar = queryLowerCase.charAt(queryIndex);
2095
2096            boolean termCharacterMatchFound = false;
2097            for (; termIndex < termLowerCase.length() && !termCharacterMatchFound; termIndex++) {
2098                final char termChar = termLowerCase.charAt(termIndex);
2099
2100                if (queryChar == termChar) {
2101                    // simple character matches result in one point
2102                    score++;
2103
2104                    // subsequent character matches further improve
2105                    // the score.
2106                    if (previousMatchingCharacterIndex + 1 == termIndex) {
2107                        score += 2;
2108                    }
2109
2110                    previousMatchingCharacterIndex = termIndex;
2111
2112                    // we can leave the nested loop. Every character in the
2113                    // query can match at most one character in the term.
2114                    termCharacterMatchFound = true;
2115                }
2116            }
2117        }
2118
2119        return score;
2120    }
2121
2122    /**
2123     * Returns either the passed in CharSequence, or if the CharSequence is {@link #isBlank(CharSequence) blank} (whitespaces, empty ({@code ""}) or
2124     * {@code null}), the value supplied by {@code defaultStrSupplier}.
2125     *
2126     * <p>
2127     * Whitespace is defined by {@link Character#isWhitespace(char)}.
2128     * </p>
2129     *
2130     * <p>
2131     * Caller responsible for thread-safety and exception handling of default value supplier
2132     * </p>
2133     *
2134     * <pre>
2135     * {@code
2136     * StringUtils.getIfBlank(null, () -> "NULL")   = "NULL"
2137     * StringUtils.getIfBlank("", () -> "NULL")     = "NULL"
2138     * StringUtils.getIfBlank(" ", () -> "NULL")    = "NULL"
2139     * StringUtils.getIfBlank("bat", () -> "NULL")  = "bat"
2140     * StringUtils.getIfBlank("", () -> null)       = null
2141     * StringUtils.getIfBlank("", null)             = null
2142     * }</pre>
2143     *
2144     * @param <T>             the specific kind of CharSequence
2145     * @param str             the CharSequence to check, may be null
2146     * @param defaultSupplier the supplier of default CharSequence to return if the input is {@link #isBlank(CharSequence) blank} (whitespaces, empty
2147     *                        ({@code ""}) or {@code null}); may be null
2148     * @return the passed in CharSequence, or the default
2149     * @see StringUtils#defaultString(String, String)
2150     * @see #isBlank(CharSequence)
2151     * @since 3.10
2152     */
2153    public static <T extends CharSequence> T getIfBlank(final T str, final Supplier<T> defaultSupplier) {
2154        return isBlank(str) ? Suppliers.get(defaultSupplier) : str;
2155    }
2156
2157    /**
2158     * Returns either the passed in CharSequence, or if the CharSequence is
2159     * empty or {@code null}, the value supplied by {@code defaultStrSupplier}.
2160     *
2161     * <p>Caller responsible for thread-safety and exception handling of default value supplier</p>
2162     *
2163     * <pre>
2164     * {@code
2165     * StringUtils.getIfEmpty(null, () -> "NULL")    = "NULL"
2166     * StringUtils.getIfEmpty("", () -> "NULL")      = "NULL"
2167     * StringUtils.getIfEmpty(" ", () -> "NULL")     = " "
2168     * StringUtils.getIfEmpty("bat", () -> "NULL")   = "bat"
2169     * StringUtils.getIfEmpty("", () -> null)        = null
2170     * StringUtils.getIfEmpty("", null)              = null
2171     * }
2172     * </pre>
2173     * @param <T> the specific kind of CharSequence
2174     * @param str  the CharSequence to check, may be null
2175     * @param defaultSupplier  the supplier of default CharSequence to return
2176     *  if the input is empty ("") or {@code null}, may be null
2177     * @return the passed in CharSequence, or the default
2178     * @see StringUtils#defaultString(String, String)
2179     * @since 3.10
2180     */
2181    public static <T extends CharSequence> T getIfEmpty(final T str, final Supplier<T> defaultSupplier) {
2182        return isEmpty(str) ? Suppliers.get(defaultSupplier) : str;
2183    }
2184
2185    /**
2186     * Find the Jaro Winkler Distance which indicates the similarity score between two Strings.
2187     *
2188     * <p>The Jaro measure is the weighted sum of percentage of matched characters from each file and transposed characters.
2189     * Winkler increased this measure for matching initial characters.</p>
2190     *
2191     * <p>This implementation is based on the Jaro Winkler similarity algorithm
2192     * from <a href="https://en.wikipedia.org/wiki/Jaro%E2%80%93Winkler_distance">https://en.wikipedia.org/wiki/Jaro%E2%80%93Winkler_distance</a>.</p>
2193     *
2194     * <pre>
2195     * StringUtils.getJaroWinklerDistance(null, null)          = IllegalArgumentException
2196     * StringUtils.getJaroWinklerDistance("", "")              = 0.0
2197     * StringUtils.getJaroWinklerDistance("", "a")             = 0.0
2198     * StringUtils.getJaroWinklerDistance("aaapppp", "")       = 0.0
2199     * StringUtils.getJaroWinklerDistance("frog", "fog")       = 0.93
2200     * StringUtils.getJaroWinklerDistance("fly", "ant")        = 0.0
2201     * StringUtils.getJaroWinklerDistance("elephant", "hippo") = 0.44
2202     * StringUtils.getJaroWinklerDistance("hippo", "elephant") = 0.44
2203     * StringUtils.getJaroWinklerDistance("hippo", "zzzzzzzz") = 0.0
2204     * StringUtils.getJaroWinklerDistance("hello", "hallo")    = 0.88
2205     * StringUtils.getJaroWinklerDistance("ABC Corporation", "ABC Corp") = 0.93
2206     * StringUtils.getJaroWinklerDistance("D N H Enterprises Inc", "D &amp; H Enterprises, Inc.") = 0.95
2207     * StringUtils.getJaroWinklerDistance("My Gym Children's Fitness Center", "My Gym. Childrens Fitness") = 0.92
2208     * StringUtils.getJaroWinklerDistance("PENNSYLVANIA", "PENNCISYLVNIA") = 0.88
2209     * </pre>
2210     *
2211     * @param first the first String, must not be null
2212     * @param second the second String, must not be null
2213     * @return result distance
2214     * @throws IllegalArgumentException if either String input {@code null}
2215     * @since 3.3
2216     * @deprecated As of 3.6, use Apache Commons Text
2217     * <a href="https://commons.apache.org/proper/commons-text/javadocs/api-release/org/apache/commons/text/similarity/JaroWinklerDistance.html">
2218     * JaroWinklerDistance</a> instead
2219     */
2220    @Deprecated
2221    public static double getJaroWinklerDistance(final CharSequence first, final CharSequence second) {
2222        final double DEFAULT_SCALING_FACTOR = 0.1;
2223
2224        if (first == null || second == null) {
2225            throw new IllegalArgumentException("Strings must not be null");
2226        }
2227
2228        final int[] mtp = matches(first, second);
2229        final double m = mtp[0];
2230        if (m == 0) {
2231            return 0D;
2232        }
2233        final double j = (m / first.length() + m / second.length() + (m - mtp[1]) / m) / 3;
2234        final double jw = j < 0.7D ? j : j + Math.min(DEFAULT_SCALING_FACTOR, 1D / mtp[3]) * mtp[2] * (1D - j);
2235        return Math.round(jw * 100.0D) / 100.0D;
2236    }
2237
2238    /**
2239     * Find the Levenshtein distance between two Strings.
2240     *
2241     * <p>This is the number of changes needed to change one String into
2242     * another, where each change is a single character modification (deletion,
2243     * insertion or substitution).</p>
2244     *
2245     * <p>The implementation uses a single-dimensional array of length s.length() + 1. See
2246     * <a href="https://blog.softwx.net/2014/12/optimizing-levenshtein-algorithm-in-c.html">
2247     * https://blog.softwx.net/2014/12/optimizing-levenshtein-algorithm-in-c.html</a> for details.</p>
2248     *
2249     * <pre>
2250     * StringUtils.getLevenshteinDistance(null, *)             = IllegalArgumentException
2251     * StringUtils.getLevenshteinDistance(*, null)             = IllegalArgumentException
2252     * StringUtils.getLevenshteinDistance("", "")              = 0
2253     * StringUtils.getLevenshteinDistance("", "a")             = 1
2254     * StringUtils.getLevenshteinDistance("aaapppp", "")       = 7
2255     * StringUtils.getLevenshteinDistance("frog", "fog")       = 1
2256     * StringUtils.getLevenshteinDistance("fly", "ant")        = 3
2257     * StringUtils.getLevenshteinDistance("elephant", "hippo") = 7
2258     * StringUtils.getLevenshteinDistance("hippo", "elephant") = 7
2259     * StringUtils.getLevenshteinDistance("hippo", "zzzzzzzz") = 8
2260     * StringUtils.getLevenshteinDistance("hello", "hallo")    = 1
2261     * </pre>
2262     *
2263     * @param s  the first String, must not be null
2264     * @param t  the second String, must not be null
2265     * @return result distance
2266     * @throws IllegalArgumentException if either String input {@code null}
2267     * @since 3.0 Changed signature from getLevenshteinDistance(String, String) to
2268     * getLevenshteinDistance(CharSequence, CharSequence)
2269     * @deprecated As of 3.6, use Apache Commons Text
2270     * <a href="https://commons.apache.org/proper/commons-text/javadocs/api-release/org/apache/commons/text/similarity/LevenshteinDistance.html">
2271     * LevenshteinDistance</a> instead
2272     */
2273    @Deprecated
2274    public static int getLevenshteinDistance(CharSequence s, CharSequence t) {
2275        if (s == null || t == null) {
2276            throw new IllegalArgumentException("Strings must not be null");
2277        }
2278
2279        int n = s.length();
2280        int m = t.length();
2281
2282        if (n == 0) {
2283            return m;
2284        }
2285        if (m == 0) {
2286            return n;
2287        }
2288
2289        if (n > m) {
2290            // swap the input strings to consume less memory
2291            final CharSequence tmp = s;
2292            s = t;
2293            t = tmp;
2294            n = m;
2295            m = t.length();
2296        }
2297
2298        final int[] p = new int[n + 1];
2299        // indexes into strings s and t
2300        int i; // iterates through s
2301        int j; // iterates through t
2302        int upperleft;
2303        int upper;
2304
2305        char jOfT; // jth character of t
2306        int cost;
2307
2308        for (i = 0; i <= n; i++) {
2309            p[i] = i;
2310        }
2311
2312        for (j = 1; j <= m; j++) {
2313            upperleft = p[0];
2314            jOfT = t.charAt(j - 1);
2315            p[0] = j;
2316
2317            for (i = 1; i <= n; i++) {
2318                upper = p[i];
2319                cost = s.charAt(i - 1) == jOfT ? 0 : 1;
2320                // minimum of cell to the left+1, to the top+1, diagonally left and up +cost
2321                p[i] = Math.min(Math.min(p[i - 1] + 1, p[i] + 1), upperleft + cost);
2322                upperleft = upper;
2323            }
2324        }
2325
2326        return p[n];
2327    }
2328
2329    /**
2330     * Find the Levenshtein distance between two Strings if it's less than or equal to a given
2331     * threshold.
2332     *
2333     * <p>This is the number of changes needed to change one String into
2334     * another, where each change is a single character modification (deletion,
2335     * insertion or substitution).</p>
2336     *
2337     * <p>This implementation follows from Algorithms on Strings, Trees and Sequences by Dan Gusfield
2338     * and Chas Emerick's implementation of the Levenshtein distance algorithm from
2339     * <a href="https://web.archive.org/web/20120212021906/http%3A//www.merriampark.com/ld.htm">http://www.merriampark.com/ld.htm</a></p>
2340     *
2341     * <pre>
2342     * StringUtils.getLevenshteinDistance(null, *, *)             = IllegalArgumentException
2343     * StringUtils.getLevenshteinDistance(*, null, *)             = IllegalArgumentException
2344     * StringUtils.getLevenshteinDistance(*, *, -1)               = IllegalArgumentException
2345     * StringUtils.getLevenshteinDistance("", "", 0)              = 0
2346     * StringUtils.getLevenshteinDistance("aaapppp", "", 8)       = 7
2347     * StringUtils.getLevenshteinDistance("aaapppp", "", 7)       = 7
2348     * StringUtils.getLevenshteinDistance("aaapppp", "", 6))      = -1
2349     * StringUtils.getLevenshteinDistance("elephant", "hippo", 7) = 7
2350     * StringUtils.getLevenshteinDistance("elephant", "hippo", 6) = -1
2351     * StringUtils.getLevenshteinDistance("hippo", "elephant", 7) = 7
2352     * StringUtils.getLevenshteinDistance("hippo", "elephant", 6) = -1
2353     * </pre>
2354     *
2355     * @param s  the first String, must not be null
2356     * @param t  the second String, must not be null
2357     * @param threshold the target threshold, must not be negative
2358     * @return result distance, or {@code -1} if the distance would be greater than the threshold
2359     * @throws IllegalArgumentException if either String input {@code null} or negative threshold
2360     * @deprecated As of 3.6, use Apache Commons Text
2361     * <a href="https://commons.apache.org/proper/commons-text/javadocs/api-release/org/apache/commons/text/similarity/LevenshteinDistance.html">
2362     * LevenshteinDistance</a> instead
2363     */
2364    @Deprecated
2365    public static int getLevenshteinDistance(CharSequence s, CharSequence t, final int threshold) {
2366        if (s == null || t == null) {
2367            throw new IllegalArgumentException("Strings must not be null");
2368        }
2369        if (threshold < 0) {
2370            throw new IllegalArgumentException("Threshold must not be negative");
2371        }
2372
2373        /*
2374        This implementation only computes the distance if it's less than or equal to the
2375        threshold value, returning -1 if it's greater.  The advantage is performance: unbounded
2376        distance is O(nm), but a bound of k allows us to reduce it to O(km) time by only
2377        computing a diagonal stripe of width 2k + 1 of the cost table.
2378        It is also possible to use this to compute the unbounded Levenshtein distance by starting
2379        the threshold at 1 and doubling each time until the distance is found; this is O(dm), where
2380        d is the distance.
2381
2382        One subtlety comes from needing to ignore entries on the border of our stripe
2383        eg.
2384        p[] = |#|#|#|*
2385        d[] =  *|#|#|#|
2386        We must ignore the entry to the left of the leftmost member
2387        We must ignore the entry above the rightmost member
2388
2389        Another subtlety comes from our stripe running off the matrix if the strings aren't
2390        of the same size.  Since string s is always swapped to be the shorter of the two,
2391        the stripe will always run off to the upper right instead of the lower left of the matrix.
2392
2393        As a concrete example, suppose s is of length 5, t is of length 7, and our threshold is 1.
2394        In this case we're going to walk a stripe of length 3.  The matrix would look like so:
2395
2396           1 2 3 4 5
2397        1 |#|#| | | |
2398        2 |#|#|#| | |
2399        3 | |#|#|#| |
2400        4 | | |#|#|#|
2401        5 | | | |#|#|
2402        6 | | | | |#|
2403        7 | | | | | |
2404
2405        Note how the stripe leads off the table as there is no possible way to turn a string of length 5
2406        into one of length 7 in edit distance of 1.
2407
2408        Additionally, this implementation decreases memory usage by using two
2409        single-dimensional arrays and swapping them back and forth instead of allocating
2410        an entire n by m matrix.  This requires a few minor changes, such as immediately returning
2411        when it's detected that the stripe has run off the matrix and initially filling the arrays with
2412        large values so that entries we don't compute are ignored.
2413
2414        See Algorithms on Strings, Trees and Sequences by Dan Gusfield for some discussion.
2415         */
2416
2417        int n = s.length(); // length of s
2418        int m = t.length(); // length of t
2419
2420        // if one string is empty, the edit distance is necessarily the length of the other
2421        if (n == 0) {
2422            return m <= threshold ? m : -1;
2423        }
2424        if (m == 0) {
2425            return n <= threshold ? n : -1;
2426        }
2427        if (Math.abs(n - m) > threshold) {
2428            // no need to calculate the distance if the length difference is greater than the threshold
2429            return -1;
2430        }
2431
2432        if (n > m) {
2433            // swap the two strings to consume less memory
2434            final CharSequence tmp = s;
2435            s = t;
2436            t = tmp;
2437            n = m;
2438            m = t.length();
2439        }
2440
2441        int[] p = new int[n + 1]; // 'previous' cost array, horizontally
2442        int[] d = new int[n + 1]; // cost array, horizontally
2443        int[] tmp; // placeholder to assist in swapping p and d
2444
2445        // fill in starting table values
2446        final int boundary = Math.min(n, threshold) + 1;
2447        for (int i = 0; i < boundary; i++) {
2448            p[i] = i;
2449        }
2450        // these fills ensure that the value above the rightmost entry of our
2451        // stripe will be ignored in following loop iterations
2452        Arrays.fill(p, boundary, p.length, Integer.MAX_VALUE);
2453        Arrays.fill(d, Integer.MAX_VALUE);
2454
2455        // iterates through t
2456        for (int j = 1; j <= m; j++) {
2457            final char jOfT = t.charAt(j - 1); // jth character of t
2458            d[0] = j;
2459
2460            // compute stripe indices, constrain to array size
2461            final int min = Math.max(1, j - threshold);
2462            final int max = j > Integer.MAX_VALUE - threshold ? n : Math.min(n, j + threshold);
2463
2464            // the stripe may lead off of the table if s and t are of different sizes
2465            if (min > max) {
2466                return -1;
2467            }
2468
2469            // ignore entry left of leftmost
2470            if (min > 1) {
2471                d[min - 1] = Integer.MAX_VALUE;
2472            }
2473
2474            // iterates through [min, max] in s
2475            for (int i = min; i <= max; i++) {
2476                if (s.charAt(i - 1) == jOfT) {
2477                    // diagonally left and up
2478                    d[i] = p[i - 1];
2479                } else {
2480                    // 1 + minimum of cell to the left, to the top, diagonally left and up
2481                    d[i] = 1 + Math.min(Math.min(d[i - 1], p[i]), p[i - 1]);
2482                }
2483            }
2484
2485            // copy current distance counts to 'previous row' distance counts
2486            tmp = p;
2487            p = d;
2488            d = tmp;
2489        }
2490
2491        // if p[n] is greater than the threshold, there's no guarantee on it being the correct
2492        // distance
2493        if (p[n] <= threshold) {
2494            return p[n];
2495        }
2496        return -1;
2497    }
2498
2499    /**
2500     * Finds the first index within a CharSequence, handling {@code null}.
2501     * This method uses {@link String#indexOf(String, int)} if possible.
2502     *
2503     * <p>A {@code null} CharSequence will return {@code -1}.</p>
2504     *
2505     * <pre>
2506     * StringUtils.indexOf(null, *)          = -1
2507     * StringUtils.indexOf(*, null)          = -1
2508     * StringUtils.indexOf("", "")           = 0
2509     * StringUtils.indexOf("", *)            = -1 (except when * = "")
2510     * StringUtils.indexOf("aabaabaa", "a")  = 0
2511     * StringUtils.indexOf("aabaabaa", "b")  = 2
2512     * StringUtils.indexOf("aabaabaa", "ab") = 1
2513     * StringUtils.indexOf("aabaabaa", "")   = 0
2514     * </pre>
2515     *
2516     * @param seq  the CharSequence to check, may be null
2517     * @param searchSeq  the CharSequence to find, may be null
2518     * @return the first index of the search CharSequence,
2519     *  -1 if no match or {@code null} string input
2520     * @since 2.0
2521     * @since 3.0 Changed signature from indexOf(String, String) to indexOf(CharSequence, CharSequence)
2522     * @deprecated Use {@link Strings#indexOf(CharSequence, CharSequence) Strings.CS.indexOf(CharSequence, CharSequence)}
2523     */
2524    @Deprecated
2525    public static int indexOf(final CharSequence seq, final CharSequence searchSeq) {
2526        return Strings.CS.indexOf(seq, searchSeq);
2527    }
2528
2529    /**
2530     * Finds the first index within a CharSequence, handling {@code null}.
2531     * This method uses {@link String#indexOf(String, int)} if possible.
2532     *
2533     * <p>A {@code null} CharSequence will return {@code -1}.
2534     * A negative start position is treated as zero.
2535     * An empty ("") search CharSequence always matches.
2536     * A start position greater than the string length only matches
2537     * an empty search CharSequence.</p>
2538     *
2539     * <pre>
2540     * StringUtils.indexOf(null, *, *)          = -1
2541     * StringUtils.indexOf(*, null, *)          = -1
2542     * StringUtils.indexOf("", "", 0)           = 0
2543     * StringUtils.indexOf("", *, 0)            = -1 (except when * = "")
2544     * StringUtils.indexOf("aabaabaa", "a", 0)  = 0
2545     * StringUtils.indexOf("aabaabaa", "b", 0)  = 2
2546     * StringUtils.indexOf("aabaabaa", "ab", 0) = 1
2547     * StringUtils.indexOf("aabaabaa", "b", 3)  = 5
2548     * StringUtils.indexOf("aabaabaa", "b", 9)  = -1
2549     * StringUtils.indexOf("aabaabaa", "b", -1) = 2
2550     * StringUtils.indexOf("aabaabaa", "", 2)   = 2
2551     * StringUtils.indexOf("abc", "", 9)        = 3
2552     * </pre>
2553     *
2554     * @param seq  the CharSequence to check, may be null
2555     * @param searchSeq  the CharSequence to find, may be null
2556     * @param startPos  the start position, negative treated as zero
2557     * @return the first index of the search CharSequence (always &ge; startPos),
2558     *  -1 if no match or {@code null} string input
2559     * @since 2.0
2560     * @since 3.0 Changed signature from indexOf(String, String, int) to indexOf(CharSequence, CharSequence, int)
2561     * @deprecated Use {@link Strings#indexOf(CharSequence, CharSequence, int) Strings.CS.indexOf(CharSequence, CharSequence, int)}
2562     */
2563    @Deprecated
2564    public static int indexOf(final CharSequence seq, final CharSequence searchSeq, final int startPos) {
2565        return Strings.CS.indexOf(seq, searchSeq, startPos);
2566    }
2567
2568    /**
2569     * Returns the index within {@code seq} of the first occurrence of
2570     * the specified character. If a character with value
2571     * {@code searchChar} occurs in the character sequence represented by
2572     * {@code seq} {@link CharSequence} object, then the index (in Unicode
2573     * code units) of the first such occurrence is returned. For
2574     * values of {@code searchChar} in the range from 0 to 0xFFFF
2575     * (inclusive), this is the smallest value <em>k</em> such that:
2576     * <blockquote><pre>
2577     * this.charAt(<em>k</em>) == searchChar
2578     * </pre></blockquote>
2579     * is true. For other values of {@code searchChar}, it is the
2580     * smallest value <em>k</em> such that:
2581     * <blockquote><pre>
2582     * this.codePointAt(<em>k</em>) == searchChar
2583     * </pre></blockquote>
2584     * is true. In either case, if no such character occurs in {@code seq},
2585     * then {@code INDEX_NOT_FOUND (-1)} is returned.
2586     *
2587     * <p>Furthermore, a {@code null} or empty ("") CharSequence will
2588     * return {@code INDEX_NOT_FOUND (-1)}.</p>
2589     *
2590     * <pre>
2591     * StringUtils.indexOf(null, *)         = -1
2592     * StringUtils.indexOf("", *)           = -1
2593     * StringUtils.indexOf("aabaabaa", 'a') = 0
2594     * StringUtils.indexOf("aabaabaa", 'b') = 2
2595     * StringUtils.indexOf("aaaaaaaa", 'Z') = -1
2596     * </pre>
2597     *
2598     * @param seq  the CharSequence to check, may be null
2599     * @param searchChar  the character to find
2600     * @return the first index of the search character,
2601     *  -1 if no match or {@code null} string input
2602     * @since 2.0
2603     * @since 3.0 Changed signature from indexOf(String, int) to indexOf(CharSequence, int)
2604     * @since 3.6 Updated {@link CharSequenceUtils} call to behave more like {@link String}
2605     */
2606    public static int indexOf(final CharSequence seq, final int searchChar) {
2607        if (isEmpty(seq)) {
2608            return INDEX_NOT_FOUND;
2609        }
2610        return CharSequenceUtils.indexOf(seq, searchChar, 0);
2611    }
2612
2613    /**
2614     * Returns the index within {@code seq} of the first occurrence of the
2615     * specified character, starting the search at the specified index.
2616     * <p>
2617     * If a character with value {@code searchChar} occurs in the
2618     * character sequence represented by the {@code seq} {@link CharSequence}
2619     * object at an index no smaller than {@code startPos}, then
2620     * the index of the first such occurrence is returned. For values
2621     * of {@code searchChar} in the range from 0 to 0xFFFF (inclusive),
2622     * this is the smallest value <em>k</em> such that:
2623     * <blockquote><pre>
2624     * (this.charAt(<em>k</em>) == searchChar) &amp;&amp; (<em>k</em> &gt;= startPos)
2625     * </pre></blockquote>
2626     * is true. For other values of {@code searchChar}, it is the
2627     * smallest value <em>k</em> such that:
2628     * <blockquote><pre>
2629     * (this.codePointAt(<em>k</em>) == searchChar) &amp;&amp; (<em>k</em> &gt;= startPos)
2630     * </pre></blockquote>
2631     * is true. In either case, if no such character occurs in {@code seq}
2632     * at or after position {@code startPos}, then
2633     * {@code -1} is returned.
2634     *
2635     * <p>
2636     * There is no restriction on the value of {@code startPos}. If it
2637     * is negative, it has the same effect as if it were zero: this entire
2638     * string may be searched. If it is greater than the length of this
2639     * string, it has the same effect as if it were equal to the length of
2640     * this string: {@code (INDEX_NOT_FOUND) -1} is returned. Furthermore, a
2641     * {@code null} or empty ("") CharSequence will
2642     * return {@code (INDEX_NOT_FOUND) -1}.
2643     *
2644     * <p>All indices are specified in {@code char} values
2645     * (Unicode code units).
2646     *
2647     * <pre>
2648     * StringUtils.indexOf(null, *, *)          = -1
2649     * StringUtils.indexOf("", *, *)            = -1
2650     * StringUtils.indexOf("aabaabaa", 'b', 0)  = 2
2651     * StringUtils.indexOf("aabaabaa", 'b', 3)  = 5
2652     * StringUtils.indexOf("aabaabaa", 'b', 9)  = -1
2653     * StringUtils.indexOf("aabaabaa", 'b', -1) = 2
2654     * </pre>
2655     *
2656     * @param seq  the CharSequence to check, may be null
2657     * @param searchChar  the character to find
2658     * @param startPos  the start position, negative treated as zero
2659     * @return the first index of the search character (always &ge; startPos),
2660     *  -1 if no match or {@code null} string input
2661     * @since 2.0
2662     * @since 3.0 Changed signature from indexOf(String, int, int) to indexOf(CharSequence, int, int)
2663     * @since 3.6 Updated {@link CharSequenceUtils} call to behave more like {@link String}
2664     */
2665    public static int indexOf(final CharSequence seq, final int searchChar, final int startPos) {
2666        if (isEmpty(seq)) {
2667            return INDEX_NOT_FOUND;
2668        }
2669        return CharSequenceUtils.indexOf(seq, searchChar, startPos);
2670    }
2671
2672    /**
2673     * Search a CharSequence to find the first index of any
2674     * character in the given set of characters.
2675     *
2676     * <p>A {@code null} String will return {@code -1}.
2677     * A {@code null} or zero length search array will return {@code -1}.</p>
2678     *
2679     * <pre>
2680     * StringUtils.indexOfAny(null, *)                  = -1
2681     * StringUtils.indexOfAny("", *)                    = -1
2682     * StringUtils.indexOfAny(*, null)                  = -1
2683     * StringUtils.indexOfAny(*, [])                    = -1
2684     * StringUtils.indexOfAny("zzabyycdxx", ['z', 'a']) = 0
2685     * StringUtils.indexOfAny("zzabyycdxx", ['b', 'y']) = 3
2686     * StringUtils.indexOfAny("aba", ['z'])             = -1
2687     * </pre>
2688     *
2689     * @param cs  the CharSequence to check, may be null
2690     * @param searchChars  the chars to search for, may be null
2691     * @return the index of any of the chars, -1 if no match or null input
2692     * @since 2.0
2693     * @since 3.0 Changed signature from indexOfAny(String, char[]) to indexOfAny(CharSequence, char...)
2694     */
2695    public static int indexOfAny(final CharSequence cs, final char... searchChars) {
2696        if (isEmpty(cs) || ArrayUtils.isEmpty(searchChars)) {
2697            return INDEX_NOT_FOUND;
2698        }
2699        final int csLen = cs.length();
2700        final int csLast = csLen - 1;
2701        final int searchLen = searchChars.length;
2702        final int searchLast = searchLen - 1;
2703        for (int i = 0; i < csLen; i++) {
2704            final char ch = cs.charAt(i);
2705            for (int j = 0; j < searchLen; j++) {
2706                if (searchChars[j] == ch) {
2707                    // ch is a supplementary character
2708                    if (i >= csLast || j >= searchLast || !Character.isHighSurrogate(ch) || searchChars[j + 1] == cs.charAt(i + 1)) {
2709                        return i;
2710                    }
2711                }
2712            }
2713        }
2714        return INDEX_NOT_FOUND;
2715    }
2716
2717    /**
2718     * Find the first index of any of a set of potential substrings.
2719     *
2720     * <p>A {@code null} CharSequence will return {@code -1}.
2721     * A {@code null} or zero length search array will return {@code -1}.
2722     * A {@code null} search array entry will be ignored, but a search
2723     * array containing "" will return {@code 0} if {@code str} is not
2724     * null. This method uses {@link String#indexOf(String)} if possible.</p>
2725     *
2726     * <pre>
2727     * StringUtils.indexOfAny(null, *)                      = -1
2728     * StringUtils.indexOfAny(*, null)                      = -1
2729     * StringUtils.indexOfAny(*, [])                        = -1
2730     * StringUtils.indexOfAny("zzabyycdxx", ["ab", "cd"])   = 2
2731     * StringUtils.indexOfAny("zzabyycdxx", ["cd", "ab"])   = 2
2732     * StringUtils.indexOfAny("zzabyycdxx", ["mn", "op"])   = -1
2733     * StringUtils.indexOfAny("zzabyycdxx", ["zab", "aby"]) = 1
2734     * StringUtils.indexOfAny("zzabyycdxx", [""])           = 0
2735     * StringUtils.indexOfAny("", [""])                     = 0
2736     * StringUtils.indexOfAny("", ["a"])                    = -1
2737     * </pre>
2738     *
2739     * @param str  the CharSequence to check, may be null
2740     * @param searchStrs  the CharSequences to search for, may be null
2741     * @return the first index of any of the searchStrs in str, -1 if no match
2742     * @since 3.0 Changed signature from indexOfAny(String, String[]) to indexOfAny(CharSequence, CharSequence...)
2743     */
2744    public static int indexOfAny(final CharSequence str, final CharSequence... searchStrs) {
2745        if (str == null || searchStrs == null) {
2746            return INDEX_NOT_FOUND;
2747        }
2748
2749        // String's can't have a MAX_VALUEth index.
2750        int ret = Integer.MAX_VALUE;
2751
2752        int tmp;
2753        for (final CharSequence search : searchStrs) {
2754            if (search == null) {
2755                continue;
2756            }
2757            tmp = CharSequenceUtils.indexOf(str, search, 0);
2758            if (tmp == INDEX_NOT_FOUND) {
2759                continue;
2760            }
2761
2762            if (tmp < ret) {
2763                ret = tmp;
2764            }
2765        }
2766
2767        return ret == Integer.MAX_VALUE ? INDEX_NOT_FOUND : ret;
2768    }
2769
2770    /**
2771     * Search a CharSequence to find the first index of any
2772     * character in the given set of characters.
2773     *
2774     * <p>A {@code null} String will return {@code -1}.
2775     * A {@code null} search string will return {@code -1}.</p>
2776     *
2777     * <pre>
2778     * StringUtils.indexOfAny(null, *)            = -1
2779     * StringUtils.indexOfAny("", *)              = -1
2780     * StringUtils.indexOfAny(*, null)            = -1
2781     * StringUtils.indexOfAny(*, "")              = -1
2782     * StringUtils.indexOfAny("zzabyycdxx", "za") = 0
2783     * StringUtils.indexOfAny("zzabyycdxx", "by") = 3
2784     * StringUtils.indexOfAny("aba", "z")         = -1
2785     * </pre>
2786     *
2787     * @param cs  the CharSequence to check, may be null
2788     * @param searchChars  the chars to search for, may be null
2789     * @return the index of any of the chars, -1 if no match or null input
2790     * @since 2.0
2791     * @since 3.0 Changed signature from indexOfAny(String, String) to indexOfAny(CharSequence, String)
2792     */
2793    public static int indexOfAny(final CharSequence cs, final String searchChars) {
2794        if (isEmpty(cs) || isEmpty(searchChars)) {
2795            return INDEX_NOT_FOUND;
2796        }
2797        return indexOfAny(cs, searchChars.toCharArray());
2798    }
2799
2800    /**
2801     * Searches a CharSequence to find the first index of any
2802     * character not in the given set of characters, i.e.,
2803     * find index i of first char in cs such that (cs.codePointAt(i) ∉ { x ∈ codepoints(searchChars) })
2804     *
2805     * <p>A {@code null} CharSequence will return {@code -1}.
2806     * A {@code null} or zero length search array will return {@code -1}.</p>
2807     *
2808     * <pre>
2809     * StringUtils.indexOfAnyBut(null, *)                              = -1
2810     * StringUtils.indexOfAnyBut("", *)                                = -1
2811     * StringUtils.indexOfAnyBut(*, null)                              = -1
2812     * StringUtils.indexOfAnyBut(*, [])                                = -1
2813     * StringUtils.indexOfAnyBut("zzabyycdxx", new char[] {'z', 'a'} ) = 3
2814     * StringUtils.indexOfAnyBut("aba", new char[] {'z'} )             = 0
2815     * StringUtils.indexOfAnyBut("aba", new char[] {'a', 'b'} )        = -1
2816
2817     * </pre>
2818     *
2819     * @param cs  the CharSequence to check, may be null
2820     * @param searchChars  the chars to search for, may be null
2821     * @return the index of any of the chars, -1 if no match or null input
2822     * @since 2.0
2823     * @since 3.0 Changed signature from indexOfAnyBut(String, char[]) to indexOfAnyBut(CharSequence, char...)
2824     */
2825    public static int indexOfAnyBut(final CharSequence cs, final char... searchChars) {
2826        if (isEmpty(cs) || ArrayUtils.isEmpty(searchChars)) {
2827            return INDEX_NOT_FOUND;
2828        }
2829        return indexOfAnyBut(cs, CharBuffer.wrap(searchChars));
2830    }
2831
2832    /**
2833     * Search a CharSequence to find the first index of any
2834     * character not in the given set of characters, i.e.,
2835     * find index i of first char in seq such that (seq.codePointAt(i) ∉ { x ∈ codepoints(searchChars) })
2836     *
2837     * <p>A {@code null} CharSequence will return {@code -1}.
2838     * A {@code null} or empty search string will return {@code -1}.</p>
2839     *
2840     * <pre>
2841     * StringUtils.indexOfAnyBut(null, *)            = -1
2842     * StringUtils.indexOfAnyBut("", *)              = -1
2843     * StringUtils.indexOfAnyBut(*, null)            = -1
2844     * StringUtils.indexOfAnyBut(*, "")              = -1
2845     * StringUtils.indexOfAnyBut("zzabyycdxx", "za") = 3
2846     * StringUtils.indexOfAnyBut("zzabyycdxx", "")   = -1
2847     * StringUtils.indexOfAnyBut("aba", "ab")        = -1
2848     * </pre>
2849     *
2850     * @param seq  the CharSequence to check, may be null
2851     * @param searchChars  the chars to search for, may be null
2852     * @return the index of any of the chars, -1 if no match or null input
2853     * @since 2.0
2854     * @since 3.0 Changed signature from indexOfAnyBut(String, String) to indexOfAnyBut(CharSequence, CharSequence)
2855     */
2856    public static int indexOfAnyBut(final CharSequence seq, final CharSequence searchChars) {
2857        if (isEmpty(seq) || isEmpty(searchChars)) {
2858            return INDEX_NOT_FOUND;
2859        }
2860        final Set<Integer> searchSetCodePoints = searchChars.codePoints()
2861                .boxed().collect(Collectors.toSet());
2862        // advance character index from one interpreted codepoint to the next
2863        for (int curSeqCharIdx = 0; curSeqCharIdx < seq.length();) {
2864            final int curSeqCodePoint = Character.codePointAt(seq, curSeqCharIdx);
2865            if (!searchSetCodePoints.contains(curSeqCodePoint)) {
2866                return curSeqCharIdx;
2867            }
2868            curSeqCharIdx += Character.charCount(curSeqCodePoint); // skip indices to paired low-surrogates
2869        }
2870        return INDEX_NOT_FOUND;
2871    }
2872
2873    /**
2874     * Compares all CharSequences in an array and returns the index at which the
2875     * CharSequences begin to differ.
2876     *
2877     * <p>For example,
2878     * {@code indexOfDifference(new String[] {"i am a machine", "i am a robot"}) -> 7}</p>
2879     *
2880     * <pre>
2881     * StringUtils.indexOfDifference(null)                             = -1
2882     * StringUtils.indexOfDifference(new String[] {})                  = -1
2883     * StringUtils.indexOfDifference(new String[] {"abc"})             = -1
2884     * StringUtils.indexOfDifference(new String[] {null, null})        = -1
2885     * StringUtils.indexOfDifference(new String[] {"", ""})            = -1
2886     * StringUtils.indexOfDifference(new String[] {"", null})          = 0
2887     * StringUtils.indexOfDifference(new String[] {"abc", null, null}) = 0
2888     * StringUtils.indexOfDifference(new String[] {null, null, "abc"}) = 0
2889     * StringUtils.indexOfDifference(new String[] {"", "abc"})         = 0
2890     * StringUtils.indexOfDifference(new String[] {"abc", ""})         = 0
2891     * StringUtils.indexOfDifference(new String[] {"abc", "abc"})      = -1
2892     * StringUtils.indexOfDifference(new String[] {"abc", "a"})        = 1
2893     * StringUtils.indexOfDifference(new String[] {"ab", "abxyz"})     = 2
2894     * StringUtils.indexOfDifference(new String[] {"abcde", "abxyz"})  = 2
2895     * StringUtils.indexOfDifference(new String[] {"abcde", "xyz"})    = 0
2896     * StringUtils.indexOfDifference(new String[] {"xyz", "abcde"})    = 0
2897     * StringUtils.indexOfDifference(new String[] {"i am a machine", "i am a robot"}) = 7
2898     * </pre>
2899     *
2900     * @param css  array of CharSequences, entries may be null
2901     * @return the index where the strings begin to differ; -1 if they are all equal
2902     * @since 2.4
2903     * @since 3.0 Changed signature from indexOfDifference(String...) to indexOfDifference(CharSequence...)
2904     */
2905    public static int indexOfDifference(final CharSequence... css) {
2906        if (ArrayUtils.getLength(css) <= 1) {
2907            return INDEX_NOT_FOUND;
2908        }
2909        boolean anyStringNull = false;
2910        boolean allStringsNull = true;
2911        final int arrayLen = css.length;
2912        int shortestStrLen = Integer.MAX_VALUE;
2913        int longestStrLen = 0;
2914
2915        // find the min and max string lengths; this avoids checking to make
2916        // sure we are not exceeding the length of the string each time through
2917        // the bottom loop.
2918        for (final CharSequence cs : css) {
2919            if (cs == null) {
2920                anyStringNull = true;
2921                shortestStrLen = 0;
2922            } else {
2923                allStringsNull = false;
2924                shortestStrLen = Math.min(cs.length(), shortestStrLen);
2925                longestStrLen = Math.max(cs.length(), longestStrLen);
2926            }
2927        }
2928
2929        // handle lists containing all nulls or all empty strings
2930        if (allStringsNull || longestStrLen == 0 && !anyStringNull) {
2931            return INDEX_NOT_FOUND;
2932        }
2933
2934        // handle lists containing some nulls or some empty strings
2935        if (shortestStrLen == 0) {
2936            return 0;
2937        }
2938
2939        // find the position with the first difference across all strings
2940        int firstDiff = -1;
2941        for (int stringPos = 0; stringPos < shortestStrLen; stringPos++) {
2942            final char comparisonChar = css[0].charAt(stringPos);
2943            for (int arrayPos = 1; arrayPos < arrayLen; arrayPos++) {
2944                if (css[arrayPos].charAt(stringPos) != comparisonChar) {
2945                    firstDiff = stringPos;
2946                    break;
2947                }
2948            }
2949            if (firstDiff != -1) {
2950                break;
2951            }
2952        }
2953
2954        if (firstDiff == -1 && shortestStrLen != longestStrLen) {
2955            // we compared all of the characters up to the length of the
2956            // shortest string and didn't find a match, but the string lengths
2957            // vary, so return the length of the shortest string.
2958            return shortestStrLen;
2959        }
2960        return firstDiff;
2961    }
2962
2963    /**
2964     * Compares two CharSequences, and returns the index at which the
2965     * CharSequences begin to differ.
2966     *
2967     * <p>For example,
2968     * {@code indexOfDifference("i am a machine", "i am a robot") -> 7}</p>
2969     *
2970     * <pre>
2971     * StringUtils.indexOfDifference(null, null)       = -1
2972     * StringUtils.indexOfDifference("", "")           = -1
2973     * StringUtils.indexOfDifference("", "abc")        = 0
2974     * StringUtils.indexOfDifference("abc", "")        = 0
2975     * StringUtils.indexOfDifference("abc", "abc")     = -1
2976     * StringUtils.indexOfDifference("ab", "abxyz")    = 2
2977     * StringUtils.indexOfDifference("abcde", "abxyz") = 2
2978     * StringUtils.indexOfDifference("abcde", "xyz")   = 0
2979     * </pre>
2980     *
2981     * @param cs1  the first CharSequence, may be null
2982     * @param cs2  the second CharSequence, may be null
2983     * @return the index where cs1 and cs2 begin to differ; -1 if they are equal
2984     * @since 2.0
2985     * @since 3.0 Changed signature from indexOfDifference(String, String) to
2986     * indexOfDifference(CharSequence, CharSequence)
2987     */
2988    public static int indexOfDifference(final CharSequence cs1, final CharSequence cs2) {
2989        if (cs1 == cs2) {
2990            return INDEX_NOT_FOUND;
2991        }
2992        if (cs1 == null || cs2 == null) {
2993            return 0;
2994        }
2995        int i;
2996        for (i = 0; i < cs1.length() && i < cs2.length(); ++i) {
2997            if (cs1.charAt(i) != cs2.charAt(i)) {
2998                break;
2999            }
3000        }
3001        if (i < cs2.length() || i < cs1.length()) {
3002            return i;
3003        }
3004        return INDEX_NOT_FOUND;
3005    }
3006
3007    /**
3008     * Case in-sensitive find of the first index within a CharSequence.
3009     *
3010     * <p>A {@code null} CharSequence will return {@code -1}.
3011     * A negative start position is treated as zero.
3012     * An empty ("") search CharSequence always matches.
3013     * A start position greater than the string length only matches
3014     * an empty search CharSequence.</p>
3015     *
3016     * <pre>
3017     * StringUtils.indexOfIgnoreCase(null, *)          = -1
3018     * StringUtils.indexOfIgnoreCase(*, null)          = -1
3019     * StringUtils.indexOfIgnoreCase("", "")           = 0
3020     * StringUtils.indexOfIgnoreCase(" ", " ")         = 0
3021     * StringUtils.indexOfIgnoreCase("aabaabaa", "a")  = 0
3022     * StringUtils.indexOfIgnoreCase("aabaabaa", "b")  = 2
3023     * StringUtils.indexOfIgnoreCase("aabaabaa", "ab") = 1
3024     * </pre>
3025     *
3026     * @param str  the CharSequence to check, may be null
3027     * @param searchStr  the CharSequence to find, may be null
3028     * @return the first index of the search CharSequence,
3029     *  -1 if no match or {@code null} string input
3030     * @since 2.5
3031     * @since 3.0 Changed signature from indexOfIgnoreCase(String, String) to indexOfIgnoreCase(CharSequence, CharSequence)
3032     * @deprecated Use {@link Strings#indexOf(CharSequence, CharSequence) Strings.CI.indexOf(CharSequence, CharSequence)}
3033     */
3034    @Deprecated
3035    public static int indexOfIgnoreCase(final CharSequence str, final CharSequence searchStr) {
3036        return Strings.CI.indexOf(str, searchStr);
3037    }
3038
3039    /**
3040     * Case in-sensitive find of the first index within a CharSequence
3041     * from the specified position.
3042     *
3043     * <p>A {@code null} CharSequence will return {@code -1}.
3044     * A negative start position is treated as zero.
3045     * An empty ("") search CharSequence always matches.
3046     * A start position greater than the string length only matches
3047     * an empty search CharSequence.</p>
3048     *
3049     * <pre>
3050     * StringUtils.indexOfIgnoreCase(null, *, *)          = -1
3051     * StringUtils.indexOfIgnoreCase(*, null, *)          = -1
3052     * StringUtils.indexOfIgnoreCase("", "", 0)           = 0
3053     * StringUtils.indexOfIgnoreCase("aabaabaa", "A", 0)  = 0
3054     * StringUtils.indexOfIgnoreCase("aabaabaa", "B", 0)  = 2
3055     * StringUtils.indexOfIgnoreCase("aabaabaa", "AB", 0) = 1
3056     * StringUtils.indexOfIgnoreCase("aabaabaa", "B", 3)  = 5
3057     * StringUtils.indexOfIgnoreCase("aabaabaa", "B", 9)  = -1
3058     * StringUtils.indexOfIgnoreCase("aabaabaa", "B", -1) = 2
3059     * StringUtils.indexOfIgnoreCase("aabaabaa", "", 2)   = 2
3060     * StringUtils.indexOfIgnoreCase("abc", "", 9)        = -1
3061     * </pre>
3062     *
3063     * @param str  the CharSequence to check, may be null
3064     * @param searchStr  the CharSequence to find, may be null
3065     * @param startPos  the start position, negative treated as zero
3066     * @return the first index of the search CharSequence (always &ge; startPos),
3067     *  -1 if no match or {@code null} string input
3068     * @since 2.5
3069     * @since 3.0 Changed signature from indexOfIgnoreCase(String, String, int) to indexOfIgnoreCase(CharSequence, CharSequence, int)
3070     * @deprecated Use {@link Strings#indexOf(CharSequence, CharSequence, int) Strings.CI.indexOf(CharSequence, CharSequence, int)}
3071     */
3072    @Deprecated
3073    public static int indexOfIgnoreCase(final CharSequence str, final CharSequence searchStr, final int startPos) {
3074        return Strings.CI.indexOf(str, searchStr, startPos);
3075    }
3076
3077    /**
3078     * Tests if all of the CharSequences are empty (""), null or whitespace only.
3079     *
3080     * <p>Whitespace is defined by {@link Character#isWhitespace(char)}.</p>
3081     *
3082     * <pre>
3083     * StringUtils.isAllBlank(null)             = true
3084     * StringUtils.isAllBlank(null, "foo")      = false
3085     * StringUtils.isAllBlank(null, null)       = true
3086     * StringUtils.isAllBlank("", "bar")        = false
3087     * StringUtils.isAllBlank("bob", "")        = false
3088     * StringUtils.isAllBlank("  bob  ", null)  = false
3089     * StringUtils.isAllBlank(" ", "bar")       = false
3090     * StringUtils.isAllBlank("foo", "bar")     = false
3091     * StringUtils.isAllBlank(new String[] {})  = true
3092     * </pre>
3093     *
3094     * @param css  the CharSequences to check, may be null or empty
3095     * @return {@code true} if all of the CharSequences are empty or null or whitespace only
3096     * @since 3.6
3097     */
3098    public static boolean isAllBlank(final CharSequence... css) {
3099        if (ArrayUtils.isEmpty(css)) {
3100            return true;
3101        }
3102        for (final CharSequence cs : css) {
3103            if (isNotBlank(cs)) {
3104               return false;
3105            }
3106        }
3107        return true;
3108    }
3109
3110    /**
3111     * Tests if all of the CharSequences are empty ("") or null.
3112     *
3113     * <pre>
3114     * StringUtils.isAllEmpty(null)             = true
3115     * StringUtils.isAllEmpty(null, "")         = true
3116     * StringUtils.isAllEmpty(new String[] {})  = true
3117     * StringUtils.isAllEmpty(null, "foo")      = false
3118     * StringUtils.isAllEmpty("", "bar")        = false
3119     * StringUtils.isAllEmpty("bob", "")        = false
3120     * StringUtils.isAllEmpty("  bob  ", null)  = false
3121     * StringUtils.isAllEmpty(" ", "bar")       = false
3122     * StringUtils.isAllEmpty("foo", "bar")     = false
3123     * </pre>
3124     *
3125     * @param css  the CharSequences to check, may be null or empty
3126     * @return {@code true} if all of the CharSequences are empty or null
3127     * @since 3.6
3128     */
3129    public static boolean isAllEmpty(final CharSequence... css) {
3130        if (ArrayUtils.isEmpty(css)) {
3131            return true;
3132        }
3133        for (final CharSequence cs : css) {
3134            if (isNotEmpty(cs)) {
3135                return false;
3136            }
3137        }
3138        return true;
3139    }
3140
3141    /**
3142     * Tests if the CharSequence contains only lowercase characters.
3143     *
3144     * <p>{@code null} will return {@code false}.
3145     * An empty CharSequence (length()=0) will return {@code false}.</p>
3146     *
3147     * <pre>
3148     * StringUtils.isAllLowerCase(null)   = false
3149     * StringUtils.isAllLowerCase("")     = false
3150     * StringUtils.isAllLowerCase("  ")   = false
3151     * StringUtils.isAllLowerCase("abc")  = true
3152     * StringUtils.isAllLowerCase("abC")  = false
3153     * StringUtils.isAllLowerCase("ab c") = false
3154     * StringUtils.isAllLowerCase("ab1c") = false
3155     * StringUtils.isAllLowerCase("ab/c") = false
3156     * </pre>
3157     *
3158     * @param cs  the CharSequence to check, may be null
3159     * @return {@code true} if only contains lowercase characters, and is non-null
3160     * @since 2.5
3161     * @since 3.0 Changed signature from isAllLowerCase(String) to isAllLowerCase(CharSequence)
3162     */
3163    public static boolean isAllLowerCase(final CharSequence cs) {
3164        if (isEmpty(cs)) {
3165            return false;
3166        }
3167        final int sz = cs.length();
3168        for (int i = 0; i < sz; i++) {
3169            if (!Character.isLowerCase(cs.charAt(i))) {
3170                return false;
3171            }
3172        }
3173        return true;
3174    }
3175
3176    /**
3177     * Tests if the CharSequence contains only uppercase characters.
3178     *
3179     * <p>{@code null} will return {@code false}.
3180     * An empty String (length()=0) will return {@code false}.</p>
3181     *
3182     * <pre>
3183     * StringUtils.isAllUpperCase(null)   = false
3184     * StringUtils.isAllUpperCase("")     = false
3185     * StringUtils.isAllUpperCase("  ")   = false
3186     * StringUtils.isAllUpperCase("ABC")  = true
3187     * StringUtils.isAllUpperCase("aBC")  = false
3188     * StringUtils.isAllUpperCase("A C")  = false
3189     * StringUtils.isAllUpperCase("A1C")  = false
3190     * StringUtils.isAllUpperCase("A/C")  = false
3191     * </pre>
3192     *
3193     * @param cs the CharSequence to check, may be null
3194     * @return {@code true} if only contains uppercase characters, and is non-null
3195     * @since 2.5
3196     * @since 3.0 Changed signature from isAllUpperCase(String) to isAllUpperCase(CharSequence)
3197     */
3198    public static boolean isAllUpperCase(final CharSequence cs) {
3199        if (isEmpty(cs)) {
3200            return false;
3201        }
3202        final int sz = cs.length();
3203        for (int i = 0; i < sz; i++) {
3204            if (!Character.isUpperCase(cs.charAt(i))) {
3205                return false;
3206            }
3207        }
3208        return true;
3209    }
3210
3211    /**
3212     * Tests if the CharSequence contains only Unicode letters.
3213     *
3214     * <p>{@code null} will return {@code false}.
3215     * An empty CharSequence (length()=0) will return {@code false}.</p>
3216     *
3217     * <pre>
3218     * StringUtils.isAlpha(null)   = false
3219     * StringUtils.isAlpha("")     = false
3220     * StringUtils.isAlpha("  ")   = false
3221     * StringUtils.isAlpha("abc")  = true
3222     * StringUtils.isAlpha("ab2c") = false
3223     * StringUtils.isAlpha("ab-c") = false
3224     * </pre>
3225     *
3226     * @param cs  the CharSequence to check, may be null
3227     * @return {@code true} if only contains letters, and is non-null
3228     * @since 3.0 Changed signature from isAlpha(String) to isAlpha(CharSequence)
3229     * @since 3.0 Changed "" to return false and not true
3230     */
3231    public static boolean isAlpha(final CharSequence cs) {
3232        if (isEmpty(cs)) {
3233            return false;
3234        }
3235        final int sz = cs.length();
3236        for (int i = 0; i < sz; i++) {
3237            if (!Character.isLetter(cs.charAt(i))) {
3238                return false;
3239            }
3240        }
3241        return true;
3242    }
3243
3244    /**
3245     * Tests if the CharSequence contains only Unicode letters or digits.
3246     *
3247     * <p>{@code null} will return {@code false}.
3248     * An empty CharSequence (length()=0) will return {@code false}.</p>
3249     *
3250     * <pre>
3251     * StringUtils.isAlphanumeric(null)   = false
3252     * StringUtils.isAlphanumeric("")     = false
3253     * StringUtils.isAlphanumeric("  ")   = false
3254     * StringUtils.isAlphanumeric("abc")  = true
3255     * StringUtils.isAlphanumeric("ab c") = false
3256     * StringUtils.isAlphanumeric("ab2c") = true
3257     * StringUtils.isAlphanumeric("ab-c") = false
3258     * </pre>
3259     *
3260     * @param cs  the CharSequence to check, may be null
3261     * @return {@code true} if only contains letters or digits,
3262     *  and is non-null
3263     * @since 3.0 Changed signature from isAlphanumeric(String) to isAlphanumeric(CharSequence)
3264     * @since 3.0 Changed "" to return false and not true
3265     */
3266    public static boolean isAlphanumeric(final CharSequence cs) {
3267        if (isEmpty(cs)) {
3268            return false;
3269        }
3270        final int sz = cs.length();
3271        for (int i = 0; i < sz; i++) {
3272            if (!Character.isLetterOrDigit(cs.charAt(i))) {
3273                return false;
3274            }
3275        }
3276        return true;
3277    }
3278
3279    /**
3280     * Tests if the CharSequence contains only Unicode letters, digits
3281     * or space ({@code ' '}).
3282     *
3283     * <p>{@code null} will return {@code false}.
3284     * An empty CharSequence (length()=0) will return {@code true}.</p>
3285     *
3286     * <pre>
3287     * StringUtils.isAlphanumericSpace(null)   = false
3288     * StringUtils.isAlphanumericSpace("")     = true
3289     * StringUtils.isAlphanumericSpace("  ")   = true
3290     * StringUtils.isAlphanumericSpace("abc")  = true
3291     * StringUtils.isAlphanumericSpace("ab c") = true
3292     * StringUtils.isAlphanumericSpace("ab2c") = true
3293     * StringUtils.isAlphanumericSpace("ab-c") = false
3294     * </pre>
3295     *
3296     * @param cs  the CharSequence to check, may be null
3297     * @return {@code true} if only contains letters, digits or space,
3298     *  and is non-null
3299     * @since 3.0 Changed signature from isAlphanumericSpace(String) to isAlphanumericSpace(CharSequence)
3300     */
3301    public static boolean isAlphanumericSpace(final CharSequence cs) {
3302        if (cs == null) {
3303            return false;
3304        }
3305        final int sz = cs.length();
3306        for (int i = 0; i < sz; i++) {
3307            final char nowChar = cs.charAt(i);
3308            if (nowChar != ' ' && !Character.isLetterOrDigit(nowChar)) {
3309                return false;
3310            }
3311        }
3312        return true;
3313    }
3314
3315    /**
3316     * Tests if the CharSequence contains only Unicode letters and
3317     * space (' ').
3318     *
3319     * <p>{@code null} will return {@code false}
3320     * An empty CharSequence (length()=0) will return {@code true}.</p>
3321     *
3322     * <pre>
3323     * StringUtils.isAlphaSpace(null)   = false
3324     * StringUtils.isAlphaSpace("")     = true
3325     * StringUtils.isAlphaSpace("  ")   = true
3326     * StringUtils.isAlphaSpace("abc")  = true
3327     * StringUtils.isAlphaSpace("ab c") = true
3328     * StringUtils.isAlphaSpace("ab2c") = false
3329     * StringUtils.isAlphaSpace("ab-c") = false
3330     * </pre>
3331     *
3332     * @param cs  the CharSequence to check, may be null
3333     * @return {@code true} if only contains letters and space,
3334     *  and is non-null
3335     * @since 3.0 Changed signature from isAlphaSpace(String) to isAlphaSpace(CharSequence)
3336     */
3337    public static boolean isAlphaSpace(final CharSequence cs) {
3338        if (cs == null) {
3339            return false;
3340        }
3341        final int sz = cs.length();
3342        for (int i = 0; i < sz; i++) {
3343            final char nowChar = cs.charAt(i);
3344            if (nowChar != ' ' && !Character.isLetter(nowChar)) {
3345                return false;
3346            }
3347        }
3348        return true;
3349    }
3350
3351    /**
3352     * Tests if any of the CharSequences are {@link #isBlank(CharSequence) blank} (whitespaces, empty ({@code ""}) or {@code null}).
3353     *
3354     * <p>
3355     * Whitespace is defined by {@link Character#isWhitespace(char)}.
3356     * </p>
3357     *
3358     * <pre>
3359     * StringUtils.isAnyBlank((String) null)    = true
3360     * StringUtils.isAnyBlank((String[]) null)  = false
3361     * StringUtils.isAnyBlank(null, "foo")      = true
3362     * StringUtils.isAnyBlank(null, null)       = true
3363     * StringUtils.isAnyBlank("", "bar")        = true
3364     * StringUtils.isAnyBlank("bob", "")        = true
3365     * StringUtils.isAnyBlank("  bob  ", null)  = true
3366     * StringUtils.isAnyBlank(" ", "bar")       = true
3367     * StringUtils.isAnyBlank(new String[] {})  = false
3368     * StringUtils.isAnyBlank(new String[]{""}) = true
3369     * StringUtils.isAnyBlank("foo", "bar")     = false
3370     * </pre>
3371     *
3372     * @param css the CharSequences to check, may be null or empty
3373     * @return {@code true} if any of the CharSequences are {@link #isBlank(CharSequence) blank} (whitespaces, empty ({@code ""}) or {@code null})
3374     * @see #isBlank(CharSequence)
3375     * @since 3.2
3376     */
3377    public static boolean isAnyBlank(final CharSequence... css) {
3378        if (ArrayUtils.isEmpty(css)) {
3379            return false;
3380        }
3381        for (final CharSequence cs : css) {
3382            if (isBlank(cs)) {
3383                return true;
3384            }
3385        }
3386        return false;
3387    }
3388
3389    /**
3390     * Tests if any of the CharSequences are empty ("") or null.
3391     *
3392     * <pre>
3393     * StringUtils.isAnyEmpty((String) null)    = true
3394     * StringUtils.isAnyEmpty((String[]) null)  = false
3395     * StringUtils.isAnyEmpty(null, "foo")      = true
3396     * StringUtils.isAnyEmpty("", "bar")        = true
3397     * StringUtils.isAnyEmpty("bob", "")        = true
3398     * StringUtils.isAnyEmpty("  bob  ", null)  = true
3399     * StringUtils.isAnyEmpty(" ", "bar")       = false
3400     * StringUtils.isAnyEmpty("foo", "bar")     = false
3401     * StringUtils.isAnyEmpty(new String[]{})   = false
3402     * StringUtils.isAnyEmpty(new String[]{""}) = true
3403     * </pre>
3404     *
3405     * @param css  the CharSequences to check, may be null or empty
3406     * @return {@code true} if any of the CharSequences are empty or null
3407     * @since 3.2
3408     */
3409    public static boolean isAnyEmpty(final CharSequence... css) {
3410        if (ArrayUtils.isEmpty(css)) {
3411            return false;
3412        }
3413        for (final CharSequence cs : css) {
3414            if (isEmpty(cs)) {
3415                return true;
3416            }
3417        }
3418        return false;
3419    }
3420
3421    /**
3422     * Tests if the CharSequence contains only ASCII printable characters.
3423     *
3424     * <p>{@code null} will return {@code false}.
3425     * An empty CharSequence (length()=0) will return {@code true}.</p>
3426     *
3427     * <pre>
3428     * StringUtils.isAsciiPrintable(null)     = false
3429     * StringUtils.isAsciiPrintable("")       = true
3430     * StringUtils.isAsciiPrintable(" ")      = true
3431     * StringUtils.isAsciiPrintable("Ceki")   = true
3432     * StringUtils.isAsciiPrintable("ab2c")   = true
3433     * StringUtils.isAsciiPrintable("!ab-c~") = true
3434     * StringUtils.isAsciiPrintable("\u0020") = true
3435     * StringUtils.isAsciiPrintable("\u0021") = true
3436     * StringUtils.isAsciiPrintable("\u007e") = true
3437     * StringUtils.isAsciiPrintable("\u007f") = false
3438     * StringUtils.isAsciiPrintable("Ceki G\u00fclc\u00fc") = false
3439     * </pre>
3440     *
3441     * @param cs the CharSequence to check, may be null
3442     * @return {@code true} if every character is in the range
3443     *  32 through 126
3444     * @since 2.1
3445     * @since 3.0 Changed signature from isAsciiPrintable(String) to isAsciiPrintable(CharSequence)
3446     */
3447    public static boolean isAsciiPrintable(final CharSequence cs) {
3448        if (cs == null) {
3449            return false;
3450        }
3451        final int sz = cs.length();
3452        for (int i = 0; i < sz; i++) {
3453            if (!CharUtils.isAsciiPrintable(cs.charAt(i))) {
3454                return false;
3455            }
3456        }
3457        return true;
3458    }
3459
3460    /**
3461     * Tests if a CharSequence is empty ({@code "")}, null, or contains only whitespace as defined by {@link Character#isWhitespace(char)}.
3462     *
3463     * <pre>
3464     * StringUtils.isBlank(null)      = true
3465     * StringUtils.isBlank("")        = true
3466     * StringUtils.isBlank(" ")       = true
3467     * StringUtils.isBlank("bob")     = false
3468     * StringUtils.isBlank("  bob  ") = false
3469     * </pre>
3470     *
3471     * @param cs the CharSequence to check, may be null
3472     * @return {@code true} if the CharSequence is null, empty or whitespace only
3473     * @since 2.0
3474     * @since 3.0 Changed signature from isBlank(String) to isBlank(CharSequence)
3475     */
3476    public static boolean isBlank(final CharSequence cs) {
3477        final int strLen = length(cs);
3478        if (strLen == 0) {
3479            return true;
3480        }
3481        for (int i = 0; i < strLen; i++) {
3482            if (!Character.isWhitespace(cs.charAt(i))) {
3483                return false;
3484            }
3485        }
3486        return true;
3487    }
3488
3489    /**
3490     * Tests if a CharSequence is empty ("") or null.
3491     *
3492     * <pre>
3493     * StringUtils.isEmpty(null)      = true
3494     * StringUtils.isEmpty("")        = true
3495     * StringUtils.isEmpty(" ")       = false
3496     * StringUtils.isEmpty("bob")     = false
3497     * StringUtils.isEmpty("  bob  ") = false
3498     * </pre>
3499     *
3500     * <p>NOTE: This method changed in Lang version 2.0.
3501     * It no longer trims the CharSequence.
3502     * That functionality is available in isBlank().</p>
3503     *
3504     * @param cs  the CharSequence to check, may be null
3505     * @return {@code true} if the CharSequence is empty or null
3506     * @since 3.0 Changed signature from isEmpty(String) to isEmpty(CharSequence)
3507     */
3508    public static boolean isEmpty(final CharSequence cs) {
3509        return cs == null || cs.length() == 0;
3510    }
3511
3512    /**
3513     * Tests if the CharSequence contains mixed casing of both uppercase and lowercase characters.
3514     *
3515     * <p>{@code null} will return {@code false}. An empty CharSequence ({@code length()=0}) will return
3516     * {@code false}.</p>
3517     *
3518     * <pre>
3519     * StringUtils.isMixedCase(null)    = false
3520     * StringUtils.isMixedCase("")      = false
3521     * StringUtils.isMixedCase(" ")     = false
3522     * StringUtils.isMixedCase("ABC")   = false
3523     * StringUtils.isMixedCase("abc")   = false
3524     * StringUtils.isMixedCase("aBc")   = true
3525     * StringUtils.isMixedCase("A c")   = true
3526     * StringUtils.isMixedCase("A1c")   = true
3527     * StringUtils.isMixedCase("a/C")   = true
3528     * StringUtils.isMixedCase("aC\t")  = true
3529     * </pre>
3530     *
3531     * @param cs the CharSequence to check, may be null
3532     * @return {@code true} if the CharSequence contains both uppercase and lowercase characters
3533     * @since 3.5
3534     */
3535    public static boolean isMixedCase(final CharSequence cs) {
3536        if (isEmpty(cs) || cs.length() == 1) {
3537            return false;
3538        }
3539        boolean containsUppercase = false;
3540        boolean containsLowercase = false;
3541        final int sz = cs.length();
3542        for (int i = 0; i < sz; i++) {
3543            final char nowChar = cs.charAt(i);
3544            if (Character.isUpperCase(nowChar)) {
3545                containsUppercase = true;
3546            } else if (Character.isLowerCase(nowChar)) {
3547                containsLowercase = true;
3548            }
3549            if (containsUppercase && containsLowercase) {
3550                return true;
3551            }
3552        }
3553        return false;
3554    }
3555
3556    /**
3557     * Tests if none of the CharSequences are empty (""), null or whitespace only.
3558     *
3559     * <p>Whitespace is defined by {@link Character#isWhitespace(char)}.</p>
3560     *
3561     * <pre>
3562     * StringUtils.isNoneBlank((String) null)    = false
3563     * StringUtils.isNoneBlank((String[]) null)  = true
3564     * StringUtils.isNoneBlank(null, "foo")      = false
3565     * StringUtils.isNoneBlank(null, null)       = false
3566     * StringUtils.isNoneBlank("", "bar")        = false
3567     * StringUtils.isNoneBlank("bob", "")        = false
3568     * StringUtils.isNoneBlank("  bob  ", null)  = false
3569     * StringUtils.isNoneBlank(" ", "bar")       = false
3570     * StringUtils.isNoneBlank(new String[] {})  = true
3571     * StringUtils.isNoneBlank(new String[]{""}) = false
3572     * StringUtils.isNoneBlank("foo", "bar")     = true
3573     * </pre>
3574     *
3575     * @param css  the CharSequences to check, may be null or empty
3576     * @return {@code true} if none of the CharSequences are empty or null or whitespace only
3577     * @since 3.2
3578     */
3579    public static boolean isNoneBlank(final CharSequence... css) {
3580      return !isAnyBlank(css);
3581    }
3582
3583    /**
3584     * Tests if none of the CharSequences are empty ("") or null.
3585     *
3586     * <pre>
3587     * StringUtils.isNoneEmpty((String) null)    = false
3588     * StringUtils.isNoneEmpty((String[]) null)  = true
3589     * StringUtils.isNoneEmpty(null, "foo")      = false
3590     * StringUtils.isNoneEmpty("", "bar")        = false
3591     * StringUtils.isNoneEmpty("bob", "")        = false
3592     * StringUtils.isNoneEmpty("  bob  ", null)  = false
3593     * StringUtils.isNoneEmpty(new String[] {})  = true
3594     * StringUtils.isNoneEmpty(new String[]{""}) = false
3595     * StringUtils.isNoneEmpty(" ", "bar")       = true
3596     * StringUtils.isNoneEmpty("foo", "bar")     = true
3597     * </pre>
3598     *
3599     * @param css  the CharSequences to check, may be null or empty
3600     * @return {@code true} if none of the CharSequences are empty or null
3601     * @since 3.2
3602     */
3603    public static boolean isNoneEmpty(final CharSequence... css) {
3604      return !isAnyEmpty(css);
3605    }
3606
3607    /**
3608     * Tests if a CharSequence is not {@link #isBlank(CharSequence) blank} (whitespaces, empty ({@code ""}) or {@code null}).
3609     *
3610     * <p>
3611     * Whitespace is defined by {@link Character#isWhitespace(char)}.
3612     * </p>
3613     *
3614     * <pre>
3615     * StringUtils.isNotBlank(null)      = false
3616     * StringUtils.isNotBlank("")        = false
3617     * StringUtils.isNotBlank(" ")       = false
3618     * StringUtils.isNotBlank("bob")     = true
3619     * StringUtils.isNotBlank("  bob  ") = true
3620     * </pre>
3621     *
3622     * @param cs the CharSequence to check, may be null
3623     * @return {@code true} if the CharSequence is not {@link #isBlank(CharSequence) blank} (whitespaces, empty ({@code ""}) or {@code null})
3624     * @see #isBlank(CharSequence)
3625     * @since 2.0
3626     * @since 3.0 Changed signature from isNotBlank(String) to isNotBlank(CharSequence)
3627     */
3628    public static boolean isNotBlank(final CharSequence cs) {
3629        return !isBlank(cs);
3630    }
3631
3632    /**
3633     * Tests if a CharSequence is not empty ("") and not null.
3634     *
3635     * <pre>
3636     * StringUtils.isNotEmpty(null)      = false
3637     * StringUtils.isNotEmpty("")        = false
3638     * StringUtils.isNotEmpty(" ")       = true
3639     * StringUtils.isNotEmpty("bob")     = true
3640     * StringUtils.isNotEmpty("  bob  ") = true
3641     * </pre>
3642     *
3643     * @param cs  the CharSequence to check, may be null
3644     * @return {@code true} if the CharSequence is not empty and not null
3645     * @since 3.0 Changed signature from isNotEmpty(String) to isNotEmpty(CharSequence)
3646     */
3647    public static boolean isNotEmpty(final CharSequence cs) {
3648        return !isEmpty(cs);
3649    }
3650
3651    /**
3652     * Tests if the CharSequence contains only Unicode digits.
3653     * A decimal point is not a Unicode digit and returns false.
3654     *
3655     * <p>{@code null} will return {@code false}.
3656     * An empty CharSequence (length()=0) will return {@code false}.</p>
3657     *
3658     * <p>Note that the method does not allow for a leading sign, either positive or negative.
3659     * Also, if a String passes the numeric test, it may still generate a NumberFormatException
3660     * when parsed by Integer.parseInt or Long.parseLong, e.g. if the value is outside the range
3661     * for int or long respectively.</p>
3662     *
3663     * <pre>
3664     * StringUtils.isNumeric(null)   = false
3665     * StringUtils.isNumeric("")     = false
3666     * StringUtils.isNumeric("  ")   = false
3667     * StringUtils.isNumeric("123")  = true
3668     * StringUtils.isNumeric("\u0967\u0968\u0969")  = true
3669     * StringUtils.isNumeric("12 3") = false
3670     * StringUtils.isNumeric("ab2c") = false
3671     * StringUtils.isNumeric("12-3") = false
3672     * StringUtils.isNumeric("12.3") = false
3673     * StringUtils.isNumeric("-123") = false
3674     * StringUtils.isNumeric("+123") = false
3675     * </pre>
3676     *
3677     * @param cs  the CharSequence to check, may be null
3678     * @return {@code true} if only contains digits, and is non-null
3679     * @since 3.0 Changed signature from isNumeric(String) to isNumeric(CharSequence)
3680     * @since 3.0 Changed "" to return false and not true
3681     */
3682    public static boolean isNumeric(final CharSequence cs) {
3683        if (isEmpty(cs)) {
3684            return false;
3685        }
3686        final int sz = cs.length();
3687        for (int i = 0; i < sz; i++) {
3688            if (!Character.isDigit(cs.charAt(i))) {
3689                return false;
3690            }
3691        }
3692        return true;
3693    }
3694
3695    /**
3696     * Tests if the CharSequence contains only Unicode digits or space
3697     * ({@code ' '}).
3698     * A decimal point is not a Unicode digit and returns false.
3699     *
3700     * <p>{@code null} will return {@code false}.
3701     * An empty CharSequence (length()=0) will return {@code true}.</p>
3702     *
3703     * <pre>
3704     * StringUtils.isNumericSpace(null)   = false
3705     * StringUtils.isNumericSpace("")     = true
3706     * StringUtils.isNumericSpace("  ")   = true
3707     * StringUtils.isNumericSpace("123")  = true
3708     * StringUtils.isNumericSpace("12 3") = true
3709     * StringUtils.isNumericSpace("\u0967\u0968\u0969")   = true
3710     * StringUtils.isNumericSpace("\u0967\u0968 \u0969")  = true
3711     * StringUtils.isNumericSpace("ab2c") = false
3712     * StringUtils.isNumericSpace("12-3") = false
3713     * StringUtils.isNumericSpace("12.3") = false
3714     * </pre>
3715     *
3716     * @param cs  the CharSequence to check, may be null
3717     * @return {@code true} if only contains digits or space,
3718     *  and is non-null
3719     * @since 3.0 Changed signature from isNumericSpace(String) to isNumericSpace(CharSequence)
3720     */
3721    public static boolean isNumericSpace(final CharSequence cs) {
3722        if (cs == null) {
3723            return false;
3724        }
3725        final int sz = cs.length();
3726        for (int i = 0; i < sz; i++) {
3727            final char nowChar = cs.charAt(i);
3728            if (nowChar != ' ' && !Character.isDigit(nowChar)) {
3729                return false;
3730            }
3731        }
3732        return true;
3733    }
3734
3735    /**
3736     * Tests if the CharSequence contains only whitespace.
3737     *
3738     * <p>Whitespace is defined by {@link Character#isWhitespace(char)}.</p>
3739     *
3740     * <p>{@code null} will return {@code false}.
3741     * An empty CharSequence (length()=0) will return {@code true}.</p>
3742     *
3743     * <pre>
3744     * StringUtils.isWhitespace(null)   = false
3745     * StringUtils.isWhitespace("")     = true
3746     * StringUtils.isWhitespace("  ")   = true
3747     * StringUtils.isWhitespace("abc")  = false
3748     * StringUtils.isWhitespace("ab2c") = false
3749     * StringUtils.isWhitespace("ab-c") = false
3750     * </pre>
3751     *
3752     * @param cs  the CharSequence to check, may be null
3753     * @return {@code true} if only contains whitespace, and is non-null
3754     * @since 2.0
3755     * @since 3.0 Changed signature from isWhitespace(String) to isWhitespace(CharSequence)
3756     */
3757    public static boolean isWhitespace(final CharSequence cs) {
3758        if (cs == null) {
3759            return false;
3760        }
3761        final int sz = cs.length();
3762        for (int i = 0; i < sz; i++) {
3763            if (!Character.isWhitespace(cs.charAt(i))) {
3764                return false;
3765            }
3766        }
3767        return true;
3768    }
3769
3770    /**
3771     * Joins the elements of the provided array into a single String containing the provided list of elements.
3772     *
3773     * <p>
3774     * No delimiter is added before or after the list. Null objects or empty strings within the array are represented
3775     * by empty strings.
3776     * </p>
3777     *
3778     * <pre>
3779     * StringUtils.join(null, *)             = null
3780     * StringUtils.join([], *)               = ""
3781     * StringUtils.join([null], *)           = ""
3782     * StringUtils.join([false, false], ';') = "false;false"
3783     * </pre>
3784     *
3785     * @param array
3786     *            the array of values to join together, may be null
3787     * @param delimiter
3788     *            the separator character to use
3789     * @return the joined String, {@code null} if null array input
3790     * @since 3.12.0
3791     */
3792    public static String join(final boolean[] array, final char delimiter) {
3793        if (array == null) {
3794            return null;
3795        }
3796        return join(array, delimiter, 0, array.length);
3797    }
3798
3799    /**
3800     * Joins the elements of the provided array into a single String containing the provided list of elements.
3801     *
3802     * <p>
3803     * No delimiter is added before or after the list. Null objects or empty strings within the array are represented
3804     * by empty strings.
3805     * </p>
3806     *
3807     * <pre>
3808     * StringUtils.join(null, *)                  = null
3809     * StringUtils.join([], *)                    = ""
3810     * StringUtils.join([null], *)                = ""
3811     * StringUtils.join([true, false, true], ';') = "true;false;true"
3812     * </pre>
3813     *
3814     * @param array
3815     *            the array of values to join together, may be null
3816     * @param delimiter
3817     *            the separator character to use
3818     * @param startIndex
3819     *            the first index to start joining from. It is an error to pass in a start index past the end of the
3820     *            array
3821     * @param endIndex
3822     *            the index to stop joining from (exclusive). It is an error to pass in an end index past the end of
3823     *            the array
3824     * @return the joined String, {@code null} if null array input
3825     * @since 3.12.0
3826     */
3827    public static String join(final boolean[] array, final char delimiter, final int startIndex, final int endIndex) {
3828        if (array == null) {
3829            return null;
3830        }
3831        if (endIndex - startIndex <= 0) {
3832            return EMPTY;
3833        }
3834        final StringBuilder stringBuilder = new StringBuilder(array.length * 5 + array.length - 1);
3835        for (int i = startIndex; i < endIndex; i++) {
3836            stringBuilder
3837                    .append(array[i])
3838                    .append(delimiter);
3839        }
3840        return stringBuilder.substring(0, stringBuilder.length() - 1);
3841    }
3842
3843    /**
3844     * Joins the elements of the provided array into a single String containing the provided list of elements.
3845     *
3846     * <p>
3847     * No delimiter is added before or after the list. Null objects or empty strings within the array are represented
3848     * by empty strings.
3849     * </p>
3850     *
3851     * <pre>
3852     * StringUtils.join(null, *)         = null
3853     * StringUtils.join([], *)           = ""
3854     * StringUtils.join([null], *)       = ""
3855     * StringUtils.join([1, 2, 3], ';')  = "1;2;3"
3856     * StringUtils.join([1, 2, 3], null) = "123"
3857     * </pre>
3858     *
3859     * @param array
3860     *            the array of values to join together, may be null
3861     * @param delimiter
3862     *            the separator character to use
3863     * @return the joined String, {@code null} if null array input
3864     * @since 3.2
3865     */
3866    public static String join(final byte[] array, final char delimiter) {
3867        if (array == null) {
3868            return null;
3869        }
3870        return join(array, delimiter, 0, array.length);
3871    }
3872
3873    /**
3874     * Joins the elements of the provided array into a single String containing the provided list of elements.
3875     *
3876     * <p>
3877     * No delimiter is added before or after the list. Null objects or empty strings within the array are represented
3878     * by empty strings.
3879     * </p>
3880     *
3881     * <pre>
3882     * StringUtils.join(null, *)         = null
3883     * StringUtils.join([], *)           = ""
3884     * StringUtils.join([null], *)       = ""
3885     * StringUtils.join([1, 2, 3], ';')  = "1;2;3"
3886     * StringUtils.join([1, 2, 3], null) = "123"
3887     * </pre>
3888     *
3889     * @param array
3890     *            the array of values to join together, may be null
3891     * @param delimiter
3892     *            the separator character to use
3893     * @param startIndex
3894     *            the first index to start joining from. It is an error to pass in a start index past the end of the
3895     *            array
3896     * @param endIndex
3897     *            the index to stop joining from (exclusive). It is an error to pass in an end index past the end of
3898     *            the array
3899     * @return the joined String, {@code null} if null array input
3900     * @since 3.2
3901     */
3902    public static String join(final byte[] array, final char delimiter, final int startIndex, final int endIndex) {
3903        if (array == null) {
3904            return null;
3905        }
3906        if (endIndex - startIndex <= 0) {
3907            return EMPTY;
3908        }
3909        final StringBuilder stringBuilder = new StringBuilder();
3910        for (int i = startIndex; i < endIndex; i++) {
3911            stringBuilder
3912                    .append(array[i])
3913                    .append(delimiter);
3914        }
3915        return stringBuilder.substring(0, stringBuilder.length() - 1);
3916    }
3917
3918    /**
3919     * Joins the elements of the provided array into a single String containing the provided list of elements.
3920     *
3921     * <p>
3922     * No delimiter is added before or after the list. Null objects or empty strings within the array are represented
3923     * by empty strings.
3924     * </p>
3925     *
3926     * <pre>
3927     * StringUtils.join(null, *)         = null
3928     * StringUtils.join([], *)           = ""
3929     * StringUtils.join([null], *)       = ""
3930     * StringUtils.join([1, 2, 3], ';')  = "1;2;3"
3931     * StringUtils.join([1, 2, 3], null) = "123"
3932     * </pre>
3933     *
3934     * @param array
3935     *            the array of values to join together, may be null
3936     * @param delimiter
3937     *            the separator character to use
3938     * @return the joined String, {@code null} if null array input
3939     * @since 3.2
3940     */
3941    public static String join(final char[] array, final char delimiter) {
3942        if (array == null) {
3943            return null;
3944        }
3945        return join(array, delimiter, 0, array.length);
3946    }
3947
3948    /**
3949     * Joins the elements of the provided array into a single String containing the provided list of elements.
3950     *
3951     * <p>
3952     * No delimiter is added before or after the list. Null objects or empty strings within the array are represented
3953     * by empty strings.
3954     * </p>
3955     *
3956     * <pre>
3957     * StringUtils.join(null, *)         = null
3958     * StringUtils.join([], *)           = ""
3959     * StringUtils.join([null], *)       = ""
3960     * StringUtils.join([1, 2, 3], ';')  = "1;2;3"
3961     * StringUtils.join([1, 2, 3], null) = "123"
3962     * </pre>
3963     *
3964     * @param array
3965     *            the array of values to join together, may be null
3966     * @param delimiter
3967     *            the separator character to use
3968     * @param startIndex
3969     *            the first index to start joining from. It is an error to pass in a start index past the end of the
3970     *            array
3971     * @param endIndex
3972     *            the index to stop joining from (exclusive). It is an error to pass in an end index past the end of
3973     *            the array
3974     * @return the joined String, {@code null} if null array input
3975     * @since 3.2
3976     */
3977    public static String join(final char[] array, final char delimiter, final int startIndex, final int endIndex) {
3978        if (array == null) {
3979            return null;
3980        }
3981        if (endIndex - startIndex <= 0) {
3982            return EMPTY;
3983        }
3984        final StringBuilder stringBuilder = new StringBuilder(array.length * 2 - 1);
3985        for (int i = startIndex; i < endIndex; i++) {
3986            stringBuilder
3987                    .append(array[i])
3988                    .append(delimiter);
3989        }
3990        return stringBuilder.substring(0, stringBuilder.length() - 1);
3991    }
3992
3993    /**
3994     * Joins the elements of the provided array into a single String containing the provided list of elements.
3995     *
3996     * <p>
3997     * No delimiter is added before or after the list. Null objects or empty strings within the array are represented
3998     * by empty strings.
3999     * </p>
4000     *
4001     * <pre>
4002     * StringUtils.join(null, *)               = null
4003     * StringUtils.join([], *)                 = ""
4004     * StringUtils.join([null], *)             = ""
4005     * StringUtils.join([1, 2, 3], ';')  = "1;2;3"
4006     * StringUtils.join([1, 2, 3], null) = "123"
4007     * </pre>
4008     *
4009     * @param array
4010     *            the array of values to join together, may be null
4011     * @param delimiter
4012     *            the separator character to use
4013     * @return the joined String, {@code null} if null array input
4014     * @since 3.2
4015     */
4016    public static String join(final double[] array, final char delimiter) {
4017        if (array == null) {
4018            return null;
4019        }
4020        return join(array, delimiter, 0, array.length);
4021    }
4022
4023    /**
4024     * Joins the elements of the provided array into a single String containing the provided list of elements.
4025     *
4026     * <p>
4027     * No delimiter is added before or after the list. Null objects or empty strings within the array are represented
4028     * by empty strings.
4029     * </p>
4030     *
4031     * <pre>
4032     * StringUtils.join(null, *)               = null
4033     * StringUtils.join([], *)                 = ""
4034     * StringUtils.join([null], *)             = ""
4035     * StringUtils.join([1, 2, 3], ';')  = "1;2;3"
4036     * StringUtils.join([1, 2, 3], null) = "123"
4037     * </pre>
4038     *
4039     * @param array
4040     *            the array of values to join together, may be null
4041     * @param delimiter
4042     *            the separator character to use
4043     * @param startIndex
4044     *            the first index to start joining from. It is an error to pass in a start index past the end of the
4045     *            array
4046     * @param endIndex
4047     *            the index to stop joining from (exclusive). It is an error to pass in an end index past the end of
4048     *            the array
4049     * @return the joined String, {@code null} if null array input
4050     * @since 3.2
4051     */
4052    public static String join(final double[] array, final char delimiter, final int startIndex, final int endIndex) {
4053        if (array == null) {
4054            return null;
4055        }
4056        if (endIndex - startIndex <= 0) {
4057            return EMPTY;
4058        }
4059        final StringBuilder stringBuilder = new StringBuilder();
4060        for (int i = startIndex; i < endIndex; i++) {
4061            stringBuilder
4062                    .append(array[i])
4063                    .append(delimiter);
4064        }
4065        return stringBuilder.substring(0, stringBuilder.length() - 1);
4066    }
4067
4068    /**
4069     * Joins the elements of the provided array into a single String containing the provided list of elements.
4070     *
4071     * <p>
4072     * No delimiter is added before or after the list. Null objects or empty strings within the array are represented
4073     * by empty strings.
4074     * </p>
4075     *
4076     * <pre>
4077     * StringUtils.join(null, *)               = null
4078     * StringUtils.join([], *)                 = ""
4079     * StringUtils.join([null], *)             = ""
4080     * StringUtils.join([1, 2, 3], ';')  = "1;2;3"
4081     * StringUtils.join([1, 2, 3], null) = "123"
4082     * </pre>
4083     *
4084     * @param array
4085     *            the array of values to join together, may be null
4086     * @param delimiter
4087     *            the separator character to use
4088     * @return the joined String, {@code null} if null array input
4089     * @since 3.2
4090     */
4091    public static String join(final float[] array, final char delimiter) {
4092        if (array == null) {
4093            return null;
4094        }
4095        return join(array, delimiter, 0, array.length);
4096    }
4097
4098    /**
4099     * Joins the elements of the provided array into a single String containing the provided list of elements.
4100     *
4101     * <p>
4102     * No delimiter is added before or after the list. Null objects or empty strings within the array are represented
4103     * by empty strings.
4104     * </p>
4105     *
4106     * <pre>
4107     * StringUtils.join(null, *)               = null
4108     * StringUtils.join([], *)                 = ""
4109     * StringUtils.join([null], *)             = ""
4110     * StringUtils.join([1, 2, 3], ';')  = "1;2;3"
4111     * StringUtils.join([1, 2, 3], null) = "123"
4112     * </pre>
4113     *
4114     * @param array
4115     *            the array of values to join together, may be null
4116     * @param delimiter
4117     *            the separator character to use
4118     * @param startIndex
4119     *            the first index to start joining from. It is an error to pass in a start index past the end of the
4120     *            array
4121     * @param endIndex
4122     *            the index to stop joining from (exclusive). It is an error to pass in an end index past the end of
4123     *            the array
4124     * @return the joined String, {@code null} if null array input
4125     * @since 3.2
4126     */
4127    public static String join(final float[] array, final char delimiter, final int startIndex, final int endIndex) {
4128        if (array == null) {
4129            return null;
4130        }
4131        if (endIndex - startIndex <= 0) {
4132            return EMPTY;
4133        }
4134        final StringBuilder stringBuilder = new StringBuilder();
4135        for (int i = startIndex; i < endIndex; i++) {
4136            stringBuilder
4137                    .append(array[i])
4138                    .append(delimiter);
4139        }
4140        return stringBuilder.substring(0, stringBuilder.length() - 1);
4141    }
4142
4143    /**
4144     * Joins the elements of the provided array into a single String containing the provided list of elements.
4145     *
4146     * <p>
4147     * No delimiter is added before or after the list. Null objects or empty strings within the array are represented
4148     * by empty strings.
4149     * </p>
4150     *
4151     * <pre>
4152     * StringUtils.join(null, *)               = null
4153     * StringUtils.join([], *)                 = ""
4154     * StringUtils.join([null], *)             = ""
4155     * StringUtils.join([1, 2, 3], ';')  = "1;2;3"
4156     * StringUtils.join([1, 2, 3], null) = "123"
4157     * </pre>
4158     *
4159     * @param array
4160     *            the array of values to join together, may be null
4161     * @param separator
4162     *            the separator character to use
4163     * @return the joined String, {@code null} if null array input
4164     * @since 3.2
4165     */
4166    public static String join(final int[] array, final char separator) {
4167        if (array == null) {
4168            return null;
4169        }
4170        return join(array, separator, 0, array.length);
4171    }
4172
4173    /**
4174     * Joins the elements of the provided array into a single String containing the provided list of elements.
4175     *
4176     * <p>
4177     * No delimiter is added before or after the list. Null objects or empty strings within the array are represented
4178     * by empty strings.
4179     * </p>
4180     *
4181     * <pre>
4182     * StringUtils.join(null, *)               = null
4183     * StringUtils.join([], *)                 = ""
4184     * StringUtils.join([null], *)             = ""
4185     * StringUtils.join([1, 2, 3], ';')  = "1;2;3"
4186     * StringUtils.join([1, 2, 3], null) = "123"
4187     * </pre>
4188     *
4189     * @param array
4190     *            the array of values to join together, may be null
4191     * @param delimiter
4192     *            the separator character to use
4193     * @param startIndex
4194     *            the first index to start joining from. It is an error to pass in a start index past the end of the
4195     *            array
4196     * @param endIndex
4197     *            the index to stop joining from (exclusive). It is an error to pass in an end index past the end of
4198     *            the array
4199     * @return the joined String, {@code null} if null array input
4200     * @since 3.2
4201     */
4202    public static String join(final int[] array, final char delimiter, final int startIndex, final int endIndex) {
4203        if (array == null) {
4204            return null;
4205        }
4206        if (endIndex - startIndex <= 0) {
4207            return EMPTY;
4208        }
4209        final StringBuilder stringBuilder = new StringBuilder();
4210        for (int i = startIndex; i < endIndex; i++) {
4211            stringBuilder
4212                    .append(array[i])
4213                    .append(delimiter);
4214        }
4215        return stringBuilder.substring(0, stringBuilder.length() - 1);
4216    }
4217
4218    /**
4219     * Joins the elements of the provided {@link Iterable} into
4220     * a single String containing the provided elements.
4221     *
4222     * <p>No delimiter is added before or after the list. Null objects or empty
4223     * strings within the iteration are represented by empty strings.</p>
4224     *
4225     * <p>See the examples here: {@link #join(Object[],char)}.</p>
4226     *
4227     * @param iterable  the {@link Iterable} providing the values to join together, may be null
4228     * @param separator  the separator character to use
4229     * @return the joined String, {@code null} if null iterator input
4230     * @since 2.3
4231     */
4232    public static String join(final Iterable<?> iterable, final char separator) {
4233        return iterable != null ? join(iterable.iterator(), separator) : null;
4234    }
4235
4236    /**
4237     * Joins the elements of the provided {@link Iterable} into
4238     * a single String containing the provided elements.
4239     *
4240     * <p>No delimiter is added before or after the list.
4241     * A {@code null} separator is the same as an empty String ("").</p>
4242     *
4243     * <p>See the examples here: {@link #join(Object[],String)}.</p>
4244     *
4245     * @param iterable  the {@link Iterable} providing the values to join together, may be null
4246     * @param separator  the separator character to use, null treated as ""
4247     * @return the joined String, {@code null} if null iterator input
4248     * @since 2.3
4249     */
4250    public static String join(final Iterable<?> iterable, final String separator) {
4251        return iterable != null ? join(iterable.iterator(), separator) : null;
4252    }
4253
4254    /**
4255     * Joins the elements of the provided {@link Iterator} into
4256     * a single String containing the provided elements.
4257     *
4258     * <p>No delimiter is added before or after the list. Null objects or empty
4259     * strings within the iteration are represented by empty strings.</p>
4260     *
4261     * <p>See the examples here: {@link #join(Object[],char)}.</p>
4262     *
4263     * @param iterator  the {@link Iterator} of values to join together, may be null
4264     * @param separator  the separator character to use
4265     * @return the joined String, {@code null} if null iterator input
4266     * @since 2.0
4267     */
4268    public static String join(final Iterator<?> iterator, final char separator) {
4269        // handle null, zero and one elements before building a buffer
4270        if (iterator == null) {
4271            return null;
4272        }
4273        if (!iterator.hasNext()) {
4274            return EMPTY;
4275        }
4276        return Streams.of(iterator).collect(LangCollectors.joining(ObjectUtils.toString(String.valueOf(separator)), EMPTY, EMPTY, ObjectUtils::toString));
4277    }
4278
4279    /**
4280     * Joins the elements of the provided {@link Iterator} into
4281     * a single String containing the provided elements.
4282     *
4283     * <p>No delimiter is added before or after the list.
4284     * A {@code null} separator is the same as an empty String ("").</p>
4285     *
4286     * <p>See the examples here: {@link #join(Object[],String)}.</p>
4287     *
4288     * @param iterator  the {@link Iterator} of values to join together, may be null
4289     * @param separator  the separator character to use, null treated as ""
4290     * @return the joined String, {@code null} if null iterator input
4291     */
4292    public static String join(final Iterator<?> iterator, final String separator) {
4293        // handle null, zero and one elements before building a buffer
4294        if (iterator == null) {
4295            return null;
4296        }
4297        if (!iterator.hasNext()) {
4298            return EMPTY;
4299        }
4300        return Streams.of(iterator).collect(LangCollectors.joining(ObjectUtils.toString(separator), EMPTY, EMPTY, ObjectUtils::toString));
4301    }
4302
4303    /**
4304     * Joins the elements of the provided {@link List} into a single String
4305     * containing the provided list of elements.
4306     *
4307     * <p>No delimiter is added before or after the list.
4308     * Null objects or empty strings within the array are represented by
4309     * empty strings.</p>
4310     *
4311     * <pre>
4312     * StringUtils.join(null, *)               = null
4313     * StringUtils.join([], *)                 = ""
4314     * StringUtils.join([null], *)             = ""
4315     * StringUtils.join(["a", "b", "c"], ';')  = "a;b;c"
4316     * StringUtils.join(["a", "b", "c"], null) = "abc"
4317     * StringUtils.join([null, "", "a"], ';')  = ";;a"
4318     * </pre>
4319     *
4320     * @param list  the {@link List} of values to join together, may be null
4321     * @param separator  the separator character to use
4322     * @param startIndex the first index to start joining from.  It is
4323     * an error to pass in a start index past the end of the list
4324     * @param endIndex the index to stop joining from (exclusive). It is
4325     * an error to pass in an end index past the end of the list
4326     * @return the joined String, {@code null} if null list input
4327     * @since 3.8
4328     */
4329    public static String join(final List<?> list, final char separator, final int startIndex, final int endIndex) {
4330        if (list == null) {
4331            return null;
4332        }
4333        final int noOfItems = endIndex - startIndex;
4334        if (noOfItems <= 0) {
4335            return EMPTY;
4336        }
4337        final List<?> subList = list.subList(startIndex, endIndex);
4338        return join(subList.iterator(), separator);
4339    }
4340
4341    /**
4342     * Joins the elements of the provided {@link List} into a single String
4343     * containing the provided list of elements.
4344     *
4345     * <p>No delimiter is added before or after the list.
4346     * Null objects or empty strings within the array are represented by
4347     * empty strings.</p>
4348     *
4349     * <pre>
4350     * StringUtils.join(null, *)               = null
4351     * StringUtils.join([], *)                 = ""
4352     * StringUtils.join([null], *)             = ""
4353     * StringUtils.join(["a", "b", "c"], ';')  = "a;b;c"
4354     * StringUtils.join(["a", "b", "c"], null) = "abc"
4355     * StringUtils.join([null, "", "a"], ';')  = ";;a"
4356     * </pre>
4357     *
4358     * @param list  the {@link List} of values to join together, may be null
4359     * @param separator  the separator character to use
4360     * @param startIndex the first index to start joining from.  It is
4361     * an error to pass in a start index past the end of the list
4362     * @param endIndex the index to stop joining from (exclusive). It is
4363     * an error to pass in an end index past the end of the list
4364     * @return the joined String, {@code null} if null list input
4365     * @since 3.8
4366     */
4367    public static String join(final List<?> list, final String separator, final int startIndex, final int endIndex) {
4368        if (list == null) {
4369            return null;
4370        }
4371        final int noOfItems = endIndex - startIndex;
4372        if (noOfItems <= 0) {
4373            return EMPTY;
4374        }
4375        final List<?> subList = list.subList(startIndex, endIndex);
4376        return join(subList.iterator(), separator);
4377    }
4378
4379    /**
4380     * Joins the elements of the provided array into a single String containing the provided list of elements.
4381     *
4382     * <p>
4383     * No delimiter is added before or after the list. Null objects or empty strings within the array are represented
4384     * by empty strings.
4385     * </p>
4386     *
4387     * <pre>
4388     * StringUtils.join(null, *)               = null
4389     * StringUtils.join([], *)                 = ""
4390     * StringUtils.join([null], *)             = ""
4391     * StringUtils.join([1, 2, 3], ';')  = "1;2;3"
4392     * StringUtils.join([1, 2, 3], null) = "123"
4393     * </pre>
4394     *
4395     * @param array
4396     *            the array of values to join together, may be null
4397     * @param separator
4398     *            the separator character to use
4399     * @return the joined String, {@code null} if null array input
4400     * @since 3.2
4401     */
4402    public static String join(final long[] array, final char separator) {
4403        if (array == null) {
4404            return null;
4405        }
4406        return join(array, separator, 0, array.length);
4407    }
4408
4409    /**
4410     * Joins the elements of the provided array into a single String containing the provided list of elements.
4411     *
4412     * <p>
4413     * No delimiter is added before or after the list. Null objects or empty strings within the array are represented
4414     * by empty strings.
4415     * </p>
4416     *
4417     * <pre>
4418     * StringUtils.join(null, *)               = null
4419     * StringUtils.join([], *)                 = ""
4420     * StringUtils.join([null], *)             = ""
4421     * StringUtils.join([1, 2, 3], ';')  = "1;2;3"
4422     * StringUtils.join([1, 2, 3], null) = "123"
4423     * </pre>
4424     *
4425     * @param array
4426     *            the array of values to join together, may be null
4427     * @param delimiter
4428     *            the separator character to use
4429     * @param startIndex
4430     *            the first index to start joining from. It is an error to pass in a start index past the end of the
4431     *            array
4432     * @param endIndex
4433     *            the index to stop joining from (exclusive). It is an error to pass in an end index past the end of
4434     *            the array
4435     * @return the joined String, {@code null} if null array input
4436     * @since 3.2
4437     */
4438    public static String join(final long[] array, final char delimiter, final int startIndex, final int endIndex) {
4439        if (array == null) {
4440            return null;
4441        }
4442        if (endIndex - startIndex <= 0) {
4443            return EMPTY;
4444        }
4445        final StringBuilder stringBuilder = new StringBuilder();
4446        for (int i = startIndex; i < endIndex; i++) {
4447            stringBuilder
4448                    .append(array[i])
4449                    .append(delimiter);
4450        }
4451        return stringBuilder.substring(0, stringBuilder.length() - 1);
4452    }
4453
4454    /**
4455     * Joins the elements of the provided array into a single String
4456     * containing the provided list of elements.
4457     *
4458     * <p>No delimiter is added before or after the list.
4459     * Null objects or empty strings within the array are represented by
4460     * empty strings.</p>
4461     *
4462     * <pre>
4463     * StringUtils.join(null, *)               = null
4464     * StringUtils.join([], *)                 = ""
4465     * StringUtils.join([null], *)             = ""
4466     * StringUtils.join(["a", "b", "c"], ';')  = "a;b;c"
4467     * StringUtils.join(["a", "b", "c"], null) = "abc"
4468     * StringUtils.join([null, "", "a"], ';')  = ";;a"
4469     * </pre>
4470     *
4471     * @param array  the array of values to join together, may be null
4472     * @param delimiter  the separator character to use
4473     * @return the joined String, {@code null} if null array input
4474     * @since 2.0
4475     */
4476    public static String join(final Object[] array, final char delimiter) {
4477        if (array == null) {
4478            return null;
4479        }
4480        return join(array, delimiter, 0, array.length);
4481    }
4482
4483    /**
4484     * Joins the elements of the provided array into a single String
4485     * containing the provided list of elements.
4486     *
4487     * <p>No delimiter is added before or after the list.
4488     * Null objects or empty strings within the array are represented by
4489     * empty strings.</p>
4490     *
4491     * <pre>
4492     * StringUtils.join(null, *)               = null
4493     * StringUtils.join([], *)                 = ""
4494     * StringUtils.join([null], *)             = ""
4495     * StringUtils.join(["a", "b", "c"], ';')  = "a;b;c"
4496     * StringUtils.join(["a", "b", "c"], null) = "abc"
4497     * StringUtils.join([null, "", "a"], ';')  = ";;a"
4498     * </pre>
4499     *
4500     * @param array  the array of values to join together, may be null
4501     * @param delimiter  the separator character to use
4502     * @param startIndex the first index to start joining from.  It is
4503     * an error to pass in a start index past the end of the array
4504     * @param endIndex the index to stop joining from (exclusive). It is
4505     * an error to pass in an end index past the end of the array
4506     * @return the joined String, {@code null} if null array input
4507     * @since 2.0
4508     */
4509    public static String join(final Object[] array, final char delimiter, final int startIndex, final int endIndex) {
4510        return join(array, String.valueOf(delimiter), startIndex, endIndex);
4511    }
4512
4513    /**
4514     * Joins the elements of the provided array into a single String
4515     * containing the provided list of elements.
4516     *
4517     * <p>No delimiter is added before or after the list.
4518     * A {@code null} separator is the same as an empty String ("").
4519     * Null objects or empty strings within the array are represented by
4520     * empty strings.</p>
4521     *
4522     * <pre>
4523     * StringUtils.join(null, *)                = null
4524     * StringUtils.join([], *)                  = ""
4525     * StringUtils.join([null], *)              = ""
4526     * StringUtils.join(["a", "b", "c"], "--")  = "a--b--c"
4527     * StringUtils.join(["a", "b", "c"], null)  = "abc"
4528     * StringUtils.join(["a", "b", "c"], "")    = "abc"
4529     * StringUtils.join([null, "", "a"], ',')   = ",,a"
4530     * </pre>
4531     *
4532     * @param array  the array of values to join together, may be null
4533     * @param delimiter  the separator character to use, null treated as ""
4534     * @return the joined String, {@code null} if null array input
4535     */
4536    public static String join(final Object[] array, final String delimiter) {
4537        return array != null ? join(array, ObjectUtils.toString(delimiter), 0, array.length) : null;
4538    }
4539
4540    /**
4541     * Joins the elements of the provided array into a single String
4542     * containing the provided list of elements.
4543     *
4544     * <p>No delimiter is added before or after the list.
4545     * A {@code null} separator is the same as an empty String ("").
4546     * Null objects or empty strings within the array are represented by
4547     * empty strings.</p>
4548     *
4549     * <pre>
4550     * StringUtils.join(null, *, *, *)                = null
4551     * StringUtils.join([], *, *, *)                  = ""
4552     * StringUtils.join([null], *, *, *)              = ""
4553     * StringUtils.join(["a", "b", "c"], "--", 0, 3)  = "a--b--c"
4554     * StringUtils.join(["a", "b", "c"], "--", 1, 3)  = "b--c"
4555     * StringUtils.join(["a", "b", "c"], "--", 2, 3)  = "c"
4556     * StringUtils.join(["a", "b", "c"], "--", 2, 2)  = ""
4557     * StringUtils.join(["a", "b", "c"], null, 0, 3)  = "abc"
4558     * StringUtils.join(["a", "b", "c"], "", 0, 3)    = "abc"
4559     * StringUtils.join([null, "", "a"], ',', 0, 3)   = ",,a"
4560     * </pre>
4561     *
4562     * @param array  the array of values to join together, may be null
4563     * @param delimiter  the separator character to use, null treated as ""
4564     * @param startIndex the first index to start joining from.
4565     * @param endIndex the index to stop joining from (exclusive).
4566     * @return the joined String, {@code null} if null array input; or the empty string
4567     * if {@code endIndex - startIndex <= 0}. The number of joined entries is given by
4568     * {@code endIndex - startIndex}
4569     * @throws ArrayIndexOutOfBoundsException ife<br>
4570     * {@code startIndex < 0} or <br>
4571     * {@code startIndex >= array.length()} or <br>
4572     * {@code endIndex < 0} or <br>
4573     * {@code endIndex > array.length()}
4574     */
4575    public static String join(final Object[] array, final String delimiter, final int startIndex, final int endIndex) {
4576        return array != null ? Streams.of(array).skip(startIndex).limit(Math.max(0, endIndex - startIndex))
4577            .collect(LangCollectors.joining(delimiter, EMPTY, EMPTY, ObjectUtils::toString)) : null;
4578    }
4579
4580    /**
4581     * Joins the elements of the provided array into a single String containing the provided list of elements.
4582     *
4583     * <p>
4584     * No delimiter is added before or after the list. Null objects or empty strings within the array are represented
4585     * by empty strings.
4586     * </p>
4587     *
4588     * <pre>
4589     * StringUtils.join(null, *)               = null
4590     * StringUtils.join([], *)                 = ""
4591     * StringUtils.join([null], *)             = ""
4592     * StringUtils.join([1, 2, 3], ';')  = "1;2;3"
4593     * StringUtils.join([1, 2, 3], null) = "123"
4594     * </pre>
4595     *
4596     * @param array
4597     *            the array of values to join together, may be null
4598     * @param delimiter
4599     *            the separator character to use
4600     * @return the joined String, {@code null} if null array input
4601     * @since 3.2
4602     */
4603    public static String join(final short[] array, final char delimiter) {
4604        if (array == null) {
4605            return null;
4606        }
4607        return join(array, delimiter, 0, array.length);
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
4615     * by empty strings.
4616     * </p>
4617     *
4618     * <pre>
4619     * StringUtils.join(null, *)               = null
4620     * StringUtils.join([], *)                 = ""
4621     * StringUtils.join([null], *)             = ""
4622     * StringUtils.join([1, 2, 3], ';')  = "1;2;3"
4623     * StringUtils.join([1, 2, 3], null) = "123"
4624     * </pre>
4625     *
4626     * @param array
4627     *            the array of values to join together, may be null
4628     * @param delimiter
4629     *            the separator character to use
4630     * @param startIndex
4631     *            the first index to start joining from. It is an error to pass in a start index past the end of the
4632     *            array
4633     * @param endIndex
4634     *            the index to stop joining from (exclusive). It is an error to pass in an end index past the end of
4635     *            the array
4636     * @return the joined String, {@code null} if null array input
4637     * @since 3.2
4638     */
4639    public static String join(final short[] array, final char delimiter, final int startIndex, final int endIndex) {
4640        if (array == null) {
4641            return null;
4642        }
4643        if (endIndex - startIndex <= 0) {
4644            return EMPTY;
4645        }
4646        final StringBuilder stringBuilder = new StringBuilder();
4647        for (int i = startIndex; i < endIndex; i++) {
4648            stringBuilder
4649                    .append(array[i])
4650                    .append(delimiter);
4651        }
4652        return stringBuilder.substring(0, stringBuilder.length() - 1);
4653    }
4654
4655    /**
4656     * Joins the elements of the provided array into a single String
4657     * containing the provided list of elements.
4658     *
4659     * <p>No separator is added to the joined String.
4660     * Null objects or empty strings within the array are represented by
4661     * empty strings.</p>
4662     *
4663     * <pre>
4664     * StringUtils.join(null)            = null
4665     * StringUtils.join([])              = ""
4666     * StringUtils.join([null])          = ""
4667     * StringUtils.join(["a", "b", "c"]) = "abc"
4668     * StringUtils.join([null, "", "a"]) = "a"
4669     * </pre>
4670     *
4671     * @param <T> the specific type of values to join together
4672     * @param elements  the values to join together, may be null
4673     * @return the joined String, {@code null} if null array input
4674     * @since 2.0
4675     * @since 3.0 Changed signature to use varargs
4676     */
4677    @SafeVarargs
4678    public static <T> String join(final T... elements) {
4679        return join(elements, null);
4680    }
4681
4682    /**
4683     * Joins the elements of the provided varargs into a
4684     * single String containing the provided elements.
4685     *
4686     * <p>No delimiter is added before or after the list.
4687     * {@code null} elements and separator are treated as empty Strings ("").</p>
4688     *
4689     * <pre>
4690     * StringUtils.joinWith(",", {"a", "b"})        = "a,b"
4691     * StringUtils.joinWith(",", {"a", "b",""})     = "a,b,"
4692     * StringUtils.joinWith(",", {"a", null, "b"})  = "a,,b"
4693     * StringUtils.joinWith(null, {"a", "b"})       = "ab"
4694     * </pre>
4695     *
4696     * @param delimiter the separator character to use, null treated as ""
4697     * @param array the varargs providing the values to join together. {@code null} elements are treated as ""
4698     * @return the joined String.
4699     * @throws IllegalArgumentException if a null varargs is provided
4700     * @since 3.5
4701     */
4702    public static String joinWith(final String delimiter, final Object... array) {
4703        if (array == null) {
4704            throw new IllegalArgumentException("Object varargs must not be null");
4705        }
4706        return join(array, delimiter);
4707    }
4708
4709    /**
4710     * Finds the last index within a CharSequence, handling {@code null}.
4711     * This method uses {@link String#lastIndexOf(String)} if possible.
4712     *
4713     * <p>A {@code null} CharSequence will return {@code -1}.</p>
4714     *
4715     * <pre>
4716     * StringUtils.lastIndexOf(null, *)          = -1
4717     * StringUtils.lastIndexOf(*, null)          = -1
4718     * StringUtils.lastIndexOf("", "")           = 0
4719     * StringUtils.lastIndexOf("aabaabaa", "a")  = 7
4720     * StringUtils.lastIndexOf("aabaabaa", "b")  = 5
4721     * StringUtils.lastIndexOf("aabaabaa", "ab") = 4
4722     * StringUtils.lastIndexOf("aabaabaa", "")   = 8
4723     * </pre>
4724     *
4725     * @param seq  the CharSequence to check, may be null
4726     * @param searchSeq  the CharSequence to find, may be null
4727     * @return the last index of the search String,
4728     *  -1 if no match or {@code null} string input
4729     * @since 2.0
4730     * @since 3.0 Changed signature from lastIndexOf(String, String) to lastIndexOf(CharSequence, CharSequence)
4731     * @deprecated Use {@link Strings#lastIndexOf(CharSequence, CharSequence) Strings.CS.lastIndexOf(CharSequence, CharSequence)}
4732     */
4733    @Deprecated
4734    public static int lastIndexOf(final CharSequence seq, final CharSequence searchSeq) {
4735        return Strings.CS.lastIndexOf(seq, searchSeq);
4736    }
4737
4738    /**
4739     * Finds the last index within a CharSequence, handling {@code null}.
4740     * This method uses {@link String#lastIndexOf(String, int)} if possible.
4741     *
4742     * <p>A {@code null} CharSequence will return {@code -1}.
4743     * A negative start position returns {@code -1}.
4744     * An empty ("") search CharSequence always matches unless the start position is negative.
4745     * A start position greater than the string length searches the whole string.
4746     * The search starts at the startPos and works backwards; matches starting after the start
4747     * position are ignored.
4748     * </p>
4749     *
4750     * <pre>
4751     * StringUtils.lastIndexOf(null, *, *)          = -1
4752     * StringUtils.lastIndexOf(*, null, *)          = -1
4753     * StringUtils.lastIndexOf("aabaabaa", "a", 8)  = 7
4754     * StringUtils.lastIndexOf("aabaabaa", "b", 8)  = 5
4755     * StringUtils.lastIndexOf("aabaabaa", "ab", 8) = 4
4756     * StringUtils.lastIndexOf("aabaabaa", "b", 9)  = 5
4757     * StringUtils.lastIndexOf("aabaabaa", "b", -1) = -1
4758     * StringUtils.lastIndexOf("aabaabaa", "a", 0)  = 0
4759     * StringUtils.lastIndexOf("aabaabaa", "b", 0)  = -1
4760     * StringUtils.lastIndexOf("aabaabaa", "b", 1)  = -1
4761     * StringUtils.lastIndexOf("aabaabaa", "b", 2)  = 2
4762     * StringUtils.lastIndexOf("aabaabaa", "ba", 2)  = 2
4763     * </pre>
4764     *
4765     * @param seq  the CharSequence to check, may be null
4766     * @param searchSeq  the CharSequence to find, may be null
4767     * @param startPos  the start position, negative treated as zero
4768     * @return the last index of the search CharSequence (always &le; startPos),
4769     *  -1 if no match or {@code null} string input
4770     * @since 2.0
4771     * @since 3.0 Changed signature from lastIndexOf(String, String, int) to lastIndexOf(CharSequence, CharSequence, int)
4772     * @deprecated Use {@link Strings#lastIndexOf(CharSequence, CharSequence, int) Strings.CS.lastIndexOf(CharSequence, CharSequence, int)}
4773     */
4774    @Deprecated
4775    public static int lastIndexOf(final CharSequence seq, final CharSequence searchSeq, final int startPos) {
4776        return Strings.CS.lastIndexOf(seq, searchSeq, startPos);
4777    }
4778
4779    /**
4780     * Returns the index within {@code seq} of the last occurrence of
4781     * the specified character. For values of {@code searchChar} in the
4782     * range from 0 to 0xFFFF (inclusive), the index (in Unicode code
4783     * units) returned is the largest value <em>k</em> such that:
4784     * <blockquote><pre>
4785     * this.charAt(<em>k</em>) == searchChar
4786     * </pre></blockquote>
4787     * is true. For other values of {@code searchChar}, it is the
4788     * largest value <em>k</em> such that:
4789     * <blockquote><pre>
4790     * this.codePointAt(<em>k</em>) == searchChar
4791     * </pre></blockquote>
4792     * is true.  In either case, if no such character occurs in this
4793     * string, then {@code -1} is returned. Furthermore, a {@code null} or empty ("")
4794     * {@link CharSequence} will return {@code -1}. The
4795     * {@code seq} {@link CharSequence} object is searched backwards
4796     * starting at the last character.
4797     *
4798     * <pre>
4799     * StringUtils.lastIndexOf(null, *)         = -1
4800     * StringUtils.lastIndexOf("", *)           = -1
4801     * StringUtils.lastIndexOf("aabaabaa", 'a') = 7
4802     * StringUtils.lastIndexOf("aabaabaa", 'b') = 5
4803     * </pre>
4804     *
4805     * @param seq  the {@link CharSequence} to check, may be null
4806     * @param searchChar  the character to find
4807     * @return the last index of the search character,
4808     *  -1 if no match or {@code null} string input
4809     * @since 2.0
4810     * @since 3.0 Changed signature from lastIndexOf(String, int) to lastIndexOf(CharSequence, int)
4811     * @since 3.6 Updated {@link CharSequenceUtils} call to behave more like {@link String}
4812     */
4813    public static int lastIndexOf(final CharSequence seq, final int searchChar) {
4814        if (isEmpty(seq)) {
4815            return INDEX_NOT_FOUND;
4816        }
4817        return CharSequenceUtils.lastIndexOf(seq, searchChar, seq.length());
4818    }
4819
4820    /**
4821     * Returns the index within {@code seq} of the last occurrence of
4822     * the specified character, searching backward starting at the
4823     * specified index. For values of {@code searchChar} in the range
4824     * from 0 to 0xFFFF (inclusive), the index returned is the largest
4825     * value <em>k</em> such that:
4826     * <blockquote><pre>
4827     * (this.charAt(<em>k</em>) == searchChar) &amp;&amp; (<em>k</em> &lt;= startPos)
4828     * </pre></blockquote>
4829     * is true. For other values of {@code searchChar}, it is the
4830     * largest value <em>k</em> such that:
4831     * <blockquote><pre>
4832     * (this.codePointAt(<em>k</em>) == searchChar) &amp;&amp; (<em>k</em> &lt;= startPos)
4833     * </pre></blockquote>
4834     * is true. In either case, if no such character occurs in {@code seq}
4835     * at or before position {@code startPos}, then
4836     * {@code -1} is returned. Furthermore, a {@code null} or empty ("")
4837     * {@link CharSequence} will return {@code -1}. A start position greater
4838     * than the string length searches the whole string.
4839     * The search starts at the {@code startPos} and works backwards;
4840     * matches starting after the start position are ignored.
4841     *
4842     * <p>All indices are specified in {@code char} values
4843     * (Unicode code units).
4844     *
4845     * <pre>
4846     * StringUtils.lastIndexOf(null, *, *)          = -1
4847     * StringUtils.lastIndexOf("", *,  *)           = -1
4848     * StringUtils.lastIndexOf("aabaabaa", 'b', 8)  = 5
4849     * StringUtils.lastIndexOf("aabaabaa", 'b', 4)  = 2
4850     * StringUtils.lastIndexOf("aabaabaa", 'b', 0)  = -1
4851     * StringUtils.lastIndexOf("aabaabaa", 'b', 9)  = 5
4852     * StringUtils.lastIndexOf("aabaabaa", 'b', -1) = -1
4853     * StringUtils.lastIndexOf("aabaabaa", 'a', 0)  = 0
4854     * </pre>
4855     *
4856     * @param seq  the CharSequence to check, may be null
4857     * @param searchChar  the character to find
4858     * @param startPos  the start position
4859     * @return the last index of the search character (always &le; startPos),
4860     *  -1 if no match or {@code null} string input
4861     * @since 2.0
4862     * @since 3.0 Changed signature from lastIndexOf(String, int, int) to lastIndexOf(CharSequence, int, int)
4863     */
4864    public static int lastIndexOf(final CharSequence seq, final int searchChar, final int startPos) {
4865        if (isEmpty(seq)) {
4866            return INDEX_NOT_FOUND;
4867        }
4868        return CharSequenceUtils.lastIndexOf(seq, searchChar, startPos);
4869    }
4870
4871    /**
4872     * Find the latest index of any substring in a set of potential substrings.
4873     *
4874     * <p>A {@code null} CharSequence will return {@code -1}.
4875     * A {@code null} search array will return {@code -1}.
4876     * A {@code null} or zero length search array entry will be ignored,
4877     * but a search array containing "" will return the length of {@code str}
4878     * if {@code str} is not null. This method uses {@link String#indexOf(String)} if possible</p>
4879     *
4880     * <pre>
4881     * StringUtils.lastIndexOfAny(null, *)                    = -1
4882     * StringUtils.lastIndexOfAny(*, null)                    = -1
4883     * StringUtils.lastIndexOfAny(*, [])                      = -1
4884     * StringUtils.lastIndexOfAny(*, [null])                  = -1
4885     * StringUtils.lastIndexOfAny("zzabyycdxx", ["ab", "cd"]) = 6
4886     * StringUtils.lastIndexOfAny("zzabyycdxx", ["cd", "ab"]) = 6
4887     * StringUtils.lastIndexOfAny("zzabyycdxx", ["mn", "op"]) = -1
4888     * StringUtils.lastIndexOfAny("zzabyycdxx", ["mn", "op"]) = -1
4889     * StringUtils.lastIndexOfAny("zzabyycdxx", ["mn", ""])   = 10
4890     * </pre>
4891     *
4892     * @param str  the CharSequence to check, may be null
4893     * @param searchStrs  the CharSequences to search for, may be null
4894     * @return the last index of any of the CharSequences, -1 if no match
4895     * @since 3.0 Changed signature from lastIndexOfAny(String, String[]) to lastIndexOfAny(CharSequence, CharSequence)
4896     */
4897    public static int lastIndexOfAny(final CharSequence str, final CharSequence... searchStrs) {
4898        if (str == null || searchStrs == null) {
4899            return INDEX_NOT_FOUND;
4900        }
4901        int ret = INDEX_NOT_FOUND;
4902        int tmp;
4903        for (final CharSequence search : searchStrs) {
4904            if (search == null) {
4905                continue;
4906            }
4907            tmp = CharSequenceUtils.lastIndexOf(str, search, str.length());
4908            if (tmp > ret) {
4909                ret = tmp;
4910            }
4911        }
4912        return ret;
4913    }
4914
4915    /**
4916     * Case in-sensitive find of the last index within a CharSequence.
4917     *
4918     * <p>A {@code null} CharSequence will return {@code -1}.
4919     * A negative start position returns {@code -1}.
4920     * An empty ("") search CharSequence always matches unless the start position is negative.
4921     * A start position greater than the string length searches the whole string.</p>
4922     *
4923     * <pre>
4924     * StringUtils.lastIndexOfIgnoreCase(null, *)          = -1
4925     * StringUtils.lastIndexOfIgnoreCase(*, null)          = -1
4926     * StringUtils.lastIndexOfIgnoreCase("aabaabaa", "A")  = 7
4927     * StringUtils.lastIndexOfIgnoreCase("aabaabaa", "B")  = 5
4928     * StringUtils.lastIndexOfIgnoreCase("aabaabaa", "AB") = 4
4929     * </pre>
4930     *
4931     * @param str  the CharSequence to check, may be null
4932     * @param searchStr  the CharSequence to find, may be null
4933     * @return the first index of the search CharSequence,
4934     *  -1 if no match or {@code null} string input
4935     * @since 2.5
4936     * @since 3.0 Changed signature from lastIndexOfIgnoreCase(String, String) to lastIndexOfIgnoreCase(CharSequence, CharSequence)
4937     * @deprecated Use {@link Strings#lastIndexOf(CharSequence, CharSequence) Strings.CI.lastIndexOf(CharSequence, CharSequence)}
4938     */
4939    @Deprecated
4940    public static int lastIndexOfIgnoreCase(final CharSequence str, final CharSequence searchStr) {
4941        return Strings.CI.lastIndexOf(str, searchStr);
4942    }
4943
4944    /**
4945     * Case in-sensitive find of the last index within a CharSequence
4946     * from the specified position.
4947     *
4948     * <p>A {@code null} CharSequence will return {@code -1}.
4949     * A negative start position returns {@code -1}.
4950     * An empty ("") search CharSequence always matches unless the start position is negative.
4951     * A start position greater than the string length searches the whole string.
4952     * The search starts at the startPos and works backwards; matches starting after the start
4953     * position are ignored.
4954     * </p>
4955     *
4956     * <pre>
4957     * StringUtils.lastIndexOfIgnoreCase(null, *, *)          = -1
4958     * StringUtils.lastIndexOfIgnoreCase(*, null, *)          = -1
4959     * StringUtils.lastIndexOfIgnoreCase("aabaabaa", "A", 8)  = 7
4960     * StringUtils.lastIndexOfIgnoreCase("aabaabaa", "B", 8)  = 5
4961     * StringUtils.lastIndexOfIgnoreCase("aabaabaa", "AB", 8) = 4
4962     * StringUtils.lastIndexOfIgnoreCase("aabaabaa", "B", 9)  = 5
4963     * StringUtils.lastIndexOfIgnoreCase("aabaabaa", "B", -1) = -1
4964     * StringUtils.lastIndexOfIgnoreCase("aabaabaa", "A", 0)  = 0
4965     * StringUtils.lastIndexOfIgnoreCase("aabaabaa", "B", 0)  = -1
4966     * </pre>
4967     *
4968     * @param str  the CharSequence to check, may be null
4969     * @param searchStr  the CharSequence to find, may be null
4970     * @param startPos  the start position
4971     * @return the last index of the search CharSequence (always &le; startPos),
4972     *  -1 if no match or {@code null} input
4973     * @since 2.5
4974     * @since 3.0 Changed signature from lastIndexOfIgnoreCase(String, String, int) to lastIndexOfIgnoreCase(CharSequence, CharSequence, int)
4975     * @deprecated Use {@link Strings#lastIndexOf(CharSequence, CharSequence, int) Strings.CI.lastIndexOf(CharSequence, CharSequence, int)}
4976     */
4977    @Deprecated
4978    public static int lastIndexOfIgnoreCase(final CharSequence str, final CharSequence searchStr, final int startPos) {
4979        return Strings.CI.lastIndexOf(str, searchStr, startPos);
4980    }
4981
4982    /**
4983     * Finds the n-th last index within a String, handling {@code null}.
4984     * This method uses {@link String#lastIndexOf(String)}.
4985     *
4986     * <p>A {@code null} String will return {@code -1}.</p>
4987     *
4988     * <pre>
4989     * StringUtils.lastOrdinalIndexOf(null, *, *)          = -1
4990     * StringUtils.lastOrdinalIndexOf(*, null, *)          = -1
4991     * StringUtils.lastOrdinalIndexOf("", "", *)           = 0
4992     * StringUtils.lastOrdinalIndexOf("aabaabaa", "a", 1)  = 7
4993     * StringUtils.lastOrdinalIndexOf("aabaabaa", "a", 2)  = 6
4994     * StringUtils.lastOrdinalIndexOf("aabaabaa", "b", 1)  = 5
4995     * StringUtils.lastOrdinalIndexOf("aabaabaa", "b", 2)  = 2
4996     * StringUtils.lastOrdinalIndexOf("aabaabaa", "ab", 1) = 4
4997     * StringUtils.lastOrdinalIndexOf("aabaabaa", "ab", 2) = 1
4998     * StringUtils.lastOrdinalIndexOf("aabaabaa", "", 1)   = 8
4999     * StringUtils.lastOrdinalIndexOf("aabaabaa", "", 2)   = 8
5000     * </pre>
5001     *
5002     * <p>Note that 'tail(CharSequence str, int n)' may be implemented as: </p>
5003     *
5004     * <pre>
5005     *   str.substring(lastOrdinalIndexOf(str, "\n", n) + 1)
5006     * </pre>
5007     *
5008     * @param str  the CharSequence to check, may be null
5009     * @param searchStr  the CharSequence to find, may be null
5010     * @param ordinal  the n-th last {@code searchStr} to find
5011     * @return the n-th last index of the search CharSequence,
5012     *  {@code -1} ({@code INDEX_NOT_FOUND}) if no match or {@code null} string input
5013     * @since 2.5
5014     * @since 3.0 Changed signature from lastOrdinalIndexOf(String, String, int) to lastOrdinalIndexOf(CharSequence, CharSequence, int)
5015     */
5016    public static int lastOrdinalIndexOf(final CharSequence str, final CharSequence searchStr, final int ordinal) {
5017        return ordinalIndexOf(str, searchStr, ordinal, true);
5018    }
5019
5020    /**
5021     * Gets the leftmost {@code len} characters of a String.
5022     *
5023     * <p>If {@code len} characters are not available, or the
5024     * String is {@code null}, the String will be returned without
5025     * an exception. An empty String is returned if len is negative.</p>
5026     *
5027     * <pre>
5028     * StringUtils.left(null, *)    = null
5029     * StringUtils.left(*, -ve)     = ""
5030     * StringUtils.left("", *)      = ""
5031     * StringUtils.left("abc", 0)   = ""
5032     * StringUtils.left("abc", 2)   = "ab"
5033     * StringUtils.left("abc", 4)   = "abc"
5034     * </pre>
5035     *
5036     * @param str  the String to get the leftmost characters from, may be null
5037     * @param len  the length of the required String
5038     * @return the leftmost characters, {@code null} if null String input
5039     */
5040    public static String left(final String str, final int len) {
5041        if (str == null) {
5042            return null;
5043        }
5044        if (len < 0) {
5045            return EMPTY;
5046        }
5047        if (str.length() <= len) {
5048            return str;
5049        }
5050        return str.substring(0, len);
5051    }
5052
5053    /**
5054     * Left pad a String with spaces (' ').
5055     *
5056     * <p>The String is padded to the size of {@code size}.</p>
5057     *
5058     * <pre>
5059     * StringUtils.leftPad(null, *)   = null
5060     * StringUtils.leftPad("", 3)     = "   "
5061     * StringUtils.leftPad("bat", 3)  = "bat"
5062     * StringUtils.leftPad("bat", 5)  = "  bat"
5063     * StringUtils.leftPad("bat", 1)  = "bat"
5064     * StringUtils.leftPad("bat", -1) = "bat"
5065     * </pre>
5066     *
5067     * @param str  the String to pad out, may be null
5068     * @param size  the size to pad to
5069     * @return left padded String or original String if no padding is necessary,
5070     *  {@code null} if null String input
5071     */
5072    public static String leftPad(final String str, final int size) {
5073        return leftPad(str, size, ' ');
5074    }
5075
5076    /**
5077     * Left pad a String with a specified character.
5078     *
5079     * <p>Pad to a size of {@code size}.</p>
5080     *
5081     * <pre>
5082     * StringUtils.leftPad(null, *, *)     = null
5083     * StringUtils.leftPad("", 3, 'z')     = "zzz"
5084     * StringUtils.leftPad("bat", 3, 'z')  = "bat"
5085     * StringUtils.leftPad("bat", 5, 'z')  = "zzbat"
5086     * StringUtils.leftPad("bat", 1, 'z')  = "bat"
5087     * StringUtils.leftPad("bat", -1, 'z') = "bat"
5088     * </pre>
5089     *
5090     * @param str  the String to pad out, may be null
5091     * @param size  the size to pad to
5092     * @param padChar  the character to pad with
5093     * @return left padded String or original String if no padding is necessary,
5094     *  {@code null} if null String input
5095     * @since 2.0
5096     */
5097    public static String leftPad(final String str, final int size, final char padChar) {
5098        if (str == null) {
5099            return null;
5100        }
5101        final int pads = size - str.length();
5102        if (pads <= 0) {
5103            return str; // returns original String when possible
5104        }
5105        if (pads > PAD_LIMIT) {
5106            return leftPad(str, size, String.valueOf(padChar));
5107        }
5108        return repeat(padChar, pads).concat(str);
5109    }
5110
5111    /**
5112     * Left pad a String with a specified String.
5113     *
5114     * <p>Pad to a size of {@code size}.</p>
5115     *
5116     * <pre>
5117     * StringUtils.leftPad(null, *, *)      = null
5118     * StringUtils.leftPad("", 3, "z")      = "zzz"
5119     * StringUtils.leftPad("bat", 3, "yz")  = "bat"
5120     * StringUtils.leftPad("bat", 5, "yz")  = "yzbat"
5121     * StringUtils.leftPad("bat", 8, "yz")  = "yzyzybat"
5122     * StringUtils.leftPad("bat", 1, "yz")  = "bat"
5123     * StringUtils.leftPad("bat", -1, "yz") = "bat"
5124     * StringUtils.leftPad("bat", 5, null)  = "  bat"
5125     * StringUtils.leftPad("bat", 5, "")    = "  bat"
5126     * </pre>
5127     *
5128     * @param str  the String to pad out, may be null
5129     * @param size  the size to pad to
5130     * @param padStr  the String to pad with, null or empty treated as single space
5131     * @return left padded String or original String if no padding is necessary,
5132     *  {@code null} if null String input
5133     */
5134    public static String leftPad(final String str, final int size, String padStr) {
5135        if (str == null) {
5136            return null;
5137        }
5138        if (isEmpty(padStr)) {
5139            padStr = SPACE;
5140        }
5141        final int padLen = padStr.length();
5142        final int strLen = str.length();
5143        final int pads = size - strLen;
5144        if (pads <= 0) {
5145            return str; // returns original String when possible
5146        }
5147        if (padLen == 1 && pads <= PAD_LIMIT) {
5148            return leftPad(str, size, padStr.charAt(0));
5149        }
5150
5151        if (pads == padLen) {
5152            return padStr.concat(str);
5153        }
5154        if (pads < padLen) {
5155            return padStr.substring(0, pads).concat(str);
5156        }
5157        final char[] padding = new char[pads];
5158        final char[] padChars = padStr.toCharArray();
5159        for (int i = 0; i < pads; i++) {
5160            padding[i] = padChars[i % padLen];
5161        }
5162        return new String(padding).concat(str);
5163    }
5164
5165    /**
5166     * Gets a CharSequence length or {@code 0} if the CharSequence is
5167     * {@code null}.
5168     *
5169     * @param cs
5170     *            a CharSequence or {@code null}
5171     * @return CharSequence length or {@code 0} if the CharSequence is
5172     *         {@code null}.
5173     * @since 2.4
5174     * @since 3.0 Changed signature from length(String) to length(CharSequence)
5175     */
5176    public static int length(final CharSequence cs) {
5177        return cs == null ? 0 : cs.length();
5178    }
5179
5180    /**
5181     * Converts a String to lower case as per {@link String#toLowerCase()}.
5182     *
5183     * <p>A {@code null} input String returns {@code null}.</p>
5184     *
5185     * <pre>
5186     * StringUtils.lowerCase(null)  = null
5187     * StringUtils.lowerCase("")    = ""
5188     * StringUtils.lowerCase("aBc") = "abc"
5189     * </pre>
5190     *
5191     * <p><strong>Note:</strong> As described in the documentation for {@link String#toLowerCase()},
5192     * the result of this method is affected by the current locale.
5193     * For platform-independent case transformations, the method {@link #lowerCase(String, Locale)}
5194     * should be used with a specific locale (e.g. {@link Locale#ENGLISH}).</p>
5195     *
5196     * @param str  the String to lower case, may be null
5197     * @return the lower cased String, {@code null} if null String input
5198     */
5199    public static String lowerCase(final String str) {
5200        if (str == null) {
5201            return null;
5202        }
5203        return str.toLowerCase();
5204    }
5205
5206    /**
5207     * Converts a String to lower case as per {@link String#toLowerCase(Locale)}.
5208     *
5209     * <p>A {@code null} input String returns {@code null}.</p>
5210     *
5211     * <pre>
5212     * StringUtils.lowerCase(null, Locale.ENGLISH)  = null
5213     * StringUtils.lowerCase("", Locale.ENGLISH)    = ""
5214     * StringUtils.lowerCase("aBc", Locale.ENGLISH) = "abc"
5215     * </pre>
5216     *
5217     * @param str  the String to lower case, may be null
5218     * @param locale  the locale that defines the case transformation rules, must not be null
5219     * @return the lower cased String, {@code null} if null String input
5220     * @since 2.5
5221     */
5222    public static String lowerCase(final String str, final Locale locale) {
5223        if (str == null) {
5224            return null;
5225        }
5226        return str.toLowerCase(LocaleUtils.toLocale(locale));
5227    }
5228
5229    private static int[] matches(final CharSequence first, final CharSequence second) {
5230        final CharSequence max;
5231        final CharSequence min;
5232        if (first.length() > second.length()) {
5233            max = first;
5234            min = second;
5235        } else {
5236            max = second;
5237            min = first;
5238        }
5239        final int range = Math.max(max.length() / 2 - 1, 0);
5240        final int[] matchIndexes = ArrayFill.fill(new int[min.length()], -1);
5241        final boolean[] matchFlags = new boolean[max.length()];
5242        int matches = 0;
5243        for (int mi = 0; mi < min.length(); mi++) {
5244            final char c1 = min.charAt(mi);
5245            for (int xi = Math.max(mi - range, 0), xn = Math.min(mi + range + 1, max.length()); xi < xn; xi++) {
5246                if (!matchFlags[xi] && c1 == max.charAt(xi)) {
5247                    matchIndexes[mi] = xi;
5248                    matchFlags[xi] = true;
5249                    matches++;
5250                    break;
5251                }
5252            }
5253        }
5254        final char[] ms1 = new char[matches];
5255        final char[] ms2 = new char[matches];
5256        for (int i = 0, si = 0; i < min.length(); i++) {
5257            if (matchIndexes[i] != -1) {
5258                ms1[si] = min.charAt(i);
5259                si++;
5260            }
5261        }
5262        for (int i = 0, si = 0; i < max.length(); i++) {
5263            if (matchFlags[i]) {
5264                ms2[si] = max.charAt(i);
5265                si++;
5266            }
5267        }
5268        int transpositions = 0;
5269        for (int mi = 0; mi < ms1.length; mi++) {
5270            if (ms1[mi] != ms2[mi]) {
5271                transpositions++;
5272            }
5273        }
5274        int prefix = 0;
5275        for (int mi = 0; mi < min.length(); mi++) {
5276            if (first.charAt(mi) != second.charAt(mi)) {
5277                break;
5278            }
5279            prefix++;
5280        }
5281        return new int[] { matches, transpositions / 2, prefix, max.length() };
5282    }
5283
5284    /**
5285     * Gets {@code len} characters from the middle of a String.
5286     *
5287     * <p>If {@code len} characters are not available, the remainder
5288     * of the String will be returned without an exception. If the
5289     * String is {@code null}, {@code null} will be returned.
5290     * An empty String is returned if len is negative or exceeds the
5291     * length of {@code str}.</p>
5292     *
5293     * <pre>
5294     * StringUtils.mid(null, *, *)    = null
5295     * StringUtils.mid(*, *, -ve)     = ""
5296     * StringUtils.mid("", 0, *)      = ""
5297     * StringUtils.mid("abc", 0, 2)   = "ab"
5298     * StringUtils.mid("abc", 0, 4)   = "abc"
5299     * StringUtils.mid("abc", 2, 4)   = "c"
5300     * StringUtils.mid("abc", 4, 2)   = ""
5301     * StringUtils.mid("abc", -2, 2)  = "ab"
5302     * </pre>
5303     *
5304     * @param str  the String to get the characters from, may be null
5305     * @param pos  the position to start from, negative treated as zero
5306     * @param len  the length of the required String
5307     * @return the middle characters, {@code null} if null String input
5308     */
5309    public static String mid(final String str, int pos, final int len) {
5310        if (str == null) {
5311            return null;
5312        }
5313        if (len < 0 || pos > str.length()) {
5314            return EMPTY;
5315        }
5316        if (pos < 0) {
5317            pos = 0;
5318        }
5319        if (str.length() <= pos + len) {
5320            return str.substring(pos);
5321        }
5322        return str.substring(pos, pos + len);
5323    }
5324
5325    /**
5326     * Similar to <a
5327     * href="https://www.w3.org/TR/xpath/#function-normalize-space">https://www.w3.org/TR/xpath/#function-normalize
5328     * -space</a>
5329     *
5330     * <p>
5331     * The function returns the argument string with whitespace normalized by using
5332     * {@code {@link #trim(String)}} to remove leading and trailing whitespace
5333     * and then replacing sequences of whitespace characters by a single space.
5334     * </p>
5335     * In XML Whitespace characters are the same as those allowed by the <a
5336     * href="https://www.w3.org/TR/REC-xml/#NT-S">S</a> production, which is S ::= (#x20 | #x9 | #xD | #xA)+
5337     * <p>
5338     * Java's regexp pattern \s defines whitespace as [ \t\n\x0B\f\r]
5339     *
5340     * <p>For reference:</p>
5341     * <ul>
5342     * <li>\x0B = vertical tab</li>
5343     * <li>\f = #xC = form feed</li>
5344     * <li>#x20 = space</li>
5345     * <li>#x9 = \t</li>
5346     * <li>#xA = \n</li>
5347     * <li>#xD = \r</li>
5348     * </ul>
5349     *
5350     * <p>
5351     * The difference is that Java's whitespace includes vertical tab and form feed, which this functional will also
5352     * normalize. Additionally {@code {@link #trim(String)}} removes control characters (char &lt;= 32) from both
5353     * ends of this String.
5354     * </p>
5355     *
5356     * @see Pattern
5357     * @see #trim(String)
5358     * @see <a
5359     *      href="https://www.w3.org/TR/xpath/#function-normalize-space">https://www.w3.org/TR/xpath/#function-normalize-space</a>
5360     * @param str the source String to normalize whitespaces from, may be null
5361     * @return the modified string with whitespace normalized, {@code null} if null String input
5362     * @since 3.0
5363     */
5364    public static String normalizeSpace(final String str) {
5365        // LANG-1020: Improved performance significantly by normalizing manually instead of using regex
5366        // See https://github.com/librucha/commons-lang-normalizespaces-benchmark for performance test
5367        if (isEmpty(str)) {
5368            return str;
5369        }
5370        final int size = str.length();
5371        final char[] newChars = new char[size];
5372        int count = 0;
5373        int whitespacesCount = 0;
5374        boolean startWhitespaces = true;
5375        for (int i = 0; i < size; i++) {
5376            final char actualChar = str.charAt(i);
5377            final boolean isWhitespace = Character.isWhitespace(actualChar);
5378            if (isWhitespace) {
5379                if (whitespacesCount == 0 && !startWhitespaces) {
5380                    newChars[count++] = SPACE.charAt(0);
5381                }
5382                whitespacesCount++;
5383            } else {
5384                startWhitespaces = false;
5385                newChars[count++] = actualChar == 160 ? 32 : actualChar;
5386                whitespacesCount = 0;
5387            }
5388        }
5389        if (startWhitespaces) {
5390            return EMPTY;
5391        }
5392        return new String(newChars, 0, count - (whitespacesCount > 0 ? 1 : 0)).trim();
5393    }
5394
5395    /**
5396     * Finds the n-th index within a CharSequence, handling {@code null}.
5397     * This method uses {@link String#indexOf(String)} if possible.
5398     * <p><strong>Note:</strong> The code starts looking for a match at the start of the target,
5399     * incrementing the starting index by one after each successful match
5400     * (unless {@code searchStr} is an empty string in which case the position
5401     * is never incremented and {@code 0} is returned immediately).
5402     * This means that matches may overlap.</p>
5403     * <p>A {@code null} CharSequence will return {@code -1}.</p>
5404     *
5405     * <pre>
5406     * StringUtils.ordinalIndexOf(null, *, *)          = -1
5407     * StringUtils.ordinalIndexOf(*, null, *)          = -1
5408     * StringUtils.ordinalIndexOf("", "", *)           = 0
5409     * StringUtils.ordinalIndexOf("aabaabaa", "a", 1)  = 0
5410     * StringUtils.ordinalIndexOf("aabaabaa", "a", 2)  = 1
5411     * StringUtils.ordinalIndexOf("aabaabaa", "b", 1)  = 2
5412     * StringUtils.ordinalIndexOf("aabaabaa", "b", 2)  = 5
5413     * StringUtils.ordinalIndexOf("aabaabaa", "ab", 1) = 1
5414     * StringUtils.ordinalIndexOf("aabaabaa", "ab", 2) = 4
5415     * StringUtils.ordinalIndexOf("aabaabaa", "", 1)   = 0
5416     * StringUtils.ordinalIndexOf("aabaabaa", "", 2)   = 0
5417     * </pre>
5418     *
5419     * <p>Matches may overlap:</p>
5420     * <pre>
5421     * StringUtils.ordinalIndexOf("ababab", "aba", 1)   = 0
5422     * StringUtils.ordinalIndexOf("ababab", "aba", 2)   = 2
5423     * StringUtils.ordinalIndexOf("ababab", "aba", 3)   = -1
5424     *
5425     * StringUtils.ordinalIndexOf("abababab", "abab", 1) = 0
5426     * StringUtils.ordinalIndexOf("abababab", "abab", 2) = 2
5427     * StringUtils.ordinalIndexOf("abababab", "abab", 3) = 4
5428     * StringUtils.ordinalIndexOf("abababab", "abab", 4) = -1
5429     * </pre>
5430     *
5431     * <p>Note that 'head(CharSequence str, int n)' may be implemented as: </p>
5432     *
5433     * <pre>
5434     *   str.substring(0, lastOrdinalIndexOf(str, "\n", n))
5435     * </pre>
5436     *
5437     * @param str  the CharSequence to check, may be null
5438     * @param searchStr  the CharSequence to find, may be null
5439     * @param ordinal  the n-th {@code searchStr} to find
5440     * @return the n-th index of the search CharSequence,
5441     *  {@code -1} ({@code INDEX_NOT_FOUND}) if no match or {@code null} string input
5442     * @since 2.1
5443     * @since 3.0 Changed signature from ordinalIndexOf(String, String, int) to ordinalIndexOf(CharSequence, CharSequence, int)
5444     */
5445    public static int ordinalIndexOf(final CharSequence str, final CharSequence searchStr, final int ordinal) {
5446        return ordinalIndexOf(str, searchStr, ordinal, false);
5447    }
5448
5449    /**
5450     * Finds the n-th index within a String, handling {@code null}.
5451     * This method uses {@link String#indexOf(String)} if possible.
5452     * <p>Note that matches may overlap<p>
5453     *
5454     * <p>A {@code null} CharSequence will return {@code -1}.</p>
5455     *
5456     * @param str  the CharSequence to check, may be null
5457     * @param searchStr  the CharSequence to find, may be null
5458     * @param ordinal  the n-th {@code searchStr} to find, overlapping matches are allowed.
5459     * @param lastIndex true if lastOrdinalIndexOf() otherwise false if ordinalIndexOf()
5460     * @return the n-th index of the search CharSequence,
5461     *  {@code -1} ({@code INDEX_NOT_FOUND}) if no match or {@code null} string input
5462     */
5463    // Shared code between ordinalIndexOf(String, String, int) and lastOrdinalIndexOf(String, String, int)
5464    private static int ordinalIndexOf(final CharSequence str, final CharSequence searchStr, final int ordinal, final boolean lastIndex) {
5465        if (str == null || searchStr == null || ordinal <= 0) {
5466            return INDEX_NOT_FOUND;
5467        }
5468        if (searchStr.length() == 0) {
5469            return lastIndex ? str.length() : 0;
5470        }
5471        int found = 0;
5472        // set the initial index beyond the end of the string
5473        // this is to allow for the initial index decrement/increment
5474        int index = lastIndex ? str.length() : INDEX_NOT_FOUND;
5475        do {
5476            if (lastIndex) {
5477                index = CharSequenceUtils.lastIndexOf(str, searchStr, index - 1); // step backwards through string
5478            } else {
5479                index = CharSequenceUtils.indexOf(str, searchStr, index + 1); // step forwards through string
5480            }
5481            if (index < 0) {
5482                return index;
5483            }
5484            found++;
5485        } while (found < ordinal);
5486        return index;
5487    }
5488
5489    /**
5490     * Overlays part of a String with another String.
5491     *
5492     * <p>A {@code null} string input returns {@code null}.
5493     * A negative index is treated as zero.
5494     * An index greater than the string length is treated as the string length.
5495     * The start index is always the smaller of the two indices.</p>
5496     *
5497     * <pre>
5498     * StringUtils.overlay(null, *, *, *)            = null
5499     * StringUtils.overlay("", "abc", 0, 0)          = "abc"
5500     * StringUtils.overlay("abcdef", null, 2, 4)     = "abef"
5501     * StringUtils.overlay("abcdef", "", 2, 4)       = "abef"
5502     * StringUtils.overlay("abcdef", "", 4, 2)       = "abef"
5503     * StringUtils.overlay("abcdef", "zzzz", 2, 4)   = "abzzzzef"
5504     * StringUtils.overlay("abcdef", "zzzz", 4, 2)   = "abzzzzef"
5505     * StringUtils.overlay("abcdef", "zzzz", -1, 4)  = "zzzzef"
5506     * StringUtils.overlay("abcdef", "zzzz", 2, 8)   = "abzzzz"
5507     * StringUtils.overlay("abcdef", "zzzz", -2, -3) = "zzzzabcdef"
5508     * StringUtils.overlay("abcdef", "zzzz", 8, 10)  = "abcdefzzzz"
5509     * </pre>
5510     *
5511     * @param str  the String to do overlaying in, may be null
5512     * @param overlay  the String to overlay, may be null
5513     * @param start  the position to start overlaying at
5514     * @param end  the position to stop overlaying before
5515     * @return overlayed String, {@code null} if null String input
5516     * @since 2.0
5517     */
5518    public static String overlay(final String str, String overlay, int start, int end) {
5519        if (str == null) {
5520            return null;
5521        }
5522        if (overlay == null) {
5523            overlay = EMPTY;
5524        }
5525        final int len = str.length();
5526        if (start < 0) {
5527            start = 0;
5528        }
5529        if (start > len) {
5530            start = len;
5531        }
5532        if (end < 0) {
5533            end = 0;
5534        }
5535        if (end > len) {
5536            end = len;
5537        }
5538        if (start > end) {
5539            final int temp = start;
5540            start = end;
5541            end = temp;
5542        }
5543        return str.substring(0, start) +
5544            overlay +
5545            str.substring(end);
5546    }
5547
5548    /**
5549     * Prepends the prefix to the start of the string if the string does not already start with any of the prefixes.
5550     *
5551     * <pre>
5552     * StringUtils.prependIfMissing(null, null) = null
5553     * StringUtils.prependIfMissing("abc", null) = "abc"
5554     * StringUtils.prependIfMissing("", "xyz") = "xyz"
5555     * StringUtils.prependIfMissing("abc", "xyz") = "xyzabc"
5556     * StringUtils.prependIfMissing("xyzabc", "xyz") = "xyzabc"
5557     * StringUtils.prependIfMissing("XYZabc", "xyz") = "xyzXYZabc"
5558     * </pre>
5559     * <p>
5560     * With additional prefixes,
5561     * </p>
5562     *
5563     * <pre>
5564     * StringUtils.prependIfMissing(null, null, null) = null
5565     * StringUtils.prependIfMissing("abc", null, null) = "abc"
5566     * StringUtils.prependIfMissing("", "xyz", null) = "xyz"
5567     * StringUtils.prependIfMissing("abc", "xyz", new CharSequence[]{null}) = "xyzabc"
5568     * StringUtils.prependIfMissing("abc", "xyz", "") = "abc"
5569     * StringUtils.prependIfMissing("abc", "xyz", "mno") = "xyzabc"
5570     * StringUtils.prependIfMissing("xyzabc", "xyz", "mno") = "xyzabc"
5571     * StringUtils.prependIfMissing("mnoabc", "xyz", "mno") = "mnoabc"
5572     * StringUtils.prependIfMissing("XYZabc", "xyz", "mno") = "xyzXYZabc"
5573     * StringUtils.prependIfMissing("MNOabc", "xyz", "mno") = "xyzMNOabc"
5574     * </pre>
5575     *
5576     * @param str      The string.
5577     * @param prefix   The prefix to prepend to the start of the string.
5578     * @param prefixes Additional prefixes that are valid.
5579     * @return A new String if prefix was prepended, the same string otherwise.
5580     * @since 3.2
5581     * @deprecated Use {@link Strings#prependIfMissing(String, CharSequence, CharSequence...) Strings.CS.prependIfMissing(String, CharSequence,
5582     *             CharSequence...)}
5583     */
5584    @Deprecated
5585    public static String prependIfMissing(final String str, final CharSequence prefix, final CharSequence... prefixes) {
5586        return Strings.CS.prependIfMissing(str, prefix, prefixes);
5587    }
5588
5589    /**
5590     * Prepends the prefix to the start of the string if the string does not
5591     * already start, case-insensitive, with any of the prefixes.
5592     *
5593     * <pre>
5594     * StringUtils.prependIfMissingIgnoreCase(null, null) = null
5595     * StringUtils.prependIfMissingIgnoreCase("abc", null) = "abc"
5596     * StringUtils.prependIfMissingIgnoreCase("", "xyz") = "xyz"
5597     * StringUtils.prependIfMissingIgnoreCase("abc", "xyz") = "xyzabc"
5598     * StringUtils.prependIfMissingIgnoreCase("xyzabc", "xyz") = "xyzabc"
5599     * StringUtils.prependIfMissingIgnoreCase("XYZabc", "xyz") = "XYZabc"
5600     * </pre>
5601     * <p>With additional prefixes,</p>
5602     * <pre>
5603     * StringUtils.prependIfMissingIgnoreCase(null, null, null) = null
5604     * StringUtils.prependIfMissingIgnoreCase("abc", null, null) = "abc"
5605     * StringUtils.prependIfMissingIgnoreCase("", "xyz", null) = "xyz"
5606     * StringUtils.prependIfMissingIgnoreCase("abc", "xyz", new CharSequence[]{null}) = "xyzabc"
5607     * StringUtils.prependIfMissingIgnoreCase("abc", "xyz", "") = "abc"
5608     * StringUtils.prependIfMissingIgnoreCase("abc", "xyz", "mno") = "xyzabc"
5609     * StringUtils.prependIfMissingIgnoreCase("xyzabc", "xyz", "mno") = "xyzabc"
5610     * StringUtils.prependIfMissingIgnoreCase("mnoabc", "xyz", "mno") = "mnoabc"
5611     * StringUtils.prependIfMissingIgnoreCase("XYZabc", "xyz", "mno") = "XYZabc"
5612     * StringUtils.prependIfMissingIgnoreCase("MNOabc", "xyz", "mno") = "MNOabc"
5613     * </pre>
5614     *
5615     * @param str The string.
5616     * @param prefix The prefix to prepend to the start of the string.
5617     * @param prefixes Additional prefixes that are valid (optional).
5618     * @return A new String if prefix was prepended, the same string otherwise.
5619     * @since 3.2
5620     * @deprecated Use {@link Strings#prependIfMissing(String, CharSequence, CharSequence...) Strings.CI.prependIfMissing(String, CharSequence,
5621     *             CharSequence...)}
5622     */
5623    @Deprecated
5624    public static String prependIfMissingIgnoreCase(final String str, final CharSequence prefix, final CharSequence... prefixes) {
5625        return Strings.CI.prependIfMissing(str, prefix, prefixes);
5626    }
5627
5628    /**
5629     * Removes all occurrences of a character from within the source string.
5630     *
5631     * <p>A {@code null} source string will return {@code null}.
5632     * An empty ("") source string will return the empty string.</p>
5633     *
5634     * <pre>
5635     * StringUtils.remove(null, *)       = null
5636     * StringUtils.remove("", *)         = ""
5637     * StringUtils.remove("queued", 'u') = "qeed"
5638     * StringUtils.remove("queued", 'z') = "queued"
5639     * </pre>
5640     *
5641     * @param str  the source String to search, may be null
5642     * @param remove  the char to search for and remove, may be null
5643     * @return the substring with the char removed if found,
5644     *  {@code null} if null String input
5645     * @since 2.1
5646     */
5647    public static String remove(final String str, final char remove) {
5648        if (isEmpty(str) || str.indexOf(remove) == INDEX_NOT_FOUND) {
5649            return str;
5650        }
5651        final char[] chars = str.toCharArray();
5652        int pos = 0;
5653        for (int i = 0; i < chars.length; i++) {
5654            if (chars[i] != remove) {
5655                chars[pos++] = chars[i];
5656            }
5657        }
5658        return new String(chars, 0, pos);
5659    }
5660
5661    /**
5662     * Removes all occurrences of a substring from within the source string.
5663     *
5664     * <p>A {@code null} source string will return {@code null}.
5665     * An empty ("") source string will return the empty string.
5666     * A {@code null} remove string will return the source string.
5667     * An empty ("") remove string will return the source string.</p>
5668     *
5669     * <pre>
5670     * StringUtils.remove(null, *)        = null
5671     * StringUtils.remove("", *)          = ""
5672     * StringUtils.remove(*, null)        = *
5673     * StringUtils.remove(*, "")          = *
5674     * StringUtils.remove("queued", "ue") = "qd"
5675     * StringUtils.remove("queued", "zz") = "queued"
5676     * </pre>
5677     *
5678     * @param str  the source String to search, may be null
5679     * @param remove  the String to search for and remove, may be null
5680     * @return the substring with the string removed if found,
5681     *  {@code null} if null String input
5682     * @since 2.1
5683     * @deprecated Use {@link Strings#remove(String, String) Strings.CS.remove(String, String)}
5684     */
5685    @Deprecated
5686    public static String remove(final String str, final String remove) {
5687        return Strings.CS.remove(str, remove);
5688    }
5689
5690    /**
5691     * Removes each substring of the text String that matches the given regular expression.
5692     *
5693     * This method is a {@code null} safe equivalent to:
5694     * <ul>
5695     *  <li>{@code text.replaceAll(regex, StringUtils.EMPTY)}</li>
5696     *  <li>{@code Pattern.compile(regex).matcher(text).replaceAll(StringUtils.EMPTY)}</li>
5697     * </ul>
5698     *
5699     * <p>A {@code null} reference passed to this method is a no-op.</p>
5700     *
5701     * <p>Unlike in the {@link #removePattern(String, String)} method, the {@link Pattern#DOTALL} option
5702     * is NOT automatically added.
5703     * To use the DOTALL option prepend {@code "(?s)"} to the regex.
5704     * DOTALL is also known as single-line mode in Perl.</p>
5705     *
5706     * <pre>{@code
5707     * StringUtils.removeAll(null, *)      = null
5708     * StringUtils.removeAll("any", (String) null)  = "any"
5709     * StringUtils.removeAll("any", "")    = "any"
5710     * StringUtils.removeAll("any", ".*")  = ""
5711     * StringUtils.removeAll("any", ".+")  = ""
5712     * StringUtils.removeAll("abc", ".?")  = ""
5713     * StringUtils.removeAll("A<__>\n<__>B", "<.*>")      = "A\nB"
5714     * StringUtils.removeAll("A<__>\n<__>B", "(?s)<.*>")  = "AB"
5715     * StringUtils.removeAll("ABCabc123abc", "[a-z]")     = "ABC123"
5716     * }</pre>
5717     *
5718     * @param text  text to remove from, may be null
5719     * @param regex  the regular expression to which this string is to be matched
5720     * @return  the text with any removes processed,
5721     *              {@code null} if null String input
5722     *
5723     * @throws  java.util.regex.PatternSyntaxException
5724     *              if the regular expression's syntax is invalid
5725     *
5726     * @see #replaceAll(String, String, String)
5727     * @see #removePattern(String, String)
5728     * @see String#replaceAll(String, String)
5729     * @see java.util.regex.Pattern
5730     * @see java.util.regex.Pattern#DOTALL
5731     * @since 3.5
5732     * @deprecated Moved to RegExUtils.
5733     */
5734    @Deprecated
5735    public static String removeAll(final String text, final String regex) {
5736        return RegExUtils.removeAll(text, regex);
5737    }
5738
5739    /**
5740     * Removes a substring only if it is at the end of a source string,
5741     * otherwise returns the source string.
5742     *
5743     * <p>A {@code null} source string will return {@code null}.
5744     * An empty ("") source string will return the empty string.
5745     * A {@code null} search string will return the source string.</p>
5746     *
5747     * <pre>
5748     * StringUtils.removeEnd(null, *)      = null
5749     * StringUtils.removeEnd("", *)        = ""
5750     * StringUtils.removeEnd(*, null)      = *
5751     * StringUtils.removeEnd("www.domain.com", ".com.")  = "www.domain.com"
5752     * StringUtils.removeEnd("www.domain.com", ".com")   = "www.domain"
5753     * StringUtils.removeEnd("www.domain.com", "domain") = "www.domain.com"
5754     * StringUtils.removeEnd("abc", "")    = "abc"
5755     * </pre>
5756     *
5757     * @param str  the source String to search, may be null
5758     * @param remove  the String to search for and remove, may be null
5759     * @return the substring with the string removed if found,
5760     *  {@code null} if null String input
5761     * @since 2.1
5762     * @deprecated Use {@link Strings#removeEnd(String, CharSequence) Strings.CS.removeEnd(String, CharSequence)}
5763     */
5764    @Deprecated
5765    public static String removeEnd(final String str, final String remove) {
5766        return Strings.CS.removeEnd(str, remove);
5767    }
5768
5769    /**
5770     * Case-insensitive removal of a substring if it is at the end of a source string,
5771     * otherwise returns the source string.
5772     *
5773     * <p>A {@code null} source string will return {@code null}.
5774     * An empty ("") source string will return the empty string.
5775     * A {@code null} search string will return the source string.</p>
5776     *
5777     * <pre>
5778     * StringUtils.removeEndIgnoreCase(null, *)      = null
5779     * StringUtils.removeEndIgnoreCase("", *)        = ""
5780     * StringUtils.removeEndIgnoreCase(*, null)      = *
5781     * StringUtils.removeEndIgnoreCase("www.domain.com", ".com.")  = "www.domain.com"
5782     * StringUtils.removeEndIgnoreCase("www.domain.com", ".com")   = "www.domain"
5783     * StringUtils.removeEndIgnoreCase("www.domain.com", "domain") = "www.domain.com"
5784     * StringUtils.removeEndIgnoreCase("abc", "")    = "abc"
5785     * StringUtils.removeEndIgnoreCase("www.domain.com", ".COM") = "www.domain")
5786     * StringUtils.removeEndIgnoreCase("www.domain.COM", ".com") = "www.domain")
5787     * </pre>
5788     *
5789     * @param str  the source String to search, may be null
5790     * @param remove  the String to search for (case-insensitive) and remove, may be null
5791     * @return the substring with the string removed if found,
5792     *  {@code null} if null String input
5793     * @since 2.4
5794     * @deprecated Use {@link Strings#removeEnd(String, CharSequence) Strings.CI.removeEnd(String, CharSequence)}
5795     */
5796    @Deprecated
5797    public static String removeEndIgnoreCase(final String str, final String remove) {
5798        return Strings.CI.removeEnd(str, remove);
5799    }
5800
5801    /**
5802     * Removes the first substring of the text string that matches the given regular expression.
5803     *
5804     * This method is a {@code null} safe equivalent to:
5805     * <ul>
5806     *  <li>{@code text.replaceFirst(regex, StringUtils.EMPTY)}</li>
5807     *  <li>{@code Pattern.compile(regex).matcher(text).replaceFirst(StringUtils.EMPTY)}</li>
5808     * </ul>
5809     *
5810     * <p>A {@code null} reference passed to this method is a no-op.</p>
5811     *
5812     * <p>The {@link Pattern#DOTALL} option is NOT automatically added.
5813     * To use the DOTALL option prepend {@code "(?s)"} to the regex.
5814     * DOTALL is also known as single-line mode in Perl.</p>
5815     *
5816     * <pre>{@code
5817     * StringUtils.removeFirst(null, *)      = null
5818     * StringUtils.removeFirst("any", (String) null)  = "any"
5819     * StringUtils.removeFirst("any", "")    = "any"
5820     * StringUtils.removeFirst("any", ".*")  = ""
5821     * StringUtils.removeFirst("any", ".+")  = ""
5822     * StringUtils.removeFirst("abc", ".?")  = "bc"
5823     * StringUtils.removeFirst("A<__>\n<__>B", "<.*>")      = "A\n<__>B"
5824     * StringUtils.removeFirst("A<__>\n<__>B", "(?s)<.*>")  = "AB"
5825     * StringUtils.removeFirst("ABCabc123", "[a-z]")          = "ABCbc123"
5826     * StringUtils.removeFirst("ABCabc123abc", "[a-z]+")      = "ABC123abc"
5827     * }</pre>
5828     *
5829     * @param text  text to remove from, may be null
5830     * @param regex  the regular expression to which this string is to be matched
5831     * @return  the text with the first replacement processed,
5832     *              {@code null} if null String input
5833     *
5834     * @throws  java.util.regex.PatternSyntaxException
5835     *              if the regular expression's syntax is invalid
5836     *
5837     * @see #replaceFirst(String, String, String)
5838     * @see String#replaceFirst(String, String)
5839     * @see java.util.regex.Pattern
5840     * @see java.util.regex.Pattern#DOTALL
5841     * @since 3.5
5842     * @deprecated Moved to RegExUtils.
5843     */
5844    @Deprecated
5845    public static String removeFirst(final String text, final String regex) {
5846        return replaceFirst(text, regex, EMPTY);
5847    }
5848
5849    /**
5850     * Case-insensitive removal of all occurrences of a substring from within
5851     * the source string.
5852     *
5853     * <p>
5854     * A {@code null} source string will return {@code null}. An empty ("")
5855     * source string will return the empty string. A {@code null} remove string
5856     * will return the source string. An empty ("") remove string will return
5857     * the source string.
5858     * </p>
5859     *
5860     * <pre>
5861     * StringUtils.removeIgnoreCase(null, *)        = null
5862     * StringUtils.removeIgnoreCase("", *)          = ""
5863     * StringUtils.removeIgnoreCase(*, null)        = *
5864     * StringUtils.removeIgnoreCase(*, "")          = *
5865     * StringUtils.removeIgnoreCase("queued", "ue") = "qd"
5866     * StringUtils.removeIgnoreCase("queued", "zz") = "queued"
5867     * StringUtils.removeIgnoreCase("quEUed", "UE") = "qd"
5868     * StringUtils.removeIgnoreCase("queued", "zZ") = "queued"
5869     * </pre>
5870     *
5871     * @param str
5872     *            the source String to search, may be null
5873     * @param remove
5874     *            the String to search for (case-insensitive) and remove, may be
5875     *            null
5876     * @return the substring with the string removed if found, {@code null} if
5877     *         null String input
5878     * @since 3.5
5879     * @deprecated Use {@link Strings#remove(String, String) Strings.CI.remove(String, String)}
5880     */
5881    @Deprecated
5882    public static String removeIgnoreCase(final String str, final String remove) {
5883        return Strings.CI.remove(str, remove);
5884    }
5885
5886    /**
5887     * Removes each substring of the source String that matches the given regular expression using the DOTALL option.
5888     *
5889     * This call is a {@code null} safe equivalent to:
5890     * <ul>
5891     * <li>{@code source.replaceAll(&quot;(?s)&quot; + regex, StringUtils.EMPTY)}</li>
5892     * <li>{@code Pattern.compile(regex, Pattern.DOTALL).matcher(source).replaceAll(StringUtils.EMPTY)}</li>
5893     * </ul>
5894     *
5895     * <p>A {@code null} reference passed to this method is a no-op.</p>
5896     *
5897     * <pre>{@code
5898     * StringUtils.removePattern(null, *)       = null
5899     * StringUtils.removePattern("any", (String) null)   = "any"
5900     * StringUtils.removePattern("A<__>\n<__>B", "<.*>")  = "AB"
5901     * StringUtils.removePattern("ABCabc123", "[a-z]")    = "ABC123"
5902     * }</pre>
5903     *
5904     * @param source
5905     *            the source string
5906     * @param regex
5907     *            the regular expression to which this string is to be matched
5908     * @return The resulting {@link String}
5909     * @see #replacePattern(String, String, String)
5910     * @see String#replaceAll(String, String)
5911     * @see Pattern#DOTALL
5912     * @since 3.2
5913     * @since 3.5 Changed {@code null} reference passed to this method is a no-op.
5914     * @deprecated Moved to RegExUtils.
5915     */
5916    @Deprecated
5917    public static String removePattern(final String source, final String regex) {
5918        return RegExUtils.removePattern(source, regex);
5919    }
5920
5921    /**
5922     * Removes a char only if it is at the beginning of a source string,
5923     * otherwise returns the source string.
5924     *
5925     * <p>A {@code null} source string will return {@code null}.
5926     * An empty ("") source string will return the empty string.
5927     * A {@code null} search char will return the source string.</p>
5928     *
5929     * <pre>
5930     * StringUtils.removeStart(null, *)      = null
5931     * StringUtils.removeStart("", *)        = ""
5932     * StringUtils.removeStart(*, null)      = *
5933     * StringUtils.removeStart("/path", '/') = "path"
5934     * StringUtils.removeStart("path", '/')  = "path"
5935     * StringUtils.removeStart("path", 0)    = "path"
5936     * </pre>
5937     *
5938     * @param str  the source String to search, may be null.
5939     * @param remove  the char to search for and remove.
5940     * @return the substring with the char removed if found,
5941     *  {@code null} if null String input.
5942     * @since 3.13.0
5943     */
5944    public static String removeStart(final String str, final char remove) {
5945        if (isEmpty(str)) {
5946            return str;
5947        }
5948        return str.charAt(0) == remove ? str.substring(1) : str;
5949    }
5950
5951    /**
5952     * Removes a substring only if it is at the beginning of a source string,
5953     * otherwise returns the source string.
5954     *
5955     * <p>A {@code null} source string will return {@code null}.
5956     * An empty ("") source string will return the empty string.
5957     * A {@code null} search string will return the source string.</p>
5958     *
5959     * <pre>
5960     * StringUtils.removeStart(null, *)      = null
5961     * StringUtils.removeStart("", *)        = ""
5962     * StringUtils.removeStart(*, null)      = *
5963     * StringUtils.removeStart("www.domain.com", "www.")   = "domain.com"
5964     * StringUtils.removeStart("domain.com", "www.")       = "domain.com"
5965     * StringUtils.removeStart("www.domain.com", "domain") = "www.domain.com"
5966     * StringUtils.removeStart("abc", "")    = "abc"
5967     * </pre>
5968     *
5969     * @param str  the source String to search, may be null
5970     * @param remove  the String to search for and remove, may be null
5971     * @return the substring with the string removed if found,
5972     *  {@code null} if null String input
5973     * @since 2.1
5974     * @deprecated Use {@link Strings#removeStart(String, CharSequence) Strings.CS.removeStart(String, CharSequence)}
5975     */
5976    @Deprecated
5977    public static String removeStart(final String str, final String remove) {
5978        return Strings.CS.removeStart(str, remove);
5979    }
5980
5981    /**
5982     * Case-insensitive removal of a substring if it is at the beginning of a source string,
5983     * otherwise returns the source string.
5984     *
5985     * <p>A {@code null} source string will return {@code null}.
5986     * An empty ("") source string will return the empty string.
5987     * A {@code null} search string will return the source string.</p>
5988     *
5989     * <pre>
5990     * StringUtils.removeStartIgnoreCase(null, *)      = null
5991     * StringUtils.removeStartIgnoreCase("", *)        = ""
5992     * StringUtils.removeStartIgnoreCase(*, null)      = *
5993     * StringUtils.removeStartIgnoreCase("www.domain.com", "www.")   = "domain.com"
5994     * StringUtils.removeStartIgnoreCase("www.domain.com", "WWW.")   = "domain.com"
5995     * StringUtils.removeStartIgnoreCase("domain.com", "www.")       = "domain.com"
5996     * StringUtils.removeStartIgnoreCase("www.domain.com", "domain") = "www.domain.com"
5997     * StringUtils.removeStartIgnoreCase("abc", "")    = "abc"
5998     * </pre>
5999     *
6000     * @param str  the source String to search, may be null
6001     * @param remove  the String to search for (case-insensitive) and remove, may be null
6002     * @return the substring with the string removed if found,
6003     *  {@code null} if null String input
6004     * @since 2.4
6005     * @deprecated Use {@link Strings#removeStart(String, CharSequence) Strings.CI.removeStart(String, CharSequence)}
6006     */
6007    @Deprecated
6008    public static String removeStartIgnoreCase(final String str, final String remove) {
6009        return Strings.CI.removeStart(str, remove);
6010    }
6011
6012    /**
6013     * Returns padding using the specified delimiter repeated
6014     * to a given length.
6015     *
6016     * <pre>
6017     * StringUtils.repeat('e', 0)  = ""
6018     * StringUtils.repeat('e', 3)  = "eee"
6019     * StringUtils.repeat('e', -2) = ""
6020     * </pre>
6021     *
6022     * <p>Note: this method does not support padding with
6023     * <a href="https://www.unicode.org/glossary/#supplementary_character">Unicode Supplementary Characters</a>
6024     * as they require a pair of {@code char}s to be represented.
6025     * If you are needing to support full I18N of your applications
6026     * consider using {@link #repeat(String, int)} instead.
6027     * </p>
6028     *
6029     * @param repeat  character to repeat
6030     * @param count  number of times to repeat char, negative treated as zero
6031     * @return String with repeated character
6032     * @see #repeat(String, int)
6033     */
6034    public static String repeat(final char repeat, final int count) {
6035        if (count <= 0) {
6036            return EMPTY;
6037        }
6038        return new String(ArrayFill.fill(new char[count], repeat));
6039    }
6040
6041    /**
6042     * Repeats a String {@code repeat} times to form a
6043     * new String.
6044     *
6045     * <pre>
6046     * StringUtils.repeat(null, 2) = null
6047     * StringUtils.repeat("", 0)   = ""
6048     * StringUtils.repeat("", 2)   = ""
6049     * StringUtils.repeat("a", 3)  = "aaa"
6050     * StringUtils.repeat("ab", 2) = "abab"
6051     * StringUtils.repeat("a", -2) = ""
6052     * </pre>
6053     *
6054     * @param repeat  the String to repeat, may be null
6055     * @param count  number of times to repeat str, negative treated as zero
6056     * @return a new String consisting of the original String repeated,
6057     *  {@code null} if null String input
6058     */
6059    public static String repeat(final String repeat, final int count) {
6060        // Performance tuned for 2.0 (JDK1.4)
6061        if (repeat == null) {
6062            return null;
6063        }
6064        if (count <= 0) {
6065            return EMPTY;
6066        }
6067        final int inputLength = repeat.length();
6068        if (count == 1 || inputLength == 0) {
6069            return repeat;
6070        }
6071        if (inputLength == 1 && count <= PAD_LIMIT) {
6072            return repeat(repeat.charAt(0), count);
6073        }
6074
6075        final int outputLength = inputLength * count;
6076        switch (inputLength) {
6077            case 1 :
6078                return repeat(repeat.charAt(0), count);
6079            case 2 :
6080                final char ch0 = repeat.charAt(0);
6081                final char ch1 = repeat.charAt(1);
6082                final char[] output2 = new char[outputLength];
6083                for (int i = count * 2 - 2; i >= 0; i--, i--) {
6084                    output2[i] = ch0;
6085                    output2[i + 1] = ch1;
6086                }
6087                return new String(output2);
6088            default :
6089                final StringBuilder buf = new StringBuilder(outputLength);
6090                for (int i = 0; i < count; i++) {
6091                    buf.append(repeat);
6092                }
6093                return buf.toString();
6094        }
6095    }
6096
6097    /**
6098     * Repeats a String {@code repeat} times to form a
6099     * new String, with a String separator injected each time.
6100     *
6101     * <pre>
6102     * StringUtils.repeat(null, null, 2) = null
6103     * StringUtils.repeat(null, "x", 2)  = null
6104     * StringUtils.repeat("", null, 0)   = ""
6105     * StringUtils.repeat("", "", 2)     = ""
6106     * StringUtils.repeat("", "x", 3)    = "xx"
6107     * StringUtils.repeat("?", ", ", 3)  = "?, ?, ?"
6108     * </pre>
6109     *
6110     * @param repeat        the String to repeat, may be null
6111     * @param separator  the String to inject, may be null
6112     * @param count     number of times to repeat str, negative treated as zero
6113     * @return a new String consisting of the original String repeated,
6114     *  {@code null} if null String input
6115     * @since 2.5
6116     */
6117    public static String repeat(final String repeat, final String separator, final int count) {
6118        if (repeat == null || separator == null) {
6119            return repeat(repeat, count);
6120        }
6121        // given that repeat(String, int) is quite optimized, better to rely on it than try and splice this into it
6122        final String result = repeat(repeat + separator, count);
6123        return Strings.CS.removeEnd(result, separator);
6124    }
6125
6126    /**
6127     * Replaces all occurrences of a String within another String.
6128     *
6129     * <p>A {@code null} reference passed to this method is a no-op.</p>
6130     *
6131     * <pre>
6132     * StringUtils.replace(null, *, *)        = null
6133     * StringUtils.replace("", *, *)          = ""
6134     * StringUtils.replace("any", null, *)    = "any"
6135     * StringUtils.replace("any", *, null)    = "any"
6136     * StringUtils.replace("any", "", *)      = "any"
6137     * StringUtils.replace("aba", "a", null)  = "aba"
6138     * StringUtils.replace("aba", "a", "")    = "b"
6139     * StringUtils.replace("aba", "a", "z")   = "zbz"
6140     * </pre>
6141     *
6142     * @see #replace(String text, String searchString, String replacement, int max)
6143     * @param text  text to search and replace in, may be null
6144     * @param searchString  the String to search for, may be null
6145     * @param replacement  the String to replace it with, may be null
6146     * @return the text with any replacements processed,
6147     *  {@code null} if null String input
6148     * @deprecated Use {@link Strings#replace(String, String, String) Strings.CS.replace(String, String, String)}
6149     */
6150    @Deprecated
6151    public static String replace(final String text, final String searchString, final String replacement) {
6152        return Strings.CS.replace(text, searchString, replacement);
6153    }
6154
6155    /**
6156     * Replaces a String with another String inside a larger String,
6157     * for the first {@code max} values of the search String.
6158     *
6159     * <p>A {@code null} reference passed to this method is a no-op.</p>
6160     *
6161     * <pre>
6162     * StringUtils.replace(null, *, *, *)         = null
6163     * StringUtils.replace("", *, *, *)           = ""
6164     * StringUtils.replace("any", null, *, *)     = "any"
6165     * StringUtils.replace("any", *, null, *)     = "any"
6166     * StringUtils.replace("any", "", *, *)       = "any"
6167     * StringUtils.replace("any", *, *, 0)        = "any"
6168     * StringUtils.replace("abaa", "a", null, -1) = "abaa"
6169     * StringUtils.replace("abaa", "a", "", -1)   = "b"
6170     * StringUtils.replace("abaa", "a", "z", 0)   = "abaa"
6171     * StringUtils.replace("abaa", "a", "z", 1)   = "zbaa"
6172     * StringUtils.replace("abaa", "a", "z", 2)   = "zbza"
6173     * StringUtils.replace("abaa", "a", "z", -1)  = "zbzz"
6174     * </pre>
6175     *
6176     * @param text  text to search and replace in, may be null
6177     * @param searchString  the String to search for, may be null
6178     * @param replacement  the String to replace it with, may be null
6179     * @param max  maximum number of values to replace, or {@code -1} if no maximum
6180     * @return the text with any replacements processed,
6181     *  {@code null} if null String input
6182     * @deprecated Use {@link Strings#replace(String, String, String, int) Strings.CS.replace(String, String, String, int)}
6183     */
6184    @Deprecated
6185    public static String replace(final String text, final String searchString, final String replacement, final int max) {
6186        return Strings.CS.replace(text, searchString, replacement, max);
6187    }
6188
6189    /**
6190     * Replaces each substring of the text String that matches the given regular expression
6191     * with the given replacement.
6192     *
6193     * This method is a {@code null} safe equivalent to:
6194     * <ul>
6195     *  <li>{@code text.replaceAll(regex, replacement)}</li>
6196     *  <li>{@code Pattern.compile(regex).matcher(text).replaceAll(replacement)}</li>
6197     * </ul>
6198     *
6199     * <p>A {@code null} reference passed to this method is a no-op.</p>
6200     *
6201     * <p>Unlike in the {@link #replacePattern(String, String, String)} method, the {@link Pattern#DOTALL} option
6202     * is NOT automatically added.
6203     * To use the DOTALL option prepend {@code "(?s)"} to the regex.
6204     * DOTALL is also known as single-line mode in Perl.</p>
6205     *
6206     * <pre>{@code
6207     * StringUtils.replaceAll(null, *, *)       = null
6208     * StringUtils.replaceAll("any", (String) null, *)   = "any"
6209     * StringUtils.replaceAll("any", *, null)   = "any"
6210     * StringUtils.replaceAll("", "", "zzz")    = "zzz"
6211     * StringUtils.replaceAll("", ".*", "zzz")  = "zzz"
6212     * StringUtils.replaceAll("", ".+", "zzz")  = ""
6213     * StringUtils.replaceAll("abc", "", "ZZ")  = "ZZaZZbZZcZZ"
6214     * StringUtils.replaceAll("<__>\n<__>", "<.*>", "z")      = "z\nz"
6215     * StringUtils.replaceAll("<__>\n<__>", "(?s)<.*>", "z")  = "z"
6216     * StringUtils.replaceAll("ABCabc123", "[a-z]", "_")       = "ABC___123"
6217     * StringUtils.replaceAll("ABCabc123", "[^A-Z0-9]+", "_")  = "ABC_123"
6218     * StringUtils.replaceAll("ABCabc123", "[^A-Z0-9]+", "")   = "ABC123"
6219     * StringUtils.replaceAll("Lorem ipsum  dolor   sit", "( +)([a-z]+)", "_$2")  = "Lorem_ipsum_dolor_sit"
6220     * }</pre>
6221     *
6222     * @param text  text to search and replace in, may be null
6223     * @param regex  the regular expression to which this string is to be matched
6224     * @param replacement  the string to be substituted for each match
6225     * @return  the text with any replacements processed,
6226     *              {@code null} if null String input
6227     *
6228     * @throws  java.util.regex.PatternSyntaxException
6229     *              if the regular expression's syntax is invalid
6230     *
6231     * @see #replacePattern(String, String, String)
6232     * @see String#replaceAll(String, String)
6233     * @see java.util.regex.Pattern
6234     * @see java.util.regex.Pattern#DOTALL
6235     * @since 3.5
6236     * @deprecated Moved to RegExUtils.
6237     */
6238    @Deprecated
6239    public static String replaceAll(final String text, final String regex, final String replacement) {
6240        return RegExUtils.replaceAll(text, regex, replacement);
6241    }
6242
6243    /**
6244     * Replaces all occurrences of a character in a String with another.
6245     * This is a null-safe version of {@link String#replace(char, char)}.
6246     *
6247     * <p>A {@code null} string input returns {@code null}.
6248     * An empty ("") string input returns an empty string.</p>
6249     *
6250     * <pre>
6251     * StringUtils.replaceChars(null, *, *)        = null
6252     * StringUtils.replaceChars("", *, *)          = ""
6253     * StringUtils.replaceChars("abcba", 'b', 'y') = "aycya"
6254     * StringUtils.replaceChars("abcba", 'z', 'y') = "abcba"
6255     * </pre>
6256     *
6257     * @param str  String to replace characters in, may be null
6258     * @param searchChar  the character to search for, may be null
6259     * @param replaceChar  the character to replace, may be null
6260     * @return modified String, {@code null} if null string input
6261     * @since 2.0
6262     */
6263    public static String replaceChars(final String str, final char searchChar, final char replaceChar) {
6264        if (str == null) {
6265            return null;
6266        }
6267        return str.replace(searchChar, replaceChar);
6268    }
6269
6270    /**
6271     * Replaces multiple characters in a String in one go.
6272     * This method can also be used to delete characters.
6273     *
6274     * <p>For example:<br>
6275     * {@code replaceChars(&quot;hello&quot;, &quot;ho&quot;, &quot;jy&quot;) = jelly}.</p>
6276     *
6277     * <p>A {@code null} string input returns {@code null}.
6278     * An empty ("") string input returns an empty string.
6279     * A null or empty set of search characters returns the input string.</p>
6280     *
6281     * <p>The length of the search characters should normally equal the length
6282     * of the replace characters.
6283     * If the search characters is longer, then the extra search characters
6284     * are deleted.
6285     * If the search characters is shorter, then the extra replace characters
6286     * are ignored.</p>
6287     *
6288     * <pre>
6289     * StringUtils.replaceChars(null, *, *)           = null
6290     * StringUtils.replaceChars("", *, *)             = ""
6291     * StringUtils.replaceChars("abc", null, *)       = "abc"
6292     * StringUtils.replaceChars("abc", "", *)         = "abc"
6293     * StringUtils.replaceChars("abc", "b", null)     = "ac"
6294     * StringUtils.replaceChars("abc", "b", "")       = "ac"
6295     * StringUtils.replaceChars("abcba", "bc", "yz")  = "ayzya"
6296     * StringUtils.replaceChars("abcba", "bc", "y")   = "ayya"
6297     * StringUtils.replaceChars("abcba", "bc", "yzx") = "ayzya"
6298     * </pre>
6299     *
6300     * @param str  String to replace characters in, may be null
6301     * @param searchChars  a set of characters to search for, may be null
6302     * @param replaceChars  a set of characters to replace, may be null
6303     * @return modified String, {@code null} if null string input
6304     * @since 2.0
6305     */
6306    public static String replaceChars(final String str, final String searchChars, String replaceChars) {
6307        if (isEmpty(str) || isEmpty(searchChars)) {
6308            return str;
6309        }
6310        replaceChars = ObjectUtils.toString(replaceChars);
6311        boolean modified = false;
6312        final int replaceCharsLength = replaceChars.length();
6313        final int strLength = str.length();
6314        final StringBuilder buf = new StringBuilder(strLength);
6315        for (int i = 0; i < strLength; i++) {
6316            final char ch = str.charAt(i);
6317            final int index = searchChars.indexOf(ch);
6318            if (index >= 0) {
6319                modified = true;
6320                if (index < replaceCharsLength) {
6321                    buf.append(replaceChars.charAt(index));
6322                }
6323            } else {
6324                buf.append(ch);
6325            }
6326        }
6327        if (modified) {
6328            return buf.toString();
6329        }
6330        return str;
6331    }
6332
6333    /**
6334     * Replaces all occurrences of Strings within another String.
6335     *
6336     * <p>
6337     * A {@code null} reference passed to this method is a no-op, or if
6338     * any "search string" or "string to replace" is null, that replace will be
6339     * ignored. This will not repeat. For repeating replaces, call the
6340     * overloaded method.
6341     * </p>
6342     *
6343     * <pre>
6344     *  StringUtils.replaceEach(null, *, *)        = null
6345     *  StringUtils.replaceEach("", *, *)          = ""
6346     *  StringUtils.replaceEach("aba", null, null) = "aba"
6347     *  StringUtils.replaceEach("aba", new String[0], null) = "aba"
6348     *  StringUtils.replaceEach("aba", null, new String[0]) = "aba"
6349     *  StringUtils.replaceEach("aba", new String[]{"a"}, null)  = "aba"
6350     *  StringUtils.replaceEach("aba", new String[]{"a"}, new String[]{""})  = "b"
6351     *  StringUtils.replaceEach("aba", new String[]{null}, new String[]{"a"})  = "aba"
6352     *  StringUtils.replaceEach("abcde", new String[]{"ab", "d"}, new String[]{"w", "t"})  = "wcte"
6353     *  (example of how it does not repeat)
6354     *  StringUtils.replaceEach("abcde", new String[]{"ab", "d"}, new String[]{"d", "t"})  = "dcte"
6355     * </pre>
6356     *
6357     * @param text
6358     *            text to search and replace in, no-op if null
6359     * @param searchList
6360     *            the Strings to search for, no-op if null
6361     * @param replacementList
6362     *            the Strings to replace them with, no-op if null
6363     * @return the text with any replacements processed, {@code null} if
6364     *         null String input
6365     * @throws IllegalArgumentException
6366     *             if the lengths of the arrays are not the same (null is ok,
6367     *             and/or size 0)
6368     * @since 2.4
6369     */
6370    public static String replaceEach(final String text, final String[] searchList, final String[] replacementList) {
6371        return replaceEach(text, searchList, replacementList, false, 0);
6372    }
6373
6374    /**
6375     * Replace all occurrences of Strings within another String.
6376     * This is a private recursive helper method for {@link #replaceEachRepeatedly(String, String[], String[])} and
6377     * {@link #replaceEach(String, String[], String[])}
6378     *
6379     * <p>
6380     * A {@code null} reference passed to this method is a no-op, or if
6381     * any "search string" or "string to replace" is null, that replace will be
6382     * ignored.
6383     * </p>
6384     *
6385     * <pre>
6386     *  StringUtils.replaceEach(null, *, *, *, *) = null
6387     *  StringUtils.replaceEach("", *, *, *, *) = ""
6388     *  StringUtils.replaceEach("aba", null, null, *, *) = "aba"
6389     *  StringUtils.replaceEach("aba", new String[0], null, *, *) = "aba"
6390     *  StringUtils.replaceEach("aba", null, new String[0], *, *) = "aba"
6391     *  StringUtils.replaceEach("aba", new String[]{"a"}, null, *, *) = "aba"
6392     *  StringUtils.replaceEach("aba", new String[]{"a"}, new String[]{""}, *, >=0) = "b"
6393     *  StringUtils.replaceEach("aba", new String[]{null}, new String[]{"a"}, *, >=0) = "aba"
6394     *  StringUtils.replaceEach("abcde", new String[]{"ab", "d"}, new String[]{"w", "t"}, *, >=0) = "wcte"
6395     *  (example of how it repeats)
6396     *  StringUtils.replaceEach("abcde", new String[]{"ab", "d"}, new String[]{"d", "t"}, false, >=0) = "dcte"
6397     *  StringUtils.replaceEach("abcde", new String[]{"ab", "d"}, new String[]{"d", "t"}, true, >=2) = "tcte"
6398     *  StringUtils.replaceEach("abcde", new String[]{"ab", "d"}, new String[]{"d", "ab"}, *, *) = IllegalStateException
6399     * </pre>
6400     *
6401     * @param text
6402     *            text to search and replace in, no-op if null
6403     * @param searchList
6404     *            the Strings to search for, no-op if null
6405     * @param replacementList
6406     *            the Strings to replace them with, no-op if null
6407     * @param repeat if true, then replace repeatedly
6408     *       until there are no more possible replacements or timeToLive < 0
6409     * @param timeToLive
6410     *            if less than 0 then there is a circular reference and endless
6411     *            loop
6412     * @return the text with any replacements processed, {@code null} if
6413     *         null String input
6414     * @throws IllegalStateException
6415     *             if the search is repeating and there is an endless loop due
6416     *             to outputs of one being inputs to another
6417     * @throws IllegalArgumentException
6418     *             if the lengths of the arrays are not the same (null is ok,
6419     *             and/or size 0)
6420     * @since 2.4
6421     */
6422    private static String replaceEach(
6423            final String text, final String[] searchList, final String[] replacementList, final boolean repeat, final int timeToLive) {
6424
6425        // mchyzer Performance note: This creates very few new objects (one major goal)
6426        // let me know if there are performance requests, we can create a harness to measure
6427        if (isEmpty(text) || ArrayUtils.isEmpty(searchList) || ArrayUtils.isEmpty(replacementList)) {
6428            return text;
6429        }
6430
6431        // if recursing, this shouldn't be less than 0
6432        if (timeToLive < 0) {
6433            throw new IllegalStateException("Aborting to protect against StackOverflowError - " +
6434                "output of one loop is the input of another");
6435        }
6436
6437        final int searchLength = searchList.length;
6438        final int replacementLength = replacementList.length;
6439
6440        // make sure lengths are ok, these need to be equal
6441        if (searchLength != replacementLength) {
6442            throw new IllegalArgumentException("Search and Replace array lengths don't match: "
6443                + searchLength
6444                + " vs "
6445                + replacementLength);
6446        }
6447
6448        // keep track of which still have matches
6449        final boolean[] noMoreMatchesForReplIndex = new boolean[searchLength];
6450
6451        // index on index that the match was found
6452        int textIndex = -1;
6453        int replaceIndex = -1;
6454        int tempIndex;
6455
6456        // index of replace array that will replace the search string found
6457        // NOTE: logic duplicated below START
6458        for (int i = 0; i < searchLength; i++) {
6459            if (noMoreMatchesForReplIndex[i] || isEmpty(searchList[i]) || replacementList[i] == null) {
6460                continue;
6461            }
6462            tempIndex = text.indexOf(searchList[i]);
6463
6464            // see if we need to keep searching for this
6465            if (tempIndex == -1) {
6466                noMoreMatchesForReplIndex[i] = true;
6467            } else if (textIndex == -1 || tempIndex < textIndex) {
6468                textIndex = tempIndex;
6469                replaceIndex = i;
6470            }
6471        }
6472        // NOTE: logic mostly below END
6473
6474        // no search strings found, we are done
6475        if (textIndex == -1) {
6476            return text;
6477        }
6478
6479        int start = 0;
6480
6481        // get a good guess on the size of the result buffer so it doesn't have to double if it goes over a bit
6482        int increase = 0;
6483
6484        // count the replacement text elements that are larger than their corresponding text being replaced
6485        for (int i = 0; i < searchList.length; i++) {
6486            if (searchList[i] == null || replacementList[i] == null) {
6487                continue;
6488            }
6489            final int greater = replacementList[i].length() - searchList[i].length();
6490            if (greater > 0) {
6491                increase += 3 * greater; // assume 3 matches
6492            }
6493        }
6494        // have upper-bound at 20% increase, then let Java take over
6495        increase = Math.min(increase, text.length() / 5);
6496
6497        final StringBuilder buf = new StringBuilder(text.length() + increase);
6498
6499        while (textIndex != -1) {
6500
6501            for (int i = start; i < textIndex; i++) {
6502                buf.append(text.charAt(i));
6503            }
6504            buf.append(replacementList[replaceIndex]);
6505
6506            start = textIndex + searchList[replaceIndex].length();
6507
6508            textIndex = -1;
6509            replaceIndex = -1;
6510            // find the next earliest match
6511            // NOTE: logic mostly duplicated above START
6512            for (int i = 0; i < searchLength; i++) {
6513                if (noMoreMatchesForReplIndex[i] || isEmpty(searchList[i]) || replacementList[i] == null) {
6514                    continue;
6515                }
6516                tempIndex = text.indexOf(searchList[i], start);
6517
6518                // see if we need to keep searching for this
6519                if (tempIndex == -1) {
6520                    noMoreMatchesForReplIndex[i] = true;
6521                } else if (textIndex == -1 || tempIndex < textIndex) {
6522                    textIndex = tempIndex;
6523                    replaceIndex = i;
6524                }
6525            }
6526            // NOTE: logic duplicated above END
6527
6528        }
6529        final int textLength = text.length();
6530        for (int i = start; i < textLength; i++) {
6531            buf.append(text.charAt(i));
6532        }
6533        final String result = buf.toString();
6534        if (!repeat) {
6535            return result;
6536        }
6537
6538        return replaceEach(result, searchList, replacementList, repeat, timeToLive - 1);
6539    }
6540
6541    /**
6542     * Replaces all occurrences of Strings within another String.
6543     *
6544     * <p>
6545     * A {@code null} reference passed to this method is a no-op, or if
6546     * any "search string" or "string to replace" is null, that replace will be
6547     * ignored.
6548     * </p>
6549     *
6550     * <pre>
6551     *  StringUtils.replaceEachRepeatedly(null, *, *) = null
6552     *  StringUtils.replaceEachRepeatedly("", *, *) = ""
6553     *  StringUtils.replaceEachRepeatedly("aba", null, null) = "aba"
6554     *  StringUtils.replaceEachRepeatedly("aba", new String[0], null) = "aba"
6555     *  StringUtils.replaceEachRepeatedly("aba", null, new String[0]) = "aba"
6556     *  StringUtils.replaceEachRepeatedly("aba", new String[]{"a"}, null) = "aba"
6557     *  StringUtils.replaceEachRepeatedly("aba", new String[]{"a"}, new String[]{""}) = "b"
6558     *  StringUtils.replaceEachRepeatedly("aba", new String[]{null}, new String[]{"a"}) = "aba"
6559     *  StringUtils.replaceEachRepeatedly("abcde", new String[]{"ab", "d"}, new String[]{"w", "t"}) = "wcte"
6560     *  (example of how it repeats)
6561     *  StringUtils.replaceEachRepeatedly("abcde", new String[]{"ab", "d"}, new String[]{"d", "t"}) = "tcte"
6562     *  StringUtils.replaceEachRepeatedly("abcde", new String[]{"ab", "d"}, new String[]{"d", "ab"}) = IllegalStateException
6563     * </pre>
6564     *
6565     * @param text
6566     *            text to search and replace in, no-op if null
6567     * @param searchList
6568     *            the Strings to search for, no-op if null
6569     * @param replacementList
6570     *            the Strings to replace them with, no-op if null
6571     * @return the text with any replacements processed, {@code null} if
6572     *         null String input
6573     * @throws IllegalStateException
6574     *             if the search is repeating and there is an endless loop due
6575     *             to outputs of one being inputs to another
6576     * @throws IllegalArgumentException
6577     *             if the lengths of the arrays are not the same (null is ok,
6578     *             and/or size 0)
6579     * @since 2.4
6580     */
6581    public static String replaceEachRepeatedly(final String text, final String[] searchList, final String[] replacementList) {
6582        final int timeToLive = Math.max(ArrayUtils.getLength(searchList), DEFAULT_TTL);
6583        return replaceEach(text, searchList, replacementList, true, timeToLive);
6584    }
6585
6586    /**
6587     * Replaces the first substring of the text string that matches the given regular expression
6588     * with the given replacement.
6589     *
6590     * This method is a {@code null} safe equivalent to:
6591     * <ul>
6592     *  <li>{@code text.replaceFirst(regex, replacement)}</li>
6593     *  <li>{@code Pattern.compile(regex).matcher(text).replaceFirst(replacement)}</li>
6594     * </ul>
6595     *
6596     * <p>A {@code null} reference passed to this method is a no-op.</p>
6597     *
6598     * <p>The {@link Pattern#DOTALL} option is NOT automatically added.
6599     * To use the DOTALL option prepend {@code "(?s)"} to the regex.
6600     * DOTALL is also known as single-line mode in Perl.</p>
6601     *
6602     * <pre>{@code
6603     * StringUtils.replaceFirst(null, *, *)       = null
6604     * StringUtils.replaceFirst("any", (String) null, *)   = "any"
6605     * StringUtils.replaceFirst("any", *, null)   = "any"
6606     * StringUtils.replaceFirst("", "", "zzz")    = "zzz"
6607     * StringUtils.replaceFirst("", ".*", "zzz")  = "zzz"
6608     * StringUtils.replaceFirst("", ".+", "zzz")  = ""
6609     * StringUtils.replaceFirst("abc", "", "ZZ")  = "ZZabc"
6610     * StringUtils.replaceFirst("<__>\n<__>", "<.*>", "z")      = "z\n<__>"
6611     * StringUtils.replaceFirst("<__>\n<__>", "(?s)<.*>", "z")  = "z"
6612     * StringUtils.replaceFirst("ABCabc123", "[a-z]", "_")          = "ABC_bc123"
6613     * StringUtils.replaceFirst("ABCabc123abc", "[^A-Z0-9]+", "_")  = "ABC_123abc"
6614     * StringUtils.replaceFirst("ABCabc123abc", "[^A-Z0-9]+", "")   = "ABC123abc"
6615     * StringUtils.replaceFirst("Lorem ipsum  dolor   sit", "( +)([a-z]+)", "_$2")  = "Lorem_ipsum  dolor   sit"
6616     * }</pre>
6617     *
6618     * @param text  text to search and replace in, may be null
6619     * @param regex  the regular expression to which this string is to be matched
6620     * @param replacement  the string to be substituted for the first match
6621     * @return  the text with the first replacement processed,
6622     *              {@code null} if null String input
6623     *
6624     * @throws  java.util.regex.PatternSyntaxException
6625     *              if the regular expression's syntax is invalid
6626     *
6627     * @see String#replaceFirst(String, String)
6628     * @see java.util.regex.Pattern
6629     * @see java.util.regex.Pattern#DOTALL
6630     * @since 3.5
6631     * @deprecated Moved to RegExUtils.
6632     */
6633    @Deprecated
6634    public static String replaceFirst(final String text, final String regex, final String replacement) {
6635        return RegExUtils.replaceFirst(text, regex, replacement);
6636    }
6637
6638    /**
6639     * Case insensitively replaces all occurrences of a String within another String.
6640     *
6641     * <p>A {@code null} reference passed to this method is a no-op.</p>
6642     *
6643     * <pre>
6644     * StringUtils.replaceIgnoreCase(null, *, *)        = null
6645     * StringUtils.replaceIgnoreCase("", *, *)          = ""
6646     * StringUtils.replaceIgnoreCase("any", null, *)    = "any"
6647     * StringUtils.replaceIgnoreCase("any", *, null)    = "any"
6648     * StringUtils.replaceIgnoreCase("any", "", *)      = "any"
6649     * StringUtils.replaceIgnoreCase("aba", "a", null)  = "aba"
6650     * StringUtils.replaceIgnoreCase("abA", "A", "")    = "b"
6651     * StringUtils.replaceIgnoreCase("aba", "A", "z")   = "zbz"
6652     * </pre>
6653     *
6654     * @see #replaceIgnoreCase(String text, String searchString, String replacement, int max)
6655     * @param text  text to search and replace in, may be null
6656     * @param searchString  the String to search for (case-insensitive), may be null
6657     * @param replacement  the String to replace it with, may be null
6658     * @return the text with any replacements processed,
6659     *  {@code null} if null String input
6660     * @since 3.5
6661     * @deprecated Use {@link Strings#replace(String, String, String) Strings.CI.replace(String, String, String)}
6662     */
6663    @Deprecated
6664     public static String replaceIgnoreCase(final String text, final String searchString, final String replacement) {
6665         return Strings.CI.replace(text, searchString, replacement);
6666     }
6667
6668    /**
6669     * Case insensitively replaces a String with another String inside a larger String,
6670     * for the first {@code max} values of the search String.
6671     *
6672     * <p>A {@code null} reference passed to this method is a no-op.</p>
6673     *
6674     * <pre>
6675     * StringUtils.replaceIgnoreCase(null, *, *, *)         = null
6676     * StringUtils.replaceIgnoreCase("", *, *, *)           = ""
6677     * StringUtils.replaceIgnoreCase("any", null, *, *)     = "any"
6678     * StringUtils.replaceIgnoreCase("any", *, null, *)     = "any"
6679     * StringUtils.replaceIgnoreCase("any", "", *, *)       = "any"
6680     * StringUtils.replaceIgnoreCase("any", *, *, 0)        = "any"
6681     * StringUtils.replaceIgnoreCase("abaa", "a", null, -1) = "abaa"
6682     * StringUtils.replaceIgnoreCase("abaa", "a", "", -1)   = "b"
6683     * StringUtils.replaceIgnoreCase("abaa", "a", "z", 0)   = "abaa"
6684     * StringUtils.replaceIgnoreCase("abaa", "A", "z", 1)   = "zbaa"
6685     * StringUtils.replaceIgnoreCase("abAa", "a", "z", 2)   = "zbza"
6686     * StringUtils.replaceIgnoreCase("abAa", "a", "z", -1)  = "zbzz"
6687     * </pre>
6688     *
6689     * @param text  text to search and replace in, may be null
6690     * @param searchString  the String to search for (case-insensitive), may be null
6691     * @param replacement  the String to replace it with, may be null
6692     * @param max  maximum number of values to replace, or {@code -1} if no maximum
6693     * @return the text with any replacements processed,
6694     *  {@code null} if null String input
6695     * @since 3.5
6696     * @deprecated Use {@link Strings#replace(String, String, String, int) Strings.CI.replace(String, String, String, int)}
6697     */
6698    @Deprecated
6699    public static String replaceIgnoreCase(final String text, final String searchString, final String replacement, final int max) {
6700        return Strings.CI.replace(text, searchString, replacement, max);
6701    }
6702
6703    /**
6704     * Replaces a String with another String inside a larger String, once.
6705     *
6706     * <p>A {@code null} reference passed to this method is a no-op.</p>
6707     *
6708     * <pre>
6709     * StringUtils.replaceOnce(null, *, *)        = null
6710     * StringUtils.replaceOnce("", *, *)          = ""
6711     * StringUtils.replaceOnce("any", null, *)    = "any"
6712     * StringUtils.replaceOnce("any", *, null)    = "any"
6713     * StringUtils.replaceOnce("any", "", *)      = "any"
6714     * StringUtils.replaceOnce("aba", "a", null)  = "aba"
6715     * StringUtils.replaceOnce("aba", "a", "")    = "ba"
6716     * StringUtils.replaceOnce("aba", "a", "z")   = "zba"
6717     * </pre>
6718     *
6719     * @see #replace(String text, String searchString, String replacement, int max)
6720     * @param text  text to search and replace in, may be null
6721     * @param searchString  the String to search for, may be null
6722     * @param replacement  the String to replace with, may be null
6723     * @return the text with any replacements processed,
6724     *  {@code null} if null String input
6725     * @deprecated Use {@link Strings#replaceOnce(String, String, String) Strings.CS.replaceOnce(String, String, String)}
6726     */
6727    @Deprecated
6728    public static String replaceOnce(final String text, final String searchString, final String replacement) {
6729        return Strings.CS.replaceOnce(text, searchString, replacement);
6730    }
6731
6732    /**
6733     * Case insensitively replaces a String with another String inside a larger String, once.
6734     *
6735     * <p>A {@code null} reference passed to this method is a no-op.</p>
6736     *
6737     * <pre>
6738     * StringUtils.replaceOnceIgnoreCase(null, *, *)        = null
6739     * StringUtils.replaceOnceIgnoreCase("", *, *)          = ""
6740     * StringUtils.replaceOnceIgnoreCase("any", null, *)    = "any"
6741     * StringUtils.replaceOnceIgnoreCase("any", *, null)    = "any"
6742     * StringUtils.replaceOnceIgnoreCase("any", "", *)      = "any"
6743     * StringUtils.replaceOnceIgnoreCase("aba", "a", null)  = "aba"
6744     * StringUtils.replaceOnceIgnoreCase("aba", "a", "")    = "ba"
6745     * StringUtils.replaceOnceIgnoreCase("aba", "a", "z")   = "zba"
6746     * StringUtils.replaceOnceIgnoreCase("FoOFoofoo", "foo", "") = "Foofoo"
6747     * </pre>
6748     *
6749     * @see #replaceIgnoreCase(String text, String searchString, String replacement, int max)
6750     * @param text  text to search and replace in, may be null
6751     * @param searchString  the String to search for (case-insensitive), may be null
6752     * @param replacement  the String to replace with, may be null
6753     * @return the text with any replacements processed,
6754     *  {@code null} if null String input
6755     * @since 3.5
6756     * @deprecated Use {@link Strings#replaceOnce(String, String, String) Strings.CI.replaceOnce(String, String, String)}
6757     */
6758    @Deprecated
6759    public static String replaceOnceIgnoreCase(final String text, final String searchString, final String replacement) {
6760        return Strings.CI.replaceOnce(text, searchString, replacement);
6761    }
6762
6763    /**
6764     * Replaces each substring of the source String that matches the given regular expression with the given
6765     * replacement using the {@link Pattern#DOTALL} option. DOTALL is also known as single-line mode in Perl.
6766     *
6767     * This call is a {@code null} safe equivalent to:
6768     * <ul>
6769     * <li>{@code source.replaceAll(&quot;(?s)&quot; + regex, replacement)}</li>
6770     * <li>{@code Pattern.compile(regex, Pattern.DOTALL).matcher(source).replaceAll(replacement)}</li>
6771     * </ul>
6772     *
6773     * <p>A {@code null} reference passed to this method is a no-op.</p>
6774     *
6775     * <pre>{@code
6776     * StringUtils.replacePattern(null, *, *)       = null
6777     * StringUtils.replacePattern("any", (String) null, *)   = "any"
6778     * StringUtils.replacePattern("any", *, null)   = "any"
6779     * StringUtils.replacePattern("", "", "zzz")    = "zzz"
6780     * StringUtils.replacePattern("", ".*", "zzz")  = "zzz"
6781     * StringUtils.replacePattern("", ".+", "zzz")  = ""
6782     * StringUtils.replacePattern("<__>\n<__>", "<.*>", "z")       = "z"
6783     * StringUtils.replacePattern("ABCabc123", "[a-z]", "_")       = "ABC___123"
6784     * StringUtils.replacePattern("ABCabc123", "[^A-Z0-9]+", "_")  = "ABC_123"
6785     * StringUtils.replacePattern("ABCabc123", "[^A-Z0-9]+", "")   = "ABC123"
6786     * StringUtils.replacePattern("Lorem ipsum  dolor   sit", "( +)([a-z]+)", "_$2")  = "Lorem_ipsum_dolor_sit"
6787     * }</pre>
6788     *
6789     * @param source
6790     *            the source string
6791     * @param regex
6792     *            the regular expression to which this string is to be matched
6793     * @param replacement
6794     *            the string to be substituted for each match
6795     * @return The resulting {@link String}
6796     * @see #replaceAll(String, String, String)
6797     * @see String#replaceAll(String, String)
6798     * @see Pattern#DOTALL
6799     * @since 3.2
6800     * @since 3.5 Changed {@code null} reference passed to this method is a no-op.
6801     * @deprecated Moved to RegExUtils.
6802     */
6803    @Deprecated
6804    public static String replacePattern(final String source, final String regex, final String replacement) {
6805        return RegExUtils.replacePattern(source, regex, replacement);
6806    }
6807
6808    /**
6809     * Reverses a String as per {@link StringBuilder#reverse()}.
6810     *
6811     * <p>A {@code null} String returns {@code null}.</p>
6812     *
6813     * <pre>
6814     * StringUtils.reverse(null)  = null
6815     * StringUtils.reverse("")    = ""
6816     * StringUtils.reverse("bat") = "tab"
6817     * </pre>
6818     *
6819     * @param str  the String to reverse, may be null
6820     * @return the reversed String, {@code null} if null String input
6821     */
6822    public static String reverse(final String str) {
6823        if (str == null) {
6824            return null;
6825        }
6826        return new StringBuilder(str).reverse().toString();
6827    }
6828
6829    /**
6830     * Reverses a String that is delimited by a specific character.
6831     *
6832     * <p>The Strings between the delimiters are not reversed.
6833     * Thus java.lang.String becomes String.lang.java (if the delimiter
6834     * is {@code '.'}).</p>
6835     *
6836     * <pre>
6837     * StringUtils.reverseDelimited(null, *)      = null
6838     * StringUtils.reverseDelimited("", *)        = ""
6839     * StringUtils.reverseDelimited("a.b.c", 'x') = "a.b.c"
6840     * StringUtils.reverseDelimited("a.b.c", ".") = "c.b.a"
6841     * </pre>
6842     *
6843     * @param str  the String to reverse, may be null
6844     * @param separatorChar  the separator character to use
6845     * @return the reversed String, {@code null} if null String input
6846     * @since 2.0
6847     */
6848    public static String reverseDelimited(final String str, final char separatorChar) {
6849        final String[] strs = split(str, separatorChar);
6850        ArrayUtils.reverse(strs);
6851        return join(strs, separatorChar);
6852    }
6853
6854    /**
6855     * Gets the rightmost {@code len} characters of a String.
6856     *
6857     * <p>If {@code len} characters are not available, or the String
6858     * is {@code null}, the String will be returned without an
6859     * an exception. An empty String is returned if len is negative.</p>
6860     *
6861     * <pre>
6862     * StringUtils.right(null, *)    = null
6863     * StringUtils.right(*, -ve)     = ""
6864     * StringUtils.right("", *)      = ""
6865     * StringUtils.right("abc", 0)   = ""
6866     * StringUtils.right("abc", 2)   = "bc"
6867     * StringUtils.right("abc", 4)   = "abc"
6868     * </pre>
6869     *
6870     * @param str  the String to get the rightmost characters from, may be null
6871     * @param len  the length of the required String
6872     * @return the rightmost characters, {@code null} if null String input
6873     */
6874    public static String right(final String str, final int len) {
6875        if (str == null) {
6876            return null;
6877        }
6878        if (len < 0) {
6879            return EMPTY;
6880        }
6881        if (str.length() <= len) {
6882            return str;
6883        }
6884        return str.substring(str.length() - len);
6885    }
6886
6887    /**
6888     * Right pad a String with spaces (' ').
6889     *
6890     * <p>The String is padded to the size of {@code size}.</p>
6891     *
6892     * <pre>
6893     * StringUtils.rightPad(null, *)   = null
6894     * StringUtils.rightPad("", 3)     = "   "
6895     * StringUtils.rightPad("bat", 3)  = "bat"
6896     * StringUtils.rightPad("bat", 5)  = "bat  "
6897     * StringUtils.rightPad("bat", 1)  = "bat"
6898     * StringUtils.rightPad("bat", -1) = "bat"
6899     * </pre>
6900     *
6901     * @param str  the String to pad out, may be null
6902     * @param size  the size to pad to
6903     * @return right padded String or original String if no padding is necessary,
6904     *  {@code null} if null String input
6905     */
6906    public static String rightPad(final String str, final int size) {
6907        return rightPad(str, size, ' ');
6908    }
6909
6910    /**
6911     * Right pad a String with a specified character.
6912     *
6913     * <p>The String is padded to the size of {@code size}.</p>
6914     *
6915     * <pre>
6916     * StringUtils.rightPad(null, *, *)     = null
6917     * StringUtils.rightPad("", 3, 'z')     = "zzz"
6918     * StringUtils.rightPad("bat", 3, 'z')  = "bat"
6919     * StringUtils.rightPad("bat", 5, 'z')  = "batzz"
6920     * StringUtils.rightPad("bat", 1, 'z')  = "bat"
6921     * StringUtils.rightPad("bat", -1, 'z') = "bat"
6922     * </pre>
6923     *
6924     * @param str  the String to pad out, may be null
6925     * @param size  the size to pad to
6926     * @param padChar  the character to pad with
6927     * @return right padded String or original String if no padding is necessary,
6928     *  {@code null} if null String input
6929     * @since 2.0
6930     */
6931    public static String rightPad(final String str, final int size, final char padChar) {
6932        if (str == null) {
6933            return null;
6934        }
6935        final int pads = size - str.length();
6936        if (pads <= 0) {
6937            return str; // returns original String when possible
6938        }
6939        if (pads > PAD_LIMIT) {
6940            return rightPad(str, size, String.valueOf(padChar));
6941        }
6942        return str.concat(repeat(padChar, pads));
6943    }
6944
6945    /**
6946     * Right pad a String with a specified String.
6947     *
6948     * <p>The String is padded to the size of {@code size}.</p>
6949     *
6950     * <pre>
6951     * StringUtils.rightPad(null, *, *)      = null
6952     * StringUtils.rightPad("", 3, "z")      = "zzz"
6953     * StringUtils.rightPad("bat", 3, "yz")  = "bat"
6954     * StringUtils.rightPad("bat", 5, "yz")  = "batyz"
6955     * StringUtils.rightPad("bat", 8, "yz")  = "batyzyzy"
6956     * StringUtils.rightPad("bat", 1, "yz")  = "bat"
6957     * StringUtils.rightPad("bat", -1, "yz") = "bat"
6958     * StringUtils.rightPad("bat", 5, null)  = "bat  "
6959     * StringUtils.rightPad("bat", 5, "")    = "bat  "
6960     * </pre>
6961     *
6962     * @param str  the String to pad out, may be null
6963     * @param size  the size to pad to
6964     * @param padStr  the String to pad with, null or empty treated as single space
6965     * @return right padded String or original String if no padding is necessary,
6966     *  {@code null} if null String input
6967     */
6968    public static String rightPad(final String str, final int size, String padStr) {
6969        if (str == null) {
6970            return null;
6971        }
6972        if (isEmpty(padStr)) {
6973            padStr = SPACE;
6974        }
6975        final int padLen = padStr.length();
6976        final int strLen = str.length();
6977        final int pads = size - strLen;
6978        if (pads <= 0) {
6979            return str; // returns original String when possible
6980        }
6981        if (padLen == 1 && pads <= PAD_LIMIT) {
6982            return rightPad(str, size, padStr.charAt(0));
6983        }
6984
6985        if (pads == padLen) {
6986            return str.concat(padStr);
6987        }
6988        if (pads < padLen) {
6989            return str.concat(padStr.substring(0, pads));
6990        }
6991        final char[] padding = new char[pads];
6992        final char[] padChars = padStr.toCharArray();
6993        for (int i = 0; i < pads; i++) {
6994            padding[i] = padChars[i % padLen];
6995        }
6996        return str.concat(new String(padding));
6997    }
6998
6999    /**
7000     * Rotate (circular shift) a String of {@code shift} characters.
7001     * <ul>
7002     *  <li>If {@code shift > 0}, right circular shift (ex : ABCDEF =&gt; FABCDE)</li>
7003     *  <li>If {@code shift < 0}, left circular shift (ex : ABCDEF =&gt; BCDEFA)</li>
7004     * </ul>
7005     *
7006     * <pre>
7007     * StringUtils.rotate(null, *)        = null
7008     * StringUtils.rotate("", *)          = ""
7009     * StringUtils.rotate("abcdefg", 0)   = "abcdefg"
7010     * StringUtils.rotate("abcdefg", 2)   = "fgabcde"
7011     * StringUtils.rotate("abcdefg", -2)  = "cdefgab"
7012     * StringUtils.rotate("abcdefg", 7)   = "abcdefg"
7013     * StringUtils.rotate("abcdefg", -7)  = "abcdefg"
7014     * StringUtils.rotate("abcdefg", 9)   = "fgabcde"
7015     * StringUtils.rotate("abcdefg", -9)  = "cdefgab"
7016     * </pre>
7017     *
7018     * @param str  the String to rotate, may be null
7019     * @param shift  number of time to shift (positive : right shift, negative : left shift)
7020     * @return the rotated String,
7021     *          or the original String if {@code shift == 0},
7022     *          or {@code null} if null String input
7023     * @since 3.5
7024     */
7025    public static String rotate(final String str, final int shift) {
7026        if (str == null) {
7027            return null;
7028        }
7029
7030        final int strLen = str.length();
7031        if (shift == 0 || strLen == 0 || shift % strLen == 0) {
7032            return str;
7033        }
7034
7035        final StringBuilder builder = new StringBuilder(strLen);
7036        final int offset = - (shift % strLen);
7037        builder.append(substring(str, offset));
7038        builder.append(substring(str, 0, offset));
7039        return builder.toString();
7040    }
7041
7042    /**
7043     * Splits the provided text into an array, using whitespace as the
7044     * separator.
7045     * Whitespace is defined by {@link Character#isWhitespace(char)}.
7046     *
7047     * <p>The separator is not included in the returned String array.
7048     * Adjacent separators are treated as one separator.
7049     * For more control over the split use the StrTokenizer class.</p>
7050     *
7051     * <p>A {@code null} input String returns {@code null}.</p>
7052     *
7053     * <pre>
7054     * StringUtils.split(null)       = null
7055     * StringUtils.split("")         = []
7056     * StringUtils.split("abc def")  = ["abc", "def"]
7057     * StringUtils.split("abc  def") = ["abc", "def"]
7058     * StringUtils.split(" abc ")    = ["abc"]
7059     * </pre>
7060     *
7061     * @param str  the String to parse, may be null
7062     * @return an array of parsed Strings, {@code null} if null String input
7063     */
7064    public static String[] split(final String str) {
7065        return split(str, null, -1);
7066    }
7067
7068    /**
7069     * Splits the provided text into an array, separator specified.
7070     * This is an alternative to using StringTokenizer.
7071     *
7072     * <p>The separator is not included in the returned String array.
7073     * Adjacent separators are treated as one separator.
7074     * For more control over the split use the StrTokenizer class.</p>
7075     *
7076     * <p>A {@code null} input String returns {@code null}.</p>
7077     *
7078     * <pre>
7079     * StringUtils.split(null, *)         = null
7080     * StringUtils.split("", *)           = []
7081     * StringUtils.split("a.b.c", '.')    = ["a", "b", "c"]
7082     * StringUtils.split("a..b.c", '.')   = ["a", "b", "c"]
7083     * StringUtils.split("a:b:c", '.')    = ["a:b:c"]
7084     * StringUtils.split("a b c", ' ')    = ["a", "b", "c"]
7085     * </pre>
7086     *
7087     * @param str  the String to parse, may be null
7088     * @param separatorChar  the character used as the delimiter
7089     * @return an array of parsed Strings, {@code null} if null String input
7090     * @since 2.0
7091     */
7092    public static String[] split(final String str, final char separatorChar) {
7093        return splitWorker(str, separatorChar, false);
7094    }
7095
7096    /**
7097     * Splits the provided text into an array, separators specified.
7098     * This is an alternative to using StringTokenizer.
7099     *
7100     * <p>The separator is not included in the returned String array.
7101     * Adjacent separators are treated as one separator.
7102     * For more control over the split use the StrTokenizer class.</p>
7103     *
7104     * <p>A {@code null} input String returns {@code null}.
7105     * A {@code null} separatorChars splits on whitespace.</p>
7106     *
7107     * <pre>
7108     * StringUtils.split(null, *)         = null
7109     * StringUtils.split("", *)           = []
7110     * StringUtils.split("abc def", null) = ["abc", "def"]
7111     * StringUtils.split("abc def", " ")  = ["abc", "def"]
7112     * StringUtils.split("abc  def", " ") = ["abc", "def"]
7113     * StringUtils.split("ab:cd:ef", ":") = ["ab", "cd", "ef"]
7114     * </pre>
7115     *
7116     * @param str  the String to parse, may be null
7117     * @param separatorChars  the characters used as the delimiters,
7118     *  {@code null} splits on whitespace
7119     * @return an array of parsed Strings, {@code null} if null String input
7120     */
7121    public static String[] split(final String str, final String separatorChars) {
7122        return splitWorker(str, separatorChars, -1, false);
7123    }
7124
7125    /**
7126     * Splits the provided text into an array with a maximum length,
7127     * separators specified.
7128     *
7129     * <p>The separator is not included in the returned String array.
7130     * Adjacent separators are treated as one separator.</p>
7131     *
7132     * <p>A {@code null} input String returns {@code null}.
7133     * A {@code null} separatorChars splits on whitespace.</p>
7134     *
7135     * <p>If more than {@code max} delimited substrings are found, the last
7136     * returned string includes all characters after the first {@code max - 1}
7137     * returned strings (including separator characters).</p>
7138     *
7139     * <pre>
7140     * StringUtils.split(null, *, *)            = null
7141     * StringUtils.split("", *, *)              = []
7142     * StringUtils.split("ab cd ef", null, 0)   = ["ab", "cd", "ef"]
7143     * StringUtils.split("ab   cd ef", null, 0) = ["ab", "cd", "ef"]
7144     * StringUtils.split("ab:cd:ef", ":", 0)    = ["ab", "cd", "ef"]
7145     * StringUtils.split("ab:cd:ef", ":", 2)    = ["ab", "cd:ef"]
7146     * </pre>
7147     *
7148     * @param str  the String to parse, may be null
7149     * @param separatorChars  the characters used as the delimiters,
7150     *  {@code null} splits on whitespace
7151     * @param max  the maximum number of elements to include in the
7152     *  array. A zero or negative value implies no limit
7153     * @return an array of parsed Strings, {@code null} if null String input
7154     */
7155    public static String[] split(final String str, final String separatorChars, final int max) {
7156        return splitWorker(str, separatorChars, max, false);
7157    }
7158
7159    /**
7160     * Splits a String by Character type as returned by
7161     * {@code java.lang.Character.getType(char)}. Groups of contiguous
7162     * characters of the same type are returned as complete tokens.
7163     * <pre>
7164     * StringUtils.splitByCharacterType(null)         = null
7165     * StringUtils.splitByCharacterType("")           = []
7166     * StringUtils.splitByCharacterType("ab de fg")   = ["ab", " ", "de", " ", "fg"]
7167     * StringUtils.splitByCharacterType("ab   de fg") = ["ab", "   ", "de", " ", "fg"]
7168     * StringUtils.splitByCharacterType("ab:cd:ef")   = ["ab", ":", "cd", ":", "ef"]
7169     * StringUtils.splitByCharacterType("number5")    = ["number", "5"]
7170     * StringUtils.splitByCharacterType("fooBar")     = ["foo", "B", "ar"]
7171     * StringUtils.splitByCharacterType("foo200Bar")  = ["foo", "200", "B", "ar"]
7172     * StringUtils.splitByCharacterType("ASFRules")   = ["ASFR", "ules"]
7173     * </pre>
7174     * @param str the String to split, may be {@code null}
7175     * @return an array of parsed Strings, {@code null} if null String input
7176     * @since 2.4
7177     */
7178    public static String[] splitByCharacterType(final String str) {
7179        return splitByCharacterType(str, false);
7180    }
7181
7182    /**
7183     * <p>Splits a String by Character type as returned by
7184     * {@code java.lang.Character.getType(char)}. Groups of contiguous
7185     * characters of the same type are returned as complete tokens, with the
7186     * following exception: if {@code camelCase} is {@code true},
7187     * the character of type {@code Character.UPPERCASE_LETTER}, if any,
7188     * immediately preceding a token of type {@code Character.LOWERCASE_LETTER}
7189     * will belong to the following token rather than to the preceding, if any,
7190     * {@code Character.UPPERCASE_LETTER} token.
7191     * @param str the String to split, may be {@code null}
7192     * @param camelCase whether to use so-called "camel-case" for letter types
7193     * @return an array of parsed Strings, {@code null} if null String input
7194     * @since 2.4
7195     */
7196    private static String[] splitByCharacterType(final String str, final boolean camelCase) {
7197        if (str == null) {
7198            return null;
7199        }
7200        if (str.isEmpty()) {
7201            return ArrayUtils.EMPTY_STRING_ARRAY;
7202        }
7203        final char[] c = str.toCharArray();
7204        final List<String> list = new ArrayList<>();
7205        int tokenStart = 0;
7206        int currentType = Character.getType(c[tokenStart]);
7207        for (int pos = tokenStart + 1; pos < c.length; pos++) {
7208            final int type = Character.getType(c[pos]);
7209            if (type == currentType) {
7210                continue;
7211            }
7212            if (camelCase && type == Character.LOWERCASE_LETTER && currentType == Character.UPPERCASE_LETTER) {
7213                final int newTokenStart = pos - 1;
7214                if (newTokenStart != tokenStart) {
7215                    list.add(new String(c, tokenStart, newTokenStart - tokenStart));
7216                    tokenStart = newTokenStart;
7217                }
7218            } else {
7219                list.add(new String(c, tokenStart, pos - tokenStart));
7220                tokenStart = pos;
7221            }
7222            currentType = type;
7223        }
7224        list.add(new String(c, tokenStart, c.length - tokenStart));
7225        return list.toArray(ArrayUtils.EMPTY_STRING_ARRAY);
7226    }
7227
7228    /**
7229     * <p>Splits a String by Character type as returned by
7230     * {@code java.lang.Character.getType(char)}. Groups of contiguous
7231     * characters of the same type are returned as complete tokens, with the
7232     * following exception: the character of type
7233     * {@code Character.UPPERCASE_LETTER}, if any, immediately
7234     * preceding a token of type {@code Character.LOWERCASE_LETTER}
7235     * will belong to the following token rather than to the preceding, if any,
7236     * {@code Character.UPPERCASE_LETTER} token.
7237     * <pre>
7238     * StringUtils.splitByCharacterTypeCamelCase(null)         = null
7239     * StringUtils.splitByCharacterTypeCamelCase("")           = []
7240     * StringUtils.splitByCharacterTypeCamelCase("ab de fg")   = ["ab", " ", "de", " ", "fg"]
7241     * StringUtils.splitByCharacterTypeCamelCase("ab   de fg") = ["ab", "   ", "de", " ", "fg"]
7242     * StringUtils.splitByCharacterTypeCamelCase("ab:cd:ef")   = ["ab", ":", "cd", ":", "ef"]
7243     * StringUtils.splitByCharacterTypeCamelCase("number5")    = ["number", "5"]
7244     * StringUtils.splitByCharacterTypeCamelCase("fooBar")     = ["foo", "Bar"]
7245     * StringUtils.splitByCharacterTypeCamelCase("foo200Bar")  = ["foo", "200", "Bar"]
7246     * StringUtils.splitByCharacterTypeCamelCase("ASFRules")   = ["ASF", "Rules"]
7247     * </pre>
7248     * @param str the String to split, may be {@code null}
7249     * @return an array of parsed Strings, {@code null} if null String input
7250     * @since 2.4
7251     */
7252    public static String[] splitByCharacterTypeCamelCase(final String str) {
7253        return splitByCharacterType(str, true);
7254    }
7255
7256    /**
7257     * <p>Splits the provided text into an array, separator string specified.
7258     *
7259     * <p>The separator(s) will not be included in the returned String array.
7260     * Adjacent separators are treated as one separator.</p>
7261     *
7262     * <p>A {@code null} input String returns {@code null}.
7263     * A {@code null} separator splits on whitespace.</p>
7264     *
7265     * <pre>
7266     * StringUtils.splitByWholeSeparator(null, *)               = null
7267     * StringUtils.splitByWholeSeparator("", *)                 = []
7268     * StringUtils.splitByWholeSeparator("ab de fg", null)      = ["ab", "de", "fg"]
7269     * StringUtils.splitByWholeSeparator("ab   de fg", null)    = ["ab", "de", "fg"]
7270     * StringUtils.splitByWholeSeparator("ab:cd:ef", ":")       = ["ab", "cd", "ef"]
7271     * StringUtils.splitByWholeSeparator("ab-!-cd-!-ef", "-!-") = ["ab", "cd", "ef"]
7272     * </pre>
7273     *
7274     * @param str  the String to parse, may be null
7275     * @param separator  String containing the String to be used as a delimiter,
7276     *  {@code null} splits on whitespace
7277     * @return an array of parsed Strings, {@code null} if null String was input
7278     */
7279    public static String[] splitByWholeSeparator(final String str, final String separator) {
7280        return splitByWholeSeparatorWorker(str, separator, -1, false);
7281    }
7282
7283    /**
7284     * Splits the provided text into an array, separator string specified.
7285     * Returns a maximum of {@code max} substrings.
7286     *
7287     * <p>The separator(s) will not be included in the returned String array.
7288     * Adjacent separators are treated as one separator.</p>
7289     *
7290     * <p>A {@code null} input String returns {@code null}.
7291     * A {@code null} separator splits on whitespace.</p>
7292     *
7293     * <pre>
7294     * StringUtils.splitByWholeSeparator(null, *, *)               = null
7295     * StringUtils.splitByWholeSeparator("", *, *)                 = []
7296     * StringUtils.splitByWholeSeparator("ab de fg", null, 0)      = ["ab", "de", "fg"]
7297     * StringUtils.splitByWholeSeparator("ab   de fg", null, 0)    = ["ab", "de", "fg"]
7298     * StringUtils.splitByWholeSeparator("ab:cd:ef", ":", 2)       = ["ab", "cd:ef"]
7299     * StringUtils.splitByWholeSeparator("ab-!-cd-!-ef", "-!-", 5) = ["ab", "cd", "ef"]
7300     * StringUtils.splitByWholeSeparator("ab-!-cd-!-ef", "-!-", 2) = ["ab", "cd-!-ef"]
7301     * </pre>
7302     *
7303     * @param str  the String to parse, may be null
7304     * @param separator  String containing the String to be used as a delimiter,
7305     *  {@code null} splits on whitespace
7306     * @param max  the maximum number of elements to include in the returned
7307     *  array. A zero or negative value implies no limit.
7308     * @return an array of parsed Strings, {@code null} if null String was input
7309     */
7310    public static String[] splitByWholeSeparator(final String str, final String separator, final int max) {
7311        return splitByWholeSeparatorWorker(str, separator, max, false);
7312    }
7313
7314    /**
7315     * Splits the provided text into an array, separator string specified.
7316     *
7317     * <p>The separator is not included in the returned String array.
7318     * Adjacent separators are treated as separators for empty tokens.
7319     * For more control over the split use the StrTokenizer class.</p>
7320     *
7321     * <p>A {@code null} input String returns {@code null}.
7322     * A {@code null} separator splits on whitespace.</p>
7323     *
7324     * <pre>
7325     * StringUtils.splitByWholeSeparatorPreserveAllTokens(null, *)               = null
7326     * StringUtils.splitByWholeSeparatorPreserveAllTokens("", *)                 = []
7327     * StringUtils.splitByWholeSeparatorPreserveAllTokens("ab de fg", null)      = ["ab", "de", "fg"]
7328     * StringUtils.splitByWholeSeparatorPreserveAllTokens("ab   de fg", null)    = ["ab", "", "", "de", "fg"]
7329     * StringUtils.splitByWholeSeparatorPreserveAllTokens("ab:cd:ef", ":")       = ["ab", "cd", "ef"]
7330     * StringUtils.splitByWholeSeparatorPreserveAllTokens("ab-!-cd-!-ef", "-!-") = ["ab", "cd", "ef"]
7331     * </pre>
7332     *
7333     * @param str  the String to parse, may be null
7334     * @param separator  String containing the String to be used as a delimiter,
7335     *  {@code null} splits on whitespace
7336     * @return an array of parsed Strings, {@code null} if null String was input
7337     * @since 2.4
7338     */
7339    public static String[] splitByWholeSeparatorPreserveAllTokens(final String str, final String separator) {
7340        return splitByWholeSeparatorWorker(str, separator, -1, true);
7341    }
7342
7343    /**
7344     * Splits the provided text into an array, separator string specified.
7345     * Returns a maximum of {@code max} substrings.
7346     *
7347     * <p>The separator is not included in the returned String array.
7348     * Adjacent separators are treated as separators for empty tokens.
7349     * For more control over the split use the StrTokenizer class.</p>
7350     *
7351     * <p>A {@code null} input String returns {@code null}.
7352     * A {@code null} separator splits on whitespace.</p>
7353     *
7354     * <pre>
7355     * StringUtils.splitByWholeSeparatorPreserveAllTokens(null, *, *)               = null
7356     * StringUtils.splitByWholeSeparatorPreserveAllTokens("", *, *)                 = []
7357     * StringUtils.splitByWholeSeparatorPreserveAllTokens("ab de fg", null, 0)      = ["ab", "de", "fg"]
7358     * StringUtils.splitByWholeSeparatorPreserveAllTokens("ab   de fg", null, 0)    = ["ab", "", "", "de", "fg"]
7359     * StringUtils.splitByWholeSeparatorPreserveAllTokens("ab:cd:ef", ":", 2)       = ["ab", "cd:ef"]
7360     * StringUtils.splitByWholeSeparatorPreserveAllTokens("ab-!-cd-!-ef", "-!-", 5) = ["ab", "cd", "ef"]
7361     * StringUtils.splitByWholeSeparatorPreserveAllTokens("ab-!-cd-!-ef", "-!-", 2) = ["ab", "cd-!-ef"]
7362     * </pre>
7363     *
7364     * @param str  the String to parse, may be null
7365     * @param separator  String containing the String to be used as a delimiter,
7366     *  {@code null} splits on whitespace
7367     * @param max  the maximum number of elements to include in the returned
7368     *  array. A zero or negative value implies no limit.
7369     * @return an array of parsed Strings, {@code null} if null String was input
7370     * @since 2.4
7371     */
7372    public static String[] splitByWholeSeparatorPreserveAllTokens(final String str, final String separator, final int max) {
7373        return splitByWholeSeparatorWorker(str, separator, max, true);
7374    }
7375
7376    /**
7377     * Performs the logic for the {@code splitByWholeSeparatorPreserveAllTokens} methods.
7378     *
7379     * @param str  the String to parse, may be {@code null}
7380     * @param separator  String containing the String to be used as a delimiter,
7381     *  {@code null} splits on whitespace
7382     * @param max  the maximum number of elements to include in the returned
7383     *  array. A zero or negative value implies no limit.
7384     * @param preserveAllTokens if {@code true}, adjacent separators are
7385     * treated as empty token separators; if {@code false}, adjacent
7386     * separators are treated as one separator.
7387     * @return an array of parsed Strings, {@code null} if null String input
7388     * @since 2.4
7389     */
7390    private static String[] splitByWholeSeparatorWorker(
7391            final String str, final String separator, final int max, final boolean preserveAllTokens) {
7392        if (str == null) {
7393            return null;
7394        }
7395
7396        final int len = str.length();
7397
7398        if (len == 0) {
7399            return ArrayUtils.EMPTY_STRING_ARRAY;
7400        }
7401
7402        if (separator == null || EMPTY.equals(separator)) {
7403            // Split on whitespace.
7404            return splitWorker(str, null, max, preserveAllTokens);
7405        }
7406
7407        final int separatorLength = separator.length();
7408
7409        final ArrayList<String> substrings = new ArrayList<>();
7410        int numberOfSubstrings = 0;
7411        int beg = 0;
7412        int end = 0;
7413        while (end < len) {
7414            end = str.indexOf(separator, beg);
7415
7416            if (end > -1) {
7417                if (end > beg) {
7418                    numberOfSubstrings += 1;
7419
7420                    if (numberOfSubstrings == max) {
7421                        end = len;
7422                        substrings.add(str.substring(beg));
7423                    } else {
7424                        // The following is OK, because String.substring( beg, end ) excludes
7425                        // the character at the position 'end'.
7426                        substrings.add(str.substring(beg, end));
7427
7428                        // Set the starting point for the next search.
7429                        // The following is equivalent to beg = end + (separatorLength - 1) + 1,
7430                        // which is the right calculation:
7431                        beg = end + separatorLength;
7432                    }
7433                } else {
7434                    // We found a consecutive occurrence of the separator, so skip it.
7435                    if (preserveAllTokens) {
7436                        numberOfSubstrings += 1;
7437                        if (numberOfSubstrings == max) {
7438                            end = len;
7439                            substrings.add(str.substring(beg));
7440                        } else {
7441                            substrings.add(EMPTY);
7442                        }
7443                    }
7444                    beg = end + separatorLength;
7445                }
7446            } else {
7447                // String.substring( beg ) goes from 'beg' to the end of the String.
7448                substrings.add(str.substring(beg));
7449                end = len;
7450            }
7451        }
7452
7453        return substrings.toArray(ArrayUtils.EMPTY_STRING_ARRAY);
7454    }
7455
7456    /**
7457     * Splits the provided text into an array, using whitespace as the
7458     * separator, preserving all tokens, including empty tokens created by
7459     * adjacent separators. This is an alternative to using StringTokenizer.
7460     * Whitespace is defined by {@link Character#isWhitespace(char)}.
7461     *
7462     * <p>The separator is not included in the returned String array.
7463     * Adjacent separators are treated as separators for empty tokens.
7464     * For more control over the split use the StrTokenizer class.</p>
7465     *
7466     * <p>A {@code null} input String returns {@code null}.</p>
7467     *
7468     * <pre>
7469     * StringUtils.splitPreserveAllTokens(null)       = null
7470     * StringUtils.splitPreserveAllTokens("")         = []
7471     * StringUtils.splitPreserveAllTokens("abc def")  = ["abc", "def"]
7472     * StringUtils.splitPreserveAllTokens("abc  def") = ["abc", "", "def"]
7473     * StringUtils.splitPreserveAllTokens(" abc ")    = ["", "abc", ""]
7474     * </pre>
7475     *
7476     * @param str  the String to parse, may be {@code null}
7477     * @return an array of parsed Strings, {@code null} if null String input
7478     * @since 2.1
7479     */
7480    public static String[] splitPreserveAllTokens(final String str) {
7481        return splitWorker(str, null, -1, true);
7482    }
7483
7484    /**
7485     * Splits the provided text into an array, separator specified,
7486     * preserving all tokens, including empty tokens created by adjacent
7487     * separators. This is an alternative to using StringTokenizer.
7488     *
7489     * <p>The separator is not included in the returned String array.
7490     * Adjacent separators are treated as separators for empty tokens.
7491     * For more control over the split use the StrTokenizer class.</p>
7492     *
7493     * <p>A {@code null} input String returns {@code null}.</p>
7494     *
7495     * <pre>
7496     * StringUtils.splitPreserveAllTokens(null, *)         = null
7497     * StringUtils.splitPreserveAllTokens("", *)           = []
7498     * StringUtils.splitPreserveAllTokens("a.b.c", '.')    = ["a", "b", "c"]
7499     * StringUtils.splitPreserveAllTokens("a..b.c", '.')   = ["a", "", "b", "c"]
7500     * StringUtils.splitPreserveAllTokens("a:b:c", '.')    = ["a:b:c"]
7501     * StringUtils.splitPreserveAllTokens("a\tb\nc", null) = ["a", "b", "c"]
7502     * StringUtils.splitPreserveAllTokens("a b c", ' ')    = ["a", "b", "c"]
7503     * StringUtils.splitPreserveAllTokens("a b c ", ' ')   = ["a", "b", "c", ""]
7504     * StringUtils.splitPreserveAllTokens("a b c  ", ' ')  = ["a", "b", "c", "", ""]
7505     * StringUtils.splitPreserveAllTokens(" a b c", ' ')   = ["", "a", "b", "c"]
7506     * StringUtils.splitPreserveAllTokens("  a b c", ' ')  = ["", "", "a", "b", "c"]
7507     * StringUtils.splitPreserveAllTokens(" a b c ", ' ')  = ["", "a", "b", "c", ""]
7508     * </pre>
7509     *
7510     * @param str  the String to parse, may be {@code null}
7511     * @param separatorChar  the character used as the delimiter,
7512     *  {@code null} splits on whitespace
7513     * @return an array of parsed Strings, {@code null} if null String input
7514     * @since 2.1
7515     */
7516    public static String[] splitPreserveAllTokens(final String str, final char separatorChar) {
7517        return splitWorker(str, separatorChar, true);
7518    }
7519
7520    /**
7521     * Splits the provided text into an array, separators specified,
7522     * preserving all tokens, including empty tokens created by adjacent
7523     * separators. This is an alternative to using StringTokenizer.
7524     *
7525     * <p>The separator is not included in the returned String array.
7526     * Adjacent separators are treated as separators for empty tokens.
7527     * For more control over the split use the StrTokenizer class.</p>
7528     *
7529     * <p>A {@code null} input String returns {@code null}.
7530     * A {@code null} separatorChars splits on whitespace.</p>
7531     *
7532     * <pre>
7533     * StringUtils.splitPreserveAllTokens(null, *)           = null
7534     * StringUtils.splitPreserveAllTokens("", *)             = []
7535     * StringUtils.splitPreserveAllTokens("abc def", null)   = ["abc", "def"]
7536     * StringUtils.splitPreserveAllTokens("abc def", " ")    = ["abc", "def"]
7537     * StringUtils.splitPreserveAllTokens("abc  def", " ")   = ["abc", "", "def"]
7538     * StringUtils.splitPreserveAllTokens("ab:cd:ef", ":")   = ["ab", "cd", "ef"]
7539     * StringUtils.splitPreserveAllTokens("ab:cd:ef:", ":")  = ["ab", "cd", "ef", ""]
7540     * StringUtils.splitPreserveAllTokens("ab:cd:ef::", ":") = ["ab", "cd", "ef", "", ""]
7541     * StringUtils.splitPreserveAllTokens("ab::cd:ef", ":")  = ["ab", "", "cd", "ef"]
7542     * StringUtils.splitPreserveAllTokens(":cd:ef", ":")     = ["", "cd", "ef"]
7543     * StringUtils.splitPreserveAllTokens("::cd:ef", ":")    = ["", "", "cd", "ef"]
7544     * StringUtils.splitPreserveAllTokens(":cd:ef:", ":")    = ["", "cd", "ef", ""]
7545     * </pre>
7546     *
7547     * @param str  the String to parse, may be {@code null}
7548     * @param separatorChars  the characters used as the delimiters,
7549     *  {@code null} splits on whitespace
7550     * @return an array of parsed Strings, {@code null} if null String input
7551     * @since 2.1
7552     */
7553    public static String[] splitPreserveAllTokens(final String str, final String separatorChars) {
7554        return splitWorker(str, separatorChars, -1, true);
7555    }
7556
7557    /**
7558     * Splits the provided text into an array with a maximum length,
7559     * separators specified, preserving all tokens, including empty tokens
7560     * created by adjacent separators.
7561     *
7562     * <p>The separator is not included in the returned String array.
7563     * Adjacent separators are treated as separators for empty tokens.
7564     * Adjacent separators are treated as one separator.</p>
7565     *
7566     * <p>A {@code null} input String returns {@code null}.
7567     * A {@code null} separatorChars splits on whitespace.</p>
7568     *
7569     * <p>If more than {@code max} delimited substrings are found, the last
7570     * returned string includes all characters after the first {@code max - 1}
7571     * returned strings (including separator characters).</p>
7572     *
7573     * <pre>
7574     * StringUtils.splitPreserveAllTokens(null, *, *)            = null
7575     * StringUtils.splitPreserveAllTokens("", *, *)              = []
7576     * StringUtils.splitPreserveAllTokens("ab de fg", null, 0)   = ["ab", "de", "fg"]
7577     * StringUtils.splitPreserveAllTokens("ab   de fg", null, 0) = ["ab", "", "", "de", "fg"]
7578     * StringUtils.splitPreserveAllTokens("ab:cd:ef", ":", 0)    = ["ab", "cd", "ef"]
7579     * StringUtils.splitPreserveAllTokens("ab:cd:ef", ":", 2)    = ["ab", "cd:ef"]
7580     * StringUtils.splitPreserveAllTokens("ab   de fg", null, 2) = ["ab", "  de fg"]
7581     * StringUtils.splitPreserveAllTokens("ab   de fg", null, 3) = ["ab", "", " de fg"]
7582     * StringUtils.splitPreserveAllTokens("ab   de fg", null, 4) = ["ab", "", "", "de fg"]
7583     * </pre>
7584     *
7585     * @param str  the String to parse, may be {@code null}
7586     * @param separatorChars  the characters used as the delimiters,
7587     *  {@code null} splits on whitespace
7588     * @param max  the maximum number of elements to include in the
7589     *  array. A zero or negative value implies no limit
7590     * @return an array of parsed Strings, {@code null} if null String input
7591     * @since 2.1
7592     */
7593    public static String[] splitPreserveAllTokens(final String str, final String separatorChars, final int max) {
7594        return splitWorker(str, separatorChars, max, true);
7595    }
7596
7597    /**
7598     * Performs the logic for the {@code split} and
7599     * {@code splitPreserveAllTokens} methods that do not return a
7600     * maximum array length.
7601     *
7602     * @param str  the String to parse, may be {@code null}
7603     * @param separatorChar the separate character
7604     * @param preserveAllTokens if {@code true}, adjacent separators are
7605     * treated as empty token separators; if {@code false}, adjacent
7606     * separators are treated as one separator.
7607     * @return an array of parsed Strings, {@code null} if null String input
7608     */
7609    private static String[] splitWorker(final String str, final char separatorChar, final boolean preserveAllTokens) {
7610        // Performance tuned for 2.0 (JDK1.4)
7611        if (str == null) {
7612            return null;
7613        }
7614        final int len = str.length();
7615        if (len == 0) {
7616            return ArrayUtils.EMPTY_STRING_ARRAY;
7617        }
7618        final List<String> list = new ArrayList<>();
7619        int i = 0;
7620        int start = 0;
7621        boolean match = false;
7622        boolean lastMatch = false;
7623        while (i < len) {
7624            if (str.charAt(i) == separatorChar) {
7625                if (match || preserveAllTokens) {
7626                    list.add(str.substring(start, i));
7627                    match = false;
7628                    lastMatch = true;
7629                }
7630                start = ++i;
7631                continue;
7632            }
7633            lastMatch = false;
7634            match = true;
7635            i++;
7636        }
7637        if (match || preserveAllTokens && lastMatch) {
7638            list.add(str.substring(start, i));
7639        }
7640        return list.toArray(ArrayUtils.EMPTY_STRING_ARRAY);
7641    }
7642
7643    /**
7644     * Performs the logic for the {@code split} and
7645     * {@code splitPreserveAllTokens} methods that return a maximum array
7646     * length.
7647     *
7648     * @param str  the String to parse, may be {@code null}
7649     * @param separatorChars the separate character
7650     * @param max  the maximum number of elements to include in the
7651     *  array. A zero or negative value implies no limit.
7652     * @param preserveAllTokens if {@code true}, adjacent separators are
7653     * treated as empty token separators; if {@code false}, adjacent
7654     * separators are treated as one separator.
7655     * @return an array of parsed Strings, {@code null} if null String input
7656     */
7657    private static String[] splitWorker(final String str, final String separatorChars, final int max, final boolean preserveAllTokens) {
7658        // Performance tuned for 2.0 (JDK1.4)
7659        // Direct code is quicker than StringTokenizer.
7660        // Also, StringTokenizer uses isSpace() not isWhitespace()
7661
7662        if (str == null) {
7663            return null;
7664        }
7665        final int len = str.length();
7666        if (len == 0) {
7667            return ArrayUtils.EMPTY_STRING_ARRAY;
7668        }
7669        final List<String> list = new ArrayList<>();
7670        int sizePlus1 = 1;
7671        int i = 0;
7672        int start = 0;
7673        boolean match = false;
7674        boolean lastMatch = false;
7675        if (separatorChars == null) {
7676            // Null separator means use whitespace
7677            while (i < len) {
7678                if (Character.isWhitespace(str.charAt(i))) {
7679                    if (match || preserveAllTokens) {
7680                        lastMatch = true;
7681                        if (sizePlus1++ == max) {
7682                            i = len;
7683                            lastMatch = false;
7684                        }
7685                        list.add(str.substring(start, i));
7686                        match = false;
7687                    }
7688                    start = ++i;
7689                    continue;
7690                }
7691                lastMatch = false;
7692                match = true;
7693                i++;
7694            }
7695        } else if (separatorChars.length() == 1) {
7696            // Optimize 1 character case
7697            final char sep = separatorChars.charAt(0);
7698            while (i < len) {
7699                if (str.charAt(i) == sep) {
7700                    if (match || preserveAllTokens) {
7701                        lastMatch = true;
7702                        if (sizePlus1++ == max) {
7703                            i = len;
7704                            lastMatch = false;
7705                        }
7706                        list.add(str.substring(start, i));
7707                        match = false;
7708                    }
7709                    start = ++i;
7710                    continue;
7711                }
7712                lastMatch = false;
7713                match = true;
7714                i++;
7715            }
7716        } else {
7717            // standard case
7718            while (i < len) {
7719                if (separatorChars.indexOf(str.charAt(i)) >= 0) {
7720                    if (match || preserveAllTokens) {
7721                        lastMatch = true;
7722                        if (sizePlus1++ == max) {
7723                            i = len;
7724                            lastMatch = false;
7725                        }
7726                        list.add(str.substring(start, i));
7727                        match = false;
7728                    }
7729                    start = ++i;
7730                    continue;
7731                }
7732                lastMatch = false;
7733                match = true;
7734                i++;
7735            }
7736        }
7737        if (match || preserveAllTokens && lastMatch) {
7738            list.add(str.substring(start, i));
7739        }
7740        return list.toArray(ArrayUtils.EMPTY_STRING_ARRAY);
7741    }
7742
7743    /**
7744     * Tests if a CharSequence starts with a specified prefix.
7745     *
7746     * <p>{@code null}s are handled without exceptions. Two {@code null}
7747     * references are considered to be equal. The comparison is case-sensitive.</p>
7748     *
7749     * <pre>
7750     * StringUtils.startsWith(null, null)      = true
7751     * StringUtils.startsWith(null, "abc")     = false
7752     * StringUtils.startsWith("abcdef", null)  = false
7753     * StringUtils.startsWith("abcdef", "abc") = true
7754     * StringUtils.startsWith("ABCDEF", "abc") = false
7755     * </pre>
7756     *
7757     * @see String#startsWith(String)
7758     * @param str  the CharSequence to check, may be null
7759     * @param prefix the prefix to find, may be null
7760     * @return {@code true} if the CharSequence starts with the prefix, case-sensitive, or
7761     *  both {@code null}
7762     * @since 2.4
7763     * @since 3.0 Changed signature from startsWith(String, String) to startsWith(CharSequence, CharSequence)
7764     * @deprecated Use {@link Strings#startsWith(CharSequence, CharSequence) Strings.CS.startsWith(CharSequence, CharSequence)}
7765     */
7766    @Deprecated
7767    public static boolean startsWith(final CharSequence str, final CharSequence prefix) {
7768        return Strings.CS.startsWith(str, prefix);
7769    }
7770
7771    /**
7772     * Tests if a CharSequence starts with any of the provided case-sensitive prefixes.
7773     *
7774     * <pre>
7775     * StringUtils.startsWithAny(null, null)      = false
7776     * StringUtils.startsWithAny(null, new String[] {"abc"})  = false
7777     * StringUtils.startsWithAny("abcxyz", null)     = false
7778     * StringUtils.startsWithAny("abcxyz", new String[] {""}) = true
7779     * StringUtils.startsWithAny("abcxyz", new String[] {"abc"}) = true
7780     * StringUtils.startsWithAny("abcxyz", new String[] {null, "xyz", "abc"}) = true
7781     * StringUtils.startsWithAny("abcxyz", null, "xyz", "ABCX") = false
7782     * StringUtils.startsWithAny("ABCXYZ", null, "xyz", "abc") = false
7783     * </pre>
7784     *
7785     * @param sequence the CharSequence to check, may be null
7786     * @param searchStrings the case-sensitive CharSequence prefixes, may be empty or contain {@code null}
7787     * @see StringUtils#startsWith(CharSequence, CharSequence)
7788     * @return {@code true} if the input {@code sequence} is {@code null} AND no {@code searchStrings} are provided, or
7789     *   the input {@code sequence} begins with any of the provided case-sensitive {@code searchStrings}.
7790     * @since 2.5
7791     * @since 3.0 Changed signature from startsWithAny(String, String[]) to startsWithAny(CharSequence, CharSequence...)
7792     * @deprecated Use {@link Strings#startsWithAny(CharSequence, CharSequence...) Strings.CI.startsWithAny(CharSequence, CharSequence...)}
7793     */
7794    @Deprecated
7795    public static boolean startsWithAny(final CharSequence sequence, final CharSequence... searchStrings) {
7796        return Strings.CS.startsWithAny(sequence, searchStrings);
7797    }
7798
7799    /**
7800     * Case-insensitive check if a CharSequence starts with a specified prefix.
7801     *
7802     * <p>{@code null}s are handled without exceptions. Two {@code null}
7803     * references are considered to be equal. The comparison is case insensitive.</p>
7804     *
7805     * <pre>
7806     * StringUtils.startsWithIgnoreCase(null, null)      = true
7807     * StringUtils.startsWithIgnoreCase(null, "abc")     = false
7808     * StringUtils.startsWithIgnoreCase("abcdef", null)  = false
7809     * StringUtils.startsWithIgnoreCase("abcdef", "abc") = true
7810     * StringUtils.startsWithIgnoreCase("ABCDEF", "abc") = true
7811     * </pre>
7812     *
7813     * @see String#startsWith(String)
7814     * @param str  the CharSequence to check, may be null
7815     * @param prefix the prefix to find, may be null
7816     * @return {@code true} if the CharSequence starts with the prefix, case-insensitive, or
7817     *  both {@code null}
7818     * @since 2.4
7819     * @since 3.0 Changed signature from startsWithIgnoreCase(String, String) to startsWithIgnoreCase(CharSequence, CharSequence)
7820     * @deprecated Use {@link Strings#startsWith(CharSequence, CharSequence) Strings.CI.startsWith(CharSequence, CharSequence)}
7821     */
7822    @Deprecated
7823    public static boolean startsWithIgnoreCase(final CharSequence str, final CharSequence prefix) {
7824        return Strings.CI.startsWith(str, prefix);
7825    }
7826
7827    /**
7828     * Strips whitespace from the start and end of a String.
7829     *
7830     * <p>This is similar to {@link #trim(String)} but removes whitespace.
7831     * Whitespace is defined by {@link Character#isWhitespace(char)}.</p>
7832     *
7833     * <p>A {@code null} input String returns {@code null}.</p>
7834     *
7835     * <pre>
7836     * StringUtils.strip(null)     = null
7837     * StringUtils.strip("")       = ""
7838     * StringUtils.strip("   ")    = ""
7839     * StringUtils.strip("abc")    = "abc"
7840     * StringUtils.strip("  abc")  = "abc"
7841     * StringUtils.strip("abc  ")  = "abc"
7842     * StringUtils.strip(" abc ")  = "abc"
7843     * StringUtils.strip(" ab c ") = "ab c"
7844     * </pre>
7845     *
7846     * @param str  the String to remove whitespace from, may be null
7847     * @return the stripped String, {@code null} if null String input
7848     */
7849    public static String strip(final String str) {
7850        return strip(str, null);
7851    }
7852
7853    /**
7854     * Strips any of a set of characters from the start and end of a String.
7855     * This is similar to {@link String#trim()} but allows the characters
7856     * to be stripped to be controlled.
7857     *
7858     * <p>A {@code null} input String returns {@code null}.
7859     * An empty string ("") input returns the empty string.</p>
7860     *
7861     * <p>If the stripChars String is {@code null}, whitespace is
7862     * stripped as defined by {@link Character#isWhitespace(char)}.
7863     * Alternatively use {@link #strip(String)}.</p>
7864     *
7865     * <pre>
7866     * StringUtils.strip(null, *)          = null
7867     * StringUtils.strip("", *)            = ""
7868     * StringUtils.strip("abc", null)      = "abc"
7869     * StringUtils.strip("  abc", null)    = "abc"
7870     * StringUtils.strip("abc  ", null)    = "abc"
7871     * StringUtils.strip(" abc ", null)    = "abc"
7872     * StringUtils.strip("  abcyx", "xyz") = "  abc"
7873     * </pre>
7874     *
7875     * @param str  the String to remove characters from, may be null
7876     * @param stripChars  the characters to remove, null treated as whitespace
7877     * @return the stripped String, {@code null} if null String input
7878     */
7879    public static String strip(String str, final String stripChars) {
7880        str = stripStart(str, stripChars);
7881        return stripEnd(str, stripChars);
7882    }
7883
7884    /**
7885     * Removes diacritics (~= accents) from a string. The case will not be altered.
7886     * <p>
7887     * For instance, '&agrave;' will be replaced by 'a'.
7888     * </p>
7889     * <p>
7890     * Decomposes ligatures and digraphs per the KD column in the <a href = "https://www.unicode.org/charts/normalization/">Unicode Normalization Chart.</a>
7891     * </p>
7892     * <pre>
7893     * StringUtils.stripAccents(null)         = null
7894     * StringUtils.stripAccents("")           = ""
7895     * StringUtils.stripAccents("control")    = "control"
7896     * StringUtils.stripAccents("&eacute;clair")     = "eclair"
7897     * StringUtils.stripAccents("\u1d43\u1d47\u1d9c\u00b9\u00b2\u00b3")     = "abc123"
7898     * StringUtils.stripAccents("\u00BC \u00BD \u00BE")      = "1⁄4 1⁄2 3⁄4"
7899     * </pre>
7900     * <p>
7901     * See also <a href="http://www.unicode.org/unicode/reports/tr15/tr15-23.html">Unicode Standard Annex #15 Unicode Normalization Forms</a>.
7902     * </p>
7903     *
7904     * @param input String to be stripped
7905     * @return input text with diacritics removed
7906     * @since 3.0
7907     */
7908    // See also Lucene's ASCIIFoldingFilter (Lucene 2.9) that replaces accented characters by their unaccented equivalent (and uncommitted bug fix: https://issues.apache.org/jira/browse/LUCENE-1343?focusedCommentId=12858907&page=com.atlassian.jira.plugin.system.issuetabpanels%3Acomment-tabpanel#action_12858907).
7909    public static String stripAccents(final String input) {
7910        if (isEmpty(input)) {
7911            return input;
7912        }
7913        final StringBuilder decomposed = new StringBuilder(Normalizer.normalize(input, Normalizer.Form.NFKD));
7914        convertRemainingAccentCharacters(decomposed);
7915        return STRIP_ACCENTS_PATTERN.matcher(decomposed).replaceAll(EMPTY);
7916    }
7917
7918    /**
7919     * Strips whitespace from the start and end of every String in an array.
7920     * Whitespace is defined by {@link Character#isWhitespace(char)}.
7921     *
7922     * <p>A new array is returned each time, except for length zero.
7923     * A {@code null} array will return {@code null}.
7924     * An empty array will return itself.
7925     * A {@code null} array entry will be ignored.</p>
7926     *
7927     * <pre>
7928     * StringUtils.stripAll(null)             = null
7929     * StringUtils.stripAll([])               = []
7930     * StringUtils.stripAll(["abc", "  abc"]) = ["abc", "abc"]
7931     * StringUtils.stripAll(["abc  ", null])  = ["abc", null]
7932     * </pre>
7933     *
7934     * @param strs  the array to remove whitespace from, may be null
7935     * @return the stripped Strings, {@code null} if null array input
7936     */
7937    public static String[] stripAll(final String... strs) {
7938        return stripAll(strs, null);
7939    }
7940
7941    /**
7942     * Strips any of a set of characters from the start and end of every
7943     * String in an array.
7944     * <p>Whitespace is defined by {@link Character#isWhitespace(char)}.</p>
7945     *
7946     * <p>A new array is returned each time, except for length zero.
7947     * A {@code null} array will return {@code null}.
7948     * An empty array will return itself.
7949     * A {@code null} array entry will be ignored.
7950     * A {@code null} stripChars will strip whitespace as defined by
7951     * {@link Character#isWhitespace(char)}.</p>
7952     *
7953     * <pre>
7954     * StringUtils.stripAll(null, *)                = null
7955     * StringUtils.stripAll([], *)                  = []
7956     * StringUtils.stripAll(["abc", "  abc"], null) = ["abc", "abc"]
7957     * StringUtils.stripAll(["abc  ", null], null)  = ["abc", null]
7958     * StringUtils.stripAll(["abc  ", null], "yz")  = ["abc  ", null]
7959     * StringUtils.stripAll(["yabcz", null], "yz")  = ["abc", null]
7960     * </pre>
7961     *
7962     * @param strs  the array to remove characters from, may be null
7963     * @param stripChars  the characters to remove, null treated as whitespace
7964     * @return the stripped Strings, {@code null} if null array input
7965     */
7966    public static String[] stripAll(final String[] strs, final String stripChars) {
7967        final int strsLen = ArrayUtils.getLength(strs);
7968        if (strsLen == 0) {
7969            return strs;
7970        }
7971        final String[] newArr = new String[strsLen];
7972        Arrays.setAll(newArr, i -> strip(strs[i], stripChars));
7973        return newArr;
7974    }
7975
7976    /**
7977     * Strips any of a set of characters from the end of a String.
7978     *
7979     * <p>A {@code null} input String returns {@code null}.
7980     * An empty string ("") input returns the empty string.</p>
7981     *
7982     * <p>If the stripChars String is {@code null}, whitespace is
7983     * stripped as defined by {@link Character#isWhitespace(char)}.</p>
7984     *
7985     * <pre>
7986     * StringUtils.stripEnd(null, *)          = null
7987     * StringUtils.stripEnd("", *)            = ""
7988     * StringUtils.stripEnd("abc", "")        = "abc"
7989     * StringUtils.stripEnd("abc", null)      = "abc"
7990     * StringUtils.stripEnd("  abc", null)    = "  abc"
7991     * StringUtils.stripEnd("abc  ", null)    = "abc"
7992     * StringUtils.stripEnd(" abc ", null)    = " abc"
7993     * StringUtils.stripEnd("  abcyx", "xyz") = "  abc"
7994     * StringUtils.stripEnd("120.00", ".0")   = "12"
7995     * </pre>
7996     *
7997     * @param str  the String to remove characters from, may be null
7998     * @param stripChars  the set of characters to remove, null treated as whitespace
7999     * @return the stripped String, {@code null} if null String input
8000     */
8001    public static String stripEnd(final String str, final String stripChars) {
8002        int end = length(str);
8003        if (end == 0) {
8004            return str;
8005        }
8006
8007        if (stripChars == null) {
8008            while (end != 0 && Character.isWhitespace(str.charAt(end - 1))) {
8009                end--;
8010            }
8011        } else if (stripChars.isEmpty()) {
8012            return str;
8013        } else {
8014            while (end != 0 && stripChars.indexOf(str.charAt(end - 1)) != INDEX_NOT_FOUND) {
8015                end--;
8016            }
8017        }
8018        return str.substring(0, end);
8019    }
8020
8021    /**
8022     * Strips any of a set of characters from the start of a String.
8023     *
8024     * <p>A {@code null} input String returns {@code null}.
8025     * An empty string ("") input returns the empty string.</p>
8026     *
8027     * <p>If the stripChars String is {@code null}, whitespace is
8028     * stripped as defined by {@link Character#isWhitespace(char)}.</p>
8029     *
8030     * <pre>
8031     * StringUtils.stripStart(null, *)          = null
8032     * StringUtils.stripStart("", *)            = ""
8033     * StringUtils.stripStart("abc", "")        = "abc"
8034     * StringUtils.stripStart("abc", null)      = "abc"
8035     * StringUtils.stripStart("  abc", null)    = "abc"
8036     * StringUtils.stripStart("abc  ", null)    = "abc  "
8037     * StringUtils.stripStart(" abc ", null)    = "abc "
8038     * StringUtils.stripStart("yxabc  ", "xyz") = "abc  "
8039     * </pre>
8040     *
8041     * @param str  the String to remove characters from, may be null
8042     * @param stripChars  the characters to remove, null treated as whitespace
8043     * @return the stripped String, {@code null} if null String input
8044     */
8045    public static String stripStart(final String str, final String stripChars) {
8046        final int strLen = length(str);
8047        if (strLen == 0) {
8048            return str;
8049        }
8050        int start = 0;
8051        if (stripChars == null) {
8052            while (start != strLen && Character.isWhitespace(str.charAt(start))) {
8053                start++;
8054            }
8055        } else if (stripChars.isEmpty()) {
8056            return str;
8057        } else {
8058            while (start != strLen && stripChars.indexOf(str.charAt(start)) != INDEX_NOT_FOUND) {
8059                start++;
8060            }
8061        }
8062        return str.substring(start);
8063    }
8064
8065    /**
8066     * Strips whitespace from the start and end of a String  returning
8067     * an empty String if {@code null} input.
8068     *
8069     * <p>This is similar to {@link #trimToEmpty(String)} but removes whitespace.
8070     * Whitespace is defined by {@link Character#isWhitespace(char)}.</p>
8071     *
8072     * <pre>
8073     * StringUtils.stripToEmpty(null)     = ""
8074     * StringUtils.stripToEmpty("")       = ""
8075     * StringUtils.stripToEmpty("   ")    = ""
8076     * StringUtils.stripToEmpty("abc")    = "abc"
8077     * StringUtils.stripToEmpty("  abc")  = "abc"
8078     * StringUtils.stripToEmpty("abc  ")  = "abc"
8079     * StringUtils.stripToEmpty(" abc ")  = "abc"
8080     * StringUtils.stripToEmpty(" ab c ") = "ab c"
8081     * </pre>
8082     *
8083     * @param str  the String to be stripped, may be null
8084     * @return the trimmed String, or an empty String if {@code null} input
8085     * @since 2.0
8086     */
8087    public static String stripToEmpty(final String str) {
8088        return str == null ? EMPTY : strip(str, null);
8089    }
8090
8091    /**
8092     * Strips whitespace from the start and end of a String  returning
8093     * {@code null} if the String is empty ("") after the strip.
8094     *
8095     * <p>This is similar to {@link #trimToNull(String)} but removes whitespace.
8096     * Whitespace is defined by {@link Character#isWhitespace(char)}.</p>
8097     *
8098     * <pre>
8099     * StringUtils.stripToNull(null)     = null
8100     * StringUtils.stripToNull("")       = null
8101     * StringUtils.stripToNull("   ")    = null
8102     * StringUtils.stripToNull("abc")    = "abc"
8103     * StringUtils.stripToNull("  abc")  = "abc"
8104     * StringUtils.stripToNull("abc  ")  = "abc"
8105     * StringUtils.stripToNull(" abc ")  = "abc"
8106     * StringUtils.stripToNull(" ab c ") = "ab c"
8107     * </pre>
8108     *
8109     * @param str  the String to be stripped, may be null
8110     * @return the stripped String,
8111     *  {@code null} if whitespace, empty or null String input
8112     * @since 2.0
8113     */
8114    public static String stripToNull(String str) {
8115        if (str == null) {
8116            return null;
8117        }
8118        str = strip(str, null);
8119        return str.isEmpty() ? null : str; // NOSONARLINT str cannot be null here
8120    }
8121
8122    /**
8123     * Gets a substring from the specified String avoiding exceptions.
8124     *
8125     * <p>A negative start position can be used to start {@code n}
8126     * characters from the end of the String.</p>
8127     *
8128     * <p>A {@code null} String will return {@code null}.
8129     * An empty ("") String will return "".</p>
8130     *
8131     * <pre>
8132     * StringUtils.substring(null, *)   = null
8133     * StringUtils.substring("", *)     = ""
8134     * StringUtils.substring("abc", 0)  = "abc"
8135     * StringUtils.substring("abc", 2)  = "c"
8136     * StringUtils.substring("abc", 4)  = ""
8137     * StringUtils.substring("abc", -2) = "bc"
8138     * StringUtils.substring("abc", -4) = "abc"
8139     * </pre>
8140     *
8141     * @param str  the String to get the substring from, may be null
8142     * @param start  the position to start from, negative means
8143     *  count back from the end of the String by this many characters
8144     * @return substring from start position, {@code null} if null String input
8145     */
8146    public static String substring(final String str, int start) {
8147        if (str == null) {
8148            return null;
8149        }
8150
8151        // handle negatives, which means last n characters
8152        if (start < 0) {
8153            start = str.length() + start; // remember start is negative
8154        }
8155
8156        if (start < 0) {
8157            start = 0;
8158        }
8159        if (start > str.length()) {
8160            return EMPTY;
8161        }
8162
8163        return str.substring(start);
8164    }
8165
8166    /**
8167     * Gets a substring from the specified String avoiding exceptions.
8168     *
8169     * <p>A negative start position can be used to start/end {@code n}
8170     * characters from the end of the String.</p>
8171     *
8172     * <p>The returned substring starts with the character in the {@code start}
8173     * position and ends before the {@code end} position. All position counting is
8174     * zero-based -- i.e., to start at the beginning of the string use
8175     * {@code start = 0}. Negative start and end positions can be used to
8176     * specify offsets relative to the end of the String.</p>
8177     *
8178     * <p>If {@code start} is not strictly to the left of {@code end}, ""
8179     * is returned.</p>
8180     *
8181     * <pre>
8182     * StringUtils.substring(null, *, *)    = null
8183     * StringUtils.substring("", * ,  *)    = "";
8184     * StringUtils.substring("abc", 0, 2)   = "ab"
8185     * StringUtils.substring("abc", 2, 0)   = ""
8186     * StringUtils.substring("abc", 2, 4)   = "c"
8187     * StringUtils.substring("abc", 4, 6)   = ""
8188     * StringUtils.substring("abc", 2, 2)   = ""
8189     * StringUtils.substring("abc", -2, -1) = "b"
8190     * StringUtils.substring("abc", -4, 2)  = "ab"
8191     * </pre>
8192     *
8193     * @param str  the String to get the substring from, may be null
8194     * @param start  the position to start from, negative means
8195     *  count back from the end of the String by this many characters
8196     * @param end  the position to end at (exclusive), negative means
8197     *  count back from the end of the String by this many characters
8198     * @return substring from start position to end position,
8199     *  {@code null} if null String input
8200     */
8201    public static String substring(final String str, int start, int end) {
8202        if (str == null) {
8203            return null;
8204        }
8205
8206        // handle negatives
8207        if (end < 0) {
8208            end = str.length() + end; // remember end is negative
8209        }
8210        if (start < 0) {
8211            start = str.length() + start; // remember start is negative
8212        }
8213
8214        // check length next
8215        if (end > str.length()) {
8216            end = str.length();
8217        }
8218
8219        // if start is greater than end, return ""
8220        if (start > end) {
8221            return EMPTY;
8222        }
8223
8224        if (start < 0) {
8225            start = 0;
8226        }
8227        if (end < 0) {
8228            end = 0;
8229        }
8230
8231        return str.substring(start, end);
8232    }
8233
8234    /**
8235     * Gets the substring after the first occurrence of a separator.
8236     * The separator is not returned.
8237     *
8238     * <p>A {@code null} string input will return {@code null}.
8239     * An empty ("") string input will return the empty string.
8240     *
8241     * <p>If nothing is found, the empty string is returned.</p>
8242     *
8243     * <pre>
8244     * StringUtils.substringAfter(null, *)      = null
8245     * StringUtils.substringAfter("", *)        = ""
8246     * StringUtils.substringAfter("abc", 'a')   = "bc"
8247     * StringUtils.substringAfter("abcba", 'b') = "cba"
8248     * StringUtils.substringAfter("abc", 'c')   = ""
8249     * StringUtils.substringAfter("abc", 'd')   = ""
8250     * StringUtils.substringAfter(" abc", 32)   = "abc"
8251     * </pre>
8252     *
8253     * @param str  the String to get a substring from, may be null
8254     * @param separator  the character (Unicode code point) to search.
8255     * @return the substring after the first occurrence of the separator,
8256     *  {@code null} if null String input
8257     * @since 3.11
8258     */
8259    public static String substringAfter(final String str, final int separator) {
8260        if (isEmpty(str)) {
8261            return str;
8262        }
8263        final int pos = str.indexOf(separator);
8264        if (pos == INDEX_NOT_FOUND) {
8265            return EMPTY;
8266        }
8267        return str.substring(pos + 1);
8268    }
8269
8270    /**
8271     * Gets the substring after the first occurrence of a separator.
8272     * The separator is not returned.
8273     *
8274     * <p>A {@code null} string input will return {@code null}.
8275     * An empty ("") string input will return the empty string.
8276     * A {@code null} separator will return the empty string if the
8277     * input string is not {@code null}.</p>
8278     *
8279     * <p>If nothing is found, the empty string is returned.</p>
8280     *
8281     * <pre>
8282     * StringUtils.substringAfter(null, *)      = null
8283     * StringUtils.substringAfter("", *)        = ""
8284     * StringUtils.substringAfter(*, null)      = ""
8285     * StringUtils.substringAfter("abc", "a")   = "bc"
8286     * StringUtils.substringAfter("abcba", "b") = "cba"
8287     * StringUtils.substringAfter("abc", "c")   = ""
8288     * StringUtils.substringAfter("abc", "d")   = ""
8289     * StringUtils.substringAfter("abc", "")    = "abc"
8290     * </pre>
8291     *
8292     * @param str  the String to get a substring from, may be null
8293     * @param separator  the String to search for, may be null
8294     * @return the substring after the first occurrence of the separator,
8295     *  {@code null} if null String input
8296     * @since 2.0
8297     */
8298    public static String substringAfter(final String str, final String separator) {
8299        if (isEmpty(str)) {
8300            return str;
8301        }
8302        if (separator == null) {
8303            return EMPTY;
8304        }
8305        final int pos = str.indexOf(separator);
8306        if (pos == INDEX_NOT_FOUND) {
8307            return EMPTY;
8308        }
8309        return str.substring(pos + separator.length());
8310    }
8311
8312    /**
8313     * Gets the substring after the last occurrence of a separator.
8314     * The separator is not returned.
8315     *
8316     * <p>A {@code null} string input will return {@code null}.
8317     * An empty ("") string input will return the empty string.
8318     *
8319     * <p>If nothing is found, the empty string is returned.</p>
8320     *
8321     * <pre>
8322     * StringUtils.substringAfterLast(null, *)      = null
8323     * StringUtils.substringAfterLast("", *)        = ""
8324     * StringUtils.substringAfterLast("abc", 'a')   = "bc"
8325     * StringUtils.substringAfterLast(" bc", 32)    = "bc"
8326     * StringUtils.substringAfterLast("abcba", 'b') = "a"
8327     * StringUtils.substringAfterLast("abc", 'c')   = ""
8328     * StringUtils.substringAfterLast("a", 'a')     = ""
8329     * StringUtils.substringAfterLast("a", 'z')     = ""
8330     * </pre>
8331     *
8332     * @param str  the String to get a substring from, may be null
8333     * @param separator  the character (Unicode code point) to search.
8334     * @return the substring after the last occurrence of the separator,
8335     *  {@code null} if null String input
8336     * @since 3.11
8337     */
8338    public static String substringAfterLast(final String str, final int separator) {
8339        if (isEmpty(str)) {
8340            return str;
8341        }
8342        final int pos = str.lastIndexOf(separator);
8343        if (pos == INDEX_NOT_FOUND || pos == str.length() - 1) {
8344            return EMPTY;
8345        }
8346        return str.substring(pos + 1);
8347    }
8348
8349    /**
8350     * Gets the substring after the last occurrence of a separator.
8351     * The separator is not returned.
8352     *
8353     * <p>A {@code null} string input will return {@code null}.
8354     * An empty ("") string input will return the empty string.
8355     * An empty or {@code null} separator will return the empty string if
8356     * the input string is not {@code null}.</p>
8357     *
8358     * <p>If nothing is found, the empty string is returned.</p>
8359     *
8360     * <pre>
8361     * StringUtils.substringAfterLast(null, *)      = null
8362     * StringUtils.substringAfterLast("", *)        = ""
8363     * StringUtils.substringAfterLast(*, "")        = ""
8364     * StringUtils.substringAfterLast(*, null)      = ""
8365     * StringUtils.substringAfterLast("abc", "a")   = "bc"
8366     * StringUtils.substringAfterLast("abcba", "b") = "a"
8367     * StringUtils.substringAfterLast("abc", "c")   = ""
8368     * StringUtils.substringAfterLast("a", "a")     = ""
8369     * StringUtils.substringAfterLast("a", "z")     = ""
8370     * </pre>
8371     *
8372     * @param str  the String to get a substring from, may be null
8373     * @param separator  the String to search for, may be null
8374     * @return the substring after the last occurrence of the separator,
8375     *  {@code null} if null String input
8376     * @since 2.0
8377     */
8378    public static String substringAfterLast(final String str, final String separator) {
8379        if (isEmpty(str)) {
8380            return str;
8381        }
8382        if (isEmpty(separator)) {
8383            return EMPTY;
8384        }
8385        final int pos = str.lastIndexOf(separator);
8386        if (pos == INDEX_NOT_FOUND || pos == str.length() - separator.length()) {
8387            return EMPTY;
8388        }
8389        return str.substring(pos + separator.length());
8390    }
8391
8392    /**
8393     * Gets the substring before the first occurrence of a separator. The separator is not returned.
8394     *
8395     * <p>
8396     * A {@code null} string input will return {@code null}. An empty ("") string input will return the empty string.
8397     * </p>
8398     *
8399     * <p>
8400     * If nothing is found, the string input is returned.
8401     * </p>
8402     *
8403     * <pre>
8404     * StringUtils.substringBefore(null, *)      = null
8405     * StringUtils.substringBefore("", *)        = ""
8406     * StringUtils.substringBefore("abc", 'a')   = ""
8407     * StringUtils.substringBefore("abcba", 'b') = "a"
8408     * StringUtils.substringBefore("abc", 'c')   = "ab"
8409     * StringUtils.substringBefore("abc", 'd')   = "abc"
8410     * </pre>
8411     *
8412     * @param str the String to get a substring from, may be null
8413     * @param separator the character (Unicode code point) to search.
8414     * @return the substring before the first occurrence of the separator, {@code null} if null String input
8415     * @since 3.12.0
8416     */
8417    public static String substringBefore(final String str, final int separator) {
8418        if (isEmpty(str)) {
8419            return str;
8420        }
8421        final int pos = str.indexOf(separator);
8422        if (pos == INDEX_NOT_FOUND) {
8423            return str;
8424        }
8425        return str.substring(0, pos);
8426    }
8427
8428    /**
8429     * Gets the substring before the first occurrence of a separator.
8430     * The separator is not returned.
8431     *
8432     * <p>A {@code null} string input will return {@code null}.
8433     * An empty ("") string input will return the empty string.
8434     * A {@code null} separator will return the input string.</p>
8435     *
8436     * <p>If nothing is found, the string input is returned.</p>
8437     *
8438     * <pre>
8439     * StringUtils.substringBefore(null, *)      = null
8440     * StringUtils.substringBefore("", *)        = ""
8441     * StringUtils.substringBefore("abc", "a")   = ""
8442     * StringUtils.substringBefore("abcba", "b") = "a"
8443     * StringUtils.substringBefore("abc", "c")   = "ab"
8444     * StringUtils.substringBefore("abc", "d")   = "abc"
8445     * StringUtils.substringBefore("abc", "")    = ""
8446     * StringUtils.substringBefore("abc", null)  = "abc"
8447     * </pre>
8448     *
8449     * @param str  the String to get a substring from, may be null
8450     * @param separator  the String to search for, may be null
8451     * @return the substring before the first occurrence of the separator,
8452     *  {@code null} if null String input
8453     * @since 2.0
8454     */
8455    public static String substringBefore(final String str, final String separator) {
8456        if (isEmpty(str) || separator == null) {
8457            return str;
8458        }
8459        if (separator.isEmpty()) {
8460            return EMPTY;
8461        }
8462        final int pos = str.indexOf(separator);
8463        if (pos == INDEX_NOT_FOUND) {
8464            return str;
8465        }
8466        return str.substring(0, pos);
8467    }
8468
8469    /**
8470     * Gets the substring before the last occurrence of a separator.
8471     * The separator is not returned.
8472     *
8473     * <p>A {@code null} string input will return {@code null}.
8474     * An empty ("") string input will return the empty string.
8475     * An empty or {@code null} separator will return the input string.</p>
8476     *
8477     * <p>If nothing is found, the string input is returned.</p>
8478     *
8479     * <pre>
8480     * StringUtils.substringBeforeLast(null, *)      = null
8481     * StringUtils.substringBeforeLast("", *)        = ""
8482     * StringUtils.substringBeforeLast("abcba", "b") = "abc"
8483     * StringUtils.substringBeforeLast("abc", "c")   = "ab"
8484     * StringUtils.substringBeforeLast("a", "a")     = ""
8485     * StringUtils.substringBeforeLast("a", "z")     = "a"
8486     * StringUtils.substringBeforeLast("a", null)    = "a"
8487     * StringUtils.substringBeforeLast("a", "")      = "a"
8488     * </pre>
8489     *
8490     * @param str  the String to get a substring from, may be null
8491     * @param separator  the String to search for, may be null
8492     * @return the substring before the last occurrence of the separator,
8493     *  {@code null} if null String input
8494     * @since 2.0
8495     */
8496    public static String substringBeforeLast(final String str, final String separator) {
8497        if (isEmpty(str) || isEmpty(separator)) {
8498            return str;
8499        }
8500        final int pos = str.lastIndexOf(separator);
8501        if (pos == INDEX_NOT_FOUND) {
8502            return str;
8503        }
8504        return str.substring(0, pos);
8505    }
8506
8507    /**
8508     * Gets the String that is nested in between two instances of the
8509     * same String.
8510     *
8511     * <p>A {@code null} input String returns {@code null}.
8512     * A {@code null} tag returns {@code null}.</p>
8513     *
8514     * <pre>
8515     * StringUtils.substringBetween(null, *)            = null
8516     * StringUtils.substringBetween("", "")             = ""
8517     * StringUtils.substringBetween("", "tag")          = null
8518     * StringUtils.substringBetween("tagabctag", null)  = null
8519     * StringUtils.substringBetween("tagabctag", "")    = ""
8520     * StringUtils.substringBetween("tagabctag", "tag") = "abc"
8521     * </pre>
8522     *
8523     * @param str  the String containing the substring, may be null
8524     * @param tag  the String before and after the substring, may be null
8525     * @return the substring, {@code null} if no match
8526     * @since 2.0
8527     */
8528    public static String substringBetween(final String str, final String tag) {
8529        return substringBetween(str, tag, tag);
8530    }
8531
8532    /**
8533     * Gets the String that is nested in between two Strings.
8534     * Only the first match is returned.
8535     *
8536     * <p>A {@code null} input String returns {@code null}.
8537     * A {@code null} open/close returns {@code null} (no match).
8538     * An empty ("") open and close returns an empty string.</p>
8539     *
8540     * <pre>
8541     * StringUtils.substringBetween("wx[b]yz", "[", "]") = "b"
8542     * StringUtils.substringBetween(null, *, *)          = null
8543     * StringUtils.substringBetween(*, null, *)          = null
8544     * StringUtils.substringBetween(*, *, null)          = null
8545     * StringUtils.substringBetween("", "", "")          = ""
8546     * StringUtils.substringBetween("", "", "]")         = null
8547     * StringUtils.substringBetween("", "[", "]")        = null
8548     * StringUtils.substringBetween("yabcz", "", "")     = ""
8549     * StringUtils.substringBetween("yabcz", "y", "z")   = "abc"
8550     * StringUtils.substringBetween("yabczyabcz", "y", "z")   = "abc"
8551     * </pre>
8552     *
8553     * @param str  the String containing the substring, may be null
8554     * @param open  the String before the substring, may be null
8555     * @param close  the String after the substring, may be null
8556     * @return the substring, {@code null} if no match
8557     * @since 2.0
8558     */
8559    public static String substringBetween(final String str, final String open, final String close) {
8560        if (!ObjectUtils.allNotNull(str, open, close)) {
8561            return null;
8562        }
8563        final int start = str.indexOf(open);
8564        if (start != INDEX_NOT_FOUND) {
8565            final int end = str.indexOf(close, start + open.length());
8566            if (end != INDEX_NOT_FOUND) {
8567                return str.substring(start + open.length(), end);
8568            }
8569        }
8570        return null;
8571    }
8572
8573    /**
8574     * Searches a String for substrings delimited by a start and end tag,
8575     * returning all matching substrings in an array.
8576     *
8577     * <p>A {@code null} input String returns {@code null}.
8578     * A {@code null} open/close returns {@code null} (no match).
8579     * An empty ("") open/close returns {@code null} (no match).</p>
8580     *
8581     * <pre>
8582     * StringUtils.substringsBetween("[a][b][c]", "[", "]") = ["a","b","c"]
8583     * StringUtils.substringsBetween(null, *, *)            = null
8584     * StringUtils.substringsBetween(*, null, *)            = null
8585     * StringUtils.substringsBetween(*, *, null)            = null
8586     * StringUtils.substringsBetween("", "[", "]")          = []
8587     * </pre>
8588     *
8589     * @param str  the String containing the substrings, null returns null, empty returns empty
8590     * @param open  the String identifying the start of the substring, empty returns null
8591     * @param close  the String identifying the end of the substring, empty returns null
8592     * @return a String Array of substrings, or {@code null} if no match
8593     * @since 2.3
8594     */
8595    public static String[] substringsBetween(final String str, final String open, final String close) {
8596        if (str == null || isEmpty(open) || isEmpty(close)) {
8597            return null;
8598        }
8599        final int strLen = str.length();
8600        if (strLen == 0) {
8601            return ArrayUtils.EMPTY_STRING_ARRAY;
8602        }
8603        final int closeLen = close.length();
8604        final int openLen = open.length();
8605        final List<String> list = new ArrayList<>();
8606        int pos = 0;
8607        while (pos < strLen - closeLen) {
8608            int start = str.indexOf(open, pos);
8609            if (start < 0) {
8610                break;
8611            }
8612            start += openLen;
8613            final int end = str.indexOf(close, start);
8614            if (end < 0) {
8615                break;
8616            }
8617            list.add(str.substring(start, end));
8618            pos = end + closeLen;
8619        }
8620        if (list.isEmpty()) {
8621            return null;
8622        }
8623        return list.toArray(ArrayUtils.EMPTY_STRING_ARRAY);
8624    }
8625
8626    /**
8627     * Swaps the case of a String changing upper and title case to
8628     * lower case, and lower case to upper case.
8629     *
8630     * <ul>
8631     *  <li>Upper case character converts to Lower case</li>
8632     *  <li>Title case character converts to Lower case</li>
8633     *  <li>Lower case character converts to Upper case</li>
8634     * </ul>
8635     *
8636     * <p>For a word based algorithm, see {@link org.apache.commons.text.WordUtils#swapCase(String)}.
8637     * A {@code null} input String returns {@code null}.</p>
8638     *
8639     * <pre>
8640     * StringUtils.swapCase(null)                 = null
8641     * StringUtils.swapCase("")                   = ""
8642     * StringUtils.swapCase("The dog has a BONE") = "tHE DOG HAS A bone"
8643     * </pre>
8644     *
8645     * <p>NOTE: This method changed in Lang version 2.0.
8646     * It no longer performs a word based algorithm.
8647     * If you only use ASCII, you will notice no change.
8648     * That functionality is available in org.apache.commons.lang3.text.WordUtils.</p>
8649     *
8650     * @param str  the String to swap case, may be null
8651     * @return the changed String, {@code null} if null String input
8652     */
8653    public static String swapCase(final String str) {
8654        if (isEmpty(str)) {
8655            return str;
8656        }
8657
8658        final int strLen = str.length();
8659        final int[] newCodePoints = new int[strLen]; // cannot be longer than the char array
8660        int outOffset = 0;
8661        for (int i = 0; i < strLen; ) {
8662            final int oldCodepoint = str.codePointAt(i);
8663            final int newCodePoint;
8664            if (Character.isUpperCase(oldCodepoint) || Character.isTitleCase(oldCodepoint)) {
8665                newCodePoint = Character.toLowerCase(oldCodepoint);
8666            } else if (Character.isLowerCase(oldCodepoint)) {
8667                newCodePoint = Character.toUpperCase(oldCodepoint);
8668            } else {
8669                newCodePoint = oldCodepoint;
8670            }
8671            newCodePoints[outOffset++] = newCodePoint;
8672            i += Character.charCount(newCodePoint);
8673         }
8674        return new String(newCodePoints, 0, outOffset);
8675    }
8676
8677    /**
8678     * Converts a {@link CharSequence} into an array of code points.
8679     *
8680     * <p>Valid pairs of surrogate code units will be converted into a single supplementary
8681     * code point. Isolated surrogate code units (i.e. a high surrogate not followed by a low surrogate or
8682     * a low surrogate not preceded by a high surrogate) will be returned as-is.</p>
8683     *
8684     * <pre>
8685     * StringUtils.toCodePoints(null)   =  null
8686     * StringUtils.toCodePoints("")     =  []  // empty array
8687     * </pre>
8688     *
8689     * @param cs the character sequence to convert
8690     * @return an array of code points
8691     * @since 3.6
8692     */
8693    public static int[] toCodePoints(final CharSequence cs) {
8694        if (cs == null) {
8695            return null;
8696        }
8697        if (cs.length() == 0) {
8698            return ArrayUtils.EMPTY_INT_ARRAY;
8699        }
8700        return cs.toString().codePoints().toArray();
8701    }
8702
8703    /**
8704     * Converts a {@code byte[]} to a String using the specified character encoding.
8705     *
8706     * @param bytes
8707     *            the byte array to read from
8708     * @param charset
8709     *            the encoding to use, if null then use the platform default
8710     * @return a new String
8711     * @throws NullPointerException
8712     *             if {@code bytes} is null
8713     * @since 3.2
8714     * @since 3.3 No longer throws {@link UnsupportedEncodingException}.
8715     */
8716    public static String toEncodedString(final byte[] bytes, final Charset charset) {
8717        return new String(bytes, Charsets.toCharset(charset));
8718    }
8719
8720    /**
8721     * Converts the given source String as a lower-case using the {@link Locale#ROOT} locale in a null-safe manner.
8722     *
8723     * @param source A source String or null.
8724     * @return the given source String as a lower-case using the {@link Locale#ROOT} locale or null.
8725     * @since 3.10
8726     */
8727    public static String toRootLowerCase(final String source) {
8728        return source == null ? null : source.toLowerCase(Locale.ROOT);
8729    }
8730
8731    /**
8732     * Converts the given source String as an upper-case using the {@link Locale#ROOT} locale in a null-safe manner.
8733     *
8734     * @param source A source String or null.
8735     * @return the given source String as an upper-case using the {@link Locale#ROOT} locale or null.
8736     * @since 3.10
8737     */
8738    public static String toRootUpperCase(final String source) {
8739        return source == null ? null : source.toUpperCase(Locale.ROOT);
8740    }
8741
8742    /**
8743     * Converts a {@code byte[]} to a String using the specified character encoding.
8744     *
8745     * @param bytes
8746     *            the byte array to read from
8747     * @param charsetName
8748     *            the encoding to use, if null then use the platform default
8749     * @return a new String
8750     * @throws NullPointerException
8751     *             if the input is null
8752     * @deprecated use {@link StringUtils#toEncodedString(byte[], Charset)} instead of String constants in your code
8753     * @since 3.1
8754     */
8755    @Deprecated
8756    public static String toString(final byte[] bytes, final String charsetName) {
8757        return new String(bytes, Charsets.toCharset(charsetName));
8758    }
8759
8760    /**
8761     * Removes control characters (char &lt;= 32) from both
8762     * ends of this String, handling {@code null} by returning
8763     * {@code null}.
8764     *
8765     * <p>The String is trimmed using {@link String#trim()}.
8766     * Trim removes start and end characters &lt;= 32.
8767     * To strip whitespace use {@link #strip(String)}.</p>
8768     *
8769     * <p>To trim your choice of characters, use the
8770     * {@link #strip(String, String)} methods.</p>
8771     *
8772     * <pre>
8773     * StringUtils.trim(null)          = null
8774     * StringUtils.trim("")            = ""
8775     * StringUtils.trim("     ")       = ""
8776     * StringUtils.trim("abc")         = "abc"
8777     * StringUtils.trim("    abc    ") = "abc"
8778     * </pre>
8779     *
8780     * @param str  the String to be trimmed, may be null
8781     * @return the trimmed string, {@code null} if null String input
8782     */
8783    public static String trim(final String str) {
8784        return str == null ? null : str.trim();
8785    }
8786
8787    /**
8788     * Removes control characters (char &lt;= 32) from both
8789     * ends of this String returning an empty String ("") if the String
8790     * is empty ("") after the trim or if it is {@code null}.
8791     *
8792     * <p>The String is trimmed using {@link String#trim()}.
8793     * Trim removes start and end characters &lt;= 32.
8794     * To strip whitespace use {@link #stripToEmpty(String)}.
8795     *
8796     * <pre>
8797     * StringUtils.trimToEmpty(null)          = ""
8798     * StringUtils.trimToEmpty("")            = ""
8799     * StringUtils.trimToEmpty("     ")       = ""
8800     * StringUtils.trimToEmpty("abc")         = "abc"
8801     * StringUtils.trimToEmpty("    abc    ") = "abc"
8802     * </pre>
8803     *
8804     * @param str  the String to be trimmed, may be null
8805     * @return the trimmed String, or an empty String if {@code null} input
8806     * @since 2.0
8807     */
8808    public static String trimToEmpty(final String str) {
8809        return str == null ? EMPTY : str.trim();
8810    }
8811
8812    /**
8813     * Removes control characters (char &lt;= 32) from both
8814     * ends of this String returning {@code null} if the String is
8815     * empty ("") after the trim or if it is {@code null}.
8816     *
8817     * <p>The String is trimmed using {@link String#trim()}.
8818     * Trim removes start and end characters &lt;= 32.
8819     * To strip whitespace use {@link #stripToNull(String)}.
8820     *
8821     * <pre>
8822     * StringUtils.trimToNull(null)          = null
8823     * StringUtils.trimToNull("")            = null
8824     * StringUtils.trimToNull("     ")       = null
8825     * StringUtils.trimToNull("abc")         = "abc"
8826     * StringUtils.trimToNull("    abc    ") = "abc"
8827     * </pre>
8828     *
8829     * @param str  the String to be trimmed, may be null
8830     * @return the trimmed String,
8831     *  {@code null} if only chars &lt;= 32, empty or null String input
8832     * @since 2.0
8833     */
8834    public static String trimToNull(final String str) {
8835        final String ts = trim(str);
8836        return isEmpty(ts) ? null : ts;
8837    }
8838
8839    /**
8840     * Truncates a String. This will turn
8841     * "Now is the time for all good men" into "Now is the time for".
8842     *
8843     * <p>Specifically:</p>
8844     * <ul>
8845     *   <li>If {@code str} is less than {@code maxWidth} characters
8846     *       long, return it.</li>
8847     *   <li>Else truncate it to {@code substring(str, 0, maxWidth)}.</li>
8848     *   <li>If {@code maxWidth} is less than {@code 0}, throw an
8849     *       {@link IllegalArgumentException}.</li>
8850     *   <li>In no case will it return a String of length greater than
8851     *       {@code maxWidth}.</li>
8852     * </ul>
8853     *
8854     * <pre>
8855     * StringUtils.truncate(null, 0)       = null
8856     * StringUtils.truncate(null, 2)       = null
8857     * StringUtils.truncate("", 4)         = ""
8858     * StringUtils.truncate("abcdefg", 4)  = "abcd"
8859     * StringUtils.truncate("abcdefg", 6)  = "abcdef"
8860     * StringUtils.truncate("abcdefg", 7)  = "abcdefg"
8861     * StringUtils.truncate("abcdefg", 8)  = "abcdefg"
8862     * StringUtils.truncate("abcdefg", -1) = throws an IllegalArgumentException
8863     * </pre>
8864     *
8865     * @param str  the String to truncate, may be null
8866     * @param maxWidth  maximum length of result String, must be positive
8867     * @return truncated String, {@code null} if null String input
8868     * @throws IllegalArgumentException If {@code maxWidth} is less than {@code 0}
8869     * @since 3.5
8870     */
8871    public static String truncate(final String str, final int maxWidth) {
8872        return truncate(str, 0, maxWidth);
8873    }
8874
8875    /**
8876     * Truncates a String. This will turn
8877     * "Now is the time for all good men" into "is the time for all".
8878     *
8879     * <p>Works like {@code truncate(String, int)}, but allows you to specify
8880     * a "left edge" offset.
8881     *
8882     * <p>Specifically:</p>
8883     * <ul>
8884     *   <li>If {@code str} is less than {@code maxWidth} characters
8885     *       long, return it.</li>
8886     *   <li>Else truncate it to {@code substring(str, offset, maxWidth)}.</li>
8887     *   <li>If {@code maxWidth} is less than {@code 0}, throw an
8888     *       {@link IllegalArgumentException}.</li>
8889     *   <li>If {@code offset} is less than {@code 0}, throw an
8890     *       {@link IllegalArgumentException}.</li>
8891     *   <li>In no case will it return a String of length greater than
8892     *       {@code maxWidth}.</li>
8893     * </ul>
8894     *
8895     * <pre>
8896     * StringUtils.truncate(null, 0, 0) = null
8897     * StringUtils.truncate(null, 2, 4) = null
8898     * StringUtils.truncate("", 0, 10) = ""
8899     * StringUtils.truncate("", 2, 10) = ""
8900     * StringUtils.truncate("abcdefghij", 0, 3) = "abc"
8901     * StringUtils.truncate("abcdefghij", 5, 6) = "fghij"
8902     * StringUtils.truncate("raspberry peach", 10, 15) = "peach"
8903     * StringUtils.truncate("abcdefghijklmno", 0, 10) = "abcdefghij"
8904     * StringUtils.truncate("abcdefghijklmno", -1, 10) = throws an IllegalArgumentException
8905     * StringUtils.truncate("abcdefghijklmno", Integer.MIN_VALUE, 10) = throws an IllegalArgumentException
8906     * StringUtils.truncate("abcdefghijklmno", Integer.MIN_VALUE, Integer.MAX_VALUE) = throws an IllegalArgumentException
8907     * StringUtils.truncate("abcdefghijklmno", 0, Integer.MAX_VALUE) = "abcdefghijklmno"
8908     * StringUtils.truncate("abcdefghijklmno", 1, 10) = "bcdefghijk"
8909     * StringUtils.truncate("abcdefghijklmno", 2, 10) = "cdefghijkl"
8910     * StringUtils.truncate("abcdefghijklmno", 3, 10) = "defghijklm"
8911     * StringUtils.truncate("abcdefghijklmno", 4, 10) = "efghijklmn"
8912     * StringUtils.truncate("abcdefghijklmno", 5, 10) = "fghijklmno"
8913     * StringUtils.truncate("abcdefghijklmno", 5, 5) = "fghij"
8914     * StringUtils.truncate("abcdefghijklmno", 5, 3) = "fgh"
8915     * StringUtils.truncate("abcdefghijklmno", 10, 3) = "klm"
8916     * StringUtils.truncate("abcdefghijklmno", 10, Integer.MAX_VALUE) = "klmno"
8917     * StringUtils.truncate("abcdefghijklmno", 13, 1) = "n"
8918     * StringUtils.truncate("abcdefghijklmno", 13, Integer.MAX_VALUE) = "no"
8919     * StringUtils.truncate("abcdefghijklmno", 14, 1) = "o"
8920     * StringUtils.truncate("abcdefghijklmno", 14, Integer.MAX_VALUE) = "o"
8921     * StringUtils.truncate("abcdefghijklmno", 15, 1) = ""
8922     * StringUtils.truncate("abcdefghijklmno", 15, Integer.MAX_VALUE) = ""
8923     * StringUtils.truncate("abcdefghijklmno", Integer.MAX_VALUE, Integer.MAX_VALUE) = ""
8924     * StringUtils.truncate("abcdefghij", 3, -1) = throws an IllegalArgumentException
8925     * StringUtils.truncate("abcdefghij", -2, 4) = throws an IllegalArgumentException
8926     * </pre>
8927     *
8928     * @param str  the String to truncate, may be null
8929     * @param offset  left edge of source String
8930     * @param maxWidth  maximum length of result String, must be positive
8931     * @return truncated String, {@code null} if null String input
8932     * @throws IllegalArgumentException If {@code offset} or {@code maxWidth} is less than {@code 0}
8933     * @since 3.5
8934     */
8935    public static String truncate(final String str, final int offset, final int maxWidth) {
8936        if (offset < 0) {
8937            throw new IllegalArgumentException("offset cannot be negative");
8938        }
8939        if (maxWidth < 0) {
8940            throw new IllegalArgumentException("maxWith cannot be negative");
8941        }
8942        if (str == null) {
8943            return null;
8944        }
8945        if (offset > str.length()) {
8946            return EMPTY;
8947        }
8948        if (str.length() > maxWidth) {
8949            final int ix = Math.min(offset + maxWidth, str.length());
8950            return str.substring(offset, ix);
8951        }
8952        return str.substring(offset);
8953    }
8954
8955    /**
8956     * Uncapitalizes a String, changing the first character to lower case as
8957     * per {@link Character#toLowerCase(int)}. No other characters are changed.
8958     *
8959     * <p>For a word based algorithm, see {@link org.apache.commons.text.WordUtils#uncapitalize(String)}.
8960     * A {@code null} input String returns {@code null}.</p>
8961     *
8962     * <pre>
8963     * StringUtils.uncapitalize(null)  = null
8964     * StringUtils.uncapitalize("")    = ""
8965     * StringUtils.uncapitalize("cat") = "cat"
8966     * StringUtils.uncapitalize("Cat") = "cat"
8967     * StringUtils.uncapitalize("CAT") = "cAT"
8968     * </pre>
8969     *
8970     * @param str the String to uncapitalize, may be null
8971     * @return the uncapitalized String, {@code null} if null String input
8972     * @see org.apache.commons.text.WordUtils#uncapitalize(String)
8973     * @see #capitalize(String)
8974     * @since 2.0
8975     */
8976    public static String uncapitalize(final String str) {
8977        final int strLen = length(str);
8978        if (strLen == 0) {
8979            return str;
8980        }
8981        final int firstCodePoint = str.codePointAt(0);
8982        final int newCodePoint = Character.toLowerCase(firstCodePoint);
8983        if (firstCodePoint == newCodePoint) {
8984            // already uncapitalized
8985            return str;
8986        }
8987        final int[] newCodePoints = str.codePoints().toArray();
8988        newCodePoints[0] = newCodePoint; // copy the first code point
8989        return new String(newCodePoints, 0, newCodePoints.length);
8990    }
8991
8992    /**
8993     * Unwraps a given string from a character.
8994     *
8995     * <pre>
8996     * StringUtils.unwrap(null, null)         = null
8997     * StringUtils.unwrap(null, '\0')         = null
8998     * StringUtils.unwrap(null, '1')          = null
8999     * StringUtils.unwrap("a", 'a')           = "a"
9000     * StringUtils.unwrap("aa", 'a')           = ""
9001     * StringUtils.unwrap("\'abc\'", '\'')    = "abc"
9002     * StringUtils.unwrap("AABabcBAA", 'A')   = "ABabcBA"
9003     * StringUtils.unwrap("A", '#')           = "A"
9004     * StringUtils.unwrap("#A", '#')          = "#A"
9005     * StringUtils.unwrap("A#", '#')          = "A#"
9006     * </pre>
9007     *
9008     * @param str
9009     *          the String to be unwrapped, can be null
9010     * @param wrapChar
9011     *          the character used to unwrap
9012     * @return unwrapped String or the original string
9013     *          if it is not quoted properly with the wrapChar
9014     * @since 3.6
9015     */
9016    public static String unwrap(final String str, final char wrapChar) {
9017        if (isEmpty(str) || wrapChar == CharUtils.NUL || str.length() == 1) {
9018            return str;
9019        }
9020
9021        if (str.charAt(0) == wrapChar && str.charAt(str.length() - 1) == wrapChar) {
9022            final int startIndex = 0;
9023            final int endIndex = str.length() - 1;
9024
9025            return str.substring(startIndex + 1, endIndex);
9026        }
9027
9028        return str;
9029    }
9030
9031    /**
9032     * Unwraps a given string from another string.
9033     *
9034     * <pre>
9035     * StringUtils.unwrap(null, null)         = null
9036     * StringUtils.unwrap(null, "")           = null
9037     * StringUtils.unwrap(null, "1")          = null
9038     * StringUtils.unwrap("a", "a")           = "a"
9039     * StringUtils.unwrap("aa", "a")          = ""
9040     * StringUtils.unwrap("\'abc\'", "\'")    = "abc"
9041     * StringUtils.unwrap("\"abc\"", "\"")    = "abc"
9042     * StringUtils.unwrap("AABabcBAA", "AA")  = "BabcB"
9043     * StringUtils.unwrap("A", "#")           = "A"
9044     * StringUtils.unwrap("#A", "#")          = "#A"
9045     * StringUtils.unwrap("A#", "#")          = "A#"
9046     * </pre>
9047     *
9048     * @param str
9049     *          the String to be unwrapped, can be null
9050     * @param wrapToken
9051     *          the String used to unwrap
9052     * @return unwrapped String or the original string
9053     *          if it is not quoted properly with the wrapToken
9054     * @since 3.6
9055     */
9056    public static String unwrap(final String str, final String wrapToken) {
9057        if (isEmpty(str) || isEmpty(wrapToken) || str.length() < 2 * wrapToken.length()) {
9058            return str;
9059        }
9060
9061        if (Strings.CS.startsWith(str, wrapToken) && Strings.CS.endsWith(str, wrapToken)) {
9062            return str.substring(wrapToken.length(), str.lastIndexOf(wrapToken));
9063        }
9064
9065        return str;
9066    }
9067
9068    /**
9069     * Converts a String to upper case as per {@link String#toUpperCase()}.
9070     *
9071     * <p>A {@code null} input String returns {@code null}.</p>
9072     *
9073     * <pre>
9074     * StringUtils.upperCase(null)  = null
9075     * StringUtils.upperCase("")    = ""
9076     * StringUtils.upperCase("aBc") = "ABC"
9077     * </pre>
9078     *
9079     * <p><strong>Note:</strong> As described in the documentation for {@link String#toUpperCase()},
9080     * the result of this method is affected by the current locale.
9081     * For platform-independent case transformations, the method {@link #upperCase(String, Locale)}
9082     * should be used with a specific locale (e.g. {@link Locale#ENGLISH}).</p>
9083     *
9084     * @param str  the String to upper case, may be null
9085     * @return the upper-cased String, {@code null} if null String input
9086     */
9087    public static String upperCase(final String str) {
9088        if (str == null) {
9089            return null;
9090        }
9091        return str.toUpperCase();
9092    }
9093
9094    /**
9095     * Converts a String to upper case as per {@link String#toUpperCase(Locale)}.
9096     *
9097     * <p>A {@code null} input String returns {@code null}.</p>
9098     *
9099     * <pre>
9100     * StringUtils.upperCase(null, Locale.ENGLISH)  = null
9101     * StringUtils.upperCase("", Locale.ENGLISH)    = ""
9102     * StringUtils.upperCase("aBc", Locale.ENGLISH) = "ABC"
9103     * </pre>
9104     *
9105     * @param str  the String to upper case, may be null
9106     * @param locale  the locale that defines the case transformation rules, must not be null
9107     * @return the upper-cased String, {@code null} if null String input
9108     * @since 2.5
9109     */
9110    public static String upperCase(final String str, final Locale locale) {
9111        if (str == null) {
9112            return null;
9113        }
9114        return str.toUpperCase(LocaleUtils.toLocale(locale));
9115    }
9116
9117    /**
9118     * Returns the string representation of the {@code char} array or null.
9119     *
9120     * @param value the character array.
9121     * @return a String or null
9122     * @see String#valueOf(char[])
9123     * @since 3.9
9124     */
9125    public static String valueOf(final char[] value) {
9126        return value == null ? null : String.valueOf(value);
9127    }
9128
9129    /**
9130     * Wraps a string with a char.
9131     *
9132     * <pre>
9133     * StringUtils.wrap(null, *)        = null
9134     * StringUtils.wrap("", *)          = ""
9135     * StringUtils.wrap("ab", '\0')     = "ab"
9136     * StringUtils.wrap("ab", 'x')      = "xabx"
9137     * StringUtils.wrap("ab", '\'')     = "'ab'"
9138     * StringUtils.wrap("\"ab\"", '\"') = "\"\"ab\"\""
9139     * </pre>
9140     *
9141     * @param str
9142     *            the string to be wrapped, may be {@code null}
9143     * @param wrapWith
9144     *            the char that will wrap {@code str}
9145     * @return the wrapped string, or {@code null} if {@code str == null}
9146     * @since 3.4
9147     */
9148    public static String wrap(final String str, final char wrapWith) {
9149
9150        if (isEmpty(str) || wrapWith == CharUtils.NUL) {
9151            return str;
9152        }
9153
9154        return wrapWith + str + wrapWith;
9155    }
9156
9157    /**
9158     * Wraps a String with another String.
9159     *
9160     * <p>
9161     * A {@code null} input String returns {@code null}.
9162     * </p>
9163     *
9164     * <pre>
9165     * StringUtils.wrap(null, *)         = null
9166     * StringUtils.wrap("", *)           = ""
9167     * StringUtils.wrap("ab", null)      = "ab"
9168     * StringUtils.wrap("ab", "x")       = "xabx"
9169     * StringUtils.wrap("ab", "\"")      = "\"ab\""
9170     * StringUtils.wrap("\"ab\"", "\"")  = "\"\"ab\"\""
9171     * StringUtils.wrap("ab", "'")       = "'ab'"
9172     * StringUtils.wrap("'abcd'", "'")   = "''abcd''"
9173     * StringUtils.wrap("\"abcd\"", "'") = "'\"abcd\"'"
9174     * StringUtils.wrap("'abcd'", "\"")  = "\"'abcd'\""
9175     * </pre>
9176     *
9177     * @param str
9178     *            the String to be wrapper, may be null
9179     * @param wrapWith
9180     *            the String that will wrap str
9181     * @return wrapped String, {@code null} if null String input
9182     * @since 3.4
9183     */
9184    public static String wrap(final String str, final String wrapWith) {
9185
9186        if (isEmpty(str) || isEmpty(wrapWith)) {
9187            return str;
9188        }
9189
9190        return wrapWith.concat(str).concat(wrapWith);
9191    }
9192
9193    /**
9194     * Wraps a string with a char if that char is missing from the start or end of the given string.
9195     *
9196     * <p>A new {@link String} will not be created if {@code str} is already wrapped.</p>
9197     *
9198     * <pre>
9199     * StringUtils.wrapIfMissing(null, *)        = null
9200     * StringUtils.wrapIfMissing("", *)          = ""
9201     * StringUtils.wrapIfMissing("ab", '\0')     = "ab"
9202     * StringUtils.wrapIfMissing("ab", 'x')      = "xabx"
9203     * StringUtils.wrapIfMissing("ab", '\'')     = "'ab'"
9204     * StringUtils.wrapIfMissing("\"ab\"", '\"') = "\"ab\""
9205     * StringUtils.wrapIfMissing("/", '/')  = "/"
9206     * StringUtils.wrapIfMissing("a/b/c", '/')  = "/a/b/c/"
9207     * StringUtils.wrapIfMissing("/a/b/c", '/')  = "/a/b/c/"
9208     * StringUtils.wrapIfMissing("a/b/c/", '/')  = "/a/b/c/"
9209     * </pre>
9210     *
9211     * @param str
9212     *            the string to be wrapped, may be {@code null}
9213     * @param wrapWith
9214     *            the char that will wrap {@code str}
9215     * @return the wrapped string, or {@code null} if {@code str == null}
9216     * @since 3.5
9217     */
9218    public static String wrapIfMissing(final String str, final char wrapWith) {
9219        if (isEmpty(str) || wrapWith == CharUtils.NUL) {
9220            return str;
9221        }
9222        final boolean wrapStart = str.charAt(0) != wrapWith;
9223        final boolean wrapEnd = str.charAt(str.length() - 1) != wrapWith;
9224        if (!wrapStart && !wrapEnd) {
9225            return str;
9226        }
9227
9228        final StringBuilder builder = new StringBuilder(str.length() + 2);
9229        if (wrapStart) {
9230            builder.append(wrapWith);
9231        }
9232        builder.append(str);
9233        if (wrapEnd) {
9234            builder.append(wrapWith);
9235        }
9236        return builder.toString();
9237    }
9238
9239    /**
9240     * Wraps a string with a string if that string is missing from the start or end of the given string.
9241     *
9242     * <p>A new {@link String} will not be created if {@code str} is already wrapped.</p>
9243     *
9244     * <pre>
9245     * StringUtils.wrapIfMissing(null, *)         = null
9246     * StringUtils.wrapIfMissing("", *)           = ""
9247     * StringUtils.wrapIfMissing("ab", null)      = "ab"
9248     * StringUtils.wrapIfMissing("ab", "x")       = "xabx"
9249     * StringUtils.wrapIfMissing("ab", "\"")      = "\"ab\""
9250     * StringUtils.wrapIfMissing("\"ab\"", "\"")  = "\"ab\""
9251     * StringUtils.wrapIfMissing("ab", "'")       = "'ab'"
9252     * StringUtils.wrapIfMissing("'abcd'", "'")   = "'abcd'"
9253     * StringUtils.wrapIfMissing("\"abcd\"", "'") = "'\"abcd\"'"
9254     * StringUtils.wrapIfMissing("'abcd'", "\"")  = "\"'abcd'\""
9255     * StringUtils.wrapIfMissing("/", "/")  = "/"
9256     * StringUtils.wrapIfMissing("a/b/c", "/")  = "/a/b/c/"
9257     * StringUtils.wrapIfMissing("/a/b/c", "/")  = "/a/b/c/"
9258     * StringUtils.wrapIfMissing("a/b/c/", "/")  = "/a/b/c/"
9259     * </pre>
9260     *
9261     * @param str
9262     *            the string to be wrapped, may be {@code null}
9263     * @param wrapWith
9264     *            the string that will wrap {@code str}
9265     * @return the wrapped string, or {@code null} if {@code str == null}
9266     * @since 3.5
9267     */
9268    public static String wrapIfMissing(final String str, final String wrapWith) {
9269        if (isEmpty(str) || isEmpty(wrapWith)) {
9270            return str;
9271        }
9272
9273        final boolean wrapStart = !str.startsWith(wrapWith);
9274        final boolean wrapEnd = !str.endsWith(wrapWith);
9275        if (!wrapStart && !wrapEnd) {
9276            return str;
9277        }
9278
9279        final StringBuilder builder = new StringBuilder(str.length() + wrapWith.length() + wrapWith.length());
9280        if (wrapStart) {
9281            builder.append(wrapWith);
9282        }
9283        builder.append(str);
9284        if (wrapEnd) {
9285            builder.append(wrapWith);
9286        }
9287        return builder.toString();
9288    }
9289
9290    /**
9291     * {@link StringUtils} instances should NOT be constructed in
9292     * standard programming. Instead, the class should be used as
9293     * {@code StringUtils.trim(" foo ");}.
9294     *
9295     * <p>This constructor is public to permit tools that require a JavaBean
9296     * instance to operate.</p>
9297     *
9298     * @deprecated TODO Make private in 4.0.
9299     */
9300    @Deprecated
9301    public StringUtils() {
9302        // empty
9303    }
9304
9305}