001/*
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements.  See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License.  You may obtain a copy of the License at
008 *
009 *      http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017package org.apache.commons.lang3;
018
019import java.io.UnsupportedEncodingException;
020import java.nio.charset.Charset;
021import java.text.Normalizer;
022import java.util.ArrayList;
023import java.util.Arrays;
024import java.util.HashSet;
025import java.util.Iterator;
026import java.util.List;
027import java.util.Locale;
028import java.util.Objects;
029import java.util.Set;
030import java.util.function.Supplier;
031import java.util.regex.Pattern;
032
033/**
034 * <p>Operations on {@link java.lang.String} that are
035 * {@code null} safe.</p>
036 *
037 * <ul>
038 *  <li><b>IsEmpty/IsBlank</b>
039 *      - checks if a String contains text</li>
040 *  <li><b>Trim/Strip</b>
041 *      - removes leading and trailing whitespace</li>
042 *  <li><b>Equals/Compare</b>
043 *      - compares two strings in a null-safe manner</li>
044 *  <li><b>startsWith</b>
045 *      - check if a String starts with a prefix in a null-safe manner</li>
046 *  <li><b>endsWith</b>
047 *      - check if a String ends with a suffix in a null-safe manner</li>
048 *  <li><b>IndexOf/LastIndexOf/Contains</b>
049 *      - null-safe index-of checks
050 *  <li><b>IndexOfAny/LastIndexOfAny/IndexOfAnyBut/LastIndexOfAnyBut</b>
051 *      - index-of any of a set of Strings</li>
052 *  <li><b>ContainsOnly/ContainsNone/ContainsAny</b>
053 *      - checks if String contains only/none/any of these characters</li>
054 *  <li><b>Substring/Left/Right/Mid</b>
055 *      - null-safe substring extractions</li>
056 *  <li><b>SubstringBefore/SubstringAfter/SubstringBetween</b>
057 *      - substring extraction relative to other strings</li>
058 *  <li><b>Split/Join</b>
059 *      - splits a String into an array of substrings and vice versa</li>
060 *  <li><b>Remove/Delete</b>
061 *      - removes part of a String</li>
062 *  <li><b>Replace/Overlay</b>
063 *      - Searches a String and replaces one String with another</li>
064 *  <li><b>Chomp/Chop</b>
065 *      - removes the last part of a String</li>
066 *  <li><b>AppendIfMissing</b>
067 *      - appends a suffix to the end of the String if not present</li>
068 *  <li><b>PrependIfMissing</b>
069 *      - prepends a prefix to the start of the String if not present</li>
070 *  <li><b>LeftPad/RightPad/Center/Repeat</b>
071 *      - pads a String</li>
072 *  <li><b>UpperCase/LowerCase/SwapCase/Capitalize/Uncapitalize</b>
073 *      - changes the case of a String</li>
074 *  <li><b>CountMatches</b>
075 *      - counts the number of occurrences of one String in another</li>
076 *  <li><b>IsAlpha/IsNumeric/IsWhitespace/IsAsciiPrintable</b>
077 *      - checks the characters in a String</li>
078 *  <li><b>DefaultString</b>
079 *      - protects against a null input String</li>
080 *  <li><b>Rotate</b>
081 *      - rotate (circular shift) a String</li>
082 *  <li><b>Reverse/ReverseDelimited</b>
083 *      - reverses a String</li>
084 *  <li><b>Abbreviate</b>
085 *      - abbreviates a string using ellipses or another given String</li>
086 *  <li><b>Difference</b>
087 *      - compares Strings and reports on their differences</li>
088 *  <li><b>LevenshteinDistance</b>
089 *      - the number of changes needed to change one String into another</li>
090 * </ul>
091 *
092 * <p>The {@code StringUtils} class defines certain words related to
093 * String handling.</p>
094 *
095 * <ul>
096 *  <li>null - {@code null}</li>
097 *  <li>empty - a zero-length string ({@code ""})</li>
098 *  <li>space - the space character ({@code ' '}, char 32)</li>
099 *  <li>whitespace - the characters defined by {@link Character#isWhitespace(char)}</li>
100 *  <li>trim - the characters &lt;= 32 as in {@link String#trim()}</li>
101 * </ul>
102 *
103 * <p>{@code StringUtils} handles {@code null} input Strings quietly.
104 * That is to say that a {@code null} input will return {@code null}.
105 * Where a {@code boolean} or {@code int} is being returned
106 * details vary by method.</p>
107 *
108 * <p>A side effect of the {@code null} handling is that a
109 * {@code NullPointerException} should be considered a bug in
110 * {@code StringUtils}.</p>
111 *
112 * <p>Methods in this class include sample code in their Javadoc comments to explain their operation.
113 * The symbol {@code *} is used to indicate any input including {@code null}.</p>
114 *
115 * <p>#ThreadSafe#</p>
116 * @see java.lang.String
117 * @since 1.0
118 */
119//@Immutable
120public class StringUtils {
121
122    private static final int STRING_BUILDER_SIZE = 256;
123
124    // Performance testing notes (JDK 1.4, Jul03, scolebourne)
125    // Whitespace:
126    // Character.isWhitespace() is faster than WHITESPACE.indexOf()
127    // where WHITESPACE is a string of all whitespace characters
128    //
129    // Character access:
130    // String.charAt(n) versus toCharArray(), then array[n]
131    // String.charAt(n) is about 15% worse for a 10K string
132    // They are about equal for a length 50 string
133    // String.charAt(n) is about 4 times better for a length 3 string
134    // String.charAt(n) is best bet overall
135    //
136    // Append:
137    // String.concat about twice as fast as StringBuffer.append
138    // (not sure who tested this)
139
140    /**
141     * A String for a space character.
142     *
143     * @since 3.2
144     */
145    public static final String SPACE = " ";
146
147    /**
148     * The empty String {@code ""}.
149     * @since 2.0
150     */
151    public static final String EMPTY = "";
152
153    /**
154     * A String for linefeed LF ("\n").
155     *
156     * @see <a href="http://docs.oracle.com/javase/specs/jls/se7/html/jls-3.html#jls-3.10.6">JLF: Escape Sequences
157     *      for Character and String Literals</a>
158     * @since 3.2
159     */
160    public static final String LF = "\n";
161
162    /**
163     * A String for carriage return CR ("\r").
164     *
165     * @see <a href="http://docs.oracle.com/javase/specs/jls/se7/html/jls-3.html#jls-3.10.6">JLF: Escape Sequences
166     *      for Character and String Literals</a>
167     * @since 3.2
168     */
169    public static final String CR = "\r";
170
171    /**
172     * Represents a failed index search.
173     * @since 2.1
174     */
175    public static final int INDEX_NOT_FOUND = -1;
176
177    /**
178     * <p>The maximum size to which the padding constant(s) can expand.</p>
179     */
180    private static final int PAD_LIMIT = 8192;
181
182    /**
183     * Pattern used in {@link #stripAccents(String)}.
184     */
185    private static final Pattern STRIP_ACCENTS_PATTERN = Pattern.compile("\\p{InCombiningDiacriticalMarks}+"); //$NON-NLS-1$
186
187    // Abbreviating
188    //-----------------------------------------------------------------------
189    /**
190     * <p>Abbreviates a String using ellipses. This will turn
191     * "Now is the time for all good men" into "Now is the time for..."</p>
192     *
193     * <p>Specifically:</p>
194     * <ul>
195     *   <li>If the number of characters in {@code str} is less than or equal to
196     *       {@code maxWidth}, return {@code str}.</li>
197     *   <li>Else abbreviate it to {@code (substring(str, 0, max-3) + "...")}.</li>
198     *   <li>If {@code maxWidth} is less than {@code 4}, throw an
199     *       {@code IllegalArgumentException}.</li>
200     *   <li>In no case will it return a String of length greater than
201     *       {@code maxWidth}.</li>
202     * </ul>
203     *
204     * <pre>
205     * StringUtils.abbreviate(null, *)      = null
206     * StringUtils.abbreviate("", 4)        = ""
207     * StringUtils.abbreviate("abcdefg", 6) = "abc..."
208     * StringUtils.abbreviate("abcdefg", 7) = "abcdefg"
209     * StringUtils.abbreviate("abcdefg", 8) = "abcdefg"
210     * StringUtils.abbreviate("abcdefg", 4) = "a..."
211     * StringUtils.abbreviate("abcdefg", 3) = IllegalArgumentException
212     * </pre>
213     *
214     * @param str  the String to check, may be null
215     * @param maxWidth  maximum length of result String, must be at least 4
216     * @return abbreviated String, {@code null} if null String input
217     * @throws IllegalArgumentException if the width is too small
218     * @since 2.0
219     */
220    public static String abbreviate(final String str, final int maxWidth) {
221        return abbreviate(str, "...", 0, maxWidth);
222    }
223
224    /**
225     * <p>Abbreviates a String using ellipses. This will turn
226     * "Now is the time for all good men" into "...is the time for..."</p>
227     *
228     * <p>Works like {@code abbreviate(String, int)}, but allows you to specify
229     * a "left edge" offset.  Note that this left edge is not necessarily going to
230     * be the leftmost character in the result, or the first character following the
231     * ellipses, but it will appear somewhere in the result.
232     *
233     * <p>In no case will it return a String of length greater than
234     * {@code maxWidth}.</p>
235     *
236     * <pre>
237     * StringUtils.abbreviate(null, *, *)                = null
238     * StringUtils.abbreviate("", 0, 4)                  = ""
239     * StringUtils.abbreviate("abcdefghijklmno", -1, 10) = "abcdefg..."
240     * StringUtils.abbreviate("abcdefghijklmno", 0, 10)  = "abcdefg..."
241     * StringUtils.abbreviate("abcdefghijklmno", 1, 10)  = "abcdefg..."
242     * StringUtils.abbreviate("abcdefghijklmno", 4, 10)  = "abcdefg..."
243     * StringUtils.abbreviate("abcdefghijklmno", 5, 10)  = "...fghi..."
244     * StringUtils.abbreviate("abcdefghijklmno", 6, 10)  = "...ghij..."
245     * StringUtils.abbreviate("abcdefghijklmno", 8, 10)  = "...ijklmno"
246     * StringUtils.abbreviate("abcdefghijklmno", 10, 10) = "...ijklmno"
247     * StringUtils.abbreviate("abcdefghijklmno", 12, 10) = "...ijklmno"
248     * StringUtils.abbreviate("abcdefghij", 0, 3)        = IllegalArgumentException
249     * StringUtils.abbreviate("abcdefghij", 5, 6)        = IllegalArgumentException
250     * </pre>
251     *
252     * @param str  the String to check, may be null
253     * @param offset  left edge of source String
254     * @param maxWidth  maximum length of result String, must be at least 4
255     * @return abbreviated String, {@code null} if null String input
256     * @throws IllegalArgumentException if the width is too small
257     * @since 2.0
258     */
259    public static String abbreviate(final String str, final int offset, final int maxWidth) {
260        return abbreviate(str, "...", offset, maxWidth);
261    }
262
263    /**
264     * <p>Abbreviates a String using another given String as replacement marker. This will turn
265     * "Now is the time for all good men" into "Now is the time for..." if "..." was defined
266     * as the replacement marker.</p>
267     *
268     * <p>Specifically:</p>
269     * <ul>
270     *   <li>If the number of characters in {@code str} is less than or equal to
271     *       {@code maxWidth}, return {@code str}.</li>
272     *   <li>Else abbreviate it to {@code (substring(str, 0, max-abbrevMarker.length) + abbrevMarker)}.</li>
273     *   <li>If {@code maxWidth} is less than {@code abbrevMarker.length + 1}, throw an
274     *       {@code IllegalArgumentException}.</li>
275     *   <li>In no case will it return a String of length greater than
276     *       {@code maxWidth}.</li>
277     * </ul>
278     *
279     * <pre>
280     * StringUtils.abbreviate(null, "...", *)      = null
281     * StringUtils.abbreviate("abcdefg", null, *)  = "abcdefg"
282     * StringUtils.abbreviate("", "...", 4)        = ""
283     * StringUtils.abbreviate("abcdefg", ".", 5)   = "abcd."
284     * StringUtils.abbreviate("abcdefg", ".", 7)   = "abcdefg"
285     * StringUtils.abbreviate("abcdefg", ".", 8)   = "abcdefg"
286     * StringUtils.abbreviate("abcdefg", "..", 4)  = "ab.."
287     * StringUtils.abbreviate("abcdefg", "..", 3)  = "a.."
288     * StringUtils.abbreviate("abcdefg", "..", 2)  = IllegalArgumentException
289     * StringUtils.abbreviate("abcdefg", "...", 3) = IllegalArgumentException
290     * </pre>
291     *
292     * @param str  the String to check, may be null
293     * @param abbrevMarker  the String used as replacement marker
294     * @param maxWidth  maximum length of result String, must be at least {@code abbrevMarker.length + 1}
295     * @return abbreviated String, {@code null} if null String input
296     * @throws IllegalArgumentException if the width is too small
297     * @since 3.6
298     */
299    public static String abbreviate(final String str, final String abbrevMarker, final int maxWidth) {
300        return abbreviate(str, abbrevMarker, 0, maxWidth);
301    }
302    /**
303     * <p>Abbreviates a String using a given replacement marker. This will turn
304     * "Now is the time for all good men" into "...is the time for..." if "..." was defined
305     * as the replacement marker.</p>
306     *
307     * <p>Works like {@code abbreviate(String, String, int)}, but allows you to specify
308     * a "left edge" offset.  Note that this left edge is not necessarily going to
309     * be the leftmost character in the result, or the first character following the
310     * replacement marker, but it will appear somewhere in the result.
311     *
312     * <p>In no case will it return a String of length greater than {@code maxWidth}.</p>
313     *
314     * <pre>
315     * StringUtils.abbreviate(null, null, *, *)                 = null
316     * StringUtils.abbreviate("abcdefghijklmno", null, *, *)    = "abcdefghijklmno"
317     * StringUtils.abbreviate("", "...", 0, 4)                  = ""
318     * StringUtils.abbreviate("abcdefghijklmno", "---", -1, 10) = "abcdefg---"
319     * StringUtils.abbreviate("abcdefghijklmno", ",", 0, 10)    = "abcdefghi,"
320     * StringUtils.abbreviate("abcdefghijklmno", ",", 1, 10)    = "abcdefghi,"
321     * StringUtils.abbreviate("abcdefghijklmno", ",", 2, 10)    = "abcdefghi,"
322     * StringUtils.abbreviate("abcdefghijklmno", "::", 4, 10)   = "::efghij::"
323     * StringUtils.abbreviate("abcdefghijklmno", "...", 6, 10)  = "...ghij..."
324     * StringUtils.abbreviate("abcdefghijklmno", "*", 9, 10)    = "*ghijklmno"
325     * StringUtils.abbreviate("abcdefghijklmno", "'", 10, 10)   = "'ghijklmno"
326     * StringUtils.abbreviate("abcdefghijklmno", "!", 12, 10)   = "!ghijklmno"
327     * StringUtils.abbreviate("abcdefghij", "abra", 0, 4)       = IllegalArgumentException
328     * StringUtils.abbreviate("abcdefghij", "...", 5, 6)        = IllegalArgumentException
329     * </pre>
330     *
331     * @param str  the String to check, may be null
332     * @param abbrevMarker  the String used as replacement marker
333     * @param offset  left edge of source String
334     * @param maxWidth  maximum length of result String, must be at least 4
335     * @return abbreviated String, {@code null} if null String input
336     * @throws IllegalArgumentException if the width is too small
337     * @since 3.6
338     */
339    public static String abbreviate(final String str, final String abbrevMarker, int offset, final int maxWidth) {
340        if (isNotEmpty(str) && EMPTY.equals(abbrevMarker) && maxWidth > 0) {
341            return substring(str, 0, maxWidth);
342        } else if (isAnyEmpty(str, abbrevMarker)) {
343            return str;
344        }
345        final int abbrevMarkerLength = abbrevMarker.length();
346        final int minAbbrevWidth = abbrevMarkerLength + 1;
347        final int minAbbrevWidthOffset = abbrevMarkerLength + abbrevMarkerLength + 1;
348
349        if (maxWidth < minAbbrevWidth) {
350            throw new IllegalArgumentException(String.format("Minimum abbreviation width is %d", minAbbrevWidth));
351        }
352        if (str.length() <= maxWidth) {
353            return str;
354        }
355        if (offset > str.length()) {
356            offset = str.length();
357        }
358        if (str.length() - offset < maxWidth - abbrevMarkerLength) {
359            offset = str.length() - (maxWidth - abbrevMarkerLength);
360        }
361        if (offset <= abbrevMarkerLength+1) {
362            return str.substring(0, maxWidth - abbrevMarkerLength) + abbrevMarker;
363        }
364        if (maxWidth < minAbbrevWidthOffset) {
365            throw new IllegalArgumentException(String.format("Minimum abbreviation width with offset is %d", minAbbrevWidthOffset));
366        }
367        if (offset + maxWidth - abbrevMarkerLength < str.length()) {
368            return abbrevMarker + abbreviate(str.substring(offset), abbrevMarker, maxWidth - abbrevMarkerLength);
369        }
370        return abbrevMarker + str.substring(str.length() - (maxWidth - abbrevMarkerLength));
371    }
372
373    /**
374     * <p>Abbreviates a String to the length passed, replacing the middle characters with the supplied
375     * replacement String.</p>
376     *
377     * <p>This abbreviation only occurs if the following criteria is met:</p>
378     * <ul>
379     * <li>Neither the String for abbreviation nor the replacement String are null or empty </li>
380     * <li>The length to truncate to is less than the length of the supplied String</li>
381     * <li>The length to truncate to is greater than 0</li>
382     * <li>The abbreviated String will have enough room for the length supplied replacement String
383     * and the first and last characters of the supplied String for abbreviation</li>
384     * </ul>
385     * <p>Otherwise, the returned String will be the same as the supplied String for abbreviation.
386     * </p>
387     *
388     * <pre>
389     * StringUtils.abbreviateMiddle(null, null, 0)      = null
390     * StringUtils.abbreviateMiddle("abc", null, 0)      = "abc"
391     * StringUtils.abbreviateMiddle("abc", ".", 0)      = "abc"
392     * StringUtils.abbreviateMiddle("abc", ".", 3)      = "abc"
393     * StringUtils.abbreviateMiddle("abcdef", ".", 4)     = "ab.f"
394     * </pre>
395     *
396     * @param str  the String to abbreviate, may be null
397     * @param middle the String to replace the middle characters with, may be null
398     * @param length the length to abbreviate {@code str} to.
399     * @return the abbreviated String if the above criteria is met, or the original String supplied for abbreviation.
400     * @since 2.5
401     */
402    public static String abbreviateMiddle(final String str, final String middle, final int length) {
403        if (isAnyEmpty(str, middle) || length >= str.length() || length < middle.length()+2) {
404            return str;
405        }
406
407        final int targetSting = length-middle.length();
408        final int startOffset = targetSting/2+targetSting%2;
409        final int endOffset = str.length()-targetSting/2;
410
411        return str.substring(0, startOffset) +
412            middle +
413            str.substring(endOffset);
414    }
415
416    /**
417     * Appends the suffix to the end of the string if the string does not
418     * already end with the suffix.
419     *
420     * @param str The string.
421     * @param suffix The suffix to append to the end of the string.
422     * @param ignoreCase Indicates whether the compare should ignore case.
423     * @param suffixes Additional suffixes that are valid terminators (optional).
424     *
425     * @return A new String if suffix was appended, the same string otherwise.
426     */
427    private static String appendIfMissing(final String str, final CharSequence suffix, final boolean ignoreCase, final CharSequence... suffixes) {
428        if (str == null || isEmpty(suffix) || endsWith(str, suffix, ignoreCase)) {
429            return str;
430        }
431        if (ArrayUtils.isNotEmpty(suffixes)) {
432            for (final CharSequence s : suffixes) {
433                if (endsWith(str, s, ignoreCase)) {
434                    return str;
435                }
436            }
437        }
438        return str + suffix.toString();
439    }
440
441    /**
442     * Appends the suffix to the end of the string if the string does not
443     * already end with any of the suffixes.
444     *
445     * <pre>
446     * StringUtils.appendIfMissing(null, null) = null
447     * StringUtils.appendIfMissing("abc", null) = "abc"
448     * StringUtils.appendIfMissing("", "xyz") = "xyz"
449     * StringUtils.appendIfMissing("abc", "xyz") = "abcxyz"
450     * StringUtils.appendIfMissing("abcxyz", "xyz") = "abcxyz"
451     * StringUtils.appendIfMissing("abcXYZ", "xyz") = "abcXYZxyz"
452     * </pre>
453     * <p>With additional suffixes,</p>
454     * <pre>
455     * StringUtils.appendIfMissing(null, null, null) = null
456     * StringUtils.appendIfMissing("abc", null, null) = "abc"
457     * StringUtils.appendIfMissing("", "xyz", null) = "xyz"
458     * StringUtils.appendIfMissing("abc", "xyz", new CharSequence[]{null}) = "abcxyz"
459     * StringUtils.appendIfMissing("abc", "xyz", "") = "abc"
460     * StringUtils.appendIfMissing("abc", "xyz", "mno") = "abcxyz"
461     * StringUtils.appendIfMissing("abcxyz", "xyz", "mno") = "abcxyz"
462     * StringUtils.appendIfMissing("abcmno", "xyz", "mno") = "abcmno"
463     * StringUtils.appendIfMissing("abcXYZ", "xyz", "mno") = "abcXYZxyz"
464     * StringUtils.appendIfMissing("abcMNO", "xyz", "mno") = "abcMNOxyz"
465     * </pre>
466     *
467     * @param str The string.
468     * @param suffix The suffix to append to the end of the string.
469     * @param suffixes Additional suffixes that are valid terminators.
470     *
471     * @return A new String if suffix was appended, the same string otherwise.
472     *
473     * @since 3.2
474     */
475    public static String appendIfMissing(final String str, final CharSequence suffix, final CharSequence... suffixes) {
476        return appendIfMissing(str, suffix, false, suffixes);
477    }
478
479    /**
480     * Appends the suffix to the end of the string if the string does not
481     * already end, case insensitive, with any of the suffixes.
482     *
483     * <pre>
484     * StringUtils.appendIfMissingIgnoreCase(null, null) = null
485     * StringUtils.appendIfMissingIgnoreCase("abc", null) = "abc"
486     * StringUtils.appendIfMissingIgnoreCase("", "xyz") = "xyz"
487     * StringUtils.appendIfMissingIgnoreCase("abc", "xyz") = "abcxyz"
488     * StringUtils.appendIfMissingIgnoreCase("abcxyz", "xyz") = "abcxyz"
489     * StringUtils.appendIfMissingIgnoreCase("abcXYZ", "xyz") = "abcXYZ"
490     * </pre>
491     * <p>With additional suffixes,</p>
492     * <pre>
493     * StringUtils.appendIfMissingIgnoreCase(null, null, null) = null
494     * StringUtils.appendIfMissingIgnoreCase("abc", null, null) = "abc"
495     * StringUtils.appendIfMissingIgnoreCase("", "xyz", null) = "xyz"
496     * StringUtils.appendIfMissingIgnoreCase("abc", "xyz", new CharSequence[]{null}) = "abcxyz"
497     * StringUtils.appendIfMissingIgnoreCase("abc", "xyz", "") = "abc"
498     * StringUtils.appendIfMissingIgnoreCase("abc", "xyz", "mno") = "abcxyz"
499     * StringUtils.appendIfMissingIgnoreCase("abcxyz", "xyz", "mno") = "abcxyz"
500     * StringUtils.appendIfMissingIgnoreCase("abcmno", "xyz", "mno") = "abcmno"
501     * StringUtils.appendIfMissingIgnoreCase("abcXYZ", "xyz", "mno") = "abcXYZ"
502     * StringUtils.appendIfMissingIgnoreCase("abcMNO", "xyz", "mno") = "abcMNO"
503     * </pre>
504     *
505     * @param str The string.
506     * @param suffix The suffix to append to the end of the string.
507     * @param suffixes Additional suffixes that are valid terminators.
508     *
509     * @return A new String if suffix was appended, the same string otherwise.
510     *
511     * @since 3.2
512     */
513    public static String appendIfMissingIgnoreCase(final String str, final CharSequence suffix, final CharSequence... suffixes) {
514        return appendIfMissing(str, suffix, true, suffixes);
515    }
516
517    /**
518     * <p>Capitalizes a String changing the first character to title case as
519     * per {@link Character#toTitleCase(int)}. No other characters are changed.</p>
520     *
521     * <p>For a word based algorithm, see {@link org.apache.commons.lang3.text.WordUtils#capitalize(String)}.
522     * A {@code null} input String returns {@code null}.</p>
523     *
524     * <pre>
525     * StringUtils.capitalize(null)  = null
526     * StringUtils.capitalize("")    = ""
527     * StringUtils.capitalize("cat") = "Cat"
528     * StringUtils.capitalize("cAt") = "CAt"
529     * StringUtils.capitalize("'cat'") = "'cat'"
530     * </pre>
531     *
532     * @param str the String to capitalize, may be null
533     * @return the capitalized String, {@code null} if null String input
534     * @see org.apache.commons.lang3.text.WordUtils#capitalize(String)
535     * @see #uncapitalize(String)
536     * @since 2.0
537     */
538    public static String capitalize(final String str) {
539        final int strLen = length(str);
540        if (strLen == 0) {
541            return str;
542        }
543
544        final int firstCodepoint = str.codePointAt(0);
545        final int newCodePoint = Character.toTitleCase(firstCodepoint);
546        if (firstCodepoint == newCodePoint) {
547            // already capitalized
548            return str;
549        }
550
551        final int[] newCodePoints = new int[strLen]; // cannot be longer than the char array
552        int outOffset = 0;
553        newCodePoints[outOffset++] = newCodePoint; // copy the first codepoint
554        for (int inOffset = Character.charCount(firstCodepoint); inOffset < strLen; ) {
555            final int codepoint = str.codePointAt(inOffset);
556            newCodePoints[outOffset++] = codepoint; // copy the remaining ones
557            inOffset += Character.charCount(codepoint);
558         }
559        return new String(newCodePoints, 0, outOffset);
560    }
561
562    // Centering
563    //-----------------------------------------------------------------------
564    /**
565     * <p>Centers a String in a larger String of size {@code size}
566     * using the space character (' ').</p>
567     *
568     * <p>If the size is less than the String length, the original String is returned.
569     * A {@code null} String returns {@code null}.
570     * A negative size is treated as zero.</p>
571     *
572     * <p>Equivalent to {@code center(str, size, " ")}.</p>
573     *
574     * <pre>
575     * StringUtils.center(null, *)   = null
576     * StringUtils.center("", 4)     = "    "
577     * StringUtils.center("ab", -1)  = "ab"
578     * StringUtils.center("ab", 4)   = " ab "
579     * StringUtils.center("abcd", 2) = "abcd"
580     * StringUtils.center("a", 4)    = " a  "
581     * </pre>
582     *
583     * @param str  the String to center, may be null
584     * @param size  the int size of new String, negative treated as zero
585     * @return centered String, {@code null} if null String input
586     */
587    public static String center(final String str, final int size) {
588        return center(str, size, ' ');
589    }
590
591    /**
592     * <p>Centers a String in a larger String of size {@code size}.
593     * Uses a supplied character as the value to pad the String with.</p>
594     *
595     * <p>If the size is less than the String length, the String is returned.
596     * A {@code null} String returns {@code null}.
597     * A negative size is treated as zero.</p>
598     *
599     * <pre>
600     * StringUtils.center(null, *, *)     = null
601     * StringUtils.center("", 4, ' ')     = "    "
602     * StringUtils.center("ab", -1, ' ')  = "ab"
603     * StringUtils.center("ab", 4, ' ')   = " ab "
604     * StringUtils.center("abcd", 2, ' ') = "abcd"
605     * StringUtils.center("a", 4, ' ')    = " a  "
606     * StringUtils.center("a", 4, 'y')    = "yayy"
607     * </pre>
608     *
609     * @param str  the String to center, may be null
610     * @param size  the int size of new String, negative treated as zero
611     * @param padChar  the character to pad the new String with
612     * @return centered String, {@code null} if null String input
613     * @since 2.0
614     */
615    public static String center(String str, final int size, final char padChar) {
616        if (str == null || size <= 0) {
617            return str;
618        }
619        final int strLen = str.length();
620        final int pads = size - strLen;
621        if (pads <= 0) {
622            return str;
623        }
624        str = leftPad(str, strLen + pads / 2, padChar);
625        str = rightPad(str, size, padChar);
626        return str;
627    }
628
629    /**
630     * <p>Centers a String in a larger String of size {@code size}.
631     * Uses a supplied String as the value to pad the String with.</p>
632     *
633     * <p>If the size is less than the String length, the String is returned.
634     * A {@code null} String returns {@code null}.
635     * A negative size is treated as zero.</p>
636     *
637     * <pre>
638     * StringUtils.center(null, *, *)     = null
639     * StringUtils.center("", 4, " ")     = "    "
640     * StringUtils.center("ab", -1, " ")  = "ab"
641     * StringUtils.center("ab", 4, " ")   = " ab "
642     * StringUtils.center("abcd", 2, " ") = "abcd"
643     * StringUtils.center("a", 4, " ")    = " a  "
644     * StringUtils.center("a", 4, "yz")   = "yayz"
645     * StringUtils.center("abc", 7, null) = "  abc  "
646     * StringUtils.center("abc", 7, "")   = "  abc  "
647     * </pre>
648     *
649     * @param str  the String to center, may be null
650     * @param size  the int size of new String, negative treated as zero
651     * @param padStr  the String to pad the new String with, must not be null or empty
652     * @return centered String, {@code null} if null String input
653     * @throws IllegalArgumentException if padStr is {@code null} or empty
654     */
655    public static String center(String str, final int size, String padStr) {
656        if (str == null || size <= 0) {
657            return str;
658        }
659        if (isEmpty(padStr)) {
660            padStr = SPACE;
661        }
662        final int strLen = str.length();
663        final int pads = size - strLen;
664        if (pads <= 0) {
665            return str;
666        }
667        str = leftPad(str, strLen + pads / 2, padStr);
668        str = rightPad(str, size, padStr);
669        return str;
670    }
671
672    // Chomping
673    //-----------------------------------------------------------------------
674    /**
675     * <p>Removes one newline from end of a String if it's there,
676     * otherwise leave it alone.  A newline is &quot;{@code \n}&quot;,
677     * &quot;{@code \r}&quot;, or &quot;{@code \r\n}&quot;.</p>
678     *
679     * <p>NOTE: This method changed in 2.0.
680     * It now more closely matches Perl chomp.</p>
681     *
682     * <pre>
683     * StringUtils.chomp(null)          = null
684     * StringUtils.chomp("")            = ""
685     * StringUtils.chomp("abc \r")      = "abc "
686     * StringUtils.chomp("abc\n")       = "abc"
687     * StringUtils.chomp("abc\r\n")     = "abc"
688     * StringUtils.chomp("abc\r\n\r\n") = "abc\r\n"
689     * StringUtils.chomp("abc\n\r")     = "abc\n"
690     * StringUtils.chomp("abc\n\rabc")  = "abc\n\rabc"
691     * StringUtils.chomp("\r")          = ""
692     * StringUtils.chomp("\n")          = ""
693     * StringUtils.chomp("\r\n")        = ""
694     * </pre>
695     *
696     * @param str  the String to chomp a newline from, may be null
697     * @return String without newline, {@code null} if null String input
698     */
699    public static String chomp(final String str) {
700        if (isEmpty(str)) {
701            return str;
702        }
703
704        if (str.length() == 1) {
705            final char ch = str.charAt(0);
706            if (ch == CharUtils.CR || ch == CharUtils.LF) {
707                return EMPTY;
708            }
709            return str;
710        }
711
712        int lastIdx = str.length() - 1;
713        final char last = str.charAt(lastIdx);
714
715        if (last == CharUtils.LF) {
716            if (str.charAt(lastIdx - 1) == CharUtils.CR) {
717                lastIdx--;
718            }
719        } else if (last != CharUtils.CR) {
720            lastIdx++;
721        }
722        return str.substring(0, lastIdx);
723    }
724
725    /**
726     * <p>Removes {@code separator} from the end of
727     * {@code str} if it's there, otherwise leave it alone.</p>
728     *
729     * <p>NOTE: This method changed in version 2.0.
730     * It now more closely matches Perl chomp.
731     * For the previous behavior, use {@link #substringBeforeLast(String, String)}.
732     * This method uses {@link String#endsWith(String)}.</p>
733     *
734     * <pre>
735     * StringUtils.chomp(null, *)         = null
736     * StringUtils.chomp("", *)           = ""
737     * StringUtils.chomp("foobar", "bar") = "foo"
738     * StringUtils.chomp("foobar", "baz") = "foobar"
739     * StringUtils.chomp("foo", "foo")    = ""
740     * StringUtils.chomp("foo ", "foo")   = "foo "
741     * StringUtils.chomp(" foo", "foo")   = " "
742     * StringUtils.chomp("foo", "foooo")  = "foo"
743     * StringUtils.chomp("foo", "")       = "foo"
744     * StringUtils.chomp("foo", null)     = "foo"
745     * </pre>
746     *
747     * @param str  the String to chomp from, may be null
748     * @param separator  separator String, may be null
749     * @return String without trailing separator, {@code null} if null String input
750     * @deprecated This feature will be removed in Lang 4.0, use {@link StringUtils#removeEnd(String, String)} instead
751     */
752    @Deprecated
753    public static String chomp(final String str, final String separator) {
754        return removeEnd(str, separator);
755    }
756
757    // Chopping
758    //-----------------------------------------------------------------------
759    /**
760     * <p>Remove the last character from a String.</p>
761     *
762     * <p>If the String ends in {@code \r\n}, then remove both
763     * of them.</p>
764     *
765     * <pre>
766     * StringUtils.chop(null)          = null
767     * StringUtils.chop("")            = ""
768     * StringUtils.chop("abc \r")      = "abc "
769     * StringUtils.chop("abc\n")       = "abc"
770     * StringUtils.chop("abc\r\n")     = "abc"
771     * StringUtils.chop("abc")         = "ab"
772     * StringUtils.chop("abc\nabc")    = "abc\nab"
773     * StringUtils.chop("a")           = ""
774     * StringUtils.chop("\r")          = ""
775     * StringUtils.chop("\n")          = ""
776     * StringUtils.chop("\r\n")        = ""
777     * </pre>
778     *
779     * @param str  the String to chop last character from, may be null
780     * @return String without last character, {@code null} if null String input
781     */
782    public static String chop(final String str) {
783        if (str == null) {
784            return null;
785        }
786        final int strLen = str.length();
787        if (strLen < 2) {
788            return EMPTY;
789        }
790        final int lastIdx = strLen - 1;
791        final String ret = str.substring(0, lastIdx);
792        final char last = str.charAt(lastIdx);
793        if (last == CharUtils.LF && ret.charAt(lastIdx - 1) == CharUtils.CR) {
794            return ret.substring(0, lastIdx - 1);
795        }
796        return ret;
797    }
798
799    // Compare
800    //-----------------------------------------------------------------------
801    /**
802     * <p>Compare two Strings lexicographically, as per {@link String#compareTo(String)}, returning :</p>
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} value is considered less than non-{@code null} value.
813     * Two {@code null} references are considered equal.</p>
814     *
815     * <pre>
816     * StringUtils.compare(null, null)   = 0
817     * StringUtils.compare(null , "a")   &lt; 0
818     * StringUtils.compare("a", null)    &gt; 0
819     * StringUtils.compare("abc", "abc") = 0
820     * StringUtils.compare("a", "b")     &lt; 0
821     * StringUtils.compare("b", "a")     &gt; 0
822     * StringUtils.compare("a", "B")     &gt; 0
823     * StringUtils.compare("ab", "abc")  &lt; 0
824     * </pre>
825     *
826     * @see #compare(String, String, boolean)
827     * @see String#compareTo(String)
828     * @param str1  the String to compare from
829     * @param str2  the String to compare to
830     * @return &lt; 0, 0, &gt; 0, if {@code str1} is respectively less, equal or greater than {@code str2}
831     * @since 3.5
832     */
833    public static int compare(final String str1, final String str2) {
834        return compare(str1, str2, true);
835    }
836
837    /**
838     * <p>Compare two Strings lexicographically, as per {@link String#compareTo(String)}, returning :</p>
839     * <ul>
840     *  <li>{@code int = 0}, if {@code str1} is equal to {@code str2} (or both {@code null})</li>
841     *  <li>{@code int < 0}, if {@code str1} is less than {@code str2}</li>
842     *  <li>{@code int > 0}, if {@code str1} is greater than {@code str2}</li>
843     * </ul>
844     *
845     * <p>This is a {@code null} safe version of :</p>
846     * <blockquote><pre>str1.compareTo(str2)</pre></blockquote>
847     *
848     * <p>{@code null} inputs are handled according to the {@code nullIsLess} parameter.
849     * Two {@code null} references are considered equal.</p>
850     *
851     * <pre>
852     * StringUtils.compare(null, null, *)     = 0
853     * StringUtils.compare(null , "a", true)  &lt; 0
854     * StringUtils.compare(null , "a", false) &gt; 0
855     * StringUtils.compare("a", null, true)   &gt; 0
856     * StringUtils.compare("a", null, false)  &lt; 0
857     * StringUtils.compare("abc", "abc", *)   = 0
858     * StringUtils.compare("a", "b", *)       &lt; 0
859     * StringUtils.compare("b", "a", *)       &gt; 0
860     * StringUtils.compare("a", "B", *)       &gt; 0
861     * StringUtils.compare("ab", "abc", *)    &lt; 0
862     * </pre>
863     *
864     * @see String#compareTo(String)
865     * @param str1  the String to compare from
866     * @param str2  the String to compare to
867     * @param nullIsLess  whether consider {@code null} value less than non-{@code null} value
868     * @return &lt; 0, 0, &gt; 0, if {@code str1} is respectively less, equal ou greater than {@code str2}
869     * @since 3.5
870     */
871    public static int compare(final String str1, final String str2, final boolean nullIsLess) {
872        if (str1 == str2) {
873            return 0;
874        }
875        if (str1 == null) {
876            return nullIsLess ? -1 : 1;
877        }
878        if (str2 == null) {
879            return nullIsLess ? 1 : - 1;
880        }
881        return str1.compareTo(str2);
882    }
883
884    /**
885     * <p>Compare two Strings lexicographically, ignoring case differences,
886     * as per {@link String#compareToIgnoreCase(String)}, returning :</p>
887     * <ul>
888     *  <li>{@code int = 0}, if {@code str1} is equal to {@code str2} (or both {@code null})</li>
889     *  <li>{@code int < 0}, if {@code str1} is less than {@code str2}</li>
890     *  <li>{@code int > 0}, if {@code str1} is greater than {@code str2}</li>
891     * </ul>
892     *
893     * <p>This is a {@code null} safe version of :</p>
894     * <blockquote><pre>str1.compareToIgnoreCase(str2)</pre></blockquote>
895     *
896     * <p>{@code null} value is considered less than non-{@code null} value.
897     * Two {@code null} references are considered equal.
898     * Comparison is case insensitive.</p>
899     *
900     * <pre>
901     * StringUtils.compareIgnoreCase(null, null)   = 0
902     * StringUtils.compareIgnoreCase(null , "a")   &lt; 0
903     * StringUtils.compareIgnoreCase("a", null)    &gt; 0
904     * StringUtils.compareIgnoreCase("abc", "abc") = 0
905     * StringUtils.compareIgnoreCase("abc", "ABC") = 0
906     * StringUtils.compareIgnoreCase("a", "b")     &lt; 0
907     * StringUtils.compareIgnoreCase("b", "a")     &gt; 0
908     * StringUtils.compareIgnoreCase("a", "B")     &lt; 0
909     * StringUtils.compareIgnoreCase("A", "b")     &lt; 0
910     * StringUtils.compareIgnoreCase("ab", "ABC")  &lt; 0
911     * </pre>
912     *
913     * @see #compareIgnoreCase(String, String, boolean)
914     * @see String#compareToIgnoreCase(String)
915     * @param str1  the String to compare from
916     * @param str2  the String to compare to
917     * @return &lt; 0, 0, &gt; 0, if {@code str1} is respectively less, equal ou greater than {@code str2},
918     *          ignoring case differences.
919     * @since 3.5
920     */
921    public static int compareIgnoreCase(final String str1, final String str2) {
922        return compareIgnoreCase(str1, str2, true);
923    }
924
925    /**
926     * <p>Compare two Strings lexicographically, ignoring case differences,
927     * as per {@link String#compareToIgnoreCase(String)}, returning :</p>
928     * <ul>
929     *  <li>{@code int = 0}, if {@code str1} is equal to {@code str2} (or both {@code null})</li>
930     *  <li>{@code int < 0}, if {@code str1} is less than {@code str2}</li>
931     *  <li>{@code int > 0}, if {@code str1} is greater than {@code str2}</li>
932     * </ul>
933     *
934     * <p>This is a {@code null} safe version of :</p>
935     * <blockquote><pre>str1.compareToIgnoreCase(str2)</pre></blockquote>
936     *
937     * <p>{@code null} inputs are handled according to the {@code nullIsLess} parameter.
938     * Two {@code null} references are considered equal.
939     * Comparison is case insensitive.</p>
940     *
941     * <pre>
942     * StringUtils.compareIgnoreCase(null, null, *)     = 0
943     * StringUtils.compareIgnoreCase(null , "a", true)  &lt; 0
944     * StringUtils.compareIgnoreCase(null , "a", false) &gt; 0
945     * StringUtils.compareIgnoreCase("a", null, true)   &gt; 0
946     * StringUtils.compareIgnoreCase("a", null, false)  &lt; 0
947     * StringUtils.compareIgnoreCase("abc", "abc", *)   = 0
948     * StringUtils.compareIgnoreCase("abc", "ABC", *)   = 0
949     * StringUtils.compareIgnoreCase("a", "b", *)       &lt; 0
950     * StringUtils.compareIgnoreCase("b", "a", *)       &gt; 0
951     * StringUtils.compareIgnoreCase("a", "B", *)       &lt; 0
952     * StringUtils.compareIgnoreCase("A", "b", *)       &lt; 0
953     * StringUtils.compareIgnoreCase("ab", "abc", *)    &lt; 0
954     * </pre>
955     *
956     * @see String#compareToIgnoreCase(String)
957     * @param str1  the String to compare from
958     * @param str2  the String to compare to
959     * @param nullIsLess  whether consider {@code null} value less than non-{@code null} value
960     * @return &lt; 0, 0, &gt; 0, if {@code str1} is respectively less, equal ou greater than {@code str2},
961     *          ignoring case differences.
962     * @since 3.5
963     */
964    public static int compareIgnoreCase(final String str1, final String str2, final boolean nullIsLess) {
965        if (str1 == str2) {
966            return 0;
967        }
968        if (str1 == null) {
969            return nullIsLess ? -1 : 1;
970        }
971        if (str2 == null) {
972            return nullIsLess ? 1 : - 1;
973        }
974        return str1.compareToIgnoreCase(str2);
975    }
976
977    /**
978     * <p>Checks if CharSequence contains a search CharSequence, handling {@code null}.
979     * This method uses {@link String#indexOf(String)} if possible.</p>
980     *
981     * <p>A {@code null} CharSequence will return {@code false}.</p>
982     *
983     * <pre>
984     * StringUtils.contains(null, *)     = false
985     * StringUtils.contains(*, null)     = false
986     * StringUtils.contains("", "")      = true
987     * StringUtils.contains("abc", "")   = true
988     * StringUtils.contains("abc", "a")  = true
989     * StringUtils.contains("abc", "z")  = false
990     * </pre>
991     *
992     * @param seq  the CharSequence to check, may be null
993     * @param searchSeq  the CharSequence to find, may be null
994     * @return true if the CharSequence contains the search CharSequence,
995     *  false if not or {@code null} string input
996     * @since 2.0
997     * @since 3.0 Changed signature from contains(String, String) to contains(CharSequence, CharSequence)
998     */
999    public static boolean contains(final CharSequence seq, final CharSequence searchSeq) {
1000        if (seq == null || searchSeq == null) {
1001            return false;
1002        }
1003        return CharSequenceUtils.indexOf(seq, searchSeq, 0) >= 0;
1004    }
1005
1006    // Contains
1007    //-----------------------------------------------------------------------
1008    /**
1009     * <p>Checks if CharSequence contains a search character, handling {@code null}.
1010     * This method uses {@link String#indexOf(int)} if possible.</p>
1011     *
1012     * <p>A {@code null} or empty ("") CharSequence will return {@code false}.</p>
1013     *
1014     * <pre>
1015     * StringUtils.contains(null, *)    = false
1016     * StringUtils.contains("", *)      = false
1017     * StringUtils.contains("abc", 'a') = true
1018     * StringUtils.contains("abc", 'z') = false
1019     * </pre>
1020     *
1021     * @param seq  the CharSequence to check, may be null
1022     * @param searchChar  the character to find
1023     * @return true if the CharSequence contains the search character,
1024     *  false if not or {@code null} string input
1025     * @since 2.0
1026     * @since 3.0 Changed signature from contains(String, int) to contains(CharSequence, int)
1027     */
1028    public static boolean contains(final CharSequence seq, final int searchChar) {
1029        if (isEmpty(seq)) {
1030            return false;
1031        }
1032        return CharSequenceUtils.indexOf(seq, searchChar, 0) >= 0;
1033    }
1034
1035    // ContainsAny
1036    //-----------------------------------------------------------------------
1037    /**
1038     * <p>Checks if the CharSequence contains any character in the given
1039     * set of characters.</p>
1040     *
1041     * <p>A {@code null} CharSequence will return {@code false}.
1042     * A {@code null} or zero length search array will return {@code false}.</p>
1043     *
1044     * <pre>
1045     * StringUtils.containsAny(null, *)                  = false
1046     * StringUtils.containsAny("", *)                    = false
1047     * StringUtils.containsAny(*, null)                  = false
1048     * StringUtils.containsAny(*, [])                    = false
1049     * StringUtils.containsAny("zzabyycdxx", ['z', 'a']) = true
1050     * StringUtils.containsAny("zzabyycdxx", ['b', 'y']) = true
1051     * StringUtils.containsAny("zzabyycdxx", ['z', 'y']) = true
1052     * StringUtils.containsAny("aba", ['z'])             = false
1053     * </pre>
1054     *
1055     * @param cs  the CharSequence to check, may be null
1056     * @param searchChars  the chars to search for, may be null
1057     * @return the {@code true} if any of the chars are found,
1058     * {@code false} if no match or null input
1059     * @since 2.4
1060     * @since 3.0 Changed signature from containsAny(String, char[]) to containsAny(CharSequence, char...)
1061     */
1062    public static boolean containsAny(final CharSequence cs, final char... searchChars) {
1063        if (isEmpty(cs) || ArrayUtils.isEmpty(searchChars)) {
1064            return false;
1065        }
1066        final int csLength = cs.length();
1067        final int searchLength = searchChars.length;
1068        final int csLast = csLength - 1;
1069        final int searchLast = searchLength - 1;
1070        for (int i = 0; i < csLength; i++) {
1071            final char ch = cs.charAt(i);
1072            for (int j = 0; j < searchLength; j++) {
1073                if (searchChars[j] == ch) {
1074                    if (Character.isHighSurrogate(ch)) {
1075                        if (j == searchLast) {
1076                            // missing low surrogate, fine, like String.indexOf(String)
1077                            return true;
1078                        }
1079                        if (i < csLast && searchChars[j + 1] == cs.charAt(i + 1)) {
1080                            return true;
1081                        }
1082                    } else {
1083                        // ch is in the Basic Multilingual Plane
1084                        return true;
1085                    }
1086                }
1087            }
1088        }
1089        return false;
1090    }
1091
1092    /**
1093     * <p>
1094     * Checks if the CharSequence contains any character in the given set of characters.
1095     * </p>
1096     *
1097     * <p>
1098     * A {@code null} CharSequence will return {@code false}. A {@code null} search CharSequence will return
1099     * {@code false}.
1100     * </p>
1101     *
1102     * <pre>
1103     * StringUtils.containsAny(null, *)               = false
1104     * StringUtils.containsAny("", *)                 = false
1105     * StringUtils.containsAny(*, null)               = false
1106     * StringUtils.containsAny(*, "")                 = false
1107     * StringUtils.containsAny("zzabyycdxx", "za")    = true
1108     * StringUtils.containsAny("zzabyycdxx", "by")    = true
1109     * StringUtils.containsAny("zzabyycdxx", "zy")    = true
1110     * StringUtils.containsAny("zzabyycdxx", "\tx")   = true
1111     * StringUtils.containsAny("zzabyycdxx", "$.#yF") = true
1112     * StringUtils.containsAny("aba", "z")            = false
1113     * </pre>
1114     *
1115     * @param cs
1116     *            the CharSequence to check, may be null
1117     * @param searchChars
1118     *            the chars to search for, may be null
1119     * @return the {@code true} if any of the chars are found, {@code false} if no match or null input
1120     * @since 2.4
1121     * @since 3.0 Changed signature from containsAny(String, String) to containsAny(CharSequence, CharSequence)
1122     */
1123    public static boolean containsAny(final CharSequence cs, final CharSequence searchChars) {
1124        if (searchChars == null) {
1125            return false;
1126        }
1127        return containsAny(cs, CharSequenceUtils.toCharArray(searchChars));
1128    }
1129
1130    /**
1131     * <p>Checks if the CharSequence contains any of the CharSequences in the given array.</p>
1132     *
1133     * <p>
1134     * A {@code null} {@code cs} CharSequence will return {@code false}. A {@code null} or zero
1135     * length search array will return {@code false}.
1136     * </p>
1137     *
1138     * <pre>
1139     * StringUtils.containsAny(null, *)            = false
1140     * StringUtils.containsAny("", *)              = false
1141     * StringUtils.containsAny(*, null)            = false
1142     * StringUtils.containsAny(*, [])              = false
1143     * StringUtils.containsAny("abcd", "ab", null) = true
1144     * StringUtils.containsAny("abcd", "ab", "cd") = true
1145     * StringUtils.containsAny("abc", "d", "abc")  = true
1146     * </pre>
1147     *
1148     *
1149     * @param cs The CharSequence to check, may be null
1150     * @param searchCharSequences The array of CharSequences to search for, may be null.
1151     * Individual CharSequences may be null as well.
1152     * @return {@code true} if any of the search CharSequences are found, {@code false} otherwise
1153     * @since 3.4
1154     */
1155    public static boolean containsAny(final CharSequence cs, final CharSequence... searchCharSequences) {
1156        if (isEmpty(cs) || ArrayUtils.isEmpty(searchCharSequences)) {
1157            return false;
1158        }
1159        for (final CharSequence searchCharSequence : searchCharSequences) {
1160            if (contains(cs, searchCharSequence)) {
1161                return true;
1162            }
1163        }
1164        return false;
1165    }
1166
1167    /**
1168     * <p>Checks if CharSequence contains a search CharSequence irrespective of case,
1169     * handling {@code null}. Case-insensitivity is defined as by
1170     * {@link String#equalsIgnoreCase(String)}.
1171     *
1172     * <p>A {@code null} CharSequence will return {@code false}.</p>
1173     *
1174     * <pre>
1175     * StringUtils.containsIgnoreCase(null, *) = false
1176     * StringUtils.containsIgnoreCase(*, null) = false
1177     * StringUtils.containsIgnoreCase("", "") = true
1178     * StringUtils.containsIgnoreCase("abc", "") = true
1179     * StringUtils.containsIgnoreCase("abc", "a") = true
1180     * StringUtils.containsIgnoreCase("abc", "z") = false
1181     * StringUtils.containsIgnoreCase("abc", "A") = true
1182     * StringUtils.containsIgnoreCase("abc", "Z") = false
1183     * </pre>
1184     *
1185     * @param str  the CharSequence to check, may be null
1186     * @param searchStr  the CharSequence to find, may be null
1187     * @return true if the CharSequence contains the search CharSequence irrespective of
1188     * case or false if not or {@code null} string input
1189     * @since 3.0 Changed signature from containsIgnoreCase(String, String) to containsIgnoreCase(CharSequence, CharSequence)
1190     */
1191    public static boolean containsIgnoreCase(final CharSequence str, final CharSequence searchStr) {
1192        if (str == null || searchStr == null) {
1193            return false;
1194        }
1195        final int len = searchStr.length();
1196        final int max = str.length() - len;
1197        for (int i = 0; i <= max; i++) {
1198            if (CharSequenceUtils.regionMatches(str, true, i, searchStr, 0, len)) {
1199                return true;
1200            }
1201        }
1202        return false;
1203    }
1204
1205    // ContainsNone
1206    //-----------------------------------------------------------------------
1207    /**
1208     * <p>Checks that the CharSequence does not contain certain characters.</p>
1209     *
1210     * <p>A {@code null} CharSequence will return {@code true}.
1211     * A {@code null} invalid character array will return {@code true}.
1212     * An empty CharSequence (length()=0) always returns true.</p>
1213     *
1214     * <pre>
1215     * StringUtils.containsNone(null, *)       = true
1216     * StringUtils.containsNone(*, null)       = true
1217     * StringUtils.containsNone("", *)         = true
1218     * StringUtils.containsNone("ab", '')      = true
1219     * StringUtils.containsNone("abab", 'xyz') = true
1220     * StringUtils.containsNone("ab1", 'xyz')  = true
1221     * StringUtils.containsNone("abz", 'xyz')  = false
1222     * </pre>
1223     *
1224     * @param cs  the CharSequence to check, may be null
1225     * @param searchChars  an array of invalid chars, may be null
1226     * @return true if it contains none of the invalid chars, or is null
1227     * @since 2.0
1228     * @since 3.0 Changed signature from containsNone(String, char[]) to containsNone(CharSequence, char...)
1229     */
1230    public static boolean containsNone(final CharSequence cs, final char... searchChars) {
1231        if (cs == null || searchChars == null) {
1232            return true;
1233        }
1234        final int csLen = cs.length();
1235        final int csLast = csLen - 1;
1236        final int searchLen = searchChars.length;
1237        final int searchLast = searchLen - 1;
1238        for (int i = 0; i < csLen; i++) {
1239            final char ch = cs.charAt(i);
1240            for (int j = 0; j < searchLen; j++) {
1241                if (searchChars[j] == ch) {
1242                    if (Character.isHighSurrogate(ch)) {
1243                        if (j == searchLast) {
1244                            // missing low surrogate, fine, like String.indexOf(String)
1245                            return false;
1246                        }
1247                        if (i < csLast && searchChars[j + 1] == cs.charAt(i + 1)) {
1248                            return false;
1249                        }
1250                    } else {
1251                        // ch is in the Basic Multilingual Plane
1252                        return false;
1253                    }
1254                }
1255            }
1256        }
1257        return true;
1258    }
1259
1260    /**
1261     * <p>Checks that the CharSequence does not contain certain characters.</p>
1262     *
1263     * <p>A {@code null} CharSequence will return {@code true}.
1264     * A {@code null} invalid character array will return {@code true}.
1265     * An empty String ("") always returns true.</p>
1266     *
1267     * <pre>
1268     * StringUtils.containsNone(null, *)       = true
1269     * StringUtils.containsNone(*, null)       = true
1270     * StringUtils.containsNone("", *)         = true
1271     * StringUtils.containsNone("ab", "")      = true
1272     * StringUtils.containsNone("abab", "xyz") = true
1273     * StringUtils.containsNone("ab1", "xyz")  = true
1274     * StringUtils.containsNone("abz", "xyz")  = false
1275     * </pre>
1276     *
1277     * @param cs  the CharSequence to check, may be null
1278     * @param invalidChars  a String of invalid chars, may be null
1279     * @return true if it contains none of the invalid chars, or is null
1280     * @since 2.0
1281     * @since 3.0 Changed signature from containsNone(String, String) to containsNone(CharSequence, String)
1282     */
1283    public static boolean containsNone(final CharSequence cs, final String invalidChars) {
1284        if (cs == null || invalidChars == null) {
1285            return true;
1286        }
1287        return containsNone(cs, invalidChars.toCharArray());
1288    }
1289
1290    // ContainsOnly
1291    //-----------------------------------------------------------------------
1292    /**
1293     * <p>Checks if the CharSequence contains only certain characters.</p>
1294     *
1295     * <p>A {@code null} CharSequence will return {@code false}.
1296     * A {@code null} valid character array will return {@code false}.
1297     * An empty CharSequence (length()=0) always returns {@code true}.</p>
1298     *
1299     * <pre>
1300     * StringUtils.containsOnly(null, *)       = false
1301     * StringUtils.containsOnly(*, null)       = false
1302     * StringUtils.containsOnly("", *)         = true
1303     * StringUtils.containsOnly("ab", '')      = false
1304     * StringUtils.containsOnly("abab", 'abc') = true
1305     * StringUtils.containsOnly("ab1", 'abc')  = false
1306     * StringUtils.containsOnly("abz", 'abc')  = false
1307     * </pre>
1308     *
1309     * @param cs  the String to check, may be null
1310     * @param valid  an array of valid chars, may be null
1311     * @return true if it only contains valid chars and is non-null
1312     * @since 3.0 Changed signature from containsOnly(String, char[]) to containsOnly(CharSequence, char...)
1313     */
1314    public static boolean containsOnly(final CharSequence cs, final char... valid) {
1315        // All these pre-checks are to maintain API with an older version
1316        if (valid == null || cs == null) {
1317            return false;
1318        }
1319        if (cs.length() == 0) {
1320            return true;
1321        }
1322        if (valid.length == 0) {
1323            return false;
1324        }
1325        return indexOfAnyBut(cs, valid) == INDEX_NOT_FOUND;
1326    }
1327
1328    /**
1329     * <p>Checks if the CharSequence contains only certain characters.</p>
1330     *
1331     * <p>A {@code null} CharSequence will return {@code false}.
1332     * A {@code null} valid character String will return {@code false}.
1333     * An empty String (length()=0) always returns {@code true}.</p>
1334     *
1335     * <pre>
1336     * StringUtils.containsOnly(null, *)       = false
1337     * StringUtils.containsOnly(*, null)       = false
1338     * StringUtils.containsOnly("", *)         = true
1339     * StringUtils.containsOnly("ab", "")      = false
1340     * StringUtils.containsOnly("abab", "abc") = true
1341     * StringUtils.containsOnly("ab1", "abc")  = false
1342     * StringUtils.containsOnly("abz", "abc")  = false
1343     * </pre>
1344     *
1345     * @param cs  the CharSequence to check, may be null
1346     * @param validChars  a String of valid chars, may be null
1347     * @return true if it only contains valid chars and is non-null
1348     * @since 2.0
1349     * @since 3.0 Changed signature from containsOnly(String, String) to containsOnly(CharSequence, String)
1350     */
1351    public static boolean containsOnly(final CharSequence cs, final String validChars) {
1352        if (cs == null || validChars == null) {
1353            return false;
1354        }
1355        return containsOnly(cs, validChars.toCharArray());
1356    }
1357
1358    /**
1359     * <p>Check whether the given CharSequence contains any whitespace characters.</p>
1360     *
1361     * <p>Whitespace is defined by {@link Character#isWhitespace(char)}.</p>
1362     *
1363     * @param seq the CharSequence to check (may be {@code null})
1364     * @return {@code true} if the CharSequence is not empty and
1365     * contains at least 1 (breaking) whitespace character
1366     * @since 3.0
1367     */
1368    // From org.springframework.util.StringUtils, under Apache License 2.0
1369    public static boolean containsWhitespace(final CharSequence seq) {
1370        if (isEmpty(seq)) {
1371            return false;
1372        }
1373        final int strLen = seq.length();
1374        for (int i = 0; i < strLen; i++) {
1375            if (Character.isWhitespace(seq.charAt(i))) {
1376                return true;
1377            }
1378        }
1379        return false;
1380    }
1381
1382    private static void convertRemainingAccentCharacters(final StringBuilder decomposed) {
1383        for (int i = 0; i < decomposed.length(); i++) {
1384            if (decomposed.charAt(i) == '\u0141') {
1385                decomposed.deleteCharAt(i);
1386                decomposed.insert(i, 'L');
1387            } else if (decomposed.charAt(i) == '\u0142') {
1388                decomposed.deleteCharAt(i);
1389                decomposed.insert(i, 'l');
1390            }
1391        }
1392    }
1393
1394    /**
1395     * <p>Counts how many times the char appears in the given string.</p>
1396     *
1397     * <p>A {@code null} or empty ("") String input returns {@code 0}.</p>
1398     *
1399     * <pre>
1400     * StringUtils.countMatches(null, *)       = 0
1401     * StringUtils.countMatches("", *)         = 0
1402     * StringUtils.countMatches("abba", 0)  = 0
1403     * StringUtils.countMatches("abba", 'a')   = 2
1404     * StringUtils.countMatches("abba", 'b')  = 2
1405     * StringUtils.countMatches("abba", 'x') = 0
1406     * </pre>
1407     *
1408     * @param str  the CharSequence to check, may be null
1409     * @param ch  the char to count
1410     * @return the number of occurrences, 0 if the CharSequence is {@code null}
1411     * @since 3.4
1412     */
1413    public static int countMatches(final CharSequence str, final char ch) {
1414        if (isEmpty(str)) {
1415            return 0;
1416        }
1417        int count = 0;
1418        // We could also call str.toCharArray() for faster look ups but that would generate more garbage.
1419        for (int i = 0; i < str.length(); i++) {
1420            if (ch == str.charAt(i)) {
1421                count++;
1422            }
1423        }
1424        return count;
1425    }
1426
1427    // Count matches
1428    //-----------------------------------------------------------------------
1429    /**
1430     * <p>Counts how many times the substring appears in the larger string.</p>
1431     *
1432     * <p>A {@code null} or empty ("") String input returns {@code 0}.</p>
1433     *
1434     * <pre>
1435     * StringUtils.countMatches(null, *)       = 0
1436     * StringUtils.countMatches("", *)         = 0
1437     * StringUtils.countMatches("abba", null)  = 0
1438     * StringUtils.countMatches("abba", "")    = 0
1439     * StringUtils.countMatches("abba", "a")   = 2
1440     * StringUtils.countMatches("abba", "ab")  = 1
1441     * StringUtils.countMatches("abba", "xxx") = 0
1442     * </pre>
1443     *
1444     * @param str  the CharSequence to check, may be null
1445     * @param sub  the substring to count, may be null
1446     * @return the number of occurrences, 0 if either CharSequence is {@code null}
1447     * @since 3.0 Changed signature from countMatches(String, String) to countMatches(CharSequence, CharSequence)
1448     */
1449    public static int countMatches(final CharSequence str, final CharSequence sub) {
1450        if (isEmpty(str) || isEmpty(sub)) {
1451            return 0;
1452        }
1453        int count = 0;
1454        int idx = 0;
1455        while ((idx = CharSequenceUtils.indexOf(str, sub, idx)) != INDEX_NOT_FOUND) {
1456            count++;
1457            idx += sub.length();
1458        }
1459        return count;
1460    }
1461
1462    /**
1463     * <p>Returns either the passed in CharSequence, or if the CharSequence is
1464     * whitespace, empty ("") or {@code null}, the value of {@code defaultStr}.</p>
1465     *
1466     * <p>Whitespace is defined by {@link Character#isWhitespace(char)}.</p>
1467     *
1468     * <pre>
1469     * StringUtils.defaultIfBlank(null, "NULL")  = "NULL"
1470     * StringUtils.defaultIfBlank("", "NULL")    = "NULL"
1471     * StringUtils.defaultIfBlank(" ", "NULL")   = "NULL"
1472     * StringUtils.defaultIfBlank("bat", "NULL") = "bat"
1473     * StringUtils.defaultIfBlank("", null)      = null
1474     * </pre>
1475     * @param <T> the specific kind of CharSequence
1476     * @param str the CharSequence to check, may be null
1477     * @param defaultStr  the default CharSequence to return
1478     *  if the input is whitespace, empty ("") or {@code null}, may be null
1479     * @return the passed in CharSequence, or the default
1480     * @see StringUtils#defaultString(String, String)
1481     */
1482    public static <T extends CharSequence> T defaultIfBlank(final T str, final T defaultStr) {
1483        return isBlank(str) ? defaultStr : str;
1484    }
1485
1486    /**
1487     * <p>Returns either the passed in CharSequence, or if the CharSequence is
1488     * empty or {@code null}, the value of {@code defaultStr}.</p>
1489     *
1490     * <pre>
1491     * StringUtils.defaultIfEmpty(null, "NULL")  = "NULL"
1492     * StringUtils.defaultIfEmpty("", "NULL")    = "NULL"
1493     * StringUtils.defaultIfEmpty(" ", "NULL")   = " "
1494     * StringUtils.defaultIfEmpty("bat", "NULL") = "bat"
1495     * StringUtils.defaultIfEmpty("", null)      = null
1496     * </pre>
1497     * @param <T> the specific kind of CharSequence
1498     * @param str  the CharSequence to check, may be null
1499     * @param defaultStr  the default CharSequence to return
1500     *  if the input is empty ("") or {@code null}, may be null
1501     * @return the passed in CharSequence, or the default
1502     * @see StringUtils#defaultString(String, String)
1503     */
1504    public static <T extends CharSequence> T defaultIfEmpty(final T str, final T defaultStr) {
1505        return isEmpty(str) ? defaultStr : str;
1506    }
1507
1508    /**
1509     * <p>Returns either the passed in String,
1510     * or if the String is {@code null}, an empty String ("").</p>
1511     *
1512     * <pre>
1513     * StringUtils.defaultString(null)  = ""
1514     * StringUtils.defaultString("")    = ""
1515     * StringUtils.defaultString("bat") = "bat"
1516     * </pre>
1517     *
1518     * @see ObjectUtils#toString(Object)
1519     * @see String#valueOf(Object)
1520     * @param str  the String to check, may be null
1521     * @return the passed in String, or the empty String if it
1522     *  was {@code null}
1523     */
1524    public static String defaultString(final String str) {
1525        return defaultString(str, EMPTY);
1526    }
1527
1528    /**
1529     * <p>Returns either the passed in String, or if the String is
1530     * {@code null}, the value of {@code defaultStr}.</p>
1531     *
1532     * <pre>
1533     * StringUtils.defaultString(null, "NULL")  = "NULL"
1534     * StringUtils.defaultString("", "NULL")    = ""
1535     * StringUtils.defaultString("bat", "NULL") = "bat"
1536     * </pre>
1537     *
1538     * @see ObjectUtils#toString(Object,String)
1539     * @see String#valueOf(Object)
1540     * @param str  the String to check, may be null
1541     * @param defaultStr  the default String to return
1542     *  if the input is {@code null}, may be null
1543     * @return the passed in String, or the default if it was {@code null}
1544     */
1545    public static String defaultString(final String str, final String defaultStr) {
1546        return str == null ? defaultStr : str;
1547    }
1548
1549    // Delete
1550    //-----------------------------------------------------------------------
1551    /**
1552     * <p>Deletes all whitespaces from a String as defined by
1553     * {@link Character#isWhitespace(char)}.</p>
1554     *
1555     * <pre>
1556     * StringUtils.deleteWhitespace(null)         = null
1557     * StringUtils.deleteWhitespace("")           = ""
1558     * StringUtils.deleteWhitespace("abc")        = "abc"
1559     * StringUtils.deleteWhitespace("   ab  c  ") = "abc"
1560     * </pre>
1561     *
1562     * @param str  the String to delete whitespace from, may be null
1563     * @return the String without whitespaces, {@code null} if null String input
1564     */
1565    public static String deleteWhitespace(final String str) {
1566        if (isEmpty(str)) {
1567            return str;
1568        }
1569        final int sz = str.length();
1570        final char[] chs = new char[sz];
1571        int count = 0;
1572        for (int i = 0; i < sz; i++) {
1573            if (!Character.isWhitespace(str.charAt(i))) {
1574                chs[count++] = str.charAt(i);
1575            }
1576        }
1577        if (count == sz) {
1578            return str;
1579        }
1580        return new String(chs, 0, count);
1581    }
1582
1583    // Difference
1584    //-----------------------------------------------------------------------
1585    /**
1586     * <p>Compares two Strings, and returns the portion where they differ.
1587     * More precisely, return the remainder of the second String,
1588     * starting from where it's different from the first. This means that
1589     * the difference between "abc" and "ab" is the empty String and not "c". </p>
1590     *
1591     * <p>For example,
1592     * {@code difference("i am a machine", "i am a robot") -> "robot"}.</p>
1593     *
1594     * <pre>
1595     * StringUtils.difference(null, null) = null
1596     * StringUtils.difference("", "") = ""
1597     * StringUtils.difference("", "abc") = "abc"
1598     * StringUtils.difference("abc", "") = ""
1599     * StringUtils.difference("abc", "abc") = ""
1600     * StringUtils.difference("abc", "ab") = ""
1601     * StringUtils.difference("ab", "abxyz") = "xyz"
1602     * StringUtils.difference("abcde", "abxyz") = "xyz"
1603     * StringUtils.difference("abcde", "xyz") = "xyz"
1604     * </pre>
1605     *
1606     * @param str1  the first String, may be null
1607     * @param str2  the second String, may be null
1608     * @return the portion of str2 where it differs from str1; returns the
1609     * empty String if they are equal
1610     * @see #indexOfDifference(CharSequence,CharSequence)
1611     * @since 2.0
1612     */
1613    public static String difference(final String str1, final String str2) {
1614        if (str1 == null) {
1615            return str2;
1616        }
1617        if (str2 == null) {
1618            return str1;
1619        }
1620        final int at = indexOfDifference(str1, str2);
1621        if (at == INDEX_NOT_FOUND) {
1622            return EMPTY;
1623        }
1624        return str2.substring(at);
1625    }
1626
1627    /**
1628     * <p>Check if a CharSequence ends with a specified suffix.</p>
1629     *
1630     * <p>{@code null}s are handled without exceptions. Two {@code null}
1631     * references are considered to be equal. The comparison is case sensitive.</p>
1632     *
1633     * <pre>
1634     * StringUtils.endsWith(null, null)      = true
1635     * StringUtils.endsWith(null, "def")     = false
1636     * StringUtils.endsWith("abcdef", null)  = false
1637     * StringUtils.endsWith("abcdef", "def") = true
1638     * StringUtils.endsWith("ABCDEF", "def") = false
1639     * StringUtils.endsWith("ABCDEF", "cde") = false
1640     * StringUtils.endsWith("ABCDEF", "")    = true
1641     * </pre>
1642     *
1643     * @see java.lang.String#endsWith(String)
1644     * @param str  the CharSequence to check, may be null
1645     * @param suffix the suffix to find, may be null
1646     * @return {@code true} if the CharSequence ends with the suffix, case sensitive, or
1647     *  both {@code null}
1648     * @since 2.4
1649     * @since 3.0 Changed signature from endsWith(String, String) to endsWith(CharSequence, CharSequence)
1650     */
1651    public static boolean endsWith(final CharSequence str, final CharSequence suffix) {
1652        return endsWith(str, suffix, false);
1653    }
1654
1655    /**
1656     * <p>Check if a CharSequence ends with a specified suffix (optionally case insensitive).</p>
1657     *
1658     * @see java.lang.String#endsWith(String)
1659     * @param str  the CharSequence to check, may be null
1660     * @param suffix the suffix to find, may be null
1661     * @param ignoreCase indicates whether the compare should ignore case
1662     *  (case insensitive) or not.
1663     * @return {@code true} if the CharSequence starts with the prefix or
1664     *  both {@code null}
1665     */
1666    private static boolean endsWith(final CharSequence str, final CharSequence suffix, final boolean ignoreCase) {
1667        if (str == null || suffix == null) {
1668            return str == suffix;
1669        }
1670        if (suffix.length() > str.length()) {
1671            return false;
1672        }
1673        final int strOffset = str.length() - suffix.length();
1674        return CharSequenceUtils.regionMatches(str, ignoreCase, strOffset, suffix, 0, suffix.length());
1675    }
1676
1677    /**
1678     * <p>Check if a CharSequence ends with any of the provided case-sensitive suffixes.</p>
1679     *
1680     * <pre>
1681     * StringUtils.endsWithAny(null, null)      = false
1682     * StringUtils.endsWithAny(null, new String[] {"abc"})  = false
1683     * StringUtils.endsWithAny("abcxyz", null)     = false
1684     * StringUtils.endsWithAny("abcxyz", new String[] {""}) = true
1685     * StringUtils.endsWithAny("abcxyz", new String[] {"xyz"}) = true
1686     * StringUtils.endsWithAny("abcxyz", new String[] {null, "xyz", "abc"}) = true
1687     * StringUtils.endsWithAny("abcXYZ", "def", "XYZ") = true
1688     * StringUtils.endsWithAny("abcXYZ", "def", "xyz") = false
1689     * </pre>
1690     *
1691     * @param sequence  the CharSequence to check, may be null
1692     * @param searchStrings the case-sensitive CharSequences to find, may be empty or contain {@code null}
1693     * @see StringUtils#endsWith(CharSequence, CharSequence)
1694     * @return {@code true} if the input {@code sequence} is {@code null} AND no {@code searchStrings} are provided, or
1695     *   the input {@code sequence} ends in any of the provided case-sensitive {@code searchStrings}.
1696     * @since 3.0
1697     */
1698    public static boolean endsWithAny(final CharSequence sequence, final CharSequence... searchStrings) {
1699        if (isEmpty(sequence) || ArrayUtils.isEmpty(searchStrings)) {
1700            return false;
1701        }
1702        for (final CharSequence searchString : searchStrings) {
1703            if (endsWith(sequence, searchString)) {
1704                return true;
1705            }
1706        }
1707        return false;
1708    }
1709
1710    /**
1711     * <p>Case insensitive check if a CharSequence ends with a specified suffix.</p>
1712     *
1713     * <p>{@code null}s are handled without exceptions. Two {@code null}
1714     * references are considered to be equal. The comparison is case insensitive.</p>
1715     *
1716     * <pre>
1717     * StringUtils.endsWithIgnoreCase(null, null)      = true
1718     * StringUtils.endsWithIgnoreCase(null, "def")     = false
1719     * StringUtils.endsWithIgnoreCase("abcdef", null)  = false
1720     * StringUtils.endsWithIgnoreCase("abcdef", "def") = true
1721     * StringUtils.endsWithIgnoreCase("ABCDEF", "def") = true
1722     * StringUtils.endsWithIgnoreCase("ABCDEF", "cde") = false
1723     * </pre>
1724     *
1725     * @see java.lang.String#endsWith(String)
1726     * @param str  the CharSequence to check, may be null
1727     * @param suffix the suffix to find, may be null
1728     * @return {@code true} if the CharSequence ends with the suffix, case insensitive, or
1729     *  both {@code null}
1730     * @since 2.4
1731     * @since 3.0 Changed signature from endsWithIgnoreCase(String, String) to endsWithIgnoreCase(CharSequence, CharSequence)
1732     */
1733    public static boolean endsWithIgnoreCase(final CharSequence str, final CharSequence suffix) {
1734        return endsWith(str, suffix, true);
1735    }
1736
1737    // Equals
1738    //-----------------------------------------------------------------------
1739    /**
1740     * <p>Compares two CharSequences, returning {@code true} if they represent
1741     * equal sequences of characters.</p>
1742     *
1743     * <p>{@code null}s are handled without exceptions. Two {@code null}
1744     * references are considered to be equal. The comparison is <strong>case sensitive</strong>.</p>
1745     *
1746     * <pre>
1747     * StringUtils.equals(null, null)   = true
1748     * StringUtils.equals(null, "abc")  = false
1749     * StringUtils.equals("abc", null)  = false
1750     * StringUtils.equals("abc", "abc") = true
1751     * StringUtils.equals("abc", "ABC") = false
1752     * </pre>
1753     *
1754     * @param cs1  the first CharSequence, may be {@code null}
1755     * @param cs2  the second CharSequence, may be {@code null}
1756     * @return {@code true} if the CharSequences are equal (case-sensitive), or both {@code null}
1757     * @since 3.0 Changed signature from equals(String, String) to equals(CharSequence, CharSequence)
1758     * @see Object#equals(Object)
1759     * @see #equalsIgnoreCase(CharSequence, CharSequence)
1760     */
1761    public static boolean equals(final CharSequence cs1, final CharSequence cs2) {
1762        if (cs1 == cs2) {
1763            return true;
1764        }
1765        if (cs1 == null || cs2 == null) {
1766            return false;
1767        }
1768        if (cs1.length() != cs2.length()) {
1769            return false;
1770        }
1771        if (cs1 instanceof String && cs2 instanceof String) {
1772            return cs1.equals(cs2);
1773        }
1774        // Step-wise comparison
1775        final int length = cs1.length();
1776        for (int i = 0; i < length; i++) {
1777            if (cs1.charAt(i) != cs2.charAt(i)) {
1778                return false;
1779            }
1780        }
1781        return true;
1782    }
1783
1784    /**
1785     * <p>Compares given {@code string} to a CharSequences vararg of {@code searchStrings},
1786     * returning {@code true} if the {@code string} is equal to any of the {@code searchStrings}.</p>
1787     *
1788     * <pre>
1789     * StringUtils.equalsAny(null, (CharSequence[]) null) = false
1790     * StringUtils.equalsAny(null, null, null)    = true
1791     * StringUtils.equalsAny(null, "abc", "def")  = false
1792     * StringUtils.equalsAny("abc", null, "def")  = false
1793     * StringUtils.equalsAny("abc", "abc", "def") = true
1794     * StringUtils.equalsAny("abc", "ABC", "DEF") = false
1795     * </pre>
1796     *
1797     * @param string to compare, may be {@code null}.
1798     * @param searchStrings a vararg of strings, may be {@code null}.
1799     * @return {@code true} if the string is equal (case-sensitive) to any other element of {@code searchStrings};
1800     * {@code false} if {@code searchStrings} is null or contains no matches.
1801     * @since 3.5
1802     */
1803    public static boolean equalsAny(final CharSequence string, final CharSequence... searchStrings) {
1804        if (ArrayUtils.isNotEmpty(searchStrings)) {
1805            for (final CharSequence next : searchStrings) {
1806                if (equals(string, next)) {
1807                    return true;
1808                }
1809            }
1810        }
1811        return false;
1812    }
1813
1814    /**
1815     * <p>Compares given {@code string} to a CharSequences vararg of {@code searchStrings},
1816     * returning {@code true} if the {@code string} is equal to any of the {@code searchStrings}, ignoring case.</p>
1817     *
1818     * <pre>
1819     * StringUtils.equalsAnyIgnoreCase(null, (CharSequence[]) null) = false
1820     * StringUtils.equalsAnyIgnoreCase(null, null, null)    = true
1821     * StringUtils.equalsAnyIgnoreCase(null, "abc", "def")  = false
1822     * StringUtils.equalsAnyIgnoreCase("abc", null, "def")  = false
1823     * StringUtils.equalsAnyIgnoreCase("abc", "abc", "def") = true
1824     * StringUtils.equalsAnyIgnoreCase("abc", "ABC", "DEF") = true
1825     * </pre>
1826     *
1827     * @param string to compare, may be {@code null}.
1828     * @param searchStrings a vararg of strings, may be {@code null}.
1829     * @return {@code true} if the string is equal (case-insensitive) to any other element of {@code searchStrings};
1830     * {@code false} if {@code searchStrings} is null or contains no matches.
1831     * @since 3.5
1832     */
1833    public static boolean equalsAnyIgnoreCase(final CharSequence string, final CharSequence...searchStrings) {
1834        if (ArrayUtils.isNotEmpty(searchStrings)) {
1835            for (final CharSequence next : searchStrings) {
1836                if (equalsIgnoreCase(string, next)) {
1837                    return true;
1838                }
1839            }
1840        }
1841        return false;
1842    }
1843
1844    /**
1845     * <p>Compares two CharSequences, returning {@code true} if they represent
1846     * equal sequences of characters, ignoring case.</p>
1847     *
1848     * <p>{@code null}s are handled without exceptions. Two {@code null}
1849     * references are considered equal. The comparison is <strong>case insensitive</strong>.</p>
1850     *
1851     * <pre>
1852     * StringUtils.equalsIgnoreCase(null, null)   = true
1853     * StringUtils.equalsIgnoreCase(null, "abc")  = false
1854     * StringUtils.equalsIgnoreCase("abc", null)  = false
1855     * StringUtils.equalsIgnoreCase("abc", "abc") = true
1856     * StringUtils.equalsIgnoreCase("abc", "ABC") = true
1857     * </pre>
1858     *
1859     * @param cs1  the first CharSequence, may be {@code null}
1860     * @param cs2  the second CharSequence, may be {@code null}
1861     * @return {@code true} if the CharSequences are equal (case-insensitive), or both {@code null}
1862     * @since 3.0 Changed signature from equalsIgnoreCase(String, String) to equalsIgnoreCase(CharSequence, CharSequence)
1863     * @see #equals(CharSequence, CharSequence)
1864     */
1865    public static boolean equalsIgnoreCase(final CharSequence cs1, final CharSequence cs2) {
1866        if (cs1 == cs2) {
1867            return true;
1868        }
1869        if (cs1 == null || cs2 == null) {
1870            return false;
1871        }
1872        if (cs1.length() != cs2.length()) {
1873            return false;
1874        }
1875        return CharSequenceUtils.regionMatches(cs1, true, 0, cs2, 0, cs1.length());
1876    }
1877
1878    /**
1879     * <p>Returns the first value in the array which is not empty (""),
1880     * {@code null} or whitespace only.</p>
1881     *
1882     * <p>Whitespace is defined by {@link Character#isWhitespace(char)}.</p>
1883     *
1884     * <p>If all values are blank or the array is {@code null}
1885     * or empty then {@code null} is returned.</p>
1886     *
1887     * <pre>
1888     * StringUtils.firstNonBlank(null, null, null)     = null
1889     * StringUtils.firstNonBlank(null, "", " ")        = null
1890     * StringUtils.firstNonBlank("abc")                = "abc"
1891     * StringUtils.firstNonBlank(null, "xyz")          = "xyz"
1892     * StringUtils.firstNonBlank(null, "", " ", "xyz") = "xyz"
1893     * StringUtils.firstNonBlank(null, "xyz", "abc")   = "xyz"
1894     * StringUtils.firstNonBlank()                     = null
1895     * </pre>
1896     *
1897     * @param <T> the specific kind of CharSequence
1898     * @param values  the values to test, may be {@code null} or empty
1899     * @return the first value from {@code values} which is not blank,
1900     *  or {@code null} if there are no non-blank values
1901     * @since 3.8
1902     */
1903    @SafeVarargs
1904    public static <T extends CharSequence> T firstNonBlank(final T... values) {
1905        if (values != null) {
1906            for (final T val : values) {
1907                if (isNotBlank(val)) {
1908                    return val;
1909                }
1910            }
1911        }
1912        return null;
1913    }
1914
1915    /**
1916     * <p>Returns the first value in the array which is not empty.</p>
1917     *
1918     * <p>If all values are empty or the array is {@code null}
1919     * or empty then {@code null} is returned.</p>
1920     *
1921     * <pre>
1922     * StringUtils.firstNonEmpty(null, null, null)   = null
1923     * StringUtils.firstNonEmpty(null, null, "")     = null
1924     * StringUtils.firstNonEmpty(null, "", " ")      = " "
1925     * StringUtils.firstNonEmpty("abc")              = "abc"
1926     * StringUtils.firstNonEmpty(null, "xyz")        = "xyz"
1927     * StringUtils.firstNonEmpty("", "xyz")          = "xyz"
1928     * StringUtils.firstNonEmpty(null, "xyz", "abc") = "xyz"
1929     * StringUtils.firstNonEmpty()                   = null
1930     * </pre>
1931     *
1932     * @param <T> the specific kind of CharSequence
1933     * @param values  the values to test, may be {@code null} or empty
1934     * @return the first value from {@code values} which is not empty,
1935     *  or {@code null} if there are no non-empty values
1936     * @since 3.8
1937     */
1938    @SafeVarargs
1939    public static <T extends CharSequence> T firstNonEmpty(final T... values) {
1940        if (values != null) {
1941            for (final T val : values) {
1942                if (isNotEmpty(val)) {
1943                    return val;
1944                }
1945            }
1946        }
1947        return null;
1948    }
1949
1950    /**
1951     * Calls {@link String#getBytes(Charset)} in a null-safe manner.
1952     *
1953     * @param string input string
1954     * @param charset The {@link Charset} to encode the {@code String}. If null, then use the default Charset.
1955     * @return The empty byte[] if {@code string} is null, the result of {@link String#getBytes(Charset)} otherwise.
1956     * @see String#getBytes(Charset)
1957     * @since 3.10
1958     */
1959    public static byte[] getBytes(final String string, final Charset charset) {
1960        return string == null ? ArrayUtils.EMPTY_BYTE_ARRAY : string.getBytes(Charsets.toCharset(charset));
1961    }
1962
1963    /**
1964     * Calls {@link String#getBytes(String)} in a null-safe manner.
1965     *
1966     * @param string input string
1967     * @param charset The {@link Charset} name to encode the {@code String}. If null, then use the default Charset.
1968     * @return The empty byte[] if {@code string} is null, the result of {@link String#getBytes(String)} otherwise.
1969     * @throws UnsupportedEncodingException Thrown when the named charset is not supported.
1970     * @see String#getBytes(String)
1971     * @since 3.10
1972     */
1973    public static byte[] getBytes(final String string, final String charset) throws UnsupportedEncodingException {
1974        return string == null ? ArrayUtils.EMPTY_BYTE_ARRAY : string.getBytes(Charsets.toCharsetName(charset));
1975    }
1976
1977    /**
1978     * <p>Compares all Strings in an array and returns the initial sequence of
1979     * characters that is common to all of them.</p>
1980     *
1981     * <p>For example,
1982     * {@code getCommonPrefix(new String[] {"i am a machine", "i am a robot"}) -&gt; "i am a "}</p>
1983     *
1984     * <pre>
1985     * StringUtils.getCommonPrefix(null) = ""
1986     * StringUtils.getCommonPrefix(new String[] {}) = ""
1987     * StringUtils.getCommonPrefix(new String[] {"abc"}) = "abc"
1988     * StringUtils.getCommonPrefix(new String[] {null, null}) = ""
1989     * StringUtils.getCommonPrefix(new String[] {"", ""}) = ""
1990     * StringUtils.getCommonPrefix(new String[] {"", null}) = ""
1991     * StringUtils.getCommonPrefix(new String[] {"abc", null, null}) = ""
1992     * StringUtils.getCommonPrefix(new String[] {null, null, "abc"}) = ""
1993     * StringUtils.getCommonPrefix(new String[] {"", "abc"}) = ""
1994     * StringUtils.getCommonPrefix(new String[] {"abc", ""}) = ""
1995     * StringUtils.getCommonPrefix(new String[] {"abc", "abc"}) = "abc"
1996     * StringUtils.getCommonPrefix(new String[] {"abc", "a"}) = "a"
1997     * StringUtils.getCommonPrefix(new String[] {"ab", "abxyz"}) = "ab"
1998     * StringUtils.getCommonPrefix(new String[] {"abcde", "abxyz"}) = "ab"
1999     * StringUtils.getCommonPrefix(new String[] {"abcde", "xyz"}) = ""
2000     * StringUtils.getCommonPrefix(new String[] {"xyz", "abcde"}) = ""
2001     * StringUtils.getCommonPrefix(new String[] {"i am a machine", "i am a robot"}) = "i am a "
2002     * </pre>
2003     *
2004     * @param strs  array of String objects, entries may be null
2005     * @return the initial sequence of characters that are common to all Strings
2006     * in the array; empty String if the array is null, the elements are all null
2007     * or if there is no common prefix.
2008     * @since 2.4
2009     */
2010    public static String getCommonPrefix(final String... strs) {
2011        if (ArrayUtils.isEmpty(strs)) {
2012            return EMPTY;
2013        }
2014        final int smallestIndexOfDiff = indexOfDifference(strs);
2015        if (smallestIndexOfDiff == INDEX_NOT_FOUND) {
2016            // all strings were identical
2017            if (strs[0] == null) {
2018                return EMPTY;
2019            }
2020            return strs[0];
2021        } else if (smallestIndexOfDiff == 0) {
2022            // there were no common initial characters
2023            return EMPTY;
2024        } else {
2025            // we found a common initial character sequence
2026            return strs[0].substring(0, smallestIndexOfDiff);
2027        }
2028    }
2029
2030    /**
2031     * <p>Checks if a String {@code str} contains Unicode digits,
2032     * if yes then concatenate all the digits in {@code str} and return it as a String.</p>
2033     *
2034     * <p>An empty ("") String will be returned if no digits found in {@code str}.</p>
2035     *
2036     * <pre>
2037     * StringUtils.getDigits(null)  = null
2038     * StringUtils.getDigits("")    = ""
2039     * StringUtils.getDigits("abc") = ""
2040     * StringUtils.getDigits("1000$") = "1000"
2041     * StringUtils.getDigits("1123~45") = "112345"
2042     * StringUtils.getDigits("(541) 754-3010") = "5417543010"
2043     * StringUtils.getDigits("\u0967\u0968\u0969") = "\u0967\u0968\u0969"
2044     * </pre>
2045     *
2046     * @param str the String to extract digits from, may be null
2047     * @return String with only digits,
2048     *           or an empty ("") String if no digits found,
2049     *           or {@code null} String if {@code str} is null
2050     * @since 3.6
2051     */
2052    public static String getDigits(final String str) {
2053        if (isEmpty(str)) {
2054            return str;
2055        }
2056        final int sz = str.length();
2057        final StringBuilder strDigits = new StringBuilder(sz);
2058        for (int i = 0; i < sz; i++) {
2059            final char tempChar = str.charAt(i);
2060            if (Character.isDigit(tempChar)) {
2061                strDigits.append(tempChar);
2062            }
2063        }
2064        return strDigits.toString();
2065    }
2066
2067    /**
2068     * <p>Find the Fuzzy Distance which indicates the similarity score between two Strings.</p>
2069     *
2070     * <p>This string matching algorithm is similar to the algorithms of editors such as Sublime Text,
2071     * TextMate, Atom and others. One point is given for every matched character. Subsequent
2072     * matches yield two bonus points. A higher score indicates a higher similarity.</p>
2073     *
2074     * <pre>
2075     * StringUtils.getFuzzyDistance(null, null, null)                                    = IllegalArgumentException
2076     * StringUtils.getFuzzyDistance("", "", Locale.ENGLISH)                              = 0
2077     * StringUtils.getFuzzyDistance("Workshop", "b", Locale.ENGLISH)                     = 0
2078     * StringUtils.getFuzzyDistance("Room", "o", Locale.ENGLISH)                         = 1
2079     * StringUtils.getFuzzyDistance("Workshop", "w", Locale.ENGLISH)                     = 1
2080     * StringUtils.getFuzzyDistance("Workshop", "ws", Locale.ENGLISH)                    = 2
2081     * StringUtils.getFuzzyDistance("Workshop", "wo", Locale.ENGLISH)                    = 4
2082     * StringUtils.getFuzzyDistance("Apache Software Foundation", "asf", Locale.ENGLISH) = 3
2083     * </pre>
2084     *
2085     * @param term a full term that should be matched against, must not be null
2086     * @param query the query that will be matched against a term, must not be null
2087     * @param locale This string matching logic is case insensitive. A locale is necessary to normalize
2088     *  both Strings to lower case.
2089     * @return result score
2090     * @throws IllegalArgumentException if either String input {@code null} or Locale input {@code null}
2091     * @since 3.4
2092     * @deprecated as of 3.6, use commons-text
2093     * <a href="https://commons.apache.org/proper/commons-text/javadocs/api-release/org/apache/commons/text/similarity/FuzzyScore.html">
2094     * FuzzyScore</a> instead
2095     */
2096    @Deprecated
2097    public static int getFuzzyDistance(final CharSequence term, final CharSequence query, final Locale locale) {
2098        if (term == null || query == null) {
2099            throw new IllegalArgumentException("Strings must not be null");
2100        } else if (locale == null) {
2101            throw new IllegalArgumentException("Locale must not be null");
2102        }
2103
2104        // fuzzy logic is case insensitive. We normalize the Strings to lower
2105        // case right from the start. Turning characters to lower case
2106        // via Character.toLowerCase(char) is unfortunately insufficient
2107        // as it does not accept a locale.
2108        final String termLowerCase = term.toString().toLowerCase(locale);
2109        final String queryLowerCase = query.toString().toLowerCase(locale);
2110
2111        // the resulting score
2112        int score = 0;
2113
2114        // the position in the term which will be scanned next for potential
2115        // query character matches
2116        int termIndex = 0;
2117
2118        // index of the previously matched character in the term
2119        int previousMatchingCharacterIndex = Integer.MIN_VALUE;
2120
2121        for (int queryIndex = 0; queryIndex < queryLowerCase.length(); queryIndex++) {
2122            final char queryChar = queryLowerCase.charAt(queryIndex);
2123
2124            boolean termCharacterMatchFound = false;
2125            for (; termIndex < termLowerCase.length() && !termCharacterMatchFound; termIndex++) {
2126                final char termChar = termLowerCase.charAt(termIndex);
2127
2128                if (queryChar == termChar) {
2129                    // simple character matches result in one point
2130                    score++;
2131
2132                    // subsequent character matches further improve
2133                    // the score.
2134                    if (previousMatchingCharacterIndex + 1 == termIndex) {
2135                        score += 2;
2136                    }
2137
2138                    previousMatchingCharacterIndex = termIndex;
2139
2140                    // we can leave the nested loop. Every character in the
2141                    // query can match at most one character in the term.
2142                    termCharacterMatchFound = true;
2143                }
2144            }
2145        }
2146
2147        return score;
2148    }
2149
2150    /**
2151     * <p>Returns either the passed in CharSequence, or if the CharSequence is
2152     * whitespace, empty ("") or {@code null}, the value supplied by {@code defaultStrSupplier}.</p>
2153     *
2154     * <p>Whitespace is defined by {@link Character#isWhitespace(char)}.</p>
2155     *
2156     * <p>Caller responsible for thread-safety and exception handling of default value supplier</p>
2157     *
2158     * <pre>
2159     * {@code
2160     * StringUtils.getIfBlank(null, () -> "NULL")   = "NULL"
2161     * StringUtils.getIfBlank("", () -> "NULL")     = "NULL"
2162     * StringUtils.getIfBlank(" ", () -> "NULL")    = "NULL"
2163     * StringUtils.getIfBlank("bat", () -> "NULL")  = "bat"
2164     * StringUtils.getIfBlank("", () -> null)       = null
2165     * StringUtils.getIfBlank("", null)             = null
2166     * }</pre>
2167     * @param <T> the specific kind of CharSequence
2168     * @param str the CharSequence to check, may be null
2169     * @param defaultSupplier the supplier of default CharSequence to return
2170     *  if the input is whitespace, empty ("") or {@code null}, may be null
2171     * @return the passed in CharSequence, or the default
2172     * @see StringUtils#defaultString(String, String)
2173     * @since 3.10
2174     */
2175    public static <T extends CharSequence> T getIfBlank(final T str, final Supplier<T> defaultSupplier) {
2176        return isBlank(str) ? defaultSupplier == null ? null : defaultSupplier.get() : str;
2177    }
2178
2179    /**
2180     * <p>Returns either the passed in CharSequence, or if the CharSequence is
2181     * empty or {@code null}, the value supplied by {@code defaultStrSupplier}.</p>
2182     *
2183     * <p>Caller responsible for thread-safety and exception handling of default value supplier</p>
2184     *
2185     * <pre>
2186     * {@code
2187     * StringUtils.getIfEmpty(null, () -> "NULL")    = "NULL"
2188     * StringUtils.getIfEmpty("", () -> "NULL")      = "NULL"
2189     * StringUtils.getIfEmpty(" ", () -> "NULL")     = " "
2190     * StringUtils.getIfEmpty("bat", () -> "NULL")   = "bat"
2191     * StringUtils.getIfEmpty("", () -> null)        = null
2192     * StringUtils.getIfEmpty("", null)              = null
2193     * }
2194     * </pre>
2195     * @param <T> the specific kind of CharSequence
2196     * @param str  the CharSequence to check, may be null
2197     * @param defaultSupplier  the supplier of default CharSequence to return
2198     *  if the input is empty ("") or {@code null}, may be null
2199     * @return the passed in CharSequence, or the default
2200     * @see StringUtils#defaultString(String, String)
2201     * @since 3.10
2202     */
2203    public static <T extends CharSequence> T getIfEmpty(final T str, final Supplier<T> defaultSupplier) {
2204        return isEmpty(str) ? defaultSupplier == null ? null : defaultSupplier.get() : str;
2205    }
2206
2207    /**
2208     * <p>Find the Jaro Winkler Distance which indicates the similarity score between two Strings.</p>
2209     *
2210     * <p>The Jaro measure is the weighted sum of percentage of matched characters from each file and transposed characters.
2211     * Winkler increased this measure for matching initial characters.</p>
2212     *
2213     * <p>This implementation is based on the Jaro Winkler similarity algorithm
2214     * from <a href="http://en.wikipedia.org/wiki/Jaro%E2%80%93Winkler_distance">http://en.wikipedia.org/wiki/Jaro%E2%80%93Winkler_distance</a>.</p>
2215     *
2216     * <pre>
2217     * StringUtils.getJaroWinklerDistance(null, null)          = IllegalArgumentException
2218     * StringUtils.getJaroWinklerDistance("", "")              = 0.0
2219     * StringUtils.getJaroWinklerDistance("", "a")             = 0.0
2220     * StringUtils.getJaroWinklerDistance("aaapppp", "")       = 0.0
2221     * StringUtils.getJaroWinklerDistance("frog", "fog")       = 0.93
2222     * StringUtils.getJaroWinklerDistance("fly", "ant")        = 0.0
2223     * StringUtils.getJaroWinklerDistance("elephant", "hippo") = 0.44
2224     * StringUtils.getJaroWinklerDistance("hippo", "elephant") = 0.44
2225     * StringUtils.getJaroWinklerDistance("hippo", "zzzzzzzz") = 0.0
2226     * StringUtils.getJaroWinklerDistance("hello", "hallo")    = 0.88
2227     * StringUtils.getJaroWinklerDistance("ABC Corporation", "ABC Corp") = 0.93
2228     * StringUtils.getJaroWinklerDistance("D N H Enterprises Inc", "D &amp; H Enterprises, Inc.") = 0.95
2229     * StringUtils.getJaroWinklerDistance("My Gym Children's Fitness Center", "My Gym. Childrens Fitness") = 0.92
2230     * StringUtils.getJaroWinklerDistance("PENNSYLVANIA", "PENNCISYLVNIA") = 0.88
2231     * </pre>
2232     *
2233     * @param first the first String, must not be null
2234     * @param second the second String, must not be null
2235     * @return result distance
2236     * @throws IllegalArgumentException if either String input {@code null}
2237     * @since 3.3
2238     * @deprecated as of 3.6, use commons-text
2239     * <a href="https://commons.apache.org/proper/commons-text/javadocs/api-release/org/apache/commons/text/similarity/JaroWinklerDistance.html">
2240     * JaroWinklerDistance</a> instead
2241     */
2242    @Deprecated
2243    public static double getJaroWinklerDistance(final CharSequence first, final CharSequence second) {
2244        final double DEFAULT_SCALING_FACTOR = 0.1;
2245
2246        if (first == null || second == null) {
2247            throw new IllegalArgumentException("Strings must not be null");
2248        }
2249
2250        final int[] mtp = matches(first, second);
2251        final double m = mtp[0];
2252        if (m == 0) {
2253            return 0D;
2254        }
2255        final double j = ((m / first.length() + m / second.length() + (m - mtp[1]) / m)) / 3;
2256        final double jw = j < 0.7D ? j : j + Math.min(DEFAULT_SCALING_FACTOR, 1D / mtp[3]) * mtp[2] * (1D - j);
2257        return Math.round(jw * 100.0D) / 100.0D;
2258    }
2259
2260    // Misc
2261    //-----------------------------------------------------------------------
2262    /**
2263     * <p>Find the Levenshtein distance between two Strings.</p>
2264     *
2265     * <p>This is the number of changes needed to change one String into
2266     * another, where each change is a single character modification (deletion,
2267     * insertion or substitution).</p>
2268     *
2269     * <p>The implementation uses a single-dimensional array of length s.length() + 1. See
2270     * <a href="http://blog.softwx.net/2014/12/optimizing-levenshtein-algorithm-in-c.html">
2271     * http://blog.softwx.net/2014/12/optimizing-levenshtein-algorithm-in-c.html</a> for details.</p>
2272     *
2273     * <pre>
2274     * StringUtils.getLevenshteinDistance(null, *)             = IllegalArgumentException
2275     * StringUtils.getLevenshteinDistance(*, null)             = IllegalArgumentException
2276     * StringUtils.getLevenshteinDistance("", "")              = 0
2277     * StringUtils.getLevenshteinDistance("", "a")             = 1
2278     * StringUtils.getLevenshteinDistance("aaapppp", "")       = 7
2279     * StringUtils.getLevenshteinDistance("frog", "fog")       = 1
2280     * StringUtils.getLevenshteinDistance("fly", "ant")        = 3
2281     * StringUtils.getLevenshteinDistance("elephant", "hippo") = 7
2282     * StringUtils.getLevenshteinDistance("hippo", "elephant") = 7
2283     * StringUtils.getLevenshteinDistance("hippo", "zzzzzzzz") = 8
2284     * StringUtils.getLevenshteinDistance("hello", "hallo")    = 1
2285     * </pre>
2286     *
2287     * @param s  the first String, must not be null
2288     * @param t  the second String, must not be null
2289     * @return result distance
2290     * @throws IllegalArgumentException if either String input {@code null}
2291     * @since 3.0 Changed signature from getLevenshteinDistance(String, String) to
2292     * getLevenshteinDistance(CharSequence, CharSequence)
2293     * @deprecated as of 3.6, use commons-text
2294     * <a href="https://commons.apache.org/proper/commons-text/javadocs/api-release/org/apache/commons/text/similarity/LevenshteinDistance.html">
2295     * LevenshteinDistance</a> instead
2296     */
2297    @Deprecated
2298    public static int getLevenshteinDistance(CharSequence s, CharSequence t) {
2299        if (s == null || t == null) {
2300            throw new IllegalArgumentException("Strings must not be null");
2301        }
2302
2303        int n = s.length();
2304        int m = t.length();
2305
2306        if (n == 0) {
2307            return m;
2308        } else if (m == 0) {
2309            return n;
2310        }
2311
2312        if (n > m) {
2313            // swap the input strings to consume less memory
2314            final CharSequence tmp = s;
2315            s = t;
2316            t = tmp;
2317            n = m;
2318            m = t.length();
2319        }
2320
2321        final int[] p = new int[n + 1];
2322        // indexes into strings s and t
2323        int i; // iterates through s
2324        int j; // iterates through t
2325        int upper_left;
2326        int upper;
2327
2328        char t_j; // jth character of t
2329        int cost;
2330
2331        for (i = 0; i <= n; i++) {
2332            p[i] = i;
2333        }
2334
2335        for (j = 1; j <= m; j++) {
2336            upper_left = p[0];
2337            t_j = t.charAt(j - 1);
2338            p[0] = j;
2339
2340            for (i = 1; i <= n; i++) {
2341                upper = p[i];
2342                cost = s.charAt(i - 1) == t_j ? 0 : 1;
2343                // minimum of cell to the left+1, to the top+1, diagonally left and up +cost
2344                p[i] = Math.min(Math.min(p[i - 1] + 1, p[i] + 1), upper_left + cost);
2345                upper_left = upper;
2346            }
2347        }
2348
2349        return p[n];
2350    }
2351
2352    /**
2353     * <p>Find the Levenshtein distance between two Strings if it's less than or equal to a given
2354     * threshold.</p>
2355     *
2356     * <p>This is the number of changes needed to change one String into
2357     * another, where each change is a single character modification (deletion,
2358     * insertion or substitution).</p>
2359     *
2360     * <p>This implementation follows from Algorithms on Strings, Trees and Sequences by Dan Gusfield
2361     * and Chas Emerick's implementation of the Levenshtein distance algorithm from
2362     * <a href="http://www.merriampark.com/ld.htm">http://www.merriampark.com/ld.htm</a></p>
2363     *
2364     * <pre>
2365     * StringUtils.getLevenshteinDistance(null, *, *)             = IllegalArgumentException
2366     * StringUtils.getLevenshteinDistance(*, null, *)             = IllegalArgumentException
2367     * StringUtils.getLevenshteinDistance(*, *, -1)               = IllegalArgumentException
2368     * StringUtils.getLevenshteinDistance("", "", 0)              = 0
2369     * StringUtils.getLevenshteinDistance("aaapppp", "", 8)       = 7
2370     * StringUtils.getLevenshteinDistance("aaapppp", "", 7)       = 7
2371     * StringUtils.getLevenshteinDistance("aaapppp", "", 6))      = -1
2372     * StringUtils.getLevenshteinDistance("elephant", "hippo", 7) = 7
2373     * StringUtils.getLevenshteinDistance("elephant", "hippo", 6) = -1
2374     * StringUtils.getLevenshteinDistance("hippo", "elephant", 7) = 7
2375     * StringUtils.getLevenshteinDistance("hippo", "elephant", 6) = -1
2376     * </pre>
2377     *
2378     * @param s  the first String, must not be null
2379     * @param t  the second String, must not be null
2380     * @param threshold the target threshold, must not be negative
2381     * @return result distance, or {@code -1} if the distance would be greater than the threshold
2382     * @throws IllegalArgumentException if either String input {@code null} or negative threshold
2383     * @deprecated as of 3.6, use commons-text
2384     * <a href="https://commons.apache.org/proper/commons-text/javadocs/api-release/org/apache/commons/text/similarity/LevenshteinDistance.html">
2385     * LevenshteinDistance</a> instead
2386     */
2387    @Deprecated
2388    public static int getLevenshteinDistance(CharSequence s, CharSequence t, final int threshold) {
2389        if (s == null || t == null) {
2390            throw new IllegalArgumentException("Strings must not be null");
2391        }
2392        if (threshold < 0) {
2393            throw new IllegalArgumentException("Threshold must not be negative");
2394        }
2395
2396        /*
2397        This implementation only computes the distance if it's less than or equal to the
2398        threshold value, returning -1 if it's greater.  The advantage is performance: unbounded
2399        distance is O(nm), but a bound of k allows us to reduce it to O(km) time by only
2400        computing a diagonal stripe of width 2k + 1 of the cost table.
2401        It is also possible to use this to compute the unbounded Levenshtein distance by starting
2402        the threshold at 1 and doubling each time until the distance is found; this is O(dm), where
2403        d is the distance.
2404
2405        One subtlety comes from needing to ignore entries on the border of our stripe
2406        eg.
2407        p[] = |#|#|#|*
2408        d[] =  *|#|#|#|
2409        We must ignore the entry to the left of the leftmost member
2410        We must ignore the entry above the rightmost member
2411
2412        Another subtlety comes from our stripe running off the matrix if the strings aren't
2413        of the same size.  Since string s is always swapped to be the shorter of the two,
2414        the stripe will always run off to the upper right instead of the lower left of the matrix.
2415
2416        As a concrete example, suppose s is of length 5, t is of length 7, and our threshold is 1.
2417        In this case we're going to walk a stripe of length 3.  The matrix would look like so:
2418
2419           1 2 3 4 5
2420        1 |#|#| | | |
2421        2 |#|#|#| | |
2422        3 | |#|#|#| |
2423        4 | | |#|#|#|
2424        5 | | | |#|#|
2425        6 | | | | |#|
2426        7 | | | | | |
2427
2428        Note how the stripe leads off the table as there is no possible way to turn a string of length 5
2429        into one of length 7 in edit distance of 1.
2430
2431        Additionally, this implementation decreases memory usage by using two
2432        single-dimensional arrays and swapping them back and forth instead of allocating
2433        an entire n by m matrix.  This requires a few minor changes, such as immediately returning
2434        when it's detected that the stripe has run off the matrix and initially filling the arrays with
2435        large values so that entries we don't compute are ignored.
2436
2437        See Algorithms on Strings, Trees and Sequences by Dan Gusfield for some discussion.
2438         */
2439
2440        int n = s.length(); // length of s
2441        int m = t.length(); // length of t
2442
2443        // if one string is empty, the edit distance is necessarily the length of the other
2444        if (n == 0) {
2445            return m <= threshold ? m : -1;
2446        } else if (m == 0) {
2447            return n <= threshold ? n : -1;
2448        } else if (Math.abs(n - m) > threshold) {
2449            // no need to calculate the distance if the length difference is greater than the threshold
2450            return -1;
2451        }
2452
2453        if (n > m) {
2454            // swap the two strings to consume less memory
2455            final CharSequence tmp = s;
2456            s = t;
2457            t = tmp;
2458            n = m;
2459            m = t.length();
2460        }
2461
2462        int[] p = new int[n + 1]; // 'previous' cost array, horizontally
2463        int[] d = new int[n + 1]; // cost array, horizontally
2464        int[] _d; // placeholder to assist in swapping p and d
2465
2466        // fill in starting table values
2467        final int boundary = Math.min(n, threshold) + 1;
2468        for (int i = 0; i < boundary; i++) {
2469            p[i] = i;
2470        }
2471        // these fills ensure that the value above the rightmost entry of our
2472        // stripe will be ignored in following loop iterations
2473        Arrays.fill(p, boundary, p.length, Integer.MAX_VALUE);
2474        Arrays.fill(d, Integer.MAX_VALUE);
2475
2476        // iterates through t
2477        for (int j = 1; j <= m; j++) {
2478            final char t_j = t.charAt(j - 1); // jth character of t
2479            d[0] = j;
2480
2481            // compute stripe indices, constrain to array size
2482            final int min = Math.max(1, j - threshold);
2483            final int max = j > Integer.MAX_VALUE - threshold ? n : Math.min(n, j + threshold);
2484
2485            // the stripe may lead off of the table if s and t are of different sizes
2486            if (min > max) {
2487                return -1;
2488            }
2489
2490            // ignore entry left of leftmost
2491            if (min > 1) {
2492                d[min - 1] = Integer.MAX_VALUE;
2493            }
2494
2495            // iterates through [min, max] in s
2496            for (int i = min; i <= max; i++) {
2497                if (s.charAt(i - 1) == t_j) {
2498                    // diagonally left and up
2499                    d[i] = p[i - 1];
2500                } else {
2501                    // 1 + minimum of cell to the left, to the top, diagonally left and up
2502                    d[i] = 1 + Math.min(Math.min(d[i - 1], p[i]), p[i - 1]);
2503                }
2504            }
2505
2506            // copy current distance counts to 'previous row' distance counts
2507            _d = p;
2508            p = d;
2509            d = _d;
2510        }
2511
2512        // if p[n] is greater than the threshold, there's no guarantee on it being the correct
2513        // distance
2514        if (p[n] <= threshold) {
2515            return p[n];
2516        }
2517        return -1;
2518    }
2519
2520    /**
2521     * <p>Finds the first index within a CharSequence, handling {@code null}.
2522     * This method uses {@link String#indexOf(String, int)} if possible.</p>
2523     *
2524     * <p>A {@code null} CharSequence will return {@code -1}.</p>
2525     *
2526     * <pre>
2527     * StringUtils.indexOf(null, *)          = -1
2528     * StringUtils.indexOf(*, null)          = -1
2529     * StringUtils.indexOf("", "")           = 0
2530     * StringUtils.indexOf("", *)            = -1 (except when * = "")
2531     * StringUtils.indexOf("aabaabaa", "a")  = 0
2532     * StringUtils.indexOf("aabaabaa", "b")  = 2
2533     * StringUtils.indexOf("aabaabaa", "ab") = 1
2534     * StringUtils.indexOf("aabaabaa", "")   = 0
2535     * </pre>
2536     *
2537     * @param seq  the CharSequence to check, may be null
2538     * @param searchSeq  the CharSequence to find, may be null
2539     * @return the first index of the search CharSequence,
2540     *  -1 if no match or {@code null} string input
2541     * @since 2.0
2542     * @since 3.0 Changed signature from indexOf(String, String) to indexOf(CharSequence, CharSequence)
2543     */
2544    public static int indexOf(final CharSequence seq, final CharSequence searchSeq) {
2545        if (seq == null || searchSeq == null) {
2546            return INDEX_NOT_FOUND;
2547        }
2548        return CharSequenceUtils.indexOf(seq, searchSeq, 0);
2549    }
2550
2551    /**
2552     * <p>Finds the first index within a CharSequence, handling {@code null}.
2553     * This method uses {@link String#indexOf(String, int)} if possible.</p>
2554     *
2555     * <p>A {@code null} CharSequence will return {@code -1}.
2556     * A negative start position is treated as zero.
2557     * An empty ("") search CharSequence always matches.
2558     * A start position greater than the string length only matches
2559     * an empty search CharSequence.</p>
2560     *
2561     * <pre>
2562     * StringUtils.indexOf(null, *, *)          = -1
2563     * StringUtils.indexOf(*, null, *)          = -1
2564     * StringUtils.indexOf("", "", 0)           = 0
2565     * StringUtils.indexOf("", *, 0)            = -1 (except when * = "")
2566     * StringUtils.indexOf("aabaabaa", "a", 0)  = 0
2567     * StringUtils.indexOf("aabaabaa", "b", 0)  = 2
2568     * StringUtils.indexOf("aabaabaa", "ab", 0) = 1
2569     * StringUtils.indexOf("aabaabaa", "b", 3)  = 5
2570     * StringUtils.indexOf("aabaabaa", "b", 9)  = -1
2571     * StringUtils.indexOf("aabaabaa", "b", -1) = 2
2572     * StringUtils.indexOf("aabaabaa", "", 2)   = 2
2573     * StringUtils.indexOf("abc", "", 9)        = 3
2574     * </pre>
2575     *
2576     * @param seq  the CharSequence to check, may be null
2577     * @param searchSeq  the CharSequence to find, may be null
2578     * @param startPos  the start position, negative treated as zero
2579     * @return the first index of the search CharSequence (always &ge; startPos),
2580     *  -1 if no match or {@code null} string input
2581     * @since 2.0
2582     * @since 3.0 Changed signature from indexOf(String, String, int) to indexOf(CharSequence, CharSequence, int)
2583     */
2584    public static int indexOf(final CharSequence seq, final CharSequence searchSeq, final int startPos) {
2585        if (seq == null || searchSeq == null) {
2586            return INDEX_NOT_FOUND;
2587        }
2588        return CharSequenceUtils.indexOf(seq, searchSeq, startPos);
2589    }
2590
2591    // IndexOf
2592    //-----------------------------------------------------------------------
2593    /**
2594     * Returns the index within {@code seq} of the first occurrence of
2595     * the specified character. If a character with value
2596     * {@code searchChar} occurs in the character sequence represented by
2597     * {@code seq} {@code CharSequence} object, then the index (in Unicode
2598     * code units) of the first such occurrence is returned. For
2599     * values of {@code searchChar} in the range from 0 to 0xFFFF
2600     * (inclusive), this is the smallest value <i>k</i> such that:
2601     * <blockquote><pre>
2602     * this.charAt(<i>k</i>) == searchChar
2603     * </pre></blockquote>
2604     * is true. For other values of {@code searchChar}, it is the
2605     * smallest value <i>k</i> such that:
2606     * <blockquote><pre>
2607     * this.codePointAt(<i>k</i>) == searchChar
2608     * </pre></blockquote>
2609     * is true. In either case, if no such character occurs in {@code seq},
2610     * then {@code INDEX_NOT_FOUND (-1)} is returned.
2611     *
2612     * <p>Furthermore, a {@code null} or empty ("") CharSequence will
2613     * return {@code INDEX_NOT_FOUND (-1)}.</p>
2614     *
2615     * <pre>
2616     * StringUtils.indexOf(null, *)         = -1
2617     * StringUtils.indexOf("", *)           = -1
2618     * StringUtils.indexOf("aabaabaa", 'a') = 0
2619     * StringUtils.indexOf("aabaabaa", 'b') = 2
2620     * </pre>
2621     *
2622     * @param seq  the CharSequence to check, may be null
2623     * @param searchChar  the character to find
2624     * @return the first index of the search character,
2625     *  -1 if no match or {@code null} string input
2626     * @since 2.0
2627     * @since 3.0 Changed signature from indexOf(String, int) to indexOf(CharSequence, int)
2628     * @since 3.6 Updated {@link CharSequenceUtils} call to behave more like {@code String}
2629     */
2630    public static int indexOf(final CharSequence seq, final int searchChar) {
2631        if (isEmpty(seq)) {
2632            return INDEX_NOT_FOUND;
2633        }
2634        return CharSequenceUtils.indexOf(seq, searchChar, 0);
2635    }
2636
2637    /**
2638     *
2639     * Returns the index within {@code seq} of the first occurrence of the
2640     * specified character, starting the search at the specified index.
2641     * <p>
2642     * If a character with value {@code searchChar} occurs in the
2643     * character sequence represented by the {@code seq} {@code CharSequence}
2644     * object at an index no smaller than {@code startPos}, then
2645     * the index of the first such occurrence is returned. For values
2646     * of {@code searchChar} in the range from 0 to 0xFFFF (inclusive),
2647     * this is the smallest value <i>k</i> such that:
2648     * <blockquote><pre>
2649     * (this.charAt(<i>k</i>) == searchChar) &amp;&amp; (<i>k</i> &gt;= startPos)
2650     * </pre></blockquote>
2651     * is true. For other values of {@code searchChar}, it is the
2652     * smallest value <i>k</i> such that:
2653     * <blockquote><pre>
2654     * (this.codePointAt(<i>k</i>) == searchChar) &amp;&amp; (<i>k</i> &gt;= startPos)
2655     * </pre></blockquote>
2656     * is true. In either case, if no such character occurs in {@code seq}
2657     * at or after position {@code startPos}, then
2658     * {@code -1} is returned.
2659     *
2660     * <p>
2661     * There is no restriction on the value of {@code startPos}. If it
2662     * is negative, it has the same effect as if it were zero: this entire
2663     * string may be searched. If it is greater than the length of this
2664     * string, it has the same effect as if it were equal to the length of
2665     * this string: {@code (INDEX_NOT_FOUND) -1} is returned. Furthermore, a
2666     * {@code null} or empty ("") CharSequence will
2667     * return {@code (INDEX_NOT_FOUND) -1}.
2668     *
2669     * <p>All indices are specified in {@code char} values
2670     * (Unicode code units).
2671     *
2672     * <pre>
2673     * StringUtils.indexOf(null, *, *)          = -1
2674     * StringUtils.indexOf("", *, *)            = -1
2675     * StringUtils.indexOf("aabaabaa", 'b', 0)  = 2
2676     * StringUtils.indexOf("aabaabaa", 'b', 3)  = 5
2677     * StringUtils.indexOf("aabaabaa", 'b', 9)  = -1
2678     * StringUtils.indexOf("aabaabaa", 'b', -1) = 2
2679     * </pre>
2680     *
2681     * @param seq  the CharSequence to check, may be null
2682     * @param searchChar  the character to find
2683     * @param startPos  the start position, negative treated as zero
2684     * @return the first index of the search character (always &ge; startPos),
2685     *  -1 if no match or {@code null} string input
2686     * @since 2.0
2687     * @since 3.0 Changed signature from indexOf(String, int, int) to indexOf(CharSequence, int, int)
2688     * @since 3.6 Updated {@link CharSequenceUtils} call to behave more like {@code String}
2689     */
2690    public static int indexOf(final CharSequence seq, final int searchChar, final int startPos) {
2691        if (isEmpty(seq)) {
2692            return INDEX_NOT_FOUND;
2693        }
2694        return CharSequenceUtils.indexOf(seq, searchChar, startPos);
2695    }
2696
2697    // IndexOfAny chars
2698    //-----------------------------------------------------------------------
2699    /**
2700     * <p>Search a CharSequence to find the first index of any
2701     * character in the given set of characters.</p>
2702     *
2703     * <p>A {@code null} String will return {@code -1}.
2704     * A {@code null} or zero length search array will return {@code -1}.</p>
2705     *
2706     * <pre>
2707     * StringUtils.indexOfAny(null, *)                  = -1
2708     * StringUtils.indexOfAny("", *)                    = -1
2709     * StringUtils.indexOfAny(*, null)                  = -1
2710     * StringUtils.indexOfAny(*, [])                    = -1
2711     * StringUtils.indexOfAny("zzabyycdxx", ['z', 'a']) = 0
2712     * StringUtils.indexOfAny("zzabyycdxx", ['b', 'y']) = 3
2713     * StringUtils.indexOfAny("aba", ['z'])             = -1
2714     * </pre>
2715     *
2716     * @param cs  the CharSequence to check, may be null
2717     * @param searchChars  the chars to search for, may be null
2718     * @return the index of any of the chars, -1 if no match or null input
2719     * @since 2.0
2720     * @since 3.0 Changed signature from indexOfAny(String, char[]) to indexOfAny(CharSequence, char...)
2721     */
2722    public static int indexOfAny(final CharSequence cs, final char... searchChars) {
2723        if (isEmpty(cs) || ArrayUtils.isEmpty(searchChars)) {
2724            return INDEX_NOT_FOUND;
2725        }
2726        final int csLen = cs.length();
2727        final int csLast = csLen - 1;
2728        final int searchLen = searchChars.length;
2729        final int searchLast = searchLen - 1;
2730        for (int i = 0; i < csLen; i++) {
2731            final char ch = cs.charAt(i);
2732            for (int j = 0; j < searchLen; j++) {
2733                if (searchChars[j] == ch) {
2734                    if (i < csLast && j < searchLast && Character.isHighSurrogate(ch)) {
2735                        // ch is a supplementary character
2736                        if (searchChars[j + 1] == cs.charAt(i + 1)) {
2737                            return i;
2738                        }
2739                    } else {
2740                        return i;
2741                    }
2742                }
2743            }
2744        }
2745        return INDEX_NOT_FOUND;
2746    }
2747
2748    // IndexOfAny strings
2749    //-----------------------------------------------------------------------
2750    /**
2751     * <p>Find the first index of any of a set of potential substrings.</p>
2752     *
2753     * <p>A {@code null} CharSequence will return {@code -1}.
2754     * A {@code null} or zero length search array will return {@code -1}.
2755     * A {@code null} search array entry will be ignored, but a search
2756     * array containing "" will return {@code 0} if {@code str} is not
2757     * null. This method uses {@link String#indexOf(String)} if possible.</p>
2758     *
2759     * <pre>
2760     * StringUtils.indexOfAny(null, *)                      = -1
2761     * StringUtils.indexOfAny(*, null)                      = -1
2762     * StringUtils.indexOfAny(*, [])                        = -1
2763     * StringUtils.indexOfAny("zzabyycdxx", ["ab", "cd"])   = 2
2764     * StringUtils.indexOfAny("zzabyycdxx", ["cd", "ab"])   = 2
2765     * StringUtils.indexOfAny("zzabyycdxx", ["mn", "op"])   = -1
2766     * StringUtils.indexOfAny("zzabyycdxx", ["zab", "aby"]) = 1
2767     * StringUtils.indexOfAny("zzabyycdxx", [""])           = 0
2768     * StringUtils.indexOfAny("", [""])                     = 0
2769     * StringUtils.indexOfAny("", ["a"])                    = -1
2770     * </pre>
2771     *
2772     * @param str  the CharSequence to check, may be null
2773     * @param searchStrs  the CharSequences to search for, may be null
2774     * @return the first index of any of the searchStrs in str, -1 if no match
2775     * @since 3.0 Changed signature from indexOfAny(String, String[]) to indexOfAny(CharSequence, CharSequence...)
2776     */
2777    public static int indexOfAny(final CharSequence str, final CharSequence... searchStrs) {
2778        if (str == null || searchStrs == null) {
2779            return INDEX_NOT_FOUND;
2780        }
2781
2782        // String's can't have a MAX_VALUEth index.
2783        int ret = Integer.MAX_VALUE;
2784
2785        int tmp = 0;
2786        for (final CharSequence search : searchStrs) {
2787            if (search == null) {
2788                continue;
2789            }
2790            tmp = CharSequenceUtils.indexOf(str, search, 0);
2791            if (tmp == INDEX_NOT_FOUND) {
2792                continue;
2793            }
2794
2795            if (tmp < ret) {
2796                ret = tmp;
2797            }
2798        }
2799
2800        return ret == Integer.MAX_VALUE ? INDEX_NOT_FOUND : ret;
2801    }
2802
2803    /**
2804     * <p>Search a CharSequence to find the first index of any
2805     * character in the given set of characters.</p>
2806     *
2807     * <p>A {@code null} String will return {@code -1}.
2808     * A {@code null} search string will return {@code -1}.</p>
2809     *
2810     * <pre>
2811     * StringUtils.indexOfAny(null, *)            = -1
2812     * StringUtils.indexOfAny("", *)              = -1
2813     * StringUtils.indexOfAny(*, null)            = -1
2814     * StringUtils.indexOfAny(*, "")              = -1
2815     * StringUtils.indexOfAny("zzabyycdxx", "za") = 0
2816     * StringUtils.indexOfAny("zzabyycdxx", "by") = 3
2817     * StringUtils.indexOfAny("aba", "z")         = -1
2818     * </pre>
2819     *
2820     * @param cs  the CharSequence to check, may be null
2821     * @param searchChars  the chars to search for, may be null
2822     * @return the index of any of the chars, -1 if no match or null input
2823     * @since 2.0
2824     * @since 3.0 Changed signature from indexOfAny(String, String) to indexOfAny(CharSequence, String)
2825     */
2826    public static int indexOfAny(final CharSequence cs, final String searchChars) {
2827        if (isEmpty(cs) || isEmpty(searchChars)) {
2828            return INDEX_NOT_FOUND;
2829        }
2830        return indexOfAny(cs, searchChars.toCharArray());
2831    }
2832
2833    // IndexOfAnyBut chars
2834    //-----------------------------------------------------------------------
2835    /**
2836     * <p>Searches a CharSequence to find the first index of any
2837     * character not in the given set of characters.</p>
2838     *
2839     * <p>A {@code null} CharSequence will return {@code -1}.
2840     * A {@code null} or zero length search array will return {@code -1}.</p>
2841     *
2842     * <pre>
2843     * StringUtils.indexOfAnyBut(null, *)                              = -1
2844     * StringUtils.indexOfAnyBut("", *)                                = -1
2845     * StringUtils.indexOfAnyBut(*, null)                              = -1
2846     * StringUtils.indexOfAnyBut(*, [])                                = -1
2847     * StringUtils.indexOfAnyBut("zzabyycdxx", new char[] {'z', 'a'} ) = 3
2848     * StringUtils.indexOfAnyBut("aba", new char[] {'z'} )             = 0
2849     * StringUtils.indexOfAnyBut("aba", new char[] {'a', 'b'} )        = -1
2850
2851     * </pre>
2852     *
2853     * @param cs  the CharSequence to check, may be null
2854     * @param searchChars  the chars to search for, may be null
2855     * @return the index of any of the chars, -1 if no match or null input
2856     * @since 2.0
2857     * @since 3.0 Changed signature from indexOfAnyBut(String, char[]) to indexOfAnyBut(CharSequence, char...)
2858     */
2859    public static int indexOfAnyBut(final CharSequence cs, final char... searchChars) {
2860        if (isEmpty(cs) || ArrayUtils.isEmpty(searchChars)) {
2861            return INDEX_NOT_FOUND;
2862        }
2863        final int csLen = cs.length();
2864        final int csLast = csLen - 1;
2865        final int searchLen = searchChars.length;
2866        final int searchLast = searchLen - 1;
2867        outer:
2868        for (int i = 0; i < csLen; i++) {
2869            final char ch = cs.charAt(i);
2870            for (int j = 0; j < searchLen; j++) {
2871                if (searchChars[j] == ch) {
2872                    if (i < csLast && j < searchLast && Character.isHighSurrogate(ch)) {
2873                        if (searchChars[j + 1] == cs.charAt(i + 1)) {
2874                            continue outer;
2875                        }
2876                    } else {
2877                        continue outer;
2878                    }
2879                }
2880            }
2881            return i;
2882        }
2883        return INDEX_NOT_FOUND;
2884    }
2885
2886    /**
2887     * <p>Search a CharSequence to find the first index of any
2888     * character not in the given set of characters.</p>
2889     *
2890     * <p>A {@code null} CharSequence will return {@code -1}.
2891     * A {@code null} or empty search string will return {@code -1}.</p>
2892     *
2893     * <pre>
2894     * StringUtils.indexOfAnyBut(null, *)            = -1
2895     * StringUtils.indexOfAnyBut("", *)              = -1
2896     * StringUtils.indexOfAnyBut(*, null)            = -1
2897     * StringUtils.indexOfAnyBut(*, "")              = -1
2898     * StringUtils.indexOfAnyBut("zzabyycdxx", "za") = 3
2899     * StringUtils.indexOfAnyBut("zzabyycdxx", "")   = -1
2900     * StringUtils.indexOfAnyBut("aba", "ab")        = -1
2901     * </pre>
2902     *
2903     * @param seq  the CharSequence to check, may be null
2904     * @param searchChars  the chars to search for, may be null
2905     * @return the index of any of the chars, -1 if no match or null input
2906     * @since 2.0
2907     * @since 3.0 Changed signature from indexOfAnyBut(String, String) to indexOfAnyBut(CharSequence, CharSequence)
2908     */
2909    public static int indexOfAnyBut(final CharSequence seq, final CharSequence searchChars) {
2910        if (isEmpty(seq) || isEmpty(searchChars)) {
2911            return INDEX_NOT_FOUND;
2912        }
2913        final int strLen = seq.length();
2914        for (int i = 0; i < strLen; i++) {
2915            final char ch = seq.charAt(i);
2916            final boolean chFound = CharSequenceUtils.indexOf(searchChars, ch, 0) >= 0;
2917            if (i + 1 < strLen && Character.isHighSurrogate(ch)) {
2918                final char ch2 = seq.charAt(i + 1);
2919                if (chFound && CharSequenceUtils.indexOf(searchChars, ch2, 0) < 0) {
2920                    return i;
2921                }
2922            } else {
2923                if (!chFound) {
2924                    return i;
2925                }
2926            }
2927        }
2928        return INDEX_NOT_FOUND;
2929    }
2930
2931    /**
2932     * <p>Compares all CharSequences in an array and returns the index at which the
2933     * CharSequences begin to differ.</p>
2934     *
2935     * <p>For example,
2936     * {@code indexOfDifference(new String[] {"i am a machine", "i am a robot"}) -> 7}</p>
2937     *
2938     * <pre>
2939     * StringUtils.indexOfDifference(null) = -1
2940     * StringUtils.indexOfDifference(new String[] {}) = -1
2941     * StringUtils.indexOfDifference(new String[] {"abc"}) = -1
2942     * StringUtils.indexOfDifference(new String[] {null, null}) = -1
2943     * StringUtils.indexOfDifference(new String[] {"", ""}) = -1
2944     * StringUtils.indexOfDifference(new String[] {"", null}) = 0
2945     * StringUtils.indexOfDifference(new String[] {"abc", null, null}) = 0
2946     * StringUtils.indexOfDifference(new String[] {null, null, "abc"}) = 0
2947     * StringUtils.indexOfDifference(new String[] {"", "abc"}) = 0
2948     * StringUtils.indexOfDifference(new String[] {"abc", ""}) = 0
2949     * StringUtils.indexOfDifference(new String[] {"abc", "abc"}) = -1
2950     * StringUtils.indexOfDifference(new String[] {"abc", "a"}) = 1
2951     * StringUtils.indexOfDifference(new String[] {"ab", "abxyz"}) = 2
2952     * StringUtils.indexOfDifference(new String[] {"abcde", "abxyz"}) = 2
2953     * StringUtils.indexOfDifference(new String[] {"abcde", "xyz"}) = 0
2954     * StringUtils.indexOfDifference(new String[] {"xyz", "abcde"}) = 0
2955     * StringUtils.indexOfDifference(new String[] {"i am a machine", "i am a robot"}) = 7
2956     * </pre>
2957     *
2958     * @param css  array of CharSequences, entries may be null
2959     * @return the index where the strings begin to differ; -1 if they are all equal
2960     * @since 2.4
2961     * @since 3.0 Changed signature from indexOfDifference(String...) to indexOfDifference(CharSequence...)
2962     */
2963    public static int indexOfDifference(final CharSequence... css) {
2964        if (ArrayUtils.getLength(css) <= 1) {
2965            return INDEX_NOT_FOUND;
2966        }
2967        boolean anyStringNull = false;
2968        boolean allStringsNull = true;
2969        final int arrayLen = css.length;
2970        int shortestStrLen = Integer.MAX_VALUE;
2971        int longestStrLen = 0;
2972
2973        // find the min and max string lengths; this avoids checking to make
2974        // sure we are not exceeding the length of the string each time through
2975        // the bottom loop.
2976        for (final CharSequence cs : css) {
2977            if (cs == null) {
2978                anyStringNull = true;
2979                shortestStrLen = 0;
2980            } else {
2981                allStringsNull = false;
2982                shortestStrLen = Math.min(cs.length(), shortestStrLen);
2983                longestStrLen = Math.max(cs.length(), longestStrLen);
2984            }
2985        }
2986
2987        // handle lists containing all nulls or all empty strings
2988        if (allStringsNull || longestStrLen == 0 && !anyStringNull) {
2989            return INDEX_NOT_FOUND;
2990        }
2991
2992        // handle lists containing some nulls or some empty strings
2993        if (shortestStrLen == 0) {
2994            return 0;
2995        }
2996
2997        // find the position with the first difference across all strings
2998        int firstDiff = -1;
2999        for (int stringPos = 0; stringPos < shortestStrLen; stringPos++) {
3000            final char comparisonChar = css[0].charAt(stringPos);
3001            for (int arrayPos = 1; arrayPos < arrayLen; arrayPos++) {
3002                if (css[arrayPos].charAt(stringPos) != comparisonChar) {
3003                    firstDiff = stringPos;
3004                    break;
3005                }
3006            }
3007            if (firstDiff != -1) {
3008                break;
3009            }
3010        }
3011
3012        if (firstDiff == -1 && shortestStrLen != longestStrLen) {
3013            // we compared all of the characters up to the length of the
3014            // shortest string and didn't find a match, but the string lengths
3015            // vary, so return the length of the shortest string.
3016            return shortestStrLen;
3017        }
3018        return firstDiff;
3019    }
3020
3021    /**
3022     * <p>Compares two CharSequences, and returns the index at which the
3023     * CharSequences begin to differ.</p>
3024     *
3025     * <p>For example,
3026     * {@code indexOfDifference("i am a machine", "i am a robot") -> 7}</p>
3027     *
3028     * <pre>
3029     * StringUtils.indexOfDifference(null, null) = -1
3030     * StringUtils.indexOfDifference("", "") = -1
3031     * StringUtils.indexOfDifference("", "abc") = 0
3032     * StringUtils.indexOfDifference("abc", "") = 0
3033     * StringUtils.indexOfDifference("abc", "abc") = -1
3034     * StringUtils.indexOfDifference("ab", "abxyz") = 2
3035     * StringUtils.indexOfDifference("abcde", "abxyz") = 2
3036     * StringUtils.indexOfDifference("abcde", "xyz") = 0
3037     * </pre>
3038     *
3039     * @param cs1  the first CharSequence, may be null
3040     * @param cs2  the second CharSequence, may be null
3041     * @return the index where cs1 and cs2 begin to differ; -1 if they are equal
3042     * @since 2.0
3043     * @since 3.0 Changed signature from indexOfDifference(String, String) to
3044     * indexOfDifference(CharSequence, CharSequence)
3045     */
3046    public static int indexOfDifference(final CharSequence cs1, final CharSequence cs2) {
3047        if (cs1 == cs2) {
3048            return INDEX_NOT_FOUND;
3049        }
3050        if (cs1 == null || cs2 == null) {
3051            return 0;
3052        }
3053        int i;
3054        for (i = 0; i < cs1.length() && i < cs2.length(); ++i) {
3055            if (cs1.charAt(i) != cs2.charAt(i)) {
3056                break;
3057            }
3058        }
3059        if (i < cs2.length() || i < cs1.length()) {
3060            return i;
3061        }
3062        return INDEX_NOT_FOUND;
3063    }
3064
3065    /**
3066     * <p>Case in-sensitive find of the first index within a CharSequence.</p>
3067     *
3068     * <p>A {@code null} CharSequence will return {@code -1}.
3069     * A negative start position is treated as zero.
3070     * An empty ("") search CharSequence always matches.
3071     * A start position greater than the string length only matches
3072     * an empty search CharSequence.</p>
3073     *
3074     * <pre>
3075     * StringUtils.indexOfIgnoreCase(null, *)          = -1
3076     * StringUtils.indexOfIgnoreCase(*, null)          = -1
3077     * StringUtils.indexOfIgnoreCase("", "")           = 0
3078     * StringUtils.indexOfIgnoreCase("aabaabaa", "a")  = 0
3079     * StringUtils.indexOfIgnoreCase("aabaabaa", "b")  = 2
3080     * StringUtils.indexOfIgnoreCase("aabaabaa", "ab") = 1
3081     * </pre>
3082     *
3083     * @param str  the CharSequence to check, may be null
3084     * @param searchStr  the CharSequence to find, may be null
3085     * @return the first index of the search CharSequence,
3086     *  -1 if no match or {@code null} string input
3087     * @since 2.5
3088     * @since 3.0 Changed signature from indexOfIgnoreCase(String, String) to indexOfIgnoreCase(CharSequence, CharSequence)
3089     */
3090    public static int indexOfIgnoreCase(final CharSequence str, final CharSequence searchStr) {
3091        return indexOfIgnoreCase(str, searchStr, 0);
3092    }
3093
3094    /**
3095     * <p>Case in-sensitive find of the first index within a CharSequence
3096     * from the specified position.</p>
3097     *
3098     * <p>A {@code null} CharSequence will return {@code -1}.
3099     * A negative start position is treated as zero.
3100     * An empty ("") search CharSequence always matches.
3101     * A start position greater than the string length only matches
3102     * an empty search CharSequence.</p>
3103     *
3104     * <pre>
3105     * StringUtils.indexOfIgnoreCase(null, *, *)          = -1
3106     * StringUtils.indexOfIgnoreCase(*, null, *)          = -1
3107     * StringUtils.indexOfIgnoreCase("", "", 0)           = 0
3108     * StringUtils.indexOfIgnoreCase("aabaabaa", "A", 0)  = 0
3109     * StringUtils.indexOfIgnoreCase("aabaabaa", "B", 0)  = 2
3110     * StringUtils.indexOfIgnoreCase("aabaabaa", "AB", 0) = 1
3111     * StringUtils.indexOfIgnoreCase("aabaabaa", "B", 3)  = 5
3112     * StringUtils.indexOfIgnoreCase("aabaabaa", "B", 9)  = -1
3113     * StringUtils.indexOfIgnoreCase("aabaabaa", "B", -1) = 2
3114     * StringUtils.indexOfIgnoreCase("aabaabaa", "", 2)   = 2
3115     * StringUtils.indexOfIgnoreCase("abc", "", 9)        = -1
3116     * </pre>
3117     *
3118     * @param str  the CharSequence to check, may be null
3119     * @param searchStr  the CharSequence to find, may be null
3120     * @param startPos  the start position, negative treated as zero
3121     * @return the first index of the search CharSequence (always &ge; startPos),
3122     *  -1 if no match or {@code null} string input
3123     * @since 2.5
3124     * @since 3.0 Changed signature from indexOfIgnoreCase(String, String, int) to indexOfIgnoreCase(CharSequence, CharSequence, int)
3125     */
3126    public static int indexOfIgnoreCase(final CharSequence str, final CharSequence searchStr, int startPos) {
3127        if (str == null || searchStr == null) {
3128            return INDEX_NOT_FOUND;
3129        }
3130        if (startPos < 0) {
3131            startPos = 0;
3132        }
3133        final int endLimit = str.length() - searchStr.length() + 1;
3134        if (startPos > endLimit) {
3135            return INDEX_NOT_FOUND;
3136        }
3137        if (searchStr.length() == 0) {
3138            return startPos;
3139        }
3140        for (int i = startPos; i < endLimit; i++) {
3141            if (CharSequenceUtils.regionMatches(str, true, i, searchStr, 0, searchStr.length())) {
3142                return i;
3143            }
3144        }
3145        return INDEX_NOT_FOUND;
3146    }
3147
3148    /**
3149     * <p>Checks if all of the CharSequences are empty (""), null or whitespace only.</p>
3150     *
3151     * <p>Whitespace is defined by {@link Character#isWhitespace(char)}.</p>
3152     *
3153     * <pre>
3154     * StringUtils.isAllBlank(null)             = true
3155     * StringUtils.isAllBlank(null, "foo")      = false
3156     * StringUtils.isAllBlank(null, null)       = true
3157     * StringUtils.isAllBlank("", "bar")        = false
3158     * StringUtils.isAllBlank("bob", "")        = false
3159     * StringUtils.isAllBlank("  bob  ", null)  = false
3160     * StringUtils.isAllBlank(" ", "bar")       = false
3161     * StringUtils.isAllBlank("foo", "bar")     = false
3162     * StringUtils.isAllBlank(new String[] {})  = true
3163     * </pre>
3164     *
3165     * @param css  the CharSequences to check, may be null or empty
3166     * @return {@code true} if all of the CharSequences are empty or null or whitespace only
3167     * @since 3.6
3168     */
3169    public static boolean isAllBlank(final CharSequence... css) {
3170        if (ArrayUtils.isEmpty(css)) {
3171            return true;
3172        }
3173        for (final CharSequence cs : css) {
3174            if (isNotBlank(cs)) {
3175               return false;
3176            }
3177        }
3178        return true;
3179    }
3180
3181    /**
3182     * <p>Checks if all of the CharSequences are empty ("") or null.</p>
3183     *
3184     * <pre>
3185     * StringUtils.isAllEmpty(null)             = true
3186     * StringUtils.isAllEmpty(null, "")         = true
3187     * StringUtils.isAllEmpty(new String[] {})  = true
3188     * StringUtils.isAllEmpty(null, "foo")      = false
3189     * StringUtils.isAllEmpty("", "bar")        = false
3190     * StringUtils.isAllEmpty("bob", "")        = false
3191     * StringUtils.isAllEmpty("  bob  ", null)  = false
3192     * StringUtils.isAllEmpty(" ", "bar")       = false
3193     * StringUtils.isAllEmpty("foo", "bar")     = false
3194     * </pre>
3195     *
3196     * @param css  the CharSequences to check, may be null or empty
3197     * @return {@code true} if all of the CharSequences are empty or null
3198     * @since 3.6
3199     */
3200    public static boolean isAllEmpty(final CharSequence... css) {
3201        if (ArrayUtils.isEmpty(css)) {
3202            return true;
3203        }
3204        for (final CharSequence cs : css) {
3205            if (isNotEmpty(cs)) {
3206                return false;
3207            }
3208        }
3209        return true;
3210    }
3211
3212    /**
3213     * <p>Checks if the CharSequence contains only lowercase characters.</p>
3214     *
3215     * <p>{@code null} will return {@code false}.
3216     * An empty CharSequence (length()=0) will return {@code false}.</p>
3217     *
3218     * <pre>
3219     * StringUtils.isAllLowerCase(null)   = false
3220     * StringUtils.isAllLowerCase("")     = false
3221     * StringUtils.isAllLowerCase("  ")   = false
3222     * StringUtils.isAllLowerCase("abc")  = true
3223     * StringUtils.isAllLowerCase("abC")  = false
3224     * StringUtils.isAllLowerCase("ab c") = false
3225     * StringUtils.isAllLowerCase("ab1c") = false
3226     * StringUtils.isAllLowerCase("ab/c") = false
3227     * </pre>
3228     *
3229     * @param cs  the CharSequence to check, may be null
3230     * @return {@code true} if only contains lowercase characters, and is non-null
3231     * @since 2.5
3232     * @since 3.0 Changed signature from isAllLowerCase(String) to isAllLowerCase(CharSequence)
3233     */
3234    public static boolean isAllLowerCase(final CharSequence cs) {
3235        if (isEmpty(cs)) {
3236            return false;
3237        }
3238        final int sz = cs.length();
3239        for (int i = 0; i < sz; i++) {
3240            if (!Character.isLowerCase(cs.charAt(i))) {
3241                return false;
3242            }
3243        }
3244        return true;
3245    }
3246
3247    /**
3248     * <p>Checks if the CharSequence contains only uppercase characters.</p>
3249     *
3250     * <p>{@code null} will return {@code false}.
3251     * An empty String (length()=0) will return {@code false}.</p>
3252     *
3253     * <pre>
3254     * StringUtils.isAllUpperCase(null)   = false
3255     * StringUtils.isAllUpperCase("")     = false
3256     * StringUtils.isAllUpperCase("  ")   = false
3257     * StringUtils.isAllUpperCase("ABC")  = true
3258     * StringUtils.isAllUpperCase("aBC")  = false
3259     * StringUtils.isAllUpperCase("A C")  = false
3260     * StringUtils.isAllUpperCase("A1C")  = false
3261     * StringUtils.isAllUpperCase("A/C")  = false
3262     * </pre>
3263     *
3264     * @param cs the CharSequence to check, may be null
3265     * @return {@code true} if only contains uppercase characters, and is non-null
3266     * @since 2.5
3267     * @since 3.0 Changed signature from isAllUpperCase(String) to isAllUpperCase(CharSequence)
3268     */
3269    public static boolean isAllUpperCase(final CharSequence cs) {
3270        if (isEmpty(cs)) {
3271            return false;
3272        }
3273        final int sz = cs.length();
3274        for (int i = 0; i < sz; i++) {
3275            if (!Character.isUpperCase(cs.charAt(i))) {
3276                return false;
3277            }
3278        }
3279        return true;
3280    }
3281
3282    // Character Tests
3283    //-----------------------------------------------------------------------
3284    /**
3285     * <p>Checks if the CharSequence contains only Unicode letters.</p>
3286     *
3287     * <p>{@code null} will return {@code false}.
3288     * An empty CharSequence (length()=0) will return {@code false}.</p>
3289     *
3290     * <pre>
3291     * StringUtils.isAlpha(null)   = false
3292     * StringUtils.isAlpha("")     = false
3293     * StringUtils.isAlpha("  ")   = false
3294     * StringUtils.isAlpha("abc")  = true
3295     * StringUtils.isAlpha("ab2c") = false
3296     * StringUtils.isAlpha("ab-c") = false
3297     * </pre>
3298     *
3299     * @param cs  the CharSequence to check, may be null
3300     * @return {@code true} if only contains letters, and is non-null
3301     * @since 3.0 Changed signature from isAlpha(String) to isAlpha(CharSequence)
3302     * @since 3.0 Changed "" to return false and not true
3303     */
3304    public static boolean isAlpha(final CharSequence cs) {
3305        if (isEmpty(cs)) {
3306            return false;
3307        }
3308        final int sz = cs.length();
3309        for (int i = 0; i < sz; i++) {
3310            if (!Character.isLetter(cs.charAt(i))) {
3311                return false;
3312            }
3313        }
3314        return true;
3315    }
3316
3317    /**
3318     * <p>Checks if the CharSequence contains only Unicode letters or digits.</p>
3319     *
3320     * <p>{@code null} will return {@code false}.
3321     * An empty CharSequence (length()=0) will return {@code false}.</p>
3322     *
3323     * <pre>
3324     * StringUtils.isAlphanumeric(null)   = false
3325     * StringUtils.isAlphanumeric("")     = false
3326     * StringUtils.isAlphanumeric("  ")   = false
3327     * StringUtils.isAlphanumeric("abc")  = true
3328     * StringUtils.isAlphanumeric("ab c") = false
3329     * StringUtils.isAlphanumeric("ab2c") = true
3330     * StringUtils.isAlphanumeric("ab-c") = false
3331     * </pre>
3332     *
3333     * @param cs  the CharSequence to check, may be null
3334     * @return {@code true} if only contains letters or digits,
3335     *  and is non-null
3336     * @since 3.0 Changed signature from isAlphanumeric(String) to isAlphanumeric(CharSequence)
3337     * @since 3.0 Changed "" to return false and not true
3338     */
3339    public static boolean isAlphanumeric(final CharSequence cs) {
3340        if (isEmpty(cs)) {
3341            return false;
3342        }
3343        final int sz = cs.length();
3344        for (int i = 0; i < sz; i++) {
3345            if (!Character.isLetterOrDigit(cs.charAt(i))) {
3346                return false;
3347            }
3348        }
3349        return true;
3350    }
3351
3352    /**
3353     * <p>Checks if the CharSequence contains only Unicode letters, digits
3354     * or space ({@code ' '}).</p>
3355     *
3356     * <p>{@code null} will return {@code false}.
3357     * An empty CharSequence (length()=0) will return {@code true}.</p>
3358     *
3359     * <pre>
3360     * StringUtils.isAlphanumericSpace(null)   = false
3361     * StringUtils.isAlphanumericSpace("")     = true
3362     * StringUtils.isAlphanumericSpace("  ")   = true
3363     * StringUtils.isAlphanumericSpace("abc")  = true
3364     * StringUtils.isAlphanumericSpace("ab c") = true
3365     * StringUtils.isAlphanumericSpace("ab2c") = true
3366     * StringUtils.isAlphanumericSpace("ab-c") = false
3367     * </pre>
3368     *
3369     * @param cs  the CharSequence to check, may be null
3370     * @return {@code true} if only contains letters, digits or space,
3371     *  and is non-null
3372     * @since 3.0 Changed signature from isAlphanumericSpace(String) to isAlphanumericSpace(CharSequence)
3373     */
3374    public static boolean isAlphanumericSpace(final CharSequence cs) {
3375        if (cs == null) {
3376            return false;
3377        }
3378        final int sz = cs.length();
3379        for (int i = 0; i < sz; i++) {
3380            if (!Character.isLetterOrDigit(cs.charAt(i)) && cs.charAt(i) != ' ') {
3381                return false;
3382            }
3383        }
3384        return true;
3385    }
3386
3387    /**
3388     * <p>Checks if the CharSequence contains only Unicode letters and
3389     * space (' ').</p>
3390     *
3391     * <p>{@code null} will return {@code false}
3392     * An empty CharSequence (length()=0) will return {@code true}.</p>
3393     *
3394     * <pre>
3395     * StringUtils.isAlphaSpace(null)   = false
3396     * StringUtils.isAlphaSpace("")     = true
3397     * StringUtils.isAlphaSpace("  ")   = true
3398     * StringUtils.isAlphaSpace("abc")  = true
3399     * StringUtils.isAlphaSpace("ab c") = true
3400     * StringUtils.isAlphaSpace("ab2c") = false
3401     * StringUtils.isAlphaSpace("ab-c") = false
3402     * </pre>
3403     *
3404     * @param cs  the CharSequence to check, may be null
3405     * @return {@code true} if only contains letters and space,
3406     *  and is non-null
3407     * @since 3.0 Changed signature from isAlphaSpace(String) to isAlphaSpace(CharSequence)
3408     */
3409    public static boolean isAlphaSpace(final CharSequence cs) {
3410        if (cs == null) {
3411            return false;
3412        }
3413        final int sz = cs.length();
3414        for (int i = 0; i < sz; i++) {
3415            if (!Character.isLetter(cs.charAt(i)) && cs.charAt(i) != ' ') {
3416                return false;
3417            }
3418        }
3419        return true;
3420    }
3421
3422    /**
3423     * <p>Checks if any of the CharSequences are empty ("") or null or whitespace only.</p>
3424     *
3425     * <p>Whitespace is defined by {@link Character#isWhitespace(char)}.</p>
3426     *
3427     * <pre>
3428     * StringUtils.isAnyBlank((String) null)    = true
3429     * StringUtils.isAnyBlank((String[]) null)  = false
3430     * StringUtils.isAnyBlank(null, "foo")      = true
3431     * StringUtils.isAnyBlank(null, null)       = true
3432     * StringUtils.isAnyBlank("", "bar")        = true
3433     * StringUtils.isAnyBlank("bob", "")        = true
3434     * StringUtils.isAnyBlank("  bob  ", null)  = true
3435     * StringUtils.isAnyBlank(" ", "bar")       = true
3436     * StringUtils.isAnyBlank(new String[] {})  = false
3437     * StringUtils.isAnyBlank(new String[]{""}) = true
3438     * StringUtils.isAnyBlank("foo", "bar")     = false
3439     * </pre>
3440     *
3441     * @param css  the CharSequences to check, may be null or empty
3442     * @return {@code true} if any of the CharSequences are empty or null or whitespace only
3443     * @since 3.2
3444     */
3445    public static boolean isAnyBlank(final CharSequence... css) {
3446      if (ArrayUtils.isEmpty(css)) {
3447        return false;
3448      }
3449      for (final CharSequence cs : css) {
3450        if (isBlank(cs)) {
3451          return true;
3452        }
3453      }
3454      return false;
3455    }
3456
3457    /**
3458     * <p>Checks if any of the CharSequences are empty ("") or null.</p>
3459     *
3460     * <pre>
3461     * StringUtils.isAnyEmpty((String) null)    = true
3462     * StringUtils.isAnyEmpty((String[]) null)  = false
3463     * StringUtils.isAnyEmpty(null, "foo")      = true
3464     * StringUtils.isAnyEmpty("", "bar")        = true
3465     * StringUtils.isAnyEmpty("bob", "")        = true
3466     * StringUtils.isAnyEmpty("  bob  ", null)  = true
3467     * StringUtils.isAnyEmpty(" ", "bar")       = false
3468     * StringUtils.isAnyEmpty("foo", "bar")     = false
3469     * StringUtils.isAnyEmpty(new String[]{})   = false
3470     * StringUtils.isAnyEmpty(new String[]{""}) = true
3471     * </pre>
3472     *
3473     * @param css  the CharSequences to check, may be null or empty
3474     * @return {@code true} if any of the CharSequences are empty or null
3475     * @since 3.2
3476     */
3477    public static boolean isAnyEmpty(final CharSequence... css) {
3478      if (ArrayUtils.isEmpty(css)) {
3479        return false;
3480      }
3481      for (final CharSequence cs : css) {
3482        if (isEmpty(cs)) {
3483          return true;
3484        }
3485      }
3486      return false;
3487    }
3488
3489    /**
3490     * <p>Checks if the CharSequence contains only ASCII printable characters.</p>
3491     *
3492     * <p>{@code null} will return {@code false}.
3493     * An empty CharSequence (length()=0) will return {@code true}.</p>
3494     *
3495     * <pre>
3496     * StringUtils.isAsciiPrintable(null)     = false
3497     * StringUtils.isAsciiPrintable("")       = true
3498     * StringUtils.isAsciiPrintable(" ")      = true
3499     * StringUtils.isAsciiPrintable("Ceki")   = true
3500     * StringUtils.isAsciiPrintable("ab2c")   = true
3501     * StringUtils.isAsciiPrintable("!ab-c~") = true
3502     * StringUtils.isAsciiPrintable("\u0020") = true
3503     * StringUtils.isAsciiPrintable("\u0021") = true
3504     * StringUtils.isAsciiPrintable("\u007e") = true
3505     * StringUtils.isAsciiPrintable("\u007f") = false
3506     * StringUtils.isAsciiPrintable("Ceki G\u00fclc\u00fc") = false
3507     * </pre>
3508     *
3509     * @param cs the CharSequence to check, may be null
3510     * @return {@code true} if every character is in the range
3511     *  32 thru 126
3512     * @since 2.1
3513     * @since 3.0 Changed signature from isAsciiPrintable(String) to isAsciiPrintable(CharSequence)
3514     */
3515    public static boolean isAsciiPrintable(final CharSequence cs) {
3516        if (cs == null) {
3517            return false;
3518        }
3519        final int sz = cs.length();
3520        for (int i = 0; i < sz; i++) {
3521            if (!CharUtils.isAsciiPrintable(cs.charAt(i))) {
3522                return false;
3523            }
3524        }
3525        return true;
3526    }
3527
3528    // Nested extraction
3529    //-----------------------------------------------------------------------
3530
3531    /**
3532     * <p>Checks if a CharSequence is empty (""), null or whitespace only.</p>
3533     *
3534     * <p>Whitespace is defined by {@link Character#isWhitespace(char)}.</p>
3535     *
3536     * <pre>
3537     * StringUtils.isBlank(null)      = true
3538     * StringUtils.isBlank("")        = true
3539     * StringUtils.isBlank(" ")       = true
3540     * StringUtils.isBlank("bob")     = false
3541     * StringUtils.isBlank("  bob  ") = false
3542     * </pre>
3543     *
3544     * @param cs  the CharSequence to check, may be null
3545     * @return {@code true} if the CharSequence is null, empty or whitespace only
3546     * @since 2.0
3547     * @since 3.0 Changed signature from isBlank(String) to isBlank(CharSequence)
3548     */
3549    public static boolean isBlank(final CharSequence cs) {
3550        final int strLen = length(cs);
3551        if (strLen == 0) {
3552            return true;
3553        }
3554        for (int i = 0; i < strLen; i++) {
3555            if (!Character.isWhitespace(cs.charAt(i))) {
3556                return false;
3557            }
3558        }
3559        return true;
3560    }
3561
3562    // Empty checks
3563    //-----------------------------------------------------------------------
3564    /**
3565     * <p>Checks if a CharSequence is empty ("") or null.</p>
3566     *
3567     * <pre>
3568     * StringUtils.isEmpty(null)      = true
3569     * StringUtils.isEmpty("")        = true
3570     * StringUtils.isEmpty(" ")       = false
3571     * StringUtils.isEmpty("bob")     = false
3572     * StringUtils.isEmpty("  bob  ") = false
3573     * </pre>
3574     *
3575     * <p>NOTE: This method changed in Lang version 2.0.
3576     * It no longer trims the CharSequence.
3577     * That functionality is available in isBlank().</p>
3578     *
3579     * @param cs  the CharSequence to check, may be null
3580     * @return {@code true} if the CharSequence is empty or null
3581     * @since 3.0 Changed signature from isEmpty(String) to isEmpty(CharSequence)
3582     */
3583    public static boolean isEmpty(final CharSequence cs) {
3584        return cs == null || cs.length() == 0;
3585    }
3586
3587    /**
3588     * <p>Checks if the CharSequence contains mixed casing of both uppercase and lowercase characters.</p>
3589     *
3590     * <p>{@code null} will return {@code false}. An empty CharSequence ({@code length()=0}) will return
3591     * {@code false}.</p>
3592     *
3593     * <pre>
3594     * StringUtils.isMixedCase(null)    = false
3595     * StringUtils.isMixedCase("")      = false
3596     * StringUtils.isMixedCase("ABC")   = false
3597     * StringUtils.isMixedCase("abc")   = false
3598     * StringUtils.isMixedCase("aBc")   = true
3599     * StringUtils.isMixedCase("A c")   = true
3600     * StringUtils.isMixedCase("A1c")   = true
3601     * StringUtils.isMixedCase("a/C")   = true
3602     * StringUtils.isMixedCase("aC\t")  = true
3603     * </pre>
3604     *
3605     * @param cs the CharSequence to check, may be null
3606     * @return {@code true} if the CharSequence contains both uppercase and lowercase characters
3607     * @since 3.5
3608     */
3609    public static boolean isMixedCase(final CharSequence cs) {
3610        if (isEmpty(cs) || cs.length() == 1) {
3611            return false;
3612        }
3613        boolean containsUppercase = false;
3614        boolean containsLowercase = false;
3615        final int sz = cs.length();
3616        for (int i = 0; i < sz; i++) {
3617            if (containsUppercase && containsLowercase) {
3618                return true;
3619            } else if (Character.isUpperCase(cs.charAt(i))) {
3620                containsUppercase = true;
3621            } else if (Character.isLowerCase(cs.charAt(i))) {
3622                containsLowercase = true;
3623            }
3624        }
3625        return containsUppercase && containsLowercase;
3626    }
3627
3628    /**
3629     * <p>Checks if none of the CharSequences are empty (""), null or whitespace only.</p>
3630     *
3631     * <p>Whitespace is defined by {@link Character#isWhitespace(char)}.</p>
3632     *
3633     * <pre>
3634     * StringUtils.isNoneBlank((String) null)    = false
3635     * StringUtils.isNoneBlank((String[]) null)  = true
3636     * StringUtils.isNoneBlank(null, "foo")      = false
3637     * StringUtils.isNoneBlank(null, null)       = false
3638     * StringUtils.isNoneBlank("", "bar")        = false
3639     * StringUtils.isNoneBlank("bob", "")        = false
3640     * StringUtils.isNoneBlank("  bob  ", null)  = false
3641     * StringUtils.isNoneBlank(" ", "bar")       = false
3642     * StringUtils.isNoneBlank(new String[] {})  = true
3643     * StringUtils.isNoneBlank(new String[]{""}) = false
3644     * StringUtils.isNoneBlank("foo", "bar")     = true
3645     * </pre>
3646     *
3647     * @param css  the CharSequences to check, may be null or empty
3648     * @return {@code true} if none of the CharSequences are empty or null or whitespace only
3649     * @since 3.2
3650     */
3651    public static boolean isNoneBlank(final CharSequence... css) {
3652      return !isAnyBlank(css);
3653    }
3654
3655    /**
3656     * <p>Checks if none of the CharSequences are empty ("") or null.</p>
3657     *
3658     * <pre>
3659     * StringUtils.isNoneEmpty((String) null)    = false
3660     * StringUtils.isNoneEmpty((String[]) null)  = true
3661     * StringUtils.isNoneEmpty(null, "foo")      = false
3662     * StringUtils.isNoneEmpty("", "bar")        = false
3663     * StringUtils.isNoneEmpty("bob", "")        = false
3664     * StringUtils.isNoneEmpty("  bob  ", null)  = false
3665     * StringUtils.isNoneEmpty(new String[] {})  = true
3666     * StringUtils.isNoneEmpty(new String[]{""}) = false
3667     * StringUtils.isNoneEmpty(" ", "bar")       = true
3668     * StringUtils.isNoneEmpty("foo", "bar")     = true
3669     * </pre>
3670     *
3671     * @param css  the CharSequences to check, may be null or empty
3672     * @return {@code true} if none of the CharSequences are empty or null
3673     * @since 3.2
3674     */
3675    public static boolean isNoneEmpty(final CharSequence... css) {
3676      return !isAnyEmpty(css);
3677    }
3678
3679    /**
3680     * <p>Checks if a CharSequence is not empty (""), not null and not whitespace only.</p>
3681     *
3682     * <p>Whitespace is defined by {@link Character#isWhitespace(char)}.</p>
3683     *
3684     * <pre>
3685     * StringUtils.isNotBlank(null)      = false
3686     * StringUtils.isNotBlank("")        = false
3687     * StringUtils.isNotBlank(" ")       = false
3688     * StringUtils.isNotBlank("bob")     = true
3689     * StringUtils.isNotBlank("  bob  ") = true
3690     * </pre>
3691     *
3692     * @param cs  the CharSequence to check, may be null
3693     * @return {@code true} if the CharSequence is
3694     *  not empty and not null and not whitespace only
3695     * @since 2.0
3696     * @since 3.0 Changed signature from isNotBlank(String) to isNotBlank(CharSequence)
3697     */
3698    public static boolean isNotBlank(final CharSequence cs) {
3699        return !isBlank(cs);
3700    }
3701
3702    /**
3703     * <p>Checks if a CharSequence is not empty ("") and not null.</p>
3704     *
3705     * <pre>
3706     * StringUtils.isNotEmpty(null)      = false
3707     * StringUtils.isNotEmpty("")        = false
3708     * StringUtils.isNotEmpty(" ")       = true
3709     * StringUtils.isNotEmpty("bob")     = true
3710     * StringUtils.isNotEmpty("  bob  ") = true
3711     * </pre>
3712     *
3713     * @param cs  the CharSequence to check, may be null
3714     * @return {@code true} if the CharSequence is not empty and not null
3715     * @since 3.0 Changed signature from isNotEmpty(String) to isNotEmpty(CharSequence)
3716     */
3717    public static boolean isNotEmpty(final CharSequence cs) {
3718        return !isEmpty(cs);
3719    }
3720
3721    /**
3722     * <p>Checks if the CharSequence contains only Unicode digits.
3723     * A decimal point is not a Unicode digit and returns false.</p>
3724     *
3725     * <p>{@code null} will return {@code false}.
3726     * An empty CharSequence (length()=0) will return {@code false}.</p>
3727     *
3728     * <p>Note that the method does not allow for a leading sign, either positive or negative.
3729     * Also, if a String passes the numeric test, it may still generate a NumberFormatException
3730     * when parsed by Integer.parseInt or Long.parseLong, e.g. if the value is outside the range
3731     * for int or long respectively.</p>
3732     *
3733     * <pre>
3734     * StringUtils.isNumeric(null)   = false
3735     * StringUtils.isNumeric("")     = false
3736     * StringUtils.isNumeric("  ")   = false
3737     * StringUtils.isNumeric("123")  = true
3738     * StringUtils.isNumeric("\u0967\u0968\u0969")  = true
3739     * StringUtils.isNumeric("12 3") = false
3740     * StringUtils.isNumeric("ab2c") = false
3741     * StringUtils.isNumeric("12-3") = false
3742     * StringUtils.isNumeric("12.3") = false
3743     * StringUtils.isNumeric("-123") = false
3744     * StringUtils.isNumeric("+123") = false
3745     * </pre>
3746     *
3747     * @param cs  the CharSequence to check, may be null
3748     * @return {@code true} if only contains digits, and is non-null
3749     * @since 3.0 Changed signature from isNumeric(String) to isNumeric(CharSequence)
3750     * @since 3.0 Changed "" to return false and not true
3751     */
3752    public static boolean isNumeric(final CharSequence cs) {
3753        if (isEmpty(cs)) {
3754            return false;
3755        }
3756        final int sz = cs.length();
3757        for (int i = 0; i < sz; i++) {
3758            if (!Character.isDigit(cs.charAt(i))) {
3759                return false;
3760            }
3761        }
3762        return true;
3763    }
3764
3765    /**
3766     * <p>Checks if the CharSequence contains only Unicode digits or space
3767     * ({@code ' '}).
3768     * A decimal point is not a Unicode digit and returns false.</p>
3769     *
3770     * <p>{@code null} will return {@code false}.
3771     * An empty CharSequence (length()=0) will return {@code true}.</p>
3772     *
3773     * <pre>
3774     * StringUtils.isNumericSpace(null)   = false
3775     * StringUtils.isNumericSpace("")     = true
3776     * StringUtils.isNumericSpace("  ")   = true
3777     * StringUtils.isNumericSpace("123")  = true
3778     * StringUtils.isNumericSpace("12 3") = true
3779     * StringUtils.isNumeric("\u0967\u0968\u0969")  = true
3780     * StringUtils.isNumeric("\u0967\u0968 \u0969")  = true
3781     * StringUtils.isNumericSpace("ab2c") = false
3782     * StringUtils.isNumericSpace("12-3") = false
3783     * StringUtils.isNumericSpace("12.3") = false
3784     * </pre>
3785     *
3786     * @param cs  the CharSequence to check, may be null
3787     * @return {@code true} if only contains digits or space,
3788     *  and is non-null
3789     * @since 3.0 Changed signature from isNumericSpace(String) to isNumericSpace(CharSequence)
3790     */
3791    public static boolean isNumericSpace(final CharSequence cs) {
3792        if (cs == null) {
3793            return false;
3794        }
3795        final int sz = cs.length();
3796        for (int i = 0; i < sz; i++) {
3797            if (!Character.isDigit(cs.charAt(i)) && cs.charAt(i) != ' ') {
3798                return false;
3799            }
3800        }
3801        return true;
3802    }
3803
3804    /**
3805     * <p>Checks if the CharSequence contains only whitespace.</p>
3806     *
3807     * <p>Whitespace is defined by {@link Character#isWhitespace(char)}.</p>
3808     *
3809     * <p>{@code null} will return {@code false}.
3810     * An empty CharSequence (length()=0) will return {@code true}.</p>
3811     *
3812     * <pre>
3813     * StringUtils.isWhitespace(null)   = false
3814     * StringUtils.isWhitespace("")     = true
3815     * StringUtils.isWhitespace("  ")   = true
3816     * StringUtils.isWhitespace("abc")  = false
3817     * StringUtils.isWhitespace("ab2c") = false
3818     * StringUtils.isWhitespace("ab-c") = false
3819     * </pre>
3820     *
3821     * @param cs  the CharSequence to check, may be null
3822     * @return {@code true} if only contains whitespace, and is non-null
3823     * @since 2.0
3824     * @since 3.0 Changed signature from isWhitespace(String) to isWhitespace(CharSequence)
3825     */
3826    public static boolean isWhitespace(final CharSequence cs) {
3827        if (cs == null) {
3828            return false;
3829        }
3830        final int sz = cs.length();
3831        for (int i = 0; i < sz; i++) {
3832            if (!Character.isWhitespace(cs.charAt(i))) {
3833                return false;
3834            }
3835        }
3836        return true;
3837    }
3838
3839    /**
3840     * <p>
3841     * Joins the elements of the provided array into a single String containing the provided list of elements.
3842     * </p>
3843     *
3844     * <p>
3845     * No delimiter is added before or after the list. Null objects or empty strings within the array are represented
3846     * by empty strings.
3847     * </p>
3848     *
3849     * <pre>
3850     * StringUtils.join(null, *)               = null
3851     * StringUtils.join([], *)                 = ""
3852     * StringUtils.join([null], *)             = ""
3853     * StringUtils.join([1, 2, 3], ';')  = "1;2;3"
3854     * StringUtils.join([1, 2, 3], null) = "123"
3855     * </pre>
3856     *
3857     * @param array
3858     *            the array of values to join together, may be null
3859     * @param separator
3860     *            the separator character to use
3861     * @return the joined String, {@code null} if null array input
3862     * @since 3.2
3863     */
3864    public static String join(final byte[] array, final char separator) {
3865        if (array == null) {
3866            return null;
3867        }
3868        return join(array, separator, 0, array.length);
3869    }
3870
3871    /**
3872     * <p>
3873     * Joins the elements of the provided array into a single String containing the provided list of elements.
3874     * </p>
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 separator
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 separator, final int startIndex, final int endIndex) {
3903        if (array == null) {
3904            return null;
3905        }
3906        final int noOfItems = endIndex - startIndex;
3907        if (noOfItems <= 0) {
3908            return EMPTY;
3909        }
3910        final StringBuilder buf = newStringBuilder(noOfItems);
3911        buf.append(array[startIndex]);
3912        for (int i = startIndex + 1; i < endIndex; i++) {
3913            buf.append(separator);
3914            buf.append(array[i]);
3915        }
3916        return buf.toString();
3917    }
3918
3919    /**
3920     * <p>
3921     * Joins the elements of the provided array into a single String containing the provided list of elements.
3922     * </p>
3923     *
3924     * <p>
3925     * No delimiter is added before or after the list. Null objects or empty strings within the array are represented
3926     * by empty strings.
3927     * </p>
3928     *
3929     * <pre>
3930     * StringUtils.join(null, *)               = null
3931     * StringUtils.join([], *)                 = ""
3932     * StringUtils.join([null], *)             = ""
3933     * StringUtils.join([1, 2, 3], ';')  = "1;2;3"
3934     * StringUtils.join([1, 2, 3], null) = "123"
3935     * </pre>
3936     *
3937     * @param array
3938     *            the array of values to join together, may be null
3939     * @param separator
3940     *            the separator character to use
3941     * @return the joined String, {@code null} if null array input
3942     * @since 3.2
3943     */
3944    public static String join(final char[] array, final char separator) {
3945        if (array == null) {
3946            return null;
3947        }
3948        return join(array, separator, 0, array.length);
3949    }
3950
3951    /**
3952     * <p>
3953     * Joins the elements of the provided array into a single String containing the provided list of elements.
3954     * </p>
3955     *
3956     * <p>
3957     * No delimiter is added before or after the list. Null objects or empty strings within the array are represented
3958     * by empty strings.
3959     * </p>
3960     *
3961     * <pre>
3962     * StringUtils.join(null, *)               = null
3963     * StringUtils.join([], *)                 = ""
3964     * StringUtils.join([null], *)             = ""
3965     * StringUtils.join([1, 2, 3], ';')  = "1;2;3"
3966     * StringUtils.join([1, 2, 3], null) = "123"
3967     * </pre>
3968     *
3969     * @param array
3970     *            the array of values to join together, may be null
3971     * @param separator
3972     *            the separator character to use
3973     * @param startIndex
3974     *            the first index to start joining from. It is an error to pass in a start index past the end of the
3975     *            array
3976     * @param endIndex
3977     *            the index to stop joining from (exclusive). It is an error to pass in an end index past the end of
3978     *            the array
3979     * @return the joined String, {@code null} if null array input
3980     * @since 3.2
3981     */
3982    public static String join(final char[] array, final char separator, final int startIndex, final int endIndex) {
3983        if (array == null) {
3984            return null;
3985        }
3986        final int noOfItems = endIndex - startIndex;
3987        if (noOfItems <= 0) {
3988            return EMPTY;
3989        }
3990        final StringBuilder buf = newStringBuilder(noOfItems);
3991        buf.append(array[startIndex]);
3992        for (int i = startIndex + 1; i < endIndex; i++) {
3993            buf.append(separator);
3994            buf.append(array[i]);
3995        }
3996        return buf.toString();
3997    }
3998
3999    /**
4000     * <p>
4001     * Joins the elements of the provided array into a single String containing the provided list of elements.
4002     * </p>
4003     *
4004     * <p>
4005     * No delimiter is added before or after the list. Null objects or empty strings within the array are represented
4006     * by empty strings.
4007     * </p>
4008     *
4009     * <pre>
4010     * StringUtils.join(null, *)               = null
4011     * StringUtils.join([], *)                 = ""
4012     * StringUtils.join([null], *)             = ""
4013     * StringUtils.join([1, 2, 3], ';')  = "1;2;3"
4014     * StringUtils.join([1, 2, 3], null) = "123"
4015     * </pre>
4016     *
4017     * @param array
4018     *            the array of values to join together, may be null
4019     * @param separator
4020     *            the separator character to use
4021     * @return the joined String, {@code null} if null array input
4022     * @since 3.2
4023     */
4024    public static String join(final double[] array, final char separator) {
4025        if (array == null) {
4026            return null;
4027        }
4028        return join(array, separator, 0, array.length);
4029    }
4030
4031    /**
4032     * <p>
4033     * Joins the elements of the provided array into a single String containing the provided list of elements.
4034     * </p>
4035     *
4036     * <p>
4037     * No delimiter is added before or after the list. Null objects or empty strings within the array are represented
4038     * by empty strings.
4039     * </p>
4040     *
4041     * <pre>
4042     * StringUtils.join(null, *)               = null
4043     * StringUtils.join([], *)                 = ""
4044     * StringUtils.join([null], *)             = ""
4045     * StringUtils.join([1, 2, 3], ';')  = "1;2;3"
4046     * StringUtils.join([1, 2, 3], null) = "123"
4047     * </pre>
4048     *
4049     * @param array
4050     *            the array of values to join together, may be null
4051     * @param separator
4052     *            the separator character to use
4053     * @param startIndex
4054     *            the first index to start joining from. It is an error to pass in a start index past the end of the
4055     *            array
4056     * @param endIndex
4057     *            the index to stop joining from (exclusive). It is an error to pass in an end index past the end of
4058     *            the array
4059     * @return the joined String, {@code null} if null array input
4060     * @since 3.2
4061     */
4062    public static String join(final double[] array, final char separator, final int startIndex, final int endIndex) {
4063        if (array == null) {
4064            return null;
4065        }
4066        final int noOfItems = endIndex - startIndex;
4067        if (noOfItems <= 0) {
4068            return EMPTY;
4069        }
4070        final StringBuilder buf = newStringBuilder(noOfItems);
4071        buf.append(array[startIndex]);
4072        for (int i = startIndex + 1; i < endIndex; i++) {
4073            buf.append(separator);
4074            buf.append(array[i]);
4075        }
4076        return buf.toString();
4077    }
4078
4079    /**
4080     * <p>
4081     * Joins the elements of the provided array into a single String containing the provided list of elements.
4082     * </p>
4083     *
4084     * <p>
4085     * No delimiter is added before or after the list. Null objects or empty strings within the array are represented
4086     * by empty strings.
4087     * </p>
4088     *
4089     * <pre>
4090     * StringUtils.join(null, *)               = null
4091     * StringUtils.join([], *)                 = ""
4092     * StringUtils.join([null], *)             = ""
4093     * StringUtils.join([1, 2, 3], ';')  = "1;2;3"
4094     * StringUtils.join([1, 2, 3], null) = "123"
4095     * </pre>
4096     *
4097     * @param array
4098     *            the array of values to join together, may be null
4099     * @param separator
4100     *            the separator character to use
4101     * @return the joined String, {@code null} if null array input
4102     * @since 3.2
4103     */
4104    public static String join(final float[] array, final char separator) {
4105        if (array == null) {
4106            return null;
4107        }
4108        return join(array, separator, 0, array.length);
4109    }
4110
4111    /**
4112     * <p>
4113     * Joins the elements of the provided array into a single String containing the provided list of elements.
4114     * </p>
4115     *
4116     * <p>
4117     * No delimiter is added before or after the list. Null objects or empty strings within the array are represented
4118     * by empty strings.
4119     * </p>
4120     *
4121     * <pre>
4122     * StringUtils.join(null, *)               = null
4123     * StringUtils.join([], *)                 = ""
4124     * StringUtils.join([null], *)             = ""
4125     * StringUtils.join([1, 2, 3], ';')  = "1;2;3"
4126     * StringUtils.join([1, 2, 3], null) = "123"
4127     * </pre>
4128     *
4129     * @param array
4130     *            the array of values to join together, may be null
4131     * @param separator
4132     *            the separator character to use
4133     * @param startIndex
4134     *            the first index to start joining from. It is an error to pass in a start index past the end of the
4135     *            array
4136     * @param endIndex
4137     *            the index to stop joining from (exclusive). It is an error to pass in an end index past the end of
4138     *            the array
4139     * @return the joined String, {@code null} if null array input
4140     * @since 3.2
4141     */
4142    public static String join(final float[] array, final char separator, final int startIndex, final int endIndex) {
4143        if (array == null) {
4144            return null;
4145        }
4146        final int noOfItems = endIndex - startIndex;
4147        if (noOfItems <= 0) {
4148            return EMPTY;
4149        }
4150        final StringBuilder buf = newStringBuilder(noOfItems);
4151        buf.append(array[startIndex]);
4152        for (int i = startIndex + 1; i < endIndex; i++) {
4153            buf.append(separator);
4154            buf.append(array[i]);
4155        }
4156        return buf.toString();
4157    }
4158
4159    /**
4160     * <p>
4161     * Joins the elements of the provided array into a single String containing the provided list of elements.
4162     * </p>
4163     *
4164     * <p>
4165     * No delimiter is added before or after the list. Null objects or empty strings within the array are represented
4166     * by empty strings.
4167     * </p>
4168     *
4169     * <pre>
4170     * StringUtils.join(null, *)               = null
4171     * StringUtils.join([], *)                 = ""
4172     * StringUtils.join([null], *)             = ""
4173     * StringUtils.join([1, 2, 3], ';')  = "1;2;3"
4174     * StringUtils.join([1, 2, 3], null) = "123"
4175     * </pre>
4176     *
4177     * @param array
4178     *            the array of values to join together, may be null
4179     * @param separator
4180     *            the separator character to use
4181     * @return the joined String, {@code null} if null array input
4182     * @since 3.2
4183     */
4184    public static String join(final int[] array, final char separator) {
4185        if (array == null) {
4186            return null;
4187        }
4188        return join(array, separator, 0, array.length);
4189    }
4190
4191    /**
4192     * <p>
4193     * Joins the elements of the provided array into a single String containing the provided list of elements.
4194     * </p>
4195     *
4196     * <p>
4197     * No delimiter is added before or after the list. Null objects or empty strings within the array are represented
4198     * by empty strings.
4199     * </p>
4200     *
4201     * <pre>
4202     * StringUtils.join(null, *)               = null
4203     * StringUtils.join([], *)                 = ""
4204     * StringUtils.join([null], *)             = ""
4205     * StringUtils.join([1, 2, 3], ';')  = "1;2;3"
4206     * StringUtils.join([1, 2, 3], null) = "123"
4207     * </pre>
4208     *
4209     * @param array
4210     *            the array of values to join together, may be null
4211     * @param separator
4212     *            the separator character to use
4213     * @param startIndex
4214     *            the first index to start joining from. It is an error to pass in a start index past the end of the
4215     *            array
4216     * @param endIndex
4217     *            the index to stop joining from (exclusive). It is an error to pass in an end index past the end of
4218     *            the array
4219     * @return the joined String, {@code null} if null array input
4220     * @since 3.2
4221     */
4222    public static String join(final int[] array, final char separator, final int startIndex, final int endIndex) {
4223        if (array == null) {
4224            return null;
4225        }
4226        final int noOfItems = endIndex - startIndex;
4227        if (noOfItems <= 0) {
4228            return EMPTY;
4229        }
4230        final StringBuilder buf = newStringBuilder(noOfItems);
4231        buf.append(array[startIndex]);
4232        for (int i = startIndex + 1; i < endIndex; i++) {
4233            buf.append(separator);
4234            buf.append(array[i]);
4235        }
4236        return buf.toString();
4237    }
4238
4239    /**
4240     * <p>Joins the elements of the provided {@code Iterable} into
4241     * a single String containing the provided elements.</p>
4242     *
4243     * <p>No delimiter is added before or after the list. Null objects or empty
4244     * strings within the iteration are represented by empty strings.</p>
4245     *
4246     * <p>See the examples here: {@link #join(Object[],char)}. </p>
4247     *
4248     * @param iterable  the {@code Iterable} providing the values to join together, may be null
4249     * @param separator  the separator character to use
4250     * @return the joined String, {@code null} if null iterator input
4251     * @since 2.3
4252     */
4253    public static String join(final Iterable<?> iterable, final char separator) {
4254        if (iterable == null) {
4255            return null;
4256        }
4257        return join(iterable.iterator(), separator);
4258    }
4259
4260    /**
4261     * <p>Joins the elements of the provided {@code Iterable} into
4262     * a single String containing the provided elements.</p>
4263     *
4264     * <p>No delimiter is added before or after the list.
4265     * A {@code null} separator is the same as an empty String ("").</p>
4266     *
4267     * <p>See the examples here: {@link #join(Object[],String)}. </p>
4268     *
4269     * @param iterable  the {@code Iterable} providing the values to join together, may be null
4270     * @param separator  the separator character to use, null treated as ""
4271     * @return the joined String, {@code null} if null iterator input
4272     * @since 2.3
4273     */
4274    public static String join(final Iterable<?> iterable, final String separator) {
4275        if (iterable == null) {
4276            return null;
4277        }
4278        return join(iterable.iterator(), separator);
4279    }
4280
4281    /**
4282     * <p>Joins the elements of the provided {@code Iterator} into
4283     * a single String containing the provided elements.</p>
4284     *
4285     * <p>No delimiter is added before or after the list. Null objects or empty
4286     * strings within the iteration are represented by empty strings.</p>
4287     *
4288     * <p>See the examples here: {@link #join(Object[],char)}. </p>
4289     *
4290     * @param iterator  the {@code Iterator} of values to join together, may be null
4291     * @param separator  the separator character to use
4292     * @return the joined String, {@code null} if null iterator input
4293     * @since 2.0
4294     */
4295    public static String join(final Iterator<?> iterator, final char separator) {
4296
4297        // handle null, zero and one elements before building a buffer
4298        if (iterator == null) {
4299            return null;
4300        }
4301        if (!iterator.hasNext()) {
4302            return EMPTY;
4303        }
4304        final Object first = iterator.next();
4305        if (!iterator.hasNext()) {
4306            return Objects.toString(first, EMPTY);
4307        }
4308
4309        // two or more elements
4310        final StringBuilder buf = new StringBuilder(STRING_BUILDER_SIZE); // Java default is 16, probably too small
4311        if (first != null) {
4312            buf.append(first);
4313        }
4314
4315        while (iterator.hasNext()) {
4316            buf.append(separator);
4317            final Object obj = iterator.next();
4318            if (obj != null) {
4319                buf.append(obj);
4320            }
4321        }
4322
4323        return buf.toString();
4324    }
4325
4326    /**
4327     * <p>Joins the elements of the provided {@code Iterator} into
4328     * a single String containing the provided elements.</p>
4329     *
4330     * <p>No delimiter is added before or after the list.
4331     * A {@code null} separator is the same as an empty String ("").</p>
4332     *
4333     * <p>See the examples here: {@link #join(Object[],String)}. </p>
4334     *
4335     * @param iterator  the {@code Iterator} of values to join together, may be null
4336     * @param separator  the separator character to use, null treated as ""
4337     * @return the joined String, {@code null} if null iterator input
4338     */
4339    public static String join(final Iterator<?> iterator, final String separator) {
4340
4341        // handle null, zero and one elements before building a buffer
4342        if (iterator == null) {
4343            return null;
4344        }
4345        if (!iterator.hasNext()) {
4346            return EMPTY;
4347        }
4348        final Object first = iterator.next();
4349        if (!iterator.hasNext()) {
4350            return Objects.toString(first, "");
4351        }
4352
4353        // two or more elements
4354        final StringBuilder buf = new StringBuilder(STRING_BUILDER_SIZE); // Java default is 16, probably too small
4355        if (first != null) {
4356            buf.append(first);
4357        }
4358
4359        while (iterator.hasNext()) {
4360            if (separator != null) {
4361                buf.append(separator);
4362            }
4363            final Object obj = iterator.next();
4364            if (obj != null) {
4365                buf.append(obj);
4366            }
4367        }
4368        return buf.toString();
4369    }
4370
4371    /**
4372     * <p>Joins the elements of the provided {@code List} into a single String
4373     * containing the provided list of elements.</p>
4374     *
4375     * <p>No delimiter is added before or after the list.
4376     * Null objects or empty strings within the array are represented by
4377     * empty strings.</p>
4378     *
4379     * <pre>
4380     * StringUtils.join(null, *)               = null
4381     * StringUtils.join([], *)                 = ""
4382     * StringUtils.join([null], *)             = ""
4383     * StringUtils.join(["a", "b", "c"], ';')  = "a;b;c"
4384     * StringUtils.join(["a", "b", "c"], null) = "abc"
4385     * StringUtils.join([null, "", "a"], ';')  = ";;a"
4386     * </pre>
4387     *
4388     * @param list  the {@code List} of values to join together, may be null
4389     * @param separator  the separator character to use
4390     * @param startIndex the first index to start joining from.  It is
4391     * an error to pass in a start index past the end of the list
4392     * @param endIndex the index to stop joining from (exclusive). It is
4393     * an error to pass in an end index past the end of the list
4394     * @return the joined String, {@code null} if null list input
4395     * @since 3.8
4396     */
4397    public static String join(final List<?> list, final char separator, final int startIndex, final int endIndex) {
4398        if (list == null) {
4399            return null;
4400        }
4401        final int noOfItems = endIndex - startIndex;
4402        if (noOfItems <= 0) {
4403            return EMPTY;
4404        }
4405        final List<?> subList = list.subList(startIndex, endIndex);
4406        return join(subList.iterator(), separator);
4407    }
4408
4409    /**
4410     * <p>Joins the elements of the provided {@code List} into a single String
4411     * containing the provided list of elements.</p>
4412     *
4413     * <p>No delimiter is added before or after the list.
4414     * Null objects or empty strings within the array are represented by
4415     * empty strings.</p>
4416     *
4417     * <pre>
4418     * StringUtils.join(null, *)               = null
4419     * StringUtils.join([], *)                 = ""
4420     * StringUtils.join([null], *)             = ""
4421     * StringUtils.join(["a", "b", "c"], ';')  = "a;b;c"
4422     * StringUtils.join(["a", "b", "c"], null) = "abc"
4423     * StringUtils.join([null, "", "a"], ';')  = ";;a"
4424     * </pre>
4425     *
4426     * @param list  the {@code List} of values to join together, may be null
4427     * @param separator  the separator character to use
4428     * @param startIndex the first index to start joining from.  It is
4429     * an error to pass in a start index past the end of the list
4430     * @param endIndex the index to stop joining from (exclusive). It is
4431     * an error to pass in an end index past the end of the list
4432     * @return the joined String, {@code null} if null list input
4433     * @since 3.8
4434     */
4435    public static String join(final List<?> list, final String separator, final int startIndex, final int endIndex) {
4436        if (list == null) {
4437            return null;
4438        }
4439        final int noOfItems = endIndex - startIndex;
4440        if (noOfItems <= 0) {
4441            return EMPTY;
4442        }
4443        final List<?> subList = list.subList(startIndex, endIndex);
4444        return join(subList.iterator(), separator);
4445    }
4446
4447
4448    /**
4449     * <p>
4450     * Joins the elements of the provided array into a single String containing the provided list of elements.
4451     * </p>
4452     *
4453     * <p>
4454     * No delimiter is added before or after the list. Null objects or empty strings within the array are represented
4455     * by empty strings.
4456     * </p>
4457     *
4458     * <pre>
4459     * StringUtils.join(null, *)               = null
4460     * StringUtils.join([], *)                 = ""
4461     * StringUtils.join([null], *)             = ""
4462     * StringUtils.join([1, 2, 3], ';')  = "1;2;3"
4463     * StringUtils.join([1, 2, 3], null) = "123"
4464     * </pre>
4465     *
4466     * @param array
4467     *            the array of values to join together, may be null
4468     * @param separator
4469     *            the separator character to use
4470     * @return the joined String, {@code null} if null array input
4471     * @since 3.2
4472     */
4473    public static String join(final long[] array, final char separator) {
4474        if (array == null) {
4475            return null;
4476        }
4477        return join(array, separator, 0, array.length);
4478    }
4479
4480    /**
4481     * <p>
4482     * Joins the elements of the provided array into a single String containing the provided list of elements.
4483     * </p>
4484     *
4485     * <p>
4486     * No delimiter is added before or after the list. Null objects or empty strings within the array are represented
4487     * by empty strings.
4488     * </p>
4489     *
4490     * <pre>
4491     * StringUtils.join(null, *)               = null
4492     * StringUtils.join([], *)                 = ""
4493     * StringUtils.join([null], *)             = ""
4494     * StringUtils.join([1, 2, 3], ';')  = "1;2;3"
4495     * StringUtils.join([1, 2, 3], null) = "123"
4496     * </pre>
4497     *
4498     * @param array
4499     *            the array of values to join together, may be null
4500     * @param separator
4501     *            the separator character to use
4502     * @param startIndex
4503     *            the first index to start joining from. It is an error to pass in a start index past the end of the
4504     *            array
4505     * @param endIndex
4506     *            the index to stop joining from (exclusive). It is an error to pass in an end index past the end of
4507     *            the array
4508     * @return the joined String, {@code null} if null array input
4509     * @since 3.2
4510     */
4511    public static String join(final long[] array, final char separator, final int startIndex, final int endIndex) {
4512        if (array == null) {
4513            return null;
4514        }
4515        final int noOfItems = endIndex - startIndex;
4516        if (noOfItems <= 0) {
4517            return EMPTY;
4518        }
4519        final StringBuilder buf = newStringBuilder(noOfItems);
4520        buf.append(array[startIndex]);
4521        for (int i = startIndex + 1; i < endIndex; i++) {
4522            buf.append(separator);
4523            buf.append(array[i]);
4524        }
4525        return buf.toString();
4526    }
4527
4528    /**
4529     * <p>Joins the elements of the provided array into a single String
4530     * containing the provided list of elements.</p>
4531     *
4532     * <p>No delimiter is added before or after the list.
4533     * Null objects or empty strings within the array are represented by
4534     * empty strings.</p>
4535     *
4536     * <pre>
4537     * StringUtils.join(null, *)               = null
4538     * StringUtils.join([], *)                 = ""
4539     * StringUtils.join([null], *)             = ""
4540     * StringUtils.join(["a", "b", "c"], ';')  = "a;b;c"
4541     * StringUtils.join(["a", "b", "c"], null) = "abc"
4542     * StringUtils.join([null, "", "a"], ';')  = ";;a"
4543     * </pre>
4544     *
4545     * @param array  the array of values to join together, may be null
4546     * @param separator  the separator character to use
4547     * @return the joined String, {@code null} if null array input
4548     * @since 2.0
4549     */
4550    public static String join(final Object[] array, final char separator) {
4551        if (array == null) {
4552            return null;
4553        }
4554        return join(array, separator, 0, array.length);
4555    }
4556
4557    /**
4558     * <p>Joins the elements of the provided array into a single String
4559     * containing the provided list of elements.</p>
4560     *
4561     * <p>No delimiter is added before or after the list.
4562     * Null objects or empty strings within the array are represented by
4563     * empty strings.</p>
4564     *
4565     * <pre>
4566     * StringUtils.join(null, *)               = null
4567     * StringUtils.join([], *)                 = ""
4568     * StringUtils.join([null], *)             = ""
4569     * StringUtils.join(["a", "b", "c"], ';')  = "a;b;c"
4570     * StringUtils.join(["a", "b", "c"], null) = "abc"
4571     * StringUtils.join([null, "", "a"], ';')  = ";;a"
4572     * </pre>
4573     *
4574     * @param array  the array of values to join together, may be null
4575     * @param separator  the separator character to use
4576     * @param startIndex the first index to start joining from.  It is
4577     * an error to pass in a start index past the end of the array
4578     * @param endIndex the index to stop joining from (exclusive). It is
4579     * an error to pass in an end index past the end of the array
4580     * @return the joined String, {@code null} if null array input
4581     * @since 2.0
4582     */
4583    public static String join(final Object[] array, final char separator, final int startIndex, final int endIndex) {
4584        if (array == null) {
4585            return null;
4586        }
4587        final int noOfItems = endIndex - startIndex;
4588        if (noOfItems <= 0) {
4589            return EMPTY;
4590        }
4591        final StringBuilder buf = newStringBuilder(noOfItems);
4592        if (array[startIndex] != null) {
4593            buf.append(array[startIndex]);
4594        }
4595        for (int i = startIndex + 1; i < endIndex; i++) {
4596            buf.append(separator);
4597            if (array[i] != null) {
4598                buf.append(array[i]);
4599            }
4600        }
4601        return buf.toString();
4602    }
4603
4604    /**
4605     * <p>Joins the elements of the provided array into a single String
4606     * containing the provided list of elements.</p>
4607     *
4608     * <p>No delimiter is added before or after the list.
4609     * A {@code null} separator is the same as an empty String ("").
4610     * Null objects or empty strings within the array are represented by
4611     * empty strings.</p>
4612     *
4613     * <pre>
4614     * StringUtils.join(null, *)                = null
4615     * StringUtils.join([], *)                  = ""
4616     * StringUtils.join([null], *)              = ""
4617     * StringUtils.join(["a", "b", "c"], "--")  = "a--b--c"
4618     * StringUtils.join(["a", "b", "c"], null)  = "abc"
4619     * StringUtils.join(["a", "b", "c"], "")    = "abc"
4620     * StringUtils.join([null, "", "a"], ',')   = ",,a"
4621     * </pre>
4622     *
4623     * @param array  the array of values to join together, may be null
4624     * @param separator  the separator character to use, null treated as ""
4625     * @return the joined String, {@code null} if null array input
4626     */
4627    public static String join(final Object[] array, final String separator) {
4628        if (array == null) {
4629            return null;
4630        }
4631        return join(array, separator, 0, array.length);
4632    }
4633
4634    /**
4635     * <p>Joins the elements of the provided array into a single String
4636     * containing the provided list of elements.</p>
4637     *
4638     * <p>No delimiter is added before or after the list.
4639     * A {@code null} separator is the same as an empty String ("").
4640     * Null objects or empty strings within the array are represented by
4641     * empty strings.</p>
4642     *
4643     * <pre>
4644     * StringUtils.join(null, *, *, *)                = null
4645     * StringUtils.join([], *, *, *)                  = ""
4646     * StringUtils.join([null], *, *, *)              = ""
4647     * StringUtils.join(["a", "b", "c"], "--", 0, 3)  = "a--b--c"
4648     * StringUtils.join(["a", "b", "c"], "--", 1, 3)  = "b--c"
4649     * StringUtils.join(["a", "b", "c"], "--", 2, 3)  = "c"
4650     * StringUtils.join(["a", "b", "c"], "--", 2, 2)  = ""
4651     * StringUtils.join(["a", "b", "c"], null, 0, 3)  = "abc"
4652     * StringUtils.join(["a", "b", "c"], "", 0, 3)    = "abc"
4653     * StringUtils.join([null, "", "a"], ',', 0, 3)   = ",,a"
4654     * </pre>
4655     *
4656     * @param array  the array of values to join together, may be null
4657     * @param separator  the separator character to use, null treated as ""
4658     * @param startIndex the first index to start joining from.
4659     * @param endIndex the index to stop joining from (exclusive).
4660     * @return the joined String, {@code null} if null array input; or the empty string
4661     * if {@code endIndex - startIndex <= 0}. The number of joined entries is given by
4662     * {@code endIndex - startIndex}
4663     * @throws ArrayIndexOutOfBoundsException ife<br>
4664     * {@code startIndex < 0} or <br>
4665     * {@code startIndex >= array.length()} or <br>
4666     * {@code endIndex < 0} or <br>
4667     * {@code endIndex > array.length()}
4668     */
4669    public static String join(final Object[] array, String separator, final int startIndex, final int endIndex) {
4670        if (array == null) {
4671            return null;
4672        }
4673        if (separator == null) {
4674            separator = EMPTY;
4675        }
4676
4677        // endIndex - startIndex > 0:   Len = NofStrings *(len(firstString) + len(separator))
4678        //           (Assuming that all Strings are roughly equally long)
4679        final int noOfItems = endIndex - startIndex;
4680        if (noOfItems <= 0) {
4681            return EMPTY;
4682        }
4683
4684        final StringBuilder buf = newStringBuilder(noOfItems);
4685
4686        if (array[startIndex] != null) {
4687            buf.append(array[startIndex]);
4688        }
4689
4690        for (int i = startIndex + 1; i < endIndex; i++) {
4691            buf.append(separator);
4692
4693            if (array[i] != null) {
4694                buf.append(array[i]);
4695            }
4696        }
4697        return buf.toString();
4698    }
4699
4700    /**
4701     * <p>
4702     * Joins the elements of the provided array into a single String containing the provided list of elements.
4703     * </p>
4704     *
4705     * <p>
4706     * No delimiter is added before or after the list. Null objects or empty strings within the array are represented
4707     * by empty strings.
4708     * </p>
4709     *
4710     * <pre>
4711     * StringUtils.join(null, *)               = null
4712     * StringUtils.join([], *)                 = ""
4713     * StringUtils.join([null], *)             = ""
4714     * StringUtils.join([1, 2, 3], ';')  = "1;2;3"
4715     * StringUtils.join([1, 2, 3], null) = "123"
4716     * </pre>
4717     *
4718     * @param array
4719     *            the array of values to join together, may be null
4720     * @param separator
4721     *            the separator character to use
4722     * @return the joined String, {@code null} if null array input
4723     * @since 3.2
4724     */
4725    public static String join(final short[] array, final char separator) {
4726        if (array == null) {
4727            return null;
4728        }
4729        return join(array, separator, 0, array.length);
4730    }
4731
4732    /**
4733     * <p>
4734     * Joins the elements of the provided array into a single String containing the provided list of elements.
4735     * </p>
4736     *
4737     * <p>
4738     * No delimiter is added before or after the list. Null objects or empty strings within the array are represented
4739     * by empty strings.
4740     * </p>
4741     *
4742     * <pre>
4743     * StringUtils.join(null, *)               = null
4744     * StringUtils.join([], *)                 = ""
4745     * StringUtils.join([null], *)             = ""
4746     * StringUtils.join([1, 2, 3], ';')  = "1;2;3"
4747     * StringUtils.join([1, 2, 3], null) = "123"
4748     * </pre>
4749     *
4750     * @param array
4751     *            the array of values to join together, may be null
4752     * @param separator
4753     *            the separator character to use
4754     * @param startIndex
4755     *            the first index to start joining from. It is an error to pass in a start index past the end of the
4756     *            array
4757     * @param endIndex
4758     *            the index to stop joining from (exclusive). It is an error to pass in an end index past the end of
4759     *            the array
4760     * @return the joined String, {@code null} if null array input
4761     * @since 3.2
4762     */
4763    public static String join(final short[] array, final char separator, final int startIndex, final int endIndex) {
4764        if (array == null) {
4765            return null;
4766        }
4767        final int noOfItems = endIndex - startIndex;
4768        if (noOfItems <= 0) {
4769            return EMPTY;
4770        }
4771        final StringBuilder buf = newStringBuilder(noOfItems);
4772        buf.append(array[startIndex]);
4773        for (int i = startIndex + 1; i < endIndex; i++) {
4774            buf.append(separator);
4775            buf.append(array[i]);
4776        }
4777        return buf.toString();
4778    }
4779
4780
4781    // Joining
4782    //-----------------------------------------------------------------------
4783    /**
4784     * <p>Joins the elements of the provided array into a single String
4785     * containing the provided list of elements.</p>
4786     *
4787     * <p>No separator is added to the joined String.
4788     * Null objects or empty strings within the array are represented by
4789     * empty strings.</p>
4790     *
4791     * <pre>
4792     * StringUtils.join(null)            = null
4793     * StringUtils.join([])              = ""
4794     * StringUtils.join([null])          = ""
4795     * StringUtils.join(["a", "b", "c"]) = "abc"
4796     * StringUtils.join([null, "", "a"]) = "a"
4797     * </pre>
4798     *
4799     * @param <T> the specific type of values to join together
4800     * @param elements  the values to join together, may be null
4801     * @return the joined String, {@code null} if null array input
4802     * @since 2.0
4803     * @since 3.0 Changed signature to use varargs
4804     */
4805    @SafeVarargs
4806    public static <T> String join(final T... elements) {
4807        return join(elements, null);
4808    }
4809
4810    /**
4811     * <p>Joins the elements of the provided varargs into a
4812     * single String containing the provided elements.</p>
4813     *
4814     * <p>No delimiter is added before or after the list.
4815     * {@code null} elements and separator are treated as empty Strings ("").</p>
4816     *
4817     * <pre>
4818     * StringUtils.joinWith(",", {"a", "b"})        = "a,b"
4819     * StringUtils.joinWith(",", {"a", "b",""})     = "a,b,"
4820     * StringUtils.joinWith(",", {"a", null, "b"})  = "a,,b"
4821     * StringUtils.joinWith(null, {"a", "b"})       = "ab"
4822     * </pre>
4823     *
4824     * @param separator the separator character to use, null treated as ""
4825     * @param objects the varargs providing the values to join together. {@code null} elements are treated as ""
4826     * @return the joined String.
4827     * @throws java.lang.IllegalArgumentException if a null varargs is provided
4828     * @since 3.5
4829     */
4830    public static String joinWith(final String separator, final Object... objects) {
4831        if (objects == null) {
4832            throw new IllegalArgumentException("Object varargs must not be null");
4833        }
4834
4835        final String sanitizedSeparator = defaultString(separator);
4836
4837        final StringBuilder result = new StringBuilder();
4838
4839        final Iterator<Object> iterator = Arrays.asList(objects).iterator();
4840        while (iterator.hasNext()) {
4841            final String value = Objects.toString(iterator.next(), "");
4842            result.append(value);
4843
4844            if (iterator.hasNext()) {
4845                result.append(sanitizedSeparator);
4846            }
4847        }
4848
4849        return result.toString();
4850    }
4851
4852    /**
4853     * <p>Finds the last index within a CharSequence, handling {@code null}.
4854     * This method uses {@link String#lastIndexOf(String)} if possible.</p>
4855     *
4856     * <p>A {@code null} CharSequence will return {@code -1}.</p>
4857     *
4858     * <pre>
4859     * StringUtils.lastIndexOf(null, *)          = -1
4860     * StringUtils.lastIndexOf(*, null)          = -1
4861     * StringUtils.lastIndexOf("", "")           = 0
4862     * StringUtils.lastIndexOf("aabaabaa", "a")  = 7
4863     * StringUtils.lastIndexOf("aabaabaa", "b")  = 5
4864     * StringUtils.lastIndexOf("aabaabaa", "ab") = 4
4865     * StringUtils.lastIndexOf("aabaabaa", "")   = 8
4866     * </pre>
4867     *
4868     * @param seq  the CharSequence to check, may be null
4869     * @param searchSeq  the CharSequence to find, may be null
4870     * @return the last index of the search String,
4871     *  -1 if no match or {@code null} string input
4872     * @since 2.0
4873     * @since 3.0 Changed signature from lastIndexOf(String, String) to lastIndexOf(CharSequence, CharSequence)
4874     */
4875    public static int lastIndexOf(final CharSequence seq, final CharSequence searchSeq) {
4876        if (seq == null || searchSeq == null) {
4877            return INDEX_NOT_FOUND;
4878        }
4879        return CharSequenceUtils.lastIndexOf(seq, searchSeq, seq.length());
4880    }
4881
4882    /**
4883     * <p>Finds the last index within a CharSequence, handling {@code null}.
4884     * This method uses {@link String#lastIndexOf(String, int)} if possible.</p>
4885     *
4886     * <p>A {@code null} CharSequence will return {@code -1}.
4887     * A negative start position returns {@code -1}.
4888     * An empty ("") search CharSequence always matches unless the start position is negative.
4889     * A start position greater than the string length searches the whole string.
4890     * The search starts at the startPos and works backwards; matches starting after the start
4891     * position are ignored.
4892     * </p>
4893     *
4894     * <pre>
4895     * StringUtils.lastIndexOf(null, *, *)          = -1
4896     * StringUtils.lastIndexOf(*, null, *)          = -1
4897     * StringUtils.lastIndexOf("aabaabaa", "a", 8)  = 7
4898     * StringUtils.lastIndexOf("aabaabaa", "b", 8)  = 5
4899     * StringUtils.lastIndexOf("aabaabaa", "ab", 8) = 4
4900     * StringUtils.lastIndexOf("aabaabaa", "b", 9)  = 5
4901     * StringUtils.lastIndexOf("aabaabaa", "b", -1) = -1
4902     * StringUtils.lastIndexOf("aabaabaa", "a", 0)  = 0
4903     * StringUtils.lastIndexOf("aabaabaa", "b", 0)  = -1
4904     * StringUtils.lastIndexOf("aabaabaa", "b", 1)  = -1
4905     * StringUtils.lastIndexOf("aabaabaa", "b", 2)  = 2
4906     * StringUtils.lastIndexOf("aabaabaa", "ba", 2)  = 2
4907     * </pre>
4908     *
4909     * @param seq  the CharSequence to check, may be null
4910     * @param searchSeq  the CharSequence to find, may be null
4911     * @param startPos  the start position, negative treated as zero
4912     * @return the last index of the search CharSequence (always &le; startPos),
4913     *  -1 if no match or {@code null} string input
4914     * @since 2.0
4915     * @since 3.0 Changed signature from lastIndexOf(String, String, int) to lastIndexOf(CharSequence, CharSequence, int)
4916     */
4917    public static int lastIndexOf(final CharSequence seq, final CharSequence searchSeq, final int startPos) {
4918        if (seq == null || searchSeq == null) {
4919            return INDEX_NOT_FOUND;
4920        }
4921        return CharSequenceUtils.lastIndexOf(seq, searchSeq, startPos);
4922    }
4923
4924    // LastIndexOf
4925    //-----------------------------------------------------------------------
4926    /**
4927     * Returns the index within {@code seq} of the last occurrence of
4928     * the specified character. For values of {@code searchChar} in the
4929     * range from 0 to 0xFFFF (inclusive), the index (in Unicode code
4930     * units) returned is the largest value <i>k</i> such that:
4931     * <blockquote><pre>
4932     * this.charAt(<i>k</i>) == searchChar
4933     * </pre></blockquote>
4934     * is true. For other values of {@code searchChar}, it is the
4935     * largest value <i>k</i> such that:
4936     * <blockquote><pre>
4937     * this.codePointAt(<i>k</i>) == searchChar
4938     * </pre></blockquote>
4939     * is true.  In either case, if no such character occurs in this
4940     * string, then {@code -1} is returned. Furthermore, a {@code null} or empty ("")
4941     * {@code CharSequence} will return {@code -1}. The
4942     * {@code seq} {@code CharSequence} object is searched backwards
4943     * starting at the last character.
4944     *
4945     * <pre>
4946     * StringUtils.lastIndexOf(null, *)         = -1
4947     * StringUtils.lastIndexOf("", *)           = -1
4948     * StringUtils.lastIndexOf("aabaabaa", 'a') = 7
4949     * StringUtils.lastIndexOf("aabaabaa", 'b') = 5
4950     * </pre>
4951     *
4952     * @param seq  the {@code CharSequence} to check, may be null
4953     * @param searchChar  the character to find
4954     * @return the last index of the search character,
4955     *  -1 if no match or {@code null} string input
4956     * @since 2.0
4957     * @since 3.0 Changed signature from lastIndexOf(String, int) to lastIndexOf(CharSequence, int)
4958     * @since 3.6 Updated {@link CharSequenceUtils} call to behave more like {@code String}
4959     */
4960    public static int lastIndexOf(final CharSequence seq, final int searchChar) {
4961        if (isEmpty(seq)) {
4962            return INDEX_NOT_FOUND;
4963        }
4964        return CharSequenceUtils.lastIndexOf(seq, searchChar, seq.length());
4965    }
4966
4967    /**
4968     * Returns the index within {@code seq} of the last occurrence of
4969     * the specified character, searching backward starting at the
4970     * specified index. For values of {@code searchChar} in the range
4971     * from 0 to 0xFFFF (inclusive), the index returned is the largest
4972     * value <i>k</i> such that:
4973     * <blockquote><pre>
4974     * (this.charAt(<i>k</i>) == searchChar) &amp;&amp; (<i>k</i> &lt;= startPos)
4975     * </pre></blockquote>
4976     * is true. For other values of {@code searchChar}, it is the
4977     * largest value <i>k</i> such that:
4978     * <blockquote><pre>
4979     * (this.codePointAt(<i>k</i>) == searchChar) &amp;&amp; (<i>k</i> &lt;= startPos)
4980     * </pre></blockquote>
4981     * is true. In either case, if no such character occurs in {@code seq}
4982     * at or before position {@code startPos}, then
4983     * {@code -1} is returned. Furthermore, a {@code null} or empty ("")
4984     * {@code CharSequence} will return {@code -1}. A start position greater
4985     * than the string length searches the whole string.
4986     * The search starts at the {@code startPos} and works backwards;
4987     * matches starting after the start position are ignored.
4988     *
4989     * <p>All indices are specified in {@code char} values
4990     * (Unicode code units).
4991     *
4992     * <pre>
4993     * StringUtils.lastIndexOf(null, *, *)          = -1
4994     * StringUtils.lastIndexOf("", *,  *)           = -1
4995     * StringUtils.lastIndexOf("aabaabaa", 'b', 8)  = 5
4996     * StringUtils.lastIndexOf("aabaabaa", 'b', 4)  = 2
4997     * StringUtils.lastIndexOf("aabaabaa", 'b', 0)  = -1
4998     * StringUtils.lastIndexOf("aabaabaa", 'b', 9)  = 5
4999     * StringUtils.lastIndexOf("aabaabaa", 'b', -1) = -1
5000     * StringUtils.lastIndexOf("aabaabaa", 'a', 0)  = 0
5001     * </pre>
5002     *
5003     * @param seq  the CharSequence to check, may be null
5004     * @param searchChar  the character to find
5005     * @param startPos  the start position
5006     * @return the last index of the search character (always &le; startPos),
5007     *  -1 if no match or {@code null} string input
5008     * @since 2.0
5009     * @since 3.0 Changed signature from lastIndexOf(String, int, int) to lastIndexOf(CharSequence, int, int)
5010     */
5011    public static int lastIndexOf(final CharSequence seq, final int searchChar, final int startPos) {
5012        if (isEmpty(seq)) {
5013            return INDEX_NOT_FOUND;
5014        }
5015        return CharSequenceUtils.lastIndexOf(seq, searchChar, startPos);
5016    }
5017
5018    /**
5019     * <p>Find the latest index of any substring in a set of potential substrings.</p>
5020     *
5021     * <p>A {@code null} CharSequence will return {@code -1}.
5022     * A {@code null} search array will return {@code -1}.
5023     * A {@code null} or zero length search array entry will be ignored,
5024     * but a search array containing "" will return the length of {@code str}
5025     * if {@code str} is not null. This method uses {@link String#indexOf(String)} if possible</p>
5026     *
5027     * <pre>
5028     * StringUtils.lastIndexOfAny(null, *)                    = -1
5029     * StringUtils.lastIndexOfAny(*, null)                    = -1
5030     * StringUtils.lastIndexOfAny(*, [])                      = -1
5031     * StringUtils.lastIndexOfAny(*, [null])                  = -1
5032     * StringUtils.lastIndexOfAny("zzabyycdxx", ["ab", "cd"]) = 6
5033     * StringUtils.lastIndexOfAny("zzabyycdxx", ["cd", "ab"]) = 6
5034     * StringUtils.lastIndexOfAny("zzabyycdxx", ["mn", "op"]) = -1
5035     * StringUtils.lastIndexOfAny("zzabyycdxx", ["mn", "op"]) = -1
5036     * StringUtils.lastIndexOfAny("zzabyycdxx", ["mn", ""])   = 10
5037     * </pre>
5038     *
5039     * @param str  the CharSequence to check, may be null
5040     * @param searchStrs  the CharSequences to search for, may be null
5041     * @return the last index of any of the CharSequences, -1 if no match
5042     * @since 3.0 Changed signature from lastIndexOfAny(String, String[]) to lastIndexOfAny(CharSequence, CharSequence)
5043     */
5044    public static int lastIndexOfAny(final CharSequence str, final CharSequence... searchStrs) {
5045        if (str == null || searchStrs == null) {
5046            return INDEX_NOT_FOUND;
5047        }
5048        int ret = INDEX_NOT_FOUND;
5049        int tmp = 0;
5050        for (final CharSequence search : searchStrs) {
5051            if (search == null) {
5052                continue;
5053            }
5054            tmp = CharSequenceUtils.lastIndexOf(str, search, str.length());
5055            if (tmp > ret) {
5056                ret = tmp;
5057            }
5058        }
5059        return ret;
5060    }
5061
5062    /**
5063     * <p>Case in-sensitive find of the last index within a CharSequence.</p>
5064     *
5065     * <p>A {@code null} CharSequence will return {@code -1}.
5066     * A negative start position returns {@code -1}.
5067     * An empty ("") search CharSequence always matches unless the start position is negative.
5068     * A start position greater than the string length searches the whole string.</p>
5069     *
5070     * <pre>
5071     * StringUtils.lastIndexOfIgnoreCase(null, *)          = -1
5072     * StringUtils.lastIndexOfIgnoreCase(*, null)          = -1
5073     * StringUtils.lastIndexOfIgnoreCase("aabaabaa", "A")  = 7
5074     * StringUtils.lastIndexOfIgnoreCase("aabaabaa", "B")  = 5
5075     * StringUtils.lastIndexOfIgnoreCase("aabaabaa", "AB") = 4
5076     * </pre>
5077     *
5078     * @param str  the CharSequence to check, may be null
5079     * @param searchStr  the CharSequence to find, may be null
5080     * @return the first index of the search CharSequence,
5081     *  -1 if no match or {@code null} string input
5082     * @since 2.5
5083     * @since 3.0 Changed signature from lastIndexOfIgnoreCase(String, String) to lastIndexOfIgnoreCase(CharSequence, CharSequence)
5084     */
5085    public static int lastIndexOfIgnoreCase(final CharSequence str, final CharSequence searchStr) {
5086        if (str == null || searchStr == null) {
5087            return INDEX_NOT_FOUND;
5088        }
5089        return lastIndexOfIgnoreCase(str, searchStr, str.length());
5090    }
5091
5092    /**
5093     * <p>Case in-sensitive find of the last index within a CharSequence
5094     * from the specified position.</p>
5095     *
5096     * <p>A {@code null} CharSequence will return {@code -1}.
5097     * A negative start position returns {@code -1}.
5098     * An empty ("") search CharSequence always matches unless the start position is negative.
5099     * A start position greater than the string length searches the whole string.
5100     * The search starts at the startPos and works backwards; matches starting after the start
5101     * position are ignored.
5102     * </p>
5103     *
5104     * <pre>
5105     * StringUtils.lastIndexOfIgnoreCase(null, *, *)          = -1
5106     * StringUtils.lastIndexOfIgnoreCase(*, null, *)          = -1
5107     * StringUtils.lastIndexOfIgnoreCase("aabaabaa", "A", 8)  = 7
5108     * StringUtils.lastIndexOfIgnoreCase("aabaabaa", "B", 8)  = 5
5109     * StringUtils.lastIndexOfIgnoreCase("aabaabaa", "AB", 8) = 4
5110     * StringUtils.lastIndexOfIgnoreCase("aabaabaa", "B", 9)  = 5
5111     * StringUtils.lastIndexOfIgnoreCase("aabaabaa", "B", -1) = -1
5112     * StringUtils.lastIndexOfIgnoreCase("aabaabaa", "A", 0)  = 0
5113     * StringUtils.lastIndexOfIgnoreCase("aabaabaa", "B", 0)  = -1
5114     * </pre>
5115     *
5116     * @param str  the CharSequence to check, may be null
5117     * @param searchStr  the CharSequence to find, may be null
5118     * @param startPos  the start position
5119     * @return the last index of the search CharSequence (always &le; startPos),
5120     *  -1 if no match or {@code null} input
5121     * @since 2.5
5122     * @since 3.0 Changed signature from lastIndexOfIgnoreCase(String, String, int) to lastIndexOfIgnoreCase(CharSequence, CharSequence, int)
5123     */
5124    public static int lastIndexOfIgnoreCase(final CharSequence str, final CharSequence searchStr, int startPos) {
5125        if (str == null || searchStr == null) {
5126            return INDEX_NOT_FOUND;
5127        }
5128        if (startPos > str.length() - searchStr.length()) {
5129            startPos = str.length() - searchStr.length();
5130        }
5131        if (startPos < 0) {
5132            return INDEX_NOT_FOUND;
5133        }
5134        if (searchStr.length() == 0) {
5135            return startPos;
5136        }
5137
5138        for (int i = startPos; i >= 0; i--) {
5139            if (CharSequenceUtils.regionMatches(str, true, i, searchStr, 0, searchStr.length())) {
5140                return i;
5141            }
5142        }
5143        return INDEX_NOT_FOUND;
5144    }
5145
5146    /**
5147     * <p>Finds the n-th last index within a String, handling {@code null}.
5148     * This method uses {@link String#lastIndexOf(String)}.</p>
5149     *
5150     * <p>A {@code null} String will return {@code -1}.</p>
5151     *
5152     * <pre>
5153     * StringUtils.lastOrdinalIndexOf(null, *, *)          = -1
5154     * StringUtils.lastOrdinalIndexOf(*, null, *)          = -1
5155     * StringUtils.lastOrdinalIndexOf("", "", *)           = 0
5156     * StringUtils.lastOrdinalIndexOf("aabaabaa", "a", 1)  = 7
5157     * StringUtils.lastOrdinalIndexOf("aabaabaa", "a", 2)  = 6
5158     * StringUtils.lastOrdinalIndexOf("aabaabaa", "b", 1)  = 5
5159     * StringUtils.lastOrdinalIndexOf("aabaabaa", "b", 2)  = 2
5160     * StringUtils.lastOrdinalIndexOf("aabaabaa", "ab", 1) = 4
5161     * StringUtils.lastOrdinalIndexOf("aabaabaa", "ab", 2) = 1
5162     * StringUtils.lastOrdinalIndexOf("aabaabaa", "", 1)   = 8
5163     * StringUtils.lastOrdinalIndexOf("aabaabaa", "", 2)   = 8
5164     * </pre>
5165     *
5166     * <p>Note that 'tail(CharSequence str, int n)' may be implemented as: </p>
5167     *
5168     * <pre>
5169     *   str.substring(lastOrdinalIndexOf(str, "\n", n) + 1)
5170     * </pre>
5171     *
5172     * @param str  the CharSequence to check, may be null
5173     * @param searchStr  the CharSequence to find, may be null
5174     * @param ordinal  the n-th last {@code searchStr} to find
5175     * @return the n-th last index of the search CharSequence,
5176     *  {@code -1} ({@code INDEX_NOT_FOUND}) if no match or {@code null} string input
5177     * @since 2.5
5178     * @since 3.0 Changed signature from lastOrdinalIndexOf(String, String, int) to lastOrdinalIndexOf(CharSequence, CharSequence, int)
5179     */
5180    public static int lastOrdinalIndexOf(final CharSequence str, final CharSequence searchStr, final int ordinal) {
5181        return ordinalIndexOf(str, searchStr, ordinal, true);
5182    }
5183
5184    // Left/Right/Mid
5185    //-----------------------------------------------------------------------
5186    /**
5187     * <p>Gets the leftmost {@code len} characters of a String.</p>
5188     *
5189     * <p>If {@code len} characters are not available, or the
5190     * String is {@code null}, the String will be returned without
5191     * an exception. An empty String is returned if len is negative.</p>
5192     *
5193     * <pre>
5194     * StringUtils.left(null, *)    = null
5195     * StringUtils.left(*, -ve)     = ""
5196     * StringUtils.left("", *)      = ""
5197     * StringUtils.left("abc", 0)   = ""
5198     * StringUtils.left("abc", 2)   = "ab"
5199     * StringUtils.left("abc", 4)   = "abc"
5200     * </pre>
5201     *
5202     * @param str  the String to get the leftmost characters from, may be null
5203     * @param len  the length of the required String
5204     * @return the leftmost characters, {@code null} if null String input
5205     */
5206    public static String left(final String str, final int len) {
5207        if (str == null) {
5208            return null;
5209        }
5210        if (len < 0) {
5211            return EMPTY;
5212        }
5213        if (str.length() <= len) {
5214            return str;
5215        }
5216        return str.substring(0, len);
5217    }
5218
5219    /**
5220     * <p>Left pad a String with spaces (' ').</p>
5221     *
5222     * <p>The String is padded to the size of {@code size}.</p>
5223     *
5224     * <pre>
5225     * StringUtils.leftPad(null, *)   = null
5226     * StringUtils.leftPad("", 3)     = "   "
5227     * StringUtils.leftPad("bat", 3)  = "bat"
5228     * StringUtils.leftPad("bat", 5)  = "  bat"
5229     * StringUtils.leftPad("bat", 1)  = "bat"
5230     * StringUtils.leftPad("bat", -1) = "bat"
5231     * </pre>
5232     *
5233     * @param str  the String to pad out, may be null
5234     * @param size  the size to pad to
5235     * @return left padded String or original String if no padding is necessary,
5236     *  {@code null} if null String input
5237     */
5238    public static String leftPad(final String str, final int size) {
5239        return leftPad(str, size, ' ');
5240    }
5241
5242    /**
5243     * <p>Left pad a String with a specified character.</p>
5244     *
5245     * <p>Pad to a size of {@code size}.</p>
5246     *
5247     * <pre>
5248     * StringUtils.leftPad(null, *, *)     = null
5249     * StringUtils.leftPad("", 3, 'z')     = "zzz"
5250     * StringUtils.leftPad("bat", 3, 'z')  = "bat"
5251     * StringUtils.leftPad("bat", 5, 'z')  = "zzbat"
5252     * StringUtils.leftPad("bat", 1, 'z')  = "bat"
5253     * StringUtils.leftPad("bat", -1, 'z') = "bat"
5254     * </pre>
5255     *
5256     * @param str  the String to pad out, may be null
5257     * @param size  the size to pad to
5258     * @param padChar  the character to pad with
5259     * @return left padded String or original String if no padding is necessary,
5260     *  {@code null} if null String input
5261     * @since 2.0
5262     */
5263    public static String leftPad(final String str, final int size, final char padChar) {
5264        if (str == null) {
5265            return null;
5266        }
5267        final int pads = size - str.length();
5268        if (pads <= 0) {
5269            return str; // returns original String when possible
5270        }
5271        if (pads > PAD_LIMIT) {
5272            return leftPad(str, size, String.valueOf(padChar));
5273        }
5274        return repeat(padChar, pads).concat(str);
5275    }
5276
5277    /**
5278     * <p>Left pad a String with a specified String.</p>
5279     *
5280     * <p>Pad to a size of {@code size}.</p>
5281     *
5282     * <pre>
5283     * StringUtils.leftPad(null, *, *)      = null
5284     * StringUtils.leftPad("", 3, "z")      = "zzz"
5285     * StringUtils.leftPad("bat", 3, "yz")  = "bat"
5286     * StringUtils.leftPad("bat", 5, "yz")  = "yzbat"
5287     * StringUtils.leftPad("bat", 8, "yz")  = "yzyzybat"
5288     * StringUtils.leftPad("bat", 1, "yz")  = "bat"
5289     * StringUtils.leftPad("bat", -1, "yz") = "bat"
5290     * StringUtils.leftPad("bat", 5, null)  = "  bat"
5291     * StringUtils.leftPad("bat", 5, "")    = "  bat"
5292     * </pre>
5293     *
5294     * @param str  the String to pad out, may be null
5295     * @param size  the size to pad to
5296     * @param padStr  the String to pad with, null or empty treated as single space
5297     * @return left padded String or original String if no padding is necessary,
5298     *  {@code null} if null String input
5299     */
5300    public static String leftPad(final String str, final int size, String padStr) {
5301        if (str == null) {
5302            return null;
5303        }
5304        if (isEmpty(padStr)) {
5305            padStr = SPACE;
5306        }
5307        final int padLen = padStr.length();
5308        final int strLen = str.length();
5309        final int pads = size - strLen;
5310        if (pads <= 0) {
5311            return str; // returns original String when possible
5312        }
5313        if (padLen == 1 && pads <= PAD_LIMIT) {
5314            return leftPad(str, size, padStr.charAt(0));
5315        }
5316
5317        if (pads == padLen) {
5318            return padStr.concat(str);
5319        } else if (pads < padLen) {
5320            return padStr.substring(0, pads).concat(str);
5321        } else {
5322            final char[] padding = new char[pads];
5323            final char[] padChars = padStr.toCharArray();
5324            for (int i = 0; i < pads; i++) {
5325                padding[i] = padChars[i % padLen];
5326            }
5327            return new String(padding).concat(str);
5328        }
5329    }
5330
5331    /**
5332     * Gets a CharSequence length or {@code 0} if the CharSequence is
5333     * {@code null}.
5334     *
5335     * @param cs
5336     *            a CharSequence or {@code null}
5337     * @return CharSequence length or {@code 0} if the CharSequence is
5338     *         {@code null}.
5339     * @since 2.4
5340     * @since 3.0 Changed signature from length(String) to length(CharSequence)
5341     */
5342    public static int length(final CharSequence cs) {
5343        return cs == null ? 0 : cs.length();
5344    }
5345
5346    /**
5347     * <p>Converts a String to lower case as per {@link String#toLowerCase()}.</p>
5348     *
5349     * <p>A {@code null} input String returns {@code null}.</p>
5350     *
5351     * <pre>
5352     * StringUtils.lowerCase(null)  = null
5353     * StringUtils.lowerCase("")    = ""
5354     * StringUtils.lowerCase("aBc") = "abc"
5355     * </pre>
5356     *
5357     * <p><strong>Note:</strong> As described in the documentation for {@link String#toLowerCase()},
5358     * the result of this method is affected by the current locale.
5359     * For platform-independent case transformations, the method {@link #lowerCase(String, Locale)}
5360     * should be used with a specific locale (e.g. {@link Locale#ENGLISH}).</p>
5361     *
5362     * @param str  the String to lower case, may be null
5363     * @return the lower cased String, {@code null} if null String input
5364     */
5365    public static String lowerCase(final String str) {
5366        if (str == null) {
5367            return null;
5368        }
5369        return str.toLowerCase();
5370    }
5371
5372    /**
5373     * <p>Converts a String to lower case as per {@link String#toLowerCase(Locale)}.</p>
5374     *
5375     * <p>A {@code null} input String returns {@code null}.</p>
5376     *
5377     * <pre>
5378     * StringUtils.lowerCase(null, Locale.ENGLISH)  = null
5379     * StringUtils.lowerCase("", Locale.ENGLISH)    = ""
5380     * StringUtils.lowerCase("aBc", Locale.ENGLISH) = "abc"
5381     * </pre>
5382     *
5383     * @param str  the String to lower case, may be null
5384     * @param locale  the locale that defines the case transformation rules, must not be null
5385     * @return the lower cased String, {@code null} if null String input
5386     * @since 2.5
5387     */
5388    public static String lowerCase(final String str, final Locale locale) {
5389        if (str == null) {
5390            return null;
5391        }
5392        return str.toLowerCase(locale);
5393    }
5394
5395    private static int[] matches(final CharSequence first, final CharSequence second) {
5396        CharSequence max, min;
5397        if (first.length() > second.length()) {
5398            max = first;
5399            min = second;
5400        } else {
5401            max = second;
5402            min = first;
5403        }
5404        final int range = Math.max(max.length() / 2 - 1, 0);
5405        final int[] matchIndexes = new int[min.length()];
5406        Arrays.fill(matchIndexes, -1);
5407        final boolean[] matchFlags = new boolean[max.length()];
5408        int matches = 0;
5409        for (int mi = 0; mi < min.length(); mi++) {
5410            final char c1 = min.charAt(mi);
5411            for (int xi = Math.max(mi - range, 0), xn = Math.min(mi + range + 1, max.length()); xi < xn; xi++) {
5412                if (!matchFlags[xi] && c1 == max.charAt(xi)) {
5413                    matchIndexes[mi] = xi;
5414                    matchFlags[xi] = true;
5415                    matches++;
5416                    break;
5417                }
5418            }
5419        }
5420        final char[] ms1 = new char[matches];
5421        final char[] ms2 = new char[matches];
5422        for (int i = 0, si = 0; i < min.length(); i++) {
5423            if (matchIndexes[i] != -1) {
5424                ms1[si] = min.charAt(i);
5425                si++;
5426            }
5427        }
5428        for (int i = 0, si = 0; i < max.length(); i++) {
5429            if (matchFlags[i]) {
5430                ms2[si] = max.charAt(i);
5431                si++;
5432            }
5433        }
5434        int transpositions = 0;
5435        for (int mi = 0; mi < ms1.length; mi++) {
5436            if (ms1[mi] != ms2[mi]) {
5437                transpositions++;
5438            }
5439        }
5440        int prefix = 0;
5441        for (int mi = 0; mi < min.length(); mi++) {
5442            if (first.charAt(mi) == second.charAt(mi)) {
5443                prefix++;
5444            } else {
5445                break;
5446            }
5447        }
5448        return new int[] { matches, transpositions / 2, prefix, max.length() };
5449    }
5450
5451    /**
5452     * <p>Gets {@code len} characters from the middle of a String.</p>
5453     *
5454     * <p>If {@code len} characters are not available, the remainder
5455     * of the String will be returned without an exception. If the
5456     * String is {@code null}, {@code null} will be returned.
5457     * An empty String is returned if len is negative or exceeds the
5458     * length of {@code str}.</p>
5459     *
5460     * <pre>
5461     * StringUtils.mid(null, *, *)    = null
5462     * StringUtils.mid(*, *, -ve)     = ""
5463     * StringUtils.mid("", 0, *)      = ""
5464     * StringUtils.mid("abc", 0, 2)   = "ab"
5465     * StringUtils.mid("abc", 0, 4)   = "abc"
5466     * StringUtils.mid("abc", 2, 4)   = "c"
5467     * StringUtils.mid("abc", 4, 2)   = ""
5468     * StringUtils.mid("abc", -2, 2)  = "ab"
5469     * </pre>
5470     *
5471     * @param str  the String to get the characters from, may be null
5472     * @param pos  the position to start from, negative treated as zero
5473     * @param len  the length of the required String
5474     * @return the middle characters, {@code null} if null String input
5475     */
5476    public static String mid(final String str, int pos, final int len) {
5477        if (str == null) {
5478            return null;
5479        }
5480        if (len < 0 || pos > str.length()) {
5481            return EMPTY;
5482        }
5483        if (pos < 0) {
5484            pos = 0;
5485        }
5486        if (str.length() <= pos + len) {
5487            return str.substring(pos);
5488        }
5489        return str.substring(pos, pos + len);
5490    }
5491
5492    private static StringBuilder newStringBuilder(final int noOfItems) {
5493        return new StringBuilder(noOfItems * 16);
5494    }
5495
5496    /**
5497     * <p>
5498     * Similar to <a
5499     * href="http://www.w3.org/TR/xpath/#function-normalize-space">http://www.w3.org/TR/xpath/#function-normalize
5500     * -space</a>
5501     * </p>
5502     * <p>
5503     * The function returns the argument string with whitespace normalized by using
5504     * {@code {@link #trim(String)}} to remove leading and trailing whitespace
5505     * and then replacing sequences of whitespace characters by a single space.
5506     * </p>
5507     * In XML Whitespace characters are the same as those allowed by the <a
5508     * href="http://www.w3.org/TR/REC-xml/#NT-S">S</a> production, which is S ::= (#x20 | #x9 | #xD | #xA)+
5509     * <p>
5510     * Java's regexp pattern \s defines whitespace as [ \t\n\x0B\f\r]
5511     *
5512     * <p>For reference:</p>
5513     * <ul>
5514     * <li>\x0B = vertical tab</li>
5515     * <li>\f = #xC = form feed</li>
5516     * <li>#x20 = space</li>
5517     * <li>#x9 = \t</li>
5518     * <li>#xA = \n</li>
5519     * <li>#xD = \r</li>
5520     * </ul>
5521     *
5522     * <p>
5523     * The difference is that Java's whitespace includes vertical tab and form feed, which this functional will also
5524     * normalize. Additionally {@code {@link #trim(String)}} removes control characters (char &lt;= 32) from both
5525     * ends of this String.
5526     * </p>
5527     *
5528     * @see Pattern
5529     * @see #trim(String)
5530     * @see <a
5531     *      href="http://www.w3.org/TR/xpath/#function-normalize-space">http://www.w3.org/TR/xpath/#function-normalize-space</a>
5532     * @param str the source String to normalize whitespaces from, may be null
5533     * @return the modified string with whitespace normalized, {@code null} if null String input
5534     *
5535     * @since 3.0
5536     */
5537    public static String normalizeSpace(final String str) {
5538        // LANG-1020: Improved performance significantly by normalizing manually instead of using regex
5539        // See https://github.com/librucha/commons-lang-normalizespaces-benchmark for performance test
5540        if (isEmpty(str)) {
5541            return str;
5542        }
5543        final int size = str.length();
5544        final char[] newChars = new char[size];
5545        int count = 0;
5546        int whitespacesCount = 0;
5547        boolean startWhitespaces = true;
5548        for (int i = 0; i < size; i++) {
5549            final char actualChar = str.charAt(i);
5550            final boolean isWhitespace = Character.isWhitespace(actualChar);
5551            if (isWhitespace) {
5552                if (whitespacesCount == 0 && !startWhitespaces) {
5553                    newChars[count++] = SPACE.charAt(0);
5554                }
5555                whitespacesCount++;
5556            } else {
5557                startWhitespaces = false;
5558                newChars[count++] = (actualChar == 160 ? 32 : actualChar);
5559                whitespacesCount = 0;
5560            }
5561        }
5562        if (startWhitespaces) {
5563            return EMPTY;
5564        }
5565        return new String(newChars, 0, count - (whitespacesCount > 0 ? 1 : 0)).trim();
5566    }
5567
5568    /**
5569     * <p>Finds the n-th index within a CharSequence, handling {@code null}.
5570     * This method uses {@link String#indexOf(String)} if possible.</p>
5571     * <p><b>Note:</b> The code starts looking for a match at the start of the target,
5572     * incrementing the starting index by one after each successful match
5573     * (unless {@code searchStr} is an empty string in which case the position
5574     * is never incremented and {@code 0} is returned immediately).
5575     * This means that matches may overlap.</p>
5576     * <p>A {@code null} CharSequence will return {@code -1}.</p>
5577     *
5578     * <pre>
5579     * StringUtils.ordinalIndexOf(null, *, *)          = -1
5580     * StringUtils.ordinalIndexOf(*, null, *)          = -1
5581     * StringUtils.ordinalIndexOf("", "", *)           = 0
5582     * StringUtils.ordinalIndexOf("aabaabaa", "a", 1)  = 0
5583     * StringUtils.ordinalIndexOf("aabaabaa", "a", 2)  = 1
5584     * StringUtils.ordinalIndexOf("aabaabaa", "b", 1)  = 2
5585     * StringUtils.ordinalIndexOf("aabaabaa", "b", 2)  = 5
5586     * StringUtils.ordinalIndexOf("aabaabaa", "ab", 1) = 1
5587     * StringUtils.ordinalIndexOf("aabaabaa", "ab", 2) = 4
5588     * StringUtils.ordinalIndexOf("aabaabaa", "", 1)   = 0
5589     * StringUtils.ordinalIndexOf("aabaabaa", "", 2)   = 0
5590     * </pre>
5591     *
5592     * <p>Matches may overlap:</p>
5593     * <pre>
5594     * StringUtils.ordinalIndexOf("ababab", "aba", 1)   = 0
5595     * StringUtils.ordinalIndexOf("ababab", "aba", 2)   = 2
5596     * StringUtils.ordinalIndexOf("ababab", "aba", 3)   = -1
5597     *
5598     * StringUtils.ordinalIndexOf("abababab", "abab", 1) = 0
5599     * StringUtils.ordinalIndexOf("abababab", "abab", 2) = 2
5600     * StringUtils.ordinalIndexOf("abababab", "abab", 3) = 4
5601     * StringUtils.ordinalIndexOf("abababab", "abab", 4) = -1
5602     * </pre>
5603     *
5604     * <p>Note that 'head(CharSequence str, int n)' may be implemented as: </p>
5605     *
5606     * <pre>
5607     *   str.substring(0, lastOrdinalIndexOf(str, "\n", n))
5608     * </pre>
5609     *
5610     * @param str  the CharSequence to check, may be null
5611     * @param searchStr  the CharSequence to find, may be null
5612     * @param ordinal  the n-th {@code searchStr} to find
5613     * @return the n-th index of the search CharSequence,
5614     *  {@code -1} ({@code INDEX_NOT_FOUND}) if no match or {@code null} string input
5615     * @since 2.1
5616     * @since 3.0 Changed signature from ordinalIndexOf(String, String, int) to ordinalIndexOf(CharSequence, CharSequence, int)
5617     */
5618    public static int ordinalIndexOf(final CharSequence str, final CharSequence searchStr, final int ordinal) {
5619        return ordinalIndexOf(str, searchStr, ordinal, false);
5620    }
5621
5622    /**
5623     * <p>Finds the n-th index within a String, handling {@code null}.
5624     * This method uses {@link String#indexOf(String)} if possible.</p>
5625     * <p>Note that matches may overlap<p>
5626     *
5627     * <p>A {@code null} CharSequence will return {@code -1}.</p>
5628     *
5629     * @param str  the CharSequence to check, may be null
5630     * @param searchStr  the CharSequence to find, may be null
5631     * @param ordinal  the n-th {@code searchStr} to find, overlapping matches are allowed.
5632     * @param lastIndex true if lastOrdinalIndexOf() otherwise false if ordinalIndexOf()
5633     * @return the n-th index of the search CharSequence,
5634     *  {@code -1} ({@code INDEX_NOT_FOUND}) if no match or {@code null} string input
5635     */
5636    // Shared code between ordinalIndexOf(String, String, int) and lastOrdinalIndexOf(String, String, int)
5637    private static int ordinalIndexOf(final CharSequence str, final CharSequence searchStr, final int ordinal, final boolean lastIndex) {
5638        if (str == null || searchStr == null || ordinal <= 0) {
5639            return INDEX_NOT_FOUND;
5640        }
5641        if (searchStr.length() == 0) {
5642            return lastIndex ? str.length() : 0;
5643        }
5644        int found = 0;
5645        // set the initial index beyond the end of the string
5646        // this is to allow for the initial index decrement/increment
5647        int index = lastIndex ? str.length() : INDEX_NOT_FOUND;
5648        do {
5649            if (lastIndex) {
5650                index = CharSequenceUtils.lastIndexOf(str, searchStr, index - 1); // step backwards thru string
5651            } else {
5652                index = CharSequenceUtils.indexOf(str, searchStr, index + 1); // step forwards through string
5653            }
5654            if (index < 0) {
5655                return index;
5656            }
5657            found++;
5658        } while (found < ordinal);
5659        return index;
5660    }
5661
5662    // Overlay
5663    //-----------------------------------------------------------------------
5664    /**
5665     * <p>Overlays part of a String with another String.</p>
5666     *
5667     * <p>A {@code null} string input returns {@code null}.
5668     * A negative index is treated as zero.
5669     * An index greater than the string length is treated as the string length.
5670     * The start index is always the smaller of the two indices.</p>
5671     *
5672     * <pre>
5673     * StringUtils.overlay(null, *, *, *)            = null
5674     * StringUtils.overlay("", "abc", 0, 0)          = "abc"
5675     * StringUtils.overlay("abcdef", null, 2, 4)     = "abef"
5676     * StringUtils.overlay("abcdef", "", 2, 4)       = "abef"
5677     * StringUtils.overlay("abcdef", "", 4, 2)       = "abef"
5678     * StringUtils.overlay("abcdef", "zzzz", 2, 4)   = "abzzzzef"
5679     * StringUtils.overlay("abcdef", "zzzz", 4, 2)   = "abzzzzef"
5680     * StringUtils.overlay("abcdef", "zzzz", -1, 4)  = "zzzzef"
5681     * StringUtils.overlay("abcdef", "zzzz", 2, 8)   = "abzzzz"
5682     * StringUtils.overlay("abcdef", "zzzz", -2, -3) = "zzzzabcdef"
5683     * StringUtils.overlay("abcdef", "zzzz", 8, 10)  = "abcdefzzzz"
5684     * </pre>
5685     *
5686     * @param str  the String to do overlaying in, may be null
5687     * @param overlay  the String to overlay, may be null
5688     * @param start  the position to start overlaying at
5689     * @param end  the position to stop overlaying before
5690     * @return overlayed String, {@code null} if null String input
5691     * @since 2.0
5692     */
5693    public static String overlay(final String str, String overlay, int start, int end) {
5694        if (str == null) {
5695            return null;
5696        }
5697        if (overlay == null) {
5698            overlay = EMPTY;
5699        }
5700        final int len = str.length();
5701        if (start < 0) {
5702            start = 0;
5703        }
5704        if (start > len) {
5705            start = len;
5706        }
5707        if (end < 0) {
5708            end = 0;
5709        }
5710        if (end > len) {
5711            end = len;
5712        }
5713        if (start > end) {
5714            final int temp = start;
5715            start = end;
5716            end = temp;
5717        }
5718        return str.substring(0, start) +
5719            overlay +
5720            str.substring(end);
5721    }
5722
5723    /**
5724     * Prepends the prefix to the start of the string if the string does not
5725     * already start with any of the prefixes.
5726     *
5727     * @param str The string.
5728     * @param prefix The prefix to prepend to the start of the string.
5729     * @param ignoreCase Indicates whether the compare should ignore case.
5730     * @param prefixes Additional prefixes that are valid (optional).
5731     *
5732     * @return A new String if prefix was prepended, the same string otherwise.
5733     */
5734    private static String prependIfMissing(final String str, final CharSequence prefix, final boolean ignoreCase, final CharSequence... prefixes) {
5735        if (str == null || isEmpty(prefix) || startsWith(str, prefix, ignoreCase)) {
5736            return str;
5737        }
5738        if (ArrayUtils.isNotEmpty(prefixes)) {
5739            for (final CharSequence p : prefixes) {
5740                if (startsWith(str, p, ignoreCase)) {
5741                    return str;
5742                }
5743            }
5744        }
5745        return prefix.toString() + str;
5746    }
5747
5748    /**
5749     * Prepends the prefix to the start of the string if the string does not
5750     * already start with any of the prefixes.
5751     *
5752     * <pre>
5753     * StringUtils.prependIfMissing(null, null) = null
5754     * StringUtils.prependIfMissing("abc", null) = "abc"
5755     * StringUtils.prependIfMissing("", "xyz") = "xyz"
5756     * StringUtils.prependIfMissing("abc", "xyz") = "xyzabc"
5757     * StringUtils.prependIfMissing("xyzabc", "xyz") = "xyzabc"
5758     * StringUtils.prependIfMissing("XYZabc", "xyz") = "xyzXYZabc"
5759     * </pre>
5760     * <p>With additional prefixes,</p>
5761     * <pre>
5762     * StringUtils.prependIfMissing(null, null, null) = null
5763     * StringUtils.prependIfMissing("abc", null, null) = "abc"
5764     * StringUtils.prependIfMissing("", "xyz", null) = "xyz"
5765     * StringUtils.prependIfMissing("abc", "xyz", new CharSequence[]{null}) = "xyzabc"
5766     * StringUtils.prependIfMissing("abc", "xyz", "") = "abc"
5767     * StringUtils.prependIfMissing("abc", "xyz", "mno") = "xyzabc"
5768     * StringUtils.prependIfMissing("xyzabc", "xyz", "mno") = "xyzabc"
5769     * StringUtils.prependIfMissing("mnoabc", "xyz", "mno") = "mnoabc"
5770     * StringUtils.prependIfMissing("XYZabc", "xyz", "mno") = "xyzXYZabc"
5771     * StringUtils.prependIfMissing("MNOabc", "xyz", "mno") = "xyzMNOabc"
5772     * </pre>
5773     *
5774     * @param str The string.
5775     * @param prefix The prefix to prepend to the start of the string.
5776     * @param prefixes Additional prefixes that are valid.
5777     *
5778     * @return A new String if prefix was prepended, the same string otherwise.
5779     *
5780     * @since 3.2
5781     */
5782    public static String prependIfMissing(final String str, final CharSequence prefix, final CharSequence... prefixes) {
5783        return prependIfMissing(str, prefix, false, prefixes);
5784    }
5785
5786    /**
5787     * Prepends the prefix to the start of the string if the string does not
5788     * already start, case insensitive, with any of the prefixes.
5789     *
5790     * <pre>
5791     * StringUtils.prependIfMissingIgnoreCase(null, null) = null
5792     * StringUtils.prependIfMissingIgnoreCase("abc", null) = "abc"
5793     * StringUtils.prependIfMissingIgnoreCase("", "xyz") = "xyz"
5794     * StringUtils.prependIfMissingIgnoreCase("abc", "xyz") = "xyzabc"
5795     * StringUtils.prependIfMissingIgnoreCase("xyzabc", "xyz") = "xyzabc"
5796     * StringUtils.prependIfMissingIgnoreCase("XYZabc", "xyz") = "XYZabc"
5797     * </pre>
5798     * <p>With additional prefixes,</p>
5799     * <pre>
5800     * StringUtils.prependIfMissingIgnoreCase(null, null, null) = null
5801     * StringUtils.prependIfMissingIgnoreCase("abc", null, null) = "abc"
5802     * StringUtils.prependIfMissingIgnoreCase("", "xyz", null) = "xyz"
5803     * StringUtils.prependIfMissingIgnoreCase("abc", "xyz", new CharSequence[]{null}) = "xyzabc"
5804     * StringUtils.prependIfMissingIgnoreCase("abc", "xyz", "") = "abc"
5805     * StringUtils.prependIfMissingIgnoreCase("abc", "xyz", "mno") = "xyzabc"
5806     * StringUtils.prependIfMissingIgnoreCase("xyzabc", "xyz", "mno") = "xyzabc"
5807     * StringUtils.prependIfMissingIgnoreCase("mnoabc", "xyz", "mno") = "mnoabc"
5808     * StringUtils.prependIfMissingIgnoreCase("XYZabc", "xyz", "mno") = "XYZabc"
5809     * StringUtils.prependIfMissingIgnoreCase("MNOabc", "xyz", "mno") = "MNOabc"
5810     * </pre>
5811     *
5812     * @param str The string.
5813     * @param prefix The prefix to prepend to the start of the string.
5814     * @param prefixes Additional prefixes that are valid (optional).
5815     *
5816     * @return A new String if prefix was prepended, the same string otherwise.
5817     *
5818     * @since 3.2
5819     */
5820    public static String prependIfMissingIgnoreCase(final String str, final CharSequence prefix, final CharSequence... prefixes) {
5821        return prependIfMissing(str, prefix, true, prefixes);
5822    }
5823
5824    /**
5825     * <p>Removes all occurrences of a character from within the source string.</p>
5826     *
5827     * <p>A {@code null} source string will return {@code null}.
5828     * An empty ("") source string will return the empty string.</p>
5829     *
5830     * <pre>
5831     * StringUtils.remove(null, *)       = null
5832     * StringUtils.remove("", *)         = ""
5833     * StringUtils.remove("queued", 'u') = "qeed"
5834     * StringUtils.remove("queued", 'z') = "queued"
5835     * </pre>
5836     *
5837     * @param str  the source String to search, may be null
5838     * @param remove  the char to search for and remove, may be null
5839     * @return the substring with the char removed if found,
5840     *  {@code null} if null String input
5841     * @since 2.1
5842     */
5843    public static String remove(final String str, final char remove) {
5844        if (isEmpty(str) || str.indexOf(remove) == INDEX_NOT_FOUND) {
5845            return str;
5846        }
5847        final char[] chars = str.toCharArray();
5848        int pos = 0;
5849        for (int i = 0; i < chars.length; i++) {
5850            if (chars[i] != remove) {
5851                chars[pos++] = chars[i];
5852            }
5853        }
5854        return new String(chars, 0, pos);
5855    }
5856
5857    /**
5858     * <p>Removes all occurrences of a substring from within the source string.</p>
5859     *
5860     * <p>A {@code null} source string will return {@code null}.
5861     * An empty ("") source string will return the empty string.
5862     * A {@code null} remove string will return the source string.
5863     * An empty ("") remove string will return the source string.</p>
5864     *
5865     * <pre>
5866     * StringUtils.remove(null, *)        = null
5867     * StringUtils.remove("", *)          = ""
5868     * StringUtils.remove(*, null)        = *
5869     * StringUtils.remove(*, "")          = *
5870     * StringUtils.remove("queued", "ue") = "qd"
5871     * StringUtils.remove("queued", "zz") = "queued"
5872     * </pre>
5873     *
5874     * @param str  the source String to search, may be null
5875     * @param remove  the String to search for and remove, may be null
5876     * @return the substring with the string removed if found,
5877     *  {@code null} if null String input
5878     * @since 2.1
5879     */
5880    public static String remove(final String str, final String remove) {
5881        if (isEmpty(str) || isEmpty(remove)) {
5882            return str;
5883        }
5884        return replace(str, remove, EMPTY, -1);
5885    }
5886
5887    /**
5888     * <p>Removes each substring of the text String that matches the given regular expression.</p>
5889     *
5890     * This method is a {@code null} safe equivalent to:
5891     * <ul>
5892     *  <li>{@code text.replaceAll(regex, StringUtils.EMPTY)}</li>
5893     *  <li>{@code Pattern.compile(regex).matcher(text).replaceAll(StringUtils.EMPTY)}</li>
5894     * </ul>
5895     *
5896     * <p>A {@code null} reference passed to this method is a no-op.</p>
5897     *
5898     * <p>Unlike in the {@link #removePattern(String, String)} method, the {@link Pattern#DOTALL} option
5899     * is NOT automatically added.
5900     * To use the DOTALL option prepend {@code "(?s)"} to the regex.
5901     * DOTALL is also known as single-line mode in Perl.</p>
5902     *
5903     * <pre>
5904     * StringUtils.removeAll(null, *)      = null
5905     * StringUtils.removeAll("any", (String) null)  = "any"
5906     * StringUtils.removeAll("any", "")    = "any"
5907     * StringUtils.removeAll("any", ".*")  = ""
5908     * StringUtils.removeAll("any", ".+")  = ""
5909     * StringUtils.removeAll("abc", ".?")  = ""
5910     * StringUtils.removeAll("A&lt;__&gt;\n&lt;__&gt;B", "&lt;.*&gt;")      = "A\nB"
5911     * StringUtils.removeAll("A&lt;__&gt;\n&lt;__&gt;B", "(?s)&lt;.*&gt;")  = "AB"
5912     * StringUtils.removeAll("ABCabc123abc", "[a-z]")     = "ABC123"
5913     * </pre>
5914     *
5915     * @param text  text to remove from, may be null
5916     * @param regex  the regular expression to which this string is to be matched
5917     * @return  the text with any removes processed,
5918     *              {@code null} if null String input
5919     *
5920     * @throws  java.util.regex.PatternSyntaxException
5921     *              if the regular expression's syntax is invalid
5922     *
5923     * @see #replaceAll(String, String, String)
5924     * @see #removePattern(String, String)
5925     * @see String#replaceAll(String, String)
5926     * @see java.util.regex.Pattern
5927     * @see java.util.regex.Pattern#DOTALL
5928     * @since 3.5
5929     *
5930     * @deprecated Moved to RegExUtils.
5931     */
5932    @Deprecated
5933    public static String removeAll(final String text, final String regex) {
5934        return RegExUtils.removeAll(text, regex);
5935    }
5936
5937    /**
5938     * <p>Removes a substring only if it is at the end of a source string,
5939     * otherwise returns the source string.</p>
5940     *
5941     * <p>A {@code null} source string will return {@code null}.
5942     * An empty ("") source string will return the empty string.
5943     * A {@code null} search string will return the source string.</p>
5944     *
5945     * <pre>
5946     * StringUtils.removeEnd(null, *)      = null
5947     * StringUtils.removeEnd("", *)        = ""
5948     * StringUtils.removeEnd(*, null)      = *
5949     * StringUtils.removeEnd("www.domain.com", ".com.")  = "www.domain.com"
5950     * StringUtils.removeEnd("www.domain.com", ".com")   = "www.domain"
5951     * StringUtils.removeEnd("www.domain.com", "domain") = "www.domain.com"
5952     * StringUtils.removeEnd("abc", "")    = "abc"
5953     * </pre>
5954     *
5955     * @param str  the source String to search, may be null
5956     * @param remove  the String to search for and remove, may be null
5957     * @return the substring with the string removed if found,
5958     *  {@code null} if null String input
5959     * @since 2.1
5960     */
5961    public static String removeEnd(final String str, final String remove) {
5962        if (isEmpty(str) || isEmpty(remove)) {
5963            return str;
5964        }
5965        if (str.endsWith(remove)) {
5966            return str.substring(0, str.length() - remove.length());
5967        }
5968        return str;
5969    }
5970
5971    /**
5972     * <p>Case insensitive removal of a substring if it is at the end of a source string,
5973     * otherwise returns the source string.</p>
5974     *
5975     * <p>A {@code null} source string will return {@code null}.
5976     * An empty ("") source string will return the empty string.
5977     * A {@code null} search string will return the source string.</p>
5978     *
5979     * <pre>
5980     * StringUtils.removeEndIgnoreCase(null, *)      = null
5981     * StringUtils.removeEndIgnoreCase("", *)        = ""
5982     * StringUtils.removeEndIgnoreCase(*, null)      = *
5983     * StringUtils.removeEndIgnoreCase("www.domain.com", ".com.")  = "www.domain.com"
5984     * StringUtils.removeEndIgnoreCase("www.domain.com", ".com")   = "www.domain"
5985     * StringUtils.removeEndIgnoreCase("www.domain.com", "domain") = "www.domain.com"
5986     * StringUtils.removeEndIgnoreCase("abc", "")    = "abc"
5987     * StringUtils.removeEndIgnoreCase("www.domain.com", ".COM") = "www.domain")
5988     * StringUtils.removeEndIgnoreCase("www.domain.COM", ".com") = "www.domain")
5989     * </pre>
5990     *
5991     * @param str  the source String to search, may be null
5992     * @param remove  the String to search for (case insensitive) and remove, may be null
5993     * @return the substring with the string removed if found,
5994     *  {@code null} if null String input
5995     * @since 2.4
5996     */
5997    public static String removeEndIgnoreCase(final String str, final String remove) {
5998        if (isEmpty(str) || isEmpty(remove)) {
5999            return str;
6000        }
6001        if (endsWithIgnoreCase(str, remove)) {
6002            return str.substring(0, str.length() - remove.length());
6003        }
6004        return str;
6005    }
6006
6007    /**
6008     * <p>Removes the first substring of the text string that matches the given regular expression.</p>
6009     *
6010     * This method is a {@code null} safe equivalent to:
6011     * <ul>
6012     *  <li>{@code text.replaceFirst(regex, StringUtils.EMPTY)}</li>
6013     *  <li>{@code Pattern.compile(regex).matcher(text).replaceFirst(StringUtils.EMPTY)}</li>
6014     * </ul>
6015     *
6016     * <p>A {@code null} reference passed to this method is a no-op.</p>
6017     *
6018     * <p>The {@link Pattern#DOTALL} option is NOT automatically added.
6019     * To use the DOTALL option prepend {@code "(?s)"} to the regex.
6020     * DOTALL is also known as single-line mode in Perl.</p>
6021     *
6022     * <pre>
6023     * StringUtils.removeFirst(null, *)      = null
6024     * StringUtils.removeFirst("any", (String) null)  = "any"
6025     * StringUtils.removeFirst("any", "")    = "any"
6026     * StringUtils.removeFirst("any", ".*")  = ""
6027     * StringUtils.removeFirst("any", ".+")  = ""
6028     * StringUtils.removeFirst("abc", ".?")  = "bc"
6029     * StringUtils.removeFirst("A&lt;__&gt;\n&lt;__&gt;B", "&lt;.*&gt;")      = "A\n&lt;__&gt;B"
6030     * StringUtils.removeFirst("A&lt;__&gt;\n&lt;__&gt;B", "(?s)&lt;.*&gt;")  = "AB"
6031     * StringUtils.removeFirst("ABCabc123", "[a-z]")          = "ABCbc123"
6032     * StringUtils.removeFirst("ABCabc123abc", "[a-z]+")      = "ABC123abc"
6033     * </pre>
6034     *
6035     * @param text  text to remove from, may be null
6036     * @param regex  the regular expression to which this string is to be matched
6037     * @return  the text with the first replacement processed,
6038     *              {@code null} if null String input
6039     *
6040     * @throws  java.util.regex.PatternSyntaxException
6041     *              if the regular expression's syntax is invalid
6042     *
6043     * @see #replaceFirst(String, String, String)
6044     * @see String#replaceFirst(String, String)
6045     * @see java.util.regex.Pattern
6046     * @see java.util.regex.Pattern#DOTALL
6047     * @since 3.5
6048     *
6049     * @deprecated Moved to RegExUtils.
6050     */
6051    @Deprecated
6052    public static String removeFirst(final String text, final String regex) {
6053        return replaceFirst(text, regex, EMPTY);
6054    }
6055
6056    /**
6057     * <p>
6058     * Case insensitive removal of all occurrences of a substring from within
6059     * the source string.
6060     * </p>
6061     *
6062     * <p>
6063     * A {@code null} source string will return {@code null}. An empty ("")
6064     * source string will return the empty string. A {@code null} remove string
6065     * will return the source string. An empty ("") remove string will return
6066     * the source string.
6067     * </p>
6068     *
6069     * <pre>
6070     * StringUtils.removeIgnoreCase(null, *)        = null
6071     * StringUtils.removeIgnoreCase("", *)          = ""
6072     * StringUtils.removeIgnoreCase(*, null)        = *
6073     * StringUtils.removeIgnoreCase(*, "")          = *
6074     * StringUtils.removeIgnoreCase("queued", "ue") = "qd"
6075     * StringUtils.removeIgnoreCase("queued", "zz") = "queued"
6076     * StringUtils.removeIgnoreCase("quEUed", "UE") = "qd"
6077     * StringUtils.removeIgnoreCase("queued", "zZ") = "queued"
6078     * </pre>
6079     *
6080     * @param str
6081     *            the source String to search, may be null
6082     * @param remove
6083     *            the String to search for (case insensitive) and remove, may be
6084     *            null
6085     * @return the substring with the string removed if found, {@code null} if
6086     *         null String input
6087     * @since 3.5
6088     */
6089    public static String removeIgnoreCase(final String str, final String remove) {
6090        if (isEmpty(str) || isEmpty(remove)) {
6091            return str;
6092        }
6093        return replaceIgnoreCase(str, remove, EMPTY, -1);
6094    }
6095
6096    /**
6097     * <p>Removes each substring of the source String that matches the given regular expression using the DOTALL option.
6098     * </p>
6099     *
6100     * This call is a {@code null} safe equivalent to:
6101     * <ul>
6102     * <li>{@code source.replaceAll(&quot;(?s)&quot; + regex, StringUtils.EMPTY)}</li>
6103     * <li>{@code Pattern.compile(regex, Pattern.DOTALL).matcher(source).replaceAll(StringUtils.EMPTY)}</li>
6104     * </ul>
6105     *
6106     * <p>A {@code null} reference passed to this method is a no-op.</p>
6107     *
6108     * <pre>
6109     * StringUtils.removePattern(null, *)       = null
6110     * StringUtils.removePattern("any", (String) null)   = "any"
6111     * StringUtils.removePattern("A&lt;__&gt;\n&lt;__&gt;B", "&lt;.*&gt;")  = "AB"
6112     * StringUtils.removePattern("ABCabc123", "[a-z]")    = "ABC123"
6113     * </pre>
6114     *
6115     * @param source
6116     *            the source string
6117     * @param regex
6118     *            the regular expression to which this string is to be matched
6119     * @return The resulting {@code String}
6120     * @see #replacePattern(String, String, String)
6121     * @see String#replaceAll(String, String)
6122     * @see Pattern#DOTALL
6123     * @since 3.2
6124     * @since 3.5 Changed {@code null} reference passed to this method is a no-op.
6125     *
6126     * @deprecated Moved to RegExUtils.
6127     */
6128    @Deprecated
6129    public static String removePattern(final String source, final String regex) {
6130        return RegExUtils.removePattern(source, regex);
6131    }
6132
6133    // Remove
6134    //-----------------------------------------------------------------------
6135    /**
6136     * <p>Removes a substring only if it is at the beginning of a source string,
6137     * otherwise returns the source string.</p>
6138     *
6139     * <p>A {@code null} source string will return {@code null}.
6140     * An empty ("") source string will return the empty string.
6141     * A {@code null} search string will return the source string.</p>
6142     *
6143     * <pre>
6144     * StringUtils.removeStart(null, *)      = null
6145     * StringUtils.removeStart("", *)        = ""
6146     * StringUtils.removeStart(*, null)      = *
6147     * StringUtils.removeStart("www.domain.com", "www.")   = "domain.com"
6148     * StringUtils.removeStart("domain.com", "www.")       = "domain.com"
6149     * StringUtils.removeStart("www.domain.com", "domain") = "www.domain.com"
6150     * StringUtils.removeStart("abc", "")    = "abc"
6151     * </pre>
6152     *
6153     * @param str  the source String to search, may be null
6154     * @param remove  the String to search for and remove, may be null
6155     * @return the substring with the string removed if found,
6156     *  {@code null} if null String input
6157     * @since 2.1
6158     */
6159    public static String removeStart(final String str, final String remove) {
6160        if (isEmpty(str) || isEmpty(remove)) {
6161            return str;
6162        }
6163        if (str.startsWith(remove)) {
6164            return str.substring(remove.length());
6165        }
6166        return str;
6167    }
6168
6169    /**
6170     * <p>Case insensitive removal of a substring if it is at the beginning of a source string,
6171     * otherwise returns the source string.</p>
6172     *
6173     * <p>A {@code null} source string will return {@code null}.
6174     * An empty ("") source string will return the empty string.
6175     * A {@code null} search string will return the source string.</p>
6176     *
6177     * <pre>
6178     * StringUtils.removeStartIgnoreCase(null, *)      = null
6179     * StringUtils.removeStartIgnoreCase("", *)        = ""
6180     * StringUtils.removeStartIgnoreCase(*, null)      = *
6181     * StringUtils.removeStartIgnoreCase("www.domain.com", "www.")   = "domain.com"
6182     * StringUtils.removeStartIgnoreCase("www.domain.com", "WWW.")   = "domain.com"
6183     * StringUtils.removeStartIgnoreCase("domain.com", "www.")       = "domain.com"
6184     * StringUtils.removeStartIgnoreCase("www.domain.com", "domain") = "www.domain.com"
6185     * StringUtils.removeStartIgnoreCase("abc", "")    = "abc"
6186     * </pre>
6187     *
6188     * @param str  the source String to search, may be null
6189     * @param remove  the String to search for (case insensitive) and remove, may be null
6190     * @return the substring with the string removed if found,
6191     *  {@code null} if null String input
6192     * @since 2.4
6193     */
6194    public static String removeStartIgnoreCase(final String str, final String remove) {
6195        if (isEmpty(str) || isEmpty(remove)) {
6196            return str;
6197        }
6198        if (startsWithIgnoreCase(str, remove)) {
6199            return str.substring(remove.length());
6200        }
6201        return str;
6202    }
6203
6204    /**
6205     * <p>Returns padding using the specified delimiter repeated
6206     * to a given length.</p>
6207     *
6208     * <pre>
6209     * StringUtils.repeat('e', 0)  = ""
6210     * StringUtils.repeat('e', 3)  = "eee"
6211     * StringUtils.repeat('e', -2) = ""
6212     * </pre>
6213     *
6214     * <p>Note: this method does not support padding with
6215     * <a href="http://www.unicode.org/glossary/#supplementary_character">Unicode Supplementary Characters</a>
6216     * as they require a pair of {@code char}s to be represented.
6217     * If you are needing to support full I18N of your applications
6218     * consider using {@link #repeat(String, int)} instead.
6219     * </p>
6220     *
6221     * @param ch  character to repeat
6222     * @param repeat  number of times to repeat char, negative treated as zero
6223     * @return String with repeated character
6224     * @see #repeat(String, int)
6225     */
6226    public static String repeat(final char ch, final int repeat) {
6227        if (repeat <= 0) {
6228            return EMPTY;
6229        }
6230        final char[] buf = new char[repeat];
6231        for (int i = repeat - 1; i >= 0; i--) {
6232            buf[i] = ch;
6233        }
6234        return new String(buf);
6235    }
6236
6237    // Padding
6238    //-----------------------------------------------------------------------
6239    /**
6240     * <p>Repeat a String {@code repeat} times to form a
6241     * new String.</p>
6242     *
6243     * <pre>
6244     * StringUtils.repeat(null, 2) = null
6245     * StringUtils.repeat("", 0)   = ""
6246     * StringUtils.repeat("", 2)   = ""
6247     * StringUtils.repeat("a", 3)  = "aaa"
6248     * StringUtils.repeat("ab", 2) = "abab"
6249     * StringUtils.repeat("a", -2) = ""
6250     * </pre>
6251     *
6252     * @param str  the String to repeat, may be null
6253     * @param repeat  number of times to repeat str, negative treated as zero
6254     * @return a new String consisting of the original String repeated,
6255     *  {@code null} if null String input
6256     */
6257    public static String repeat(final String str, final int repeat) {
6258        // Performance tuned for 2.0 (JDK1.4)
6259
6260        if (str == null) {
6261            return null;
6262        }
6263        if (repeat <= 0) {
6264            return EMPTY;
6265        }
6266        final int inputLength = str.length();
6267        if (repeat == 1 || inputLength == 0) {
6268            return str;
6269        }
6270        if (inputLength == 1 && repeat <= PAD_LIMIT) {
6271            return repeat(str.charAt(0), repeat);
6272        }
6273
6274        final int outputLength = inputLength * repeat;
6275        switch (inputLength) {
6276            case 1 :
6277                return repeat(str.charAt(0), repeat);
6278            case 2 :
6279                final char ch0 = str.charAt(0);
6280                final char ch1 = str.charAt(1);
6281                final char[] output2 = new char[outputLength];
6282                for (int i = repeat * 2 - 2; i >= 0; i--, i--) {
6283                    output2[i] = ch0;
6284                    output2[i + 1] = ch1;
6285                }
6286                return new String(output2);
6287            default :
6288                final StringBuilder buf = new StringBuilder(outputLength);
6289                for (int i = 0; i < repeat; i++) {
6290                    buf.append(str);
6291                }
6292                return buf.toString();
6293        }
6294    }
6295
6296    // Conversion
6297    //-----------------------------------------------------------------------
6298
6299    /**
6300     * <p>Repeat a String {@code repeat} times to form a
6301     * new String, with a String separator injected each time. </p>
6302     *
6303     * <pre>
6304     * StringUtils.repeat(null, null, 2) = null
6305     * StringUtils.repeat(null, "x", 2)  = null
6306     * StringUtils.repeat("", null, 0)   = ""
6307     * StringUtils.repeat("", "", 2)     = ""
6308     * StringUtils.repeat("", "x", 3)    = "xxx"
6309     * StringUtils.repeat("?", ", ", 3)  = "?, ?, ?"
6310     * </pre>
6311     *
6312     * @param str        the String to repeat, may be null
6313     * @param separator  the String to inject, may be null
6314     * @param repeat     number of times to repeat str, negative treated as zero
6315     * @return a new String consisting of the original String repeated,
6316     *  {@code null} if null String input
6317     * @since 2.5
6318     */
6319    public static String repeat(final String str, final String separator, final int repeat) {
6320        if (str == null || separator == null) {
6321            return repeat(str, repeat);
6322        }
6323        // given that repeat(String, int) is quite optimized, better to rely on it than try and splice this into it
6324        final String result = repeat(str + separator, repeat);
6325        return removeEnd(result, separator);
6326    }
6327
6328    /**
6329     * <p>Replaces all occurrences of a String within another String.</p>
6330     *
6331     * <p>A {@code null} reference passed to this method is a no-op.</p>
6332     *
6333     * <pre>
6334     * StringUtils.replace(null, *, *)        = null
6335     * StringUtils.replace("", *, *)          = ""
6336     * StringUtils.replace("any", null, *)    = "any"
6337     * StringUtils.replace("any", *, null)    = "any"
6338     * StringUtils.replace("any", "", *)      = "any"
6339     * StringUtils.replace("aba", "a", null)  = "aba"
6340     * StringUtils.replace("aba", "a", "")    = "b"
6341     * StringUtils.replace("aba", "a", "z")   = "zbz"
6342     * </pre>
6343     *
6344     * @see #replace(String text, String searchString, String replacement, int max)
6345     * @param text  text to search and replace in, may be null
6346     * @param searchString  the String to search for, may be null
6347     * @param replacement  the String to replace it with, may be null
6348     * @return the text with any replacements processed,
6349     *  {@code null} if null String input
6350     */
6351    public static String replace(final String text, final String searchString, final String replacement) {
6352        return replace(text, searchString, replacement, -1);
6353    }
6354
6355    /**
6356     * <p>Replaces a String with another String inside a larger String,
6357     * for the first {@code max} values of the search String.</p>
6358     *
6359     * <p>A {@code null} reference passed to this method is a no-op.</p>
6360     *
6361     * <pre>
6362     * StringUtils.replace(null, *, *, *)         = null
6363     * StringUtils.replace("", *, *, *)           = ""
6364     * StringUtils.replace("any", null, *, *)     = "any"
6365     * StringUtils.replace("any", *, null, *)     = "any"
6366     * StringUtils.replace("any", "", *, *)       = "any"
6367     * StringUtils.replace("any", *, *, 0)        = "any"
6368     * StringUtils.replace("abaa", "a", null, -1) = "abaa"
6369     * StringUtils.replace("abaa", "a", "", -1)   = "b"
6370     * StringUtils.replace("abaa", "a", "z", 0)   = "abaa"
6371     * StringUtils.replace("abaa", "a", "z", 1)   = "zbaa"
6372     * StringUtils.replace("abaa", "a", "z", 2)   = "zbza"
6373     * StringUtils.replace("abaa", "a", "z", -1)  = "zbzz"
6374     * </pre>
6375     *
6376     * @param text  text to search and replace in, may be null
6377     * @param searchString  the String to search for, may be null
6378     * @param replacement  the String to replace it with, may be null
6379     * @param max  maximum number of values to replace, or {@code -1} if no maximum
6380     * @return the text with any replacements processed,
6381     *  {@code null} if null String input
6382     */
6383    public static String replace(final String text, final String searchString, final String replacement, final int max) {
6384        return replace(text, searchString, replacement, max, false);
6385    }
6386
6387    /**
6388     * <p>Replaces a String with another String inside a larger String,
6389     * for the first {@code max} values of the search String,
6390     * case sensitively/insensitively based on {@code ignoreCase} value.</p>
6391     *
6392     * <p>A {@code null} reference passed to this method is a no-op.</p>
6393     *
6394     * <pre>
6395     * StringUtils.replace(null, *, *, *, false)         = null
6396     * StringUtils.replace("", *, *, *, false)           = ""
6397     * StringUtils.replace("any", null, *, *, false)     = "any"
6398     * StringUtils.replace("any", *, null, *, false)     = "any"
6399     * StringUtils.replace("any", "", *, *, false)       = "any"
6400     * StringUtils.replace("any", *, *, 0, false)        = "any"
6401     * StringUtils.replace("abaa", "a", null, -1, false) = "abaa"
6402     * StringUtils.replace("abaa", "a", "", -1, false)   = "b"
6403     * StringUtils.replace("abaa", "a", "z", 0, false)   = "abaa"
6404     * StringUtils.replace("abaa", "A", "z", 1, false)   = "abaa"
6405     * StringUtils.replace("abaa", "A", "z", 1, true)   = "zbaa"
6406     * StringUtils.replace("abAa", "a", "z", 2, true)   = "zbza"
6407     * StringUtils.replace("abAa", "a", "z", -1, true)  = "zbzz"
6408     * </pre>
6409     *
6410     * @param text  text to search and replace in, may be null
6411     * @param searchString  the String to search for (case insensitive), may be null
6412     * @param replacement  the String to replace it with, may be null
6413     * @param max  maximum number of values to replace, or {@code -1} if no maximum
6414     * @param ignoreCase if true replace is case insensitive, otherwise case sensitive
6415     * @return the text with any replacements processed,
6416     *  {@code null} if null String input
6417     */
6418     private static String replace(final String text, String searchString, final String replacement, int max, final boolean ignoreCase) {
6419         if (isEmpty(text) || isEmpty(searchString) || replacement == null || max == 0) {
6420             return text;
6421         }
6422         if (ignoreCase) {
6423             searchString = searchString.toLowerCase();
6424         }
6425         int start = 0;
6426         int end = ignoreCase ? indexOfIgnoreCase(text, searchString, start) : indexOf(text, searchString, start);
6427         if (end == INDEX_NOT_FOUND) {
6428             return text;
6429         }
6430         final int replLength = searchString.length();
6431         int increase = Math.max(replacement.length() - replLength, 0);
6432         increase *= max < 0 ? 16 : Math.min(max, 64);
6433         final StringBuilder buf = new StringBuilder(text.length() + increase);
6434         while (end != INDEX_NOT_FOUND) {
6435             buf.append(text, start, end).append(replacement);
6436             start = end + replLength;
6437             if (--max == 0) {
6438                 break;
6439             }
6440             end = ignoreCase ? indexOfIgnoreCase(text, searchString, start) : indexOf(text, searchString, start);
6441         }
6442         buf.append(text, start, text.length());
6443         return buf.toString();
6444     }
6445
6446    /**
6447     * <p>Replaces each substring of the text String that matches the given regular expression
6448     * with the given replacement.</p>
6449     *
6450     * This method is a {@code null} safe equivalent to:
6451     * <ul>
6452     *  <li>{@code text.replaceAll(regex, replacement)}</li>
6453     *  <li>{@code Pattern.compile(regex).matcher(text).replaceAll(replacement)}</li>
6454     * </ul>
6455     *
6456     * <p>A {@code null} reference passed to this method is a no-op.</p>
6457     *
6458     * <p>Unlike in the {@link #replacePattern(String, String, String)} method, the {@link Pattern#DOTALL} option
6459     * is NOT automatically added.
6460     * To use the DOTALL option prepend {@code "(?s)"} to the regex.
6461     * DOTALL is also known as single-line mode in Perl.</p>
6462     *
6463     * <pre>
6464     * StringUtils.replaceAll(null, *, *)       = null
6465     * StringUtils.replaceAll("any", (String) null, *)   = "any"
6466     * StringUtils.replaceAll("any", *, null)   = "any"
6467     * StringUtils.replaceAll("", "", "zzz")    = "zzz"
6468     * StringUtils.replaceAll("", ".*", "zzz")  = "zzz"
6469     * StringUtils.replaceAll("", ".+", "zzz")  = ""
6470     * StringUtils.replaceAll("abc", "", "ZZ")  = "ZZaZZbZZcZZ"
6471     * StringUtils.replaceAll("&lt;__&gt;\n&lt;__&gt;", "&lt;.*&gt;", "z")      = "z\nz"
6472     * StringUtils.replaceAll("&lt;__&gt;\n&lt;__&gt;", "(?s)&lt;.*&gt;", "z")  = "z"
6473     * StringUtils.replaceAll("ABCabc123", "[a-z]", "_")       = "ABC___123"
6474     * StringUtils.replaceAll("ABCabc123", "[^A-Z0-9]+", "_")  = "ABC_123"
6475     * StringUtils.replaceAll("ABCabc123", "[^A-Z0-9]+", "")   = "ABC123"
6476     * StringUtils.replaceAll("Lorem ipsum  dolor   sit", "( +)([a-z]+)", "_$2")  = "Lorem_ipsum_dolor_sit"
6477     * </pre>
6478     *
6479     * @param text  text to search and replace in, may be null
6480     * @param regex  the regular expression to which this string is to be matched
6481     * @param replacement  the string to be substituted for each match
6482     * @return  the text with any replacements processed,
6483     *              {@code null} if null String input
6484     *
6485     * @throws  java.util.regex.PatternSyntaxException
6486     *              if the regular expression's syntax is invalid
6487     *
6488     * @see #replacePattern(String, String, String)
6489     * @see String#replaceAll(String, String)
6490     * @see java.util.regex.Pattern
6491     * @see java.util.regex.Pattern#DOTALL
6492     * @since 3.5
6493     *
6494     * @deprecated Moved to RegExUtils.
6495     */
6496    @Deprecated
6497    public static String replaceAll(final String text, final String regex, final String replacement) {
6498        return RegExUtils.replaceAll(text, regex, replacement);
6499    }
6500
6501    // Replace, character based
6502    //-----------------------------------------------------------------------
6503    /**
6504     * <p>Replaces all occurrences of a character in a String with another.
6505     * This is a null-safe version of {@link String#replace(char, char)}.</p>
6506     *
6507     * <p>A {@code null} string input returns {@code null}.
6508     * An empty ("") string input returns an empty string.</p>
6509     *
6510     * <pre>
6511     * StringUtils.replaceChars(null, *, *)        = null
6512     * StringUtils.replaceChars("", *, *)          = ""
6513     * StringUtils.replaceChars("abcba", 'b', 'y') = "aycya"
6514     * StringUtils.replaceChars("abcba", 'z', 'y') = "abcba"
6515     * </pre>
6516     *
6517     * @param str  String to replace characters in, may be null
6518     * @param searchChar  the character to search for, may be null
6519     * @param replaceChar  the character to replace, may be null
6520     * @return modified String, {@code null} if null string input
6521     * @since 2.0
6522     */
6523    public static String replaceChars(final String str, final char searchChar, final char replaceChar) {
6524        if (str == null) {
6525            return null;
6526        }
6527        return str.replace(searchChar, replaceChar);
6528    }
6529
6530    /**
6531     * <p>Replaces multiple characters in a String in one go.
6532     * This method can also be used to delete characters.</p>
6533     *
6534     * <p>For example:<br>
6535     * {@code replaceChars(&quot;hello&quot;, &quot;ho&quot;, &quot;jy&quot;) = jelly}.</p>
6536     *
6537     * <p>A {@code null} string input returns {@code null}.
6538     * An empty ("") string input returns an empty string.
6539     * A null or empty set of search characters returns the input string.</p>
6540     *
6541     * <p>The length of the search characters should normally equal the length
6542     * of the replace characters.
6543     * If the search characters is longer, then the extra search characters
6544     * are deleted.
6545     * If the search characters is shorter, then the extra replace characters
6546     * are ignored.</p>
6547     *
6548     * <pre>
6549     * StringUtils.replaceChars(null, *, *)           = null
6550     * StringUtils.replaceChars("", *, *)             = ""
6551     * StringUtils.replaceChars("abc", null, *)       = "abc"
6552     * StringUtils.replaceChars("abc", "", *)         = "abc"
6553     * StringUtils.replaceChars("abc", "b", null)     = "ac"
6554     * StringUtils.replaceChars("abc", "b", "")       = "ac"
6555     * StringUtils.replaceChars("abcba", "bc", "yz")  = "ayzya"
6556     * StringUtils.replaceChars("abcba", "bc", "y")   = "ayya"
6557     * StringUtils.replaceChars("abcba", "bc", "yzx") = "ayzya"
6558     * </pre>
6559     *
6560     * @param str  String to replace characters in, may be null
6561     * @param searchChars  a set of characters to search for, may be null
6562     * @param replaceChars  a set of characters to replace, may be null
6563     * @return modified String, {@code null} if null string input
6564     * @since 2.0
6565     */
6566    public static String replaceChars(final String str, final String searchChars, String replaceChars) {
6567        if (isEmpty(str) || isEmpty(searchChars)) {
6568            return str;
6569        }
6570        if (replaceChars == null) {
6571            replaceChars = EMPTY;
6572        }
6573        boolean modified = false;
6574        final int replaceCharsLength = replaceChars.length();
6575        final int strLength = str.length();
6576        final StringBuilder buf = new StringBuilder(strLength);
6577        for (int i = 0; i < strLength; i++) {
6578            final char ch = str.charAt(i);
6579            final int index = searchChars.indexOf(ch);
6580            if (index >= 0) {
6581                modified = true;
6582                if (index < replaceCharsLength) {
6583                    buf.append(replaceChars.charAt(index));
6584                }
6585            } else {
6586                buf.append(ch);
6587            }
6588        }
6589        if (modified) {
6590            return buf.toString();
6591        }
6592        return str;
6593    }
6594
6595    /**
6596     * <p>
6597     * Replaces all occurrences of Strings within another String.
6598     * </p>
6599     *
6600     * <p>
6601     * A {@code null} reference passed to this method is a no-op, or if
6602     * any "search string" or "string to replace" is null, that replace will be
6603     * ignored. This will not repeat. For repeating replaces, call the
6604     * overloaded method.
6605     * </p>
6606     *
6607     * <pre>
6608     *  StringUtils.replaceEach(null, *, *)        = null
6609     *  StringUtils.replaceEach("", *, *)          = ""
6610     *  StringUtils.replaceEach("aba", null, null) = "aba"
6611     *  StringUtils.replaceEach("aba", new String[0], null) = "aba"
6612     *  StringUtils.replaceEach("aba", null, new String[0]) = "aba"
6613     *  StringUtils.replaceEach("aba", new String[]{"a"}, null)  = "aba"
6614     *  StringUtils.replaceEach("aba", new String[]{"a"}, new String[]{""})  = "b"
6615     *  StringUtils.replaceEach("aba", new String[]{null}, new String[]{"a"})  = "aba"
6616     *  StringUtils.replaceEach("abcde", new String[]{"ab", "d"}, new String[]{"w", "t"})  = "wcte"
6617     *  (example of how it does not repeat)
6618     *  StringUtils.replaceEach("abcde", new String[]{"ab", "d"}, new String[]{"d", "t"})  = "dcte"
6619     * </pre>
6620     *
6621     * @param text
6622     *            text to search and replace in, no-op if null
6623     * @param searchList
6624     *            the Strings to search for, no-op if null
6625     * @param replacementList
6626     *            the Strings to replace them with, no-op if null
6627     * @return the text with any replacements processed, {@code null} if
6628     *         null String input
6629     * @throws IllegalArgumentException
6630     *             if the lengths of the arrays are not the same (null is ok,
6631     *             and/or size 0)
6632     * @since 2.4
6633     */
6634    public static String replaceEach(final String text, final String[] searchList, final String[] replacementList) {
6635        return replaceEach(text, searchList, replacementList, false, 0);
6636    }
6637
6638    /**
6639     * <p>
6640     * Replace all occurrences of Strings within another String.
6641     * This is a private recursive helper method for {@link #replaceEachRepeatedly(String, String[], String[])} and
6642     * {@link #replaceEach(String, String[], String[])}
6643     * </p>
6644     *
6645     * <p>
6646     * A {@code null} reference passed to this method is a no-op, or if
6647     * any "search string" or "string to replace" is null, that replace will be
6648     * ignored.
6649     * </p>
6650     *
6651     * <pre>
6652     *  StringUtils.replaceEach(null, *, *, *, *) = null
6653     *  StringUtils.replaceEach("", *, *, *, *) = ""
6654     *  StringUtils.replaceEach("aba", null, null, *, *) = "aba"
6655     *  StringUtils.replaceEach("aba", new String[0], null, *, *) = "aba"
6656     *  StringUtils.replaceEach("aba", null, new String[0], *, *) = "aba"
6657     *  StringUtils.replaceEach("aba", new String[]{"a"}, null, *, *) = "aba"
6658     *  StringUtils.replaceEach("aba", new String[]{"a"}, new String[]{""}, *, >=0) = "b"
6659     *  StringUtils.replaceEach("aba", new String[]{null}, new String[]{"a"}, *, >=0) = "aba"
6660     *  StringUtils.replaceEach("abcde", new String[]{"ab", "d"}, new String[]{"w", "t"}, *, >=0) = "wcte"
6661     *  (example of how it repeats)
6662     *  StringUtils.replaceEach("abcde", new String[]{"ab", "d"}, new String[]{"d", "t"}, false, >=0) = "dcte"
6663     *  StringUtils.replaceEach("abcde", new String[]{"ab", "d"}, new String[]{"d", "t"}, true, >=2) = "tcte"
6664     *  StringUtils.replaceEach("abcde", new String[]{"ab", "d"}, new String[]{"d", "ab"}, *, *) = IllegalStateException
6665     * </pre>
6666     *
6667     * @param text
6668     *            text to search and replace in, no-op if null
6669     * @param searchList
6670     *            the Strings to search for, no-op if null
6671     * @param replacementList
6672     *            the Strings to replace them with, no-op if null
6673     * @param repeat if true, then replace repeatedly
6674     *       until there are no more possible replacements or timeToLive < 0
6675     * @param timeToLive
6676     *            if less than 0 then there is a circular reference and endless
6677     *            loop
6678     * @return the text with any replacements processed, {@code null} if
6679     *         null String input
6680     * @throws IllegalStateException
6681     *             if the search is repeating and there is an endless loop due
6682     *             to outputs of one being inputs to another
6683     * @throws IllegalArgumentException
6684     *             if the lengths of the arrays are not the same (null is ok,
6685     *             and/or size 0)
6686     * @since 2.4
6687     */
6688    private static String replaceEach(
6689            final String text, final String[] searchList, final String[] replacementList, final boolean repeat, final int timeToLive) {
6690
6691        // mchyzer Performance note: This creates very few new objects (one major goal)
6692        // let me know if there are performance requests, we can create a harness to measure
6693
6694        // if recursing, this shouldn't be less than 0
6695        if (timeToLive < 0) {
6696            final Set<String> searchSet = new HashSet<>(Arrays.asList(searchList));
6697            final Set<String> replacementSet = new HashSet<>(Arrays.asList(replacementList));
6698            searchSet.retainAll(replacementSet);
6699            if (searchSet.size() > 0) {
6700                throw new IllegalStateException("Aborting to protect against StackOverflowError - " +
6701                        "output of one loop is the input of another");
6702            }
6703        }
6704
6705        if (isEmpty(text) || ArrayUtils.isEmpty(searchList) || ArrayUtils.isEmpty(replacementList) || (ArrayUtils.isNotEmpty(searchList) && timeToLive == -1)) {
6706            return text;
6707        }
6708
6709        final int searchLength = searchList.length;
6710        final int replacementLength = replacementList.length;
6711
6712        // make sure lengths are ok, these need to be equal
6713        if (searchLength != replacementLength) {
6714            throw new IllegalArgumentException("Search and Replace array lengths don't match: "
6715                + searchLength
6716                + " vs "
6717                + replacementLength);
6718        }
6719
6720        // keep track of which still have matches
6721        final boolean[] noMoreMatchesForReplIndex = new boolean[searchLength];
6722
6723        // index on index that the match was found
6724        int textIndex = -1;
6725        int replaceIndex = -1;
6726        int tempIndex = -1;
6727
6728        // index of replace array that will replace the search string found
6729        // NOTE: logic duplicated below START
6730        for (int i = 0; i < searchLength; i++) {
6731            if (noMoreMatchesForReplIndex[i] || isEmpty(searchList[i]) || replacementList[i] == null) {
6732                continue;
6733            }
6734            tempIndex = text.indexOf(searchList[i]);
6735
6736            // see if we need to keep searching for this
6737            if (tempIndex == -1) {
6738                noMoreMatchesForReplIndex[i] = true;
6739            } else {
6740                if (textIndex == -1 || tempIndex < textIndex) {
6741                    textIndex = tempIndex;
6742                    replaceIndex = i;
6743                }
6744            }
6745        }
6746        // NOTE: logic mostly below END
6747
6748        // no search strings found, we are done
6749        if (textIndex == -1) {
6750            return text;
6751        }
6752
6753        int start = 0;
6754
6755        // get a good guess on the size of the result buffer so it doesn't have to double if it goes over a bit
6756        int increase = 0;
6757
6758        // count the replacement text elements that are larger than their corresponding text being replaced
6759        for (int i = 0; i < searchList.length; i++) {
6760            if (searchList[i] == null || replacementList[i] == null) {
6761                continue;
6762            }
6763            final int greater = replacementList[i].length() - searchList[i].length();
6764            if (greater > 0) {
6765                increase += 3 * greater; // assume 3 matches
6766            }
6767        }
6768        // have upper-bound at 20% increase, then let Java take over
6769        increase = Math.min(increase, text.length() / 5);
6770
6771        final StringBuilder buf = new StringBuilder(text.length() + increase);
6772
6773        while (textIndex != -1) {
6774
6775            for (int i = start; i < textIndex; i++) {
6776                buf.append(text.charAt(i));
6777            }
6778            buf.append(replacementList[replaceIndex]);
6779
6780            start = textIndex + searchList[replaceIndex].length();
6781
6782            textIndex = -1;
6783            replaceIndex = -1;
6784            tempIndex = -1;
6785            // find the next earliest match
6786            // NOTE: logic mostly duplicated above START
6787            for (int i = 0; i < searchLength; i++) {
6788                if (noMoreMatchesForReplIndex[i] || searchList[i] == null ||
6789                        searchList[i].isEmpty() || replacementList[i] == null) {
6790                    continue;
6791                }
6792                tempIndex = text.indexOf(searchList[i], start);
6793
6794                // see if we need to keep searching for this
6795                if (tempIndex == -1) {
6796                    noMoreMatchesForReplIndex[i] = true;
6797                } else {
6798                    if (textIndex == -1 || tempIndex < textIndex) {
6799                        textIndex = tempIndex;
6800                        replaceIndex = i;
6801                    }
6802                }
6803            }
6804            // NOTE: logic duplicated above END
6805
6806        }
6807        final int textLength = text.length();
6808        for (int i = start; i < textLength; i++) {
6809            buf.append(text.charAt(i));
6810        }
6811        final String result = buf.toString();
6812        if (!repeat) {
6813            return result;
6814        }
6815
6816        return replaceEach(result, searchList, replacementList, repeat, timeToLive - 1);
6817    }
6818
6819    /**
6820     * <p>
6821     * Replaces all occurrences of Strings within another String.
6822     * </p>
6823     *
6824     * <p>
6825     * A {@code null} reference passed to this method is a no-op, or if
6826     * any "search string" or "string to replace" is null, that replace will be
6827     * ignored.
6828     * </p>
6829     *
6830     * <pre>
6831     *  StringUtils.replaceEachRepeatedly(null, *, *) = null
6832     *  StringUtils.replaceEachRepeatedly("", *, *) = ""
6833     *  StringUtils.replaceEachRepeatedly("aba", null, null) = "aba"
6834     *  StringUtils.replaceEachRepeatedly("aba", new String[0], null) = "aba"
6835     *  StringUtils.replaceEachRepeatedly("aba", null, new String[0]) = "aba"
6836     *  StringUtils.replaceEachRepeatedly("aba", new String[]{"a"}, null) = "aba"
6837     *  StringUtils.replaceEachRepeatedly("aba", new String[]{"a"}, new String[]{""}) = "b"
6838     *  StringUtils.replaceEachRepeatedly("aba", new String[]{null}, new String[]{"a"}) = "aba"
6839     *  StringUtils.replaceEachRepeatedly("abcde", new String[]{"ab", "d"}, new String[]{"w", "t"}) = "wcte"
6840     *  (example of how it repeats)
6841     *  StringUtils.replaceEachRepeatedly("abcde", new String[]{"ab", "d"}, new String[]{"d", "t"}) = "tcte"
6842     *  StringUtils.replaceEachRepeatedly("abcde", new String[]{"ab", "d"}, new String[]{"d", "ab"}) = IllegalStateException
6843     * </pre>
6844     *
6845     * @param text
6846     *            text to search and replace in, no-op if null
6847     * @param searchList
6848     *            the Strings to search for, no-op if null
6849     * @param replacementList
6850     *            the Strings to replace them with, no-op if null
6851     * @return the text with any replacements processed, {@code null} if
6852     *         null String input
6853     * @throws IllegalStateException
6854     *             if the search is repeating and there is an endless loop due
6855     *             to outputs of one being inputs to another
6856     * @throws IllegalArgumentException
6857     *             if the lengths of the arrays are not the same (null is ok,
6858     *             and/or size 0)
6859     * @since 2.4
6860     */
6861    public static String replaceEachRepeatedly(final String text, final String[] searchList, final String[] replacementList) {
6862        // timeToLive should be 0 if not used or nothing to replace, else it's
6863        // the length of the replace array
6864        final int timeToLive = searchList == null ? 0 : searchList.length;
6865        return replaceEach(text, searchList, replacementList, true, timeToLive);
6866    }
6867
6868    /**
6869     * <p>Replaces the first substring of the text string that matches the given regular expression
6870     * with the given replacement.</p>
6871     *
6872     * This method is a {@code null} safe equivalent to:
6873     * <ul>
6874     *  <li>{@code text.replaceFirst(regex, replacement)}</li>
6875     *  <li>{@code Pattern.compile(regex).matcher(text).replaceFirst(replacement)}</li>
6876     * </ul>
6877     *
6878     * <p>A {@code null} reference passed to this method is a no-op.</p>
6879     *
6880     * <p>The {@link Pattern#DOTALL} option is NOT automatically added.
6881     * To use the DOTALL option prepend {@code "(?s)"} to the regex.
6882     * DOTALL is also known as single-line mode in Perl.</p>
6883     *
6884     * <pre>
6885     * StringUtils.replaceFirst(null, *, *)       = null
6886     * StringUtils.replaceFirst("any", (String) null, *)   = "any"
6887     * StringUtils.replaceFirst("any", *, null)   = "any"
6888     * StringUtils.replaceFirst("", "", "zzz")    = "zzz"
6889     * StringUtils.replaceFirst("", ".*", "zzz")  = "zzz"
6890     * StringUtils.replaceFirst("", ".+", "zzz")  = ""
6891     * StringUtils.replaceFirst("abc", "", "ZZ")  = "ZZabc"
6892     * StringUtils.replaceFirst("&lt;__&gt;\n&lt;__&gt;", "&lt;.*&gt;", "z")      = "z\n&lt;__&gt;"
6893     * StringUtils.replaceFirst("&lt;__&gt;\n&lt;__&gt;", "(?s)&lt;.*&gt;", "z")  = "z"
6894     * StringUtils.replaceFirst("ABCabc123", "[a-z]", "_")          = "ABC_bc123"
6895     * StringUtils.replaceFirst("ABCabc123abc", "[^A-Z0-9]+", "_")  = "ABC_123abc"
6896     * StringUtils.replaceFirst("ABCabc123abc", "[^A-Z0-9]+", "")   = "ABC123abc"
6897     * StringUtils.replaceFirst("Lorem ipsum  dolor   sit", "( +)([a-z]+)", "_$2")  = "Lorem_ipsum  dolor   sit"
6898     * </pre>
6899     *
6900     * @param text  text to search and replace in, may be null
6901     * @param regex  the regular expression to which this string is to be matched
6902     * @param replacement  the string to be substituted for the first match
6903     * @return  the text with the first replacement processed,
6904     *              {@code null} if null String input
6905     *
6906     * @throws  java.util.regex.PatternSyntaxException
6907     *              if the regular expression's syntax is invalid
6908     *
6909     * @see String#replaceFirst(String, String)
6910     * @see java.util.regex.Pattern
6911     * @see java.util.regex.Pattern#DOTALL
6912     * @since 3.5
6913     *
6914     * @deprecated Moved to RegExUtils.
6915     */
6916    @Deprecated
6917    public static String replaceFirst(final String text, final String regex, final String replacement) {
6918        return RegExUtils.replaceFirst(text, regex, replacement);
6919    }
6920
6921    /**
6922    * <p>Case insensitively replaces all occurrences of a String within another String.</p>
6923    *
6924    * <p>A {@code null} reference passed to this method is a no-op.</p>
6925    *
6926    * <pre>
6927    * StringUtils.replaceIgnoreCase(null, *, *)        = null
6928    * StringUtils.replaceIgnoreCase("", *, *)          = ""
6929    * StringUtils.replaceIgnoreCase("any", null, *)    = "any"
6930    * StringUtils.replaceIgnoreCase("any", *, null)    = "any"
6931    * StringUtils.replaceIgnoreCase("any", "", *)      = "any"
6932    * StringUtils.replaceIgnoreCase("aba", "a", null)  = "aba"
6933    * StringUtils.replaceIgnoreCase("abA", "A", "")    = "b"
6934    * StringUtils.replaceIgnoreCase("aba", "A", "z")   = "zbz"
6935    * </pre>
6936    *
6937    * @see #replaceIgnoreCase(String text, String searchString, String replacement, int max)
6938    * @param text  text to search and replace in, may be null
6939    * @param searchString  the String to search for (case insensitive), may be null
6940    * @param replacement  the String to replace it with, may be null
6941    * @return the text with any replacements processed,
6942    *  {@code null} if null String input
6943    * @since 3.5
6944    */
6945   public static String replaceIgnoreCase(final String text, final String searchString, final String replacement) {
6946       return replaceIgnoreCase(text, searchString, replacement, -1);
6947   }
6948
6949    /**
6950     * <p>Case insensitively replaces a String with another String inside a larger String,
6951     * for the first {@code max} values of the search String.</p>
6952     *
6953     * <p>A {@code null} reference passed to this method is a no-op.</p>
6954     *
6955     * <pre>
6956     * StringUtils.replaceIgnoreCase(null, *, *, *)         = null
6957     * StringUtils.replaceIgnoreCase("", *, *, *)           = ""
6958     * StringUtils.replaceIgnoreCase("any", null, *, *)     = "any"
6959     * StringUtils.replaceIgnoreCase("any", *, null, *)     = "any"
6960     * StringUtils.replaceIgnoreCase("any", "", *, *)       = "any"
6961     * StringUtils.replaceIgnoreCase("any", *, *, 0)        = "any"
6962     * StringUtils.replaceIgnoreCase("abaa", "a", null, -1) = "abaa"
6963     * StringUtils.replaceIgnoreCase("abaa", "a", "", -1)   = "b"
6964     * StringUtils.replaceIgnoreCase("abaa", "a", "z", 0)   = "abaa"
6965     * StringUtils.replaceIgnoreCase("abaa", "A", "z", 1)   = "zbaa"
6966     * StringUtils.replaceIgnoreCase("abAa", "a", "z", 2)   = "zbza"
6967     * StringUtils.replaceIgnoreCase("abAa", "a", "z", -1)  = "zbzz"
6968     * </pre>
6969     *
6970     * @param text  text to search and replace in, may be null
6971     * @param searchString  the String to search for (case insensitive), may be null
6972     * @param replacement  the String to replace it with, may be null
6973     * @param max  maximum number of values to replace, or {@code -1} if no maximum
6974     * @return the text with any replacements processed,
6975     *  {@code null} if null String input
6976     * @since 3.5
6977     */
6978    public static String replaceIgnoreCase(final String text, final String searchString, final String replacement, final int max) {
6979        return replace(text, searchString, replacement, max, true);
6980    }
6981
6982    // Replacing
6983    //-----------------------------------------------------------------------
6984    /**
6985     * <p>Replaces a String with another String inside a larger String, once.</p>
6986     *
6987     * <p>A {@code null} reference passed to this method is a no-op.</p>
6988     *
6989     * <pre>
6990     * StringUtils.replaceOnce(null, *, *)        = null
6991     * StringUtils.replaceOnce("", *, *)          = ""
6992     * StringUtils.replaceOnce("any", null, *)    = "any"
6993     * StringUtils.replaceOnce("any", *, null)    = "any"
6994     * StringUtils.replaceOnce("any", "", *)      = "any"
6995     * StringUtils.replaceOnce("aba", "a", null)  = "aba"
6996     * StringUtils.replaceOnce("aba", "a", "")    = "ba"
6997     * StringUtils.replaceOnce("aba", "a", "z")   = "zba"
6998     * </pre>
6999     *
7000     * @see #replace(String text, String searchString, String replacement, int max)
7001     * @param text  text to search and replace in, may be null
7002     * @param searchString  the String to search for, may be null
7003     * @param replacement  the String to replace with, may be null
7004     * @return the text with any replacements processed,
7005     *  {@code null} if null String input
7006     */
7007    public static String replaceOnce(final String text, final String searchString, final String replacement) {
7008        return replace(text, searchString, replacement, 1);
7009    }
7010
7011    /**
7012     * <p>Case insensitively replaces a String with another String inside a larger String, once.</p>
7013     *
7014     * <p>A {@code null} reference passed to this method is a no-op.</p>
7015     *
7016     * <pre>
7017     * StringUtils.replaceOnceIgnoreCase(null, *, *)        = null
7018     * StringUtils.replaceOnceIgnoreCase("", *, *)          = ""
7019     * StringUtils.replaceOnceIgnoreCase("any", null, *)    = "any"
7020     * StringUtils.replaceOnceIgnoreCase("any", *, null)    = "any"
7021     * StringUtils.replaceOnceIgnoreCase("any", "", *)      = "any"
7022     * StringUtils.replaceOnceIgnoreCase("aba", "a", null)  = "aba"
7023     * StringUtils.replaceOnceIgnoreCase("aba", "a", "")    = "ba"
7024     * StringUtils.replaceOnceIgnoreCase("aba", "a", "z")   = "zba"
7025     * StringUtils.replaceOnceIgnoreCase("FoOFoofoo", "foo", "") = "Foofoo"
7026     * </pre>
7027     *
7028     * @see #replaceIgnoreCase(String text, String searchString, String replacement, int max)
7029     * @param text  text to search and replace in, may be null
7030     * @param searchString  the String to search for (case insensitive), may be null
7031     * @param replacement  the String to replace with, may be null
7032     * @return the text with any replacements processed,
7033     *  {@code null} if null String input
7034     * @since 3.5
7035     */
7036    public static String replaceOnceIgnoreCase(final String text, final String searchString, final String replacement) {
7037        return replaceIgnoreCase(text, searchString, replacement, 1);
7038    }
7039
7040    /**
7041     * <p>Replaces each substring of the source String that matches the given regular expression with the given
7042     * replacement using the {@link Pattern#DOTALL} option. DOTALL is also known as single-line mode in Perl.</p>
7043     *
7044     * This call is a {@code null} safe equivalent to:
7045     * <ul>
7046     * <li>{@code source.replaceAll(&quot;(?s)&quot; + regex, replacement)}</li>
7047     * <li>{@code Pattern.compile(regex, Pattern.DOTALL).matcher(source).replaceAll(replacement)}</li>
7048     * </ul>
7049     *
7050     * <p>A {@code null} reference passed to this method is a no-op.</p>
7051     *
7052     * <pre>
7053     * StringUtils.replacePattern(null, *, *)       = null
7054     * StringUtils.replacePattern("any", (String) null, *)   = "any"
7055     * StringUtils.replacePattern("any", *, null)   = "any"
7056     * StringUtils.replacePattern("", "", "zzz")    = "zzz"
7057     * StringUtils.replacePattern("", ".*", "zzz")  = "zzz"
7058     * StringUtils.replacePattern("", ".+", "zzz")  = ""
7059     * StringUtils.replacePattern("&lt;__&gt;\n&lt;__&gt;", "&lt;.*&gt;", "z")       = "z"
7060     * StringUtils.replacePattern("ABCabc123", "[a-z]", "_")       = "ABC___123"
7061     * StringUtils.replacePattern("ABCabc123", "[^A-Z0-9]+", "_")  = "ABC_123"
7062     * StringUtils.replacePattern("ABCabc123", "[^A-Z0-9]+", "")   = "ABC123"
7063     * StringUtils.replacePattern("Lorem ipsum  dolor   sit", "( +)([a-z]+)", "_$2")  = "Lorem_ipsum_dolor_sit"
7064     * </pre>
7065     *
7066     * @param source
7067     *            the source string
7068     * @param regex
7069     *            the regular expression to which this string is to be matched
7070     * @param replacement
7071     *            the string to be substituted for each match
7072     * @return The resulting {@code String}
7073     * @see #replaceAll(String, String, String)
7074     * @see String#replaceAll(String, String)
7075     * @see Pattern#DOTALL
7076     * @since 3.2
7077     * @since 3.5 Changed {@code null} reference passed to this method is a no-op.
7078     *
7079     * @deprecated Moved to RegExUtils.
7080     */
7081    @Deprecated
7082    public static String replacePattern(final String source, final String regex, final String replacement) {
7083        return RegExUtils.replacePattern(source, regex, replacement);
7084    }
7085
7086    // Reversing
7087    //-----------------------------------------------------------------------
7088    /**
7089     * <p>Reverses a String as per {@link StringBuilder#reverse()}.</p>
7090     *
7091     * <p>A {@code null} String returns {@code null}.</p>
7092     *
7093     * <pre>
7094     * StringUtils.reverse(null)  = null
7095     * StringUtils.reverse("")    = ""
7096     * StringUtils.reverse("bat") = "tab"
7097     * </pre>
7098     *
7099     * @param str  the String to reverse, may be null
7100     * @return the reversed String, {@code null} if null String input
7101     */
7102    public static String reverse(final String str) {
7103        if (str == null) {
7104            return null;
7105        }
7106        return new StringBuilder(str).reverse().toString();
7107    }
7108
7109    /**
7110     * <p>Reverses a String that is delimited by a specific character.</p>
7111     *
7112     * <p>The Strings between the delimiters are not reversed.
7113     * Thus java.lang.String becomes String.lang.java (if the delimiter
7114     * is {@code '.'}).</p>
7115     *
7116     * <pre>
7117     * StringUtils.reverseDelimited(null, *)      = null
7118     * StringUtils.reverseDelimited("", *)        = ""
7119     * StringUtils.reverseDelimited("a.b.c", 'x') = "a.b.c"
7120     * StringUtils.reverseDelimited("a.b.c", ".") = "c.b.a"
7121     * </pre>
7122     *
7123     * @param str  the String to reverse, may be null
7124     * @param separatorChar  the separator character to use
7125     * @return the reversed String, {@code null} if null String input
7126     * @since 2.0
7127     */
7128    public static String reverseDelimited(final String str, final char separatorChar) {
7129        if (str == null) {
7130            return null;
7131        }
7132        // could implement manually, but simple way is to reuse other,
7133        // probably slower, methods.
7134        final String[] strs = split(str, separatorChar);
7135        ArrayUtils.reverse(strs);
7136        return join(strs, separatorChar);
7137    }
7138
7139    /**
7140     * <p>Gets the rightmost {@code len} characters of a String.</p>
7141     *
7142     * <p>If {@code len} characters are not available, or the String
7143     * is {@code null}, the String will be returned without an
7144     * an exception. An empty String is returned if len is negative.</p>
7145     *
7146     * <pre>
7147     * StringUtils.right(null, *)    = null
7148     * StringUtils.right(*, -ve)     = ""
7149     * StringUtils.right("", *)      = ""
7150     * StringUtils.right("abc", 0)   = ""
7151     * StringUtils.right("abc", 2)   = "bc"
7152     * StringUtils.right("abc", 4)   = "abc"
7153     * </pre>
7154     *
7155     * @param str  the String to get the rightmost characters from, may be null
7156     * @param len  the length of the required String
7157     * @return the rightmost characters, {@code null} if null String input
7158     */
7159    public static String right(final String str, final int len) {
7160        if (str == null) {
7161            return null;
7162        }
7163        if (len < 0) {
7164            return EMPTY;
7165        }
7166        if (str.length() <= len) {
7167            return str;
7168        }
7169        return str.substring(str.length() - len);
7170    }
7171
7172    /**
7173     * <p>Right pad a String with spaces (' ').</p>
7174     *
7175     * <p>The String is padded to the size of {@code size}.</p>
7176     *
7177     * <pre>
7178     * StringUtils.rightPad(null, *)   = null
7179     * StringUtils.rightPad("", 3)     = "   "
7180     * StringUtils.rightPad("bat", 3)  = "bat"
7181     * StringUtils.rightPad("bat", 5)  = "bat  "
7182     * StringUtils.rightPad("bat", 1)  = "bat"
7183     * StringUtils.rightPad("bat", -1) = "bat"
7184     * </pre>
7185     *
7186     * @param str  the String to pad out, may be null
7187     * @param size  the size to pad to
7188     * @return right padded String or original String if no padding is necessary,
7189     *  {@code null} if null String input
7190     */
7191    public static String rightPad(final String str, final int size) {
7192        return rightPad(str, size, ' ');
7193    }
7194
7195    /**
7196     * <p>Right pad a String with a specified character.</p>
7197     *
7198     * <p>The String is padded to the size of {@code size}.</p>
7199     *
7200     * <pre>
7201     * StringUtils.rightPad(null, *, *)     = null
7202     * StringUtils.rightPad("", 3, 'z')     = "zzz"
7203     * StringUtils.rightPad("bat", 3, 'z')  = "bat"
7204     * StringUtils.rightPad("bat", 5, 'z')  = "batzz"
7205     * StringUtils.rightPad("bat", 1, 'z')  = "bat"
7206     * StringUtils.rightPad("bat", -1, 'z') = "bat"
7207     * </pre>
7208     *
7209     * @param str  the String to pad out, may be null
7210     * @param size  the size to pad to
7211     * @param padChar  the character to pad with
7212     * @return right padded String or original String if no padding is necessary,
7213     *  {@code null} if null String input
7214     * @since 2.0
7215     */
7216    public static String rightPad(final String str, final int size, final char padChar) {
7217        if (str == null) {
7218            return null;
7219        }
7220        final int pads = size - str.length();
7221        if (pads <= 0) {
7222            return str; // returns original String when possible
7223        }
7224        if (pads > PAD_LIMIT) {
7225            return rightPad(str, size, String.valueOf(padChar));
7226        }
7227        return str.concat(repeat(padChar, pads));
7228    }
7229
7230    /**
7231     * <p>Right pad a String with a specified String.</p>
7232     *
7233     * <p>The String is padded to the size of {@code size}.</p>
7234     *
7235     * <pre>
7236     * StringUtils.rightPad(null, *, *)      = null
7237     * StringUtils.rightPad("", 3, "z")      = "zzz"
7238     * StringUtils.rightPad("bat", 3, "yz")  = "bat"
7239     * StringUtils.rightPad("bat", 5, "yz")  = "batyz"
7240     * StringUtils.rightPad("bat", 8, "yz")  = "batyzyzy"
7241     * StringUtils.rightPad("bat", 1, "yz")  = "bat"
7242     * StringUtils.rightPad("bat", -1, "yz") = "bat"
7243     * StringUtils.rightPad("bat", 5, null)  = "bat  "
7244     * StringUtils.rightPad("bat", 5, "")    = "bat  "
7245     * </pre>
7246     *
7247     * @param str  the String to pad out, may be null
7248     * @param size  the size to pad to
7249     * @param padStr  the String to pad with, null or empty treated as single space
7250     * @return right padded String or original String if no padding is necessary,
7251     *  {@code null} if null String input
7252     */
7253    public static String rightPad(final String str, final int size, String padStr) {
7254        if (str == null) {
7255            return null;
7256        }
7257        if (isEmpty(padStr)) {
7258            padStr = SPACE;
7259        }
7260        final int padLen = padStr.length();
7261        final int strLen = str.length();
7262        final int pads = size - strLen;
7263        if (pads <= 0) {
7264            return str; // returns original String when possible
7265        }
7266        if (padLen == 1 && pads <= PAD_LIMIT) {
7267            return rightPad(str, size, padStr.charAt(0));
7268        }
7269
7270        if (pads == padLen) {
7271            return str.concat(padStr);
7272        } else if (pads < padLen) {
7273            return str.concat(padStr.substring(0, pads));
7274        } else {
7275            final char[] padding = new char[pads];
7276            final char[] padChars = padStr.toCharArray();
7277            for (int i = 0; i < pads; i++) {
7278                padding[i] = padChars[i % padLen];
7279            }
7280            return str.concat(new String(padding));
7281        }
7282    }
7283
7284    // Rotating (circular shift)
7285    //-----------------------------------------------------------------------
7286    /**
7287     * <p>Rotate (circular shift) a String of {@code shift} characters.</p>
7288     * <ul>
7289     *  <li>If {@code shift > 0}, right circular shift (ex : ABCDEF =&gt; FABCDE)</li>
7290     *  <li>If {@code shift < 0}, left circular shift (ex : ABCDEF =&gt; BCDEFA)</li>
7291     * </ul>
7292     *
7293     * <pre>
7294     * StringUtils.rotate(null, *)        = null
7295     * StringUtils.rotate("", *)          = ""
7296     * StringUtils.rotate("abcdefg", 0)   = "abcdefg"
7297     * StringUtils.rotate("abcdefg", 2)   = "fgabcde"
7298     * StringUtils.rotate("abcdefg", -2)  = "cdefgab"
7299     * StringUtils.rotate("abcdefg", 7)   = "abcdefg"
7300     * StringUtils.rotate("abcdefg", -7)  = "abcdefg"
7301     * StringUtils.rotate("abcdefg", 9)   = "fgabcde"
7302     * StringUtils.rotate("abcdefg", -9)  = "cdefgab"
7303     * </pre>
7304     *
7305     * @param str  the String to rotate, may be null
7306     * @param shift  number of time to shift (positive : right shift, negative : left shift)
7307     * @return the rotated String,
7308     *          or the original String if {@code shift == 0},
7309     *          or {@code null} if null String input
7310     * @since 3.5
7311     */
7312    public static String rotate(final String str, final int shift) {
7313        if (str == null) {
7314            return null;
7315        }
7316
7317        final int strLen = str.length();
7318        if (shift == 0 || strLen == 0 || shift % strLen == 0) {
7319            return str;
7320        }
7321
7322        final StringBuilder builder = new StringBuilder(strLen);
7323        final int offset = - (shift % strLen);
7324        builder.append(substring(str, offset));
7325        builder.append(substring(str, 0, offset));
7326        return builder.toString();
7327    }
7328
7329    // Splitting
7330    //-----------------------------------------------------------------------
7331    /**
7332     * <p>Splits the provided text into an array, using whitespace as the
7333     * separator.
7334     * Whitespace is defined by {@link Character#isWhitespace(char)}.</p>
7335     *
7336     * <p>The separator is not included in the returned String array.
7337     * Adjacent separators are treated as one separator.
7338     * For more control over the split use the StrTokenizer class.</p>
7339     *
7340     * <p>A {@code null} input String returns {@code null}.</p>
7341     *
7342     * <pre>
7343     * StringUtils.split(null)       = null
7344     * StringUtils.split("")         = []
7345     * StringUtils.split("abc def")  = ["abc", "def"]
7346     * StringUtils.split("abc  def") = ["abc", "def"]
7347     * StringUtils.split(" abc ")    = ["abc"]
7348     * </pre>
7349     *
7350     * @param str  the String to parse, may be null
7351     * @return an array of parsed Strings, {@code null} if null String input
7352     */
7353    public static String[] split(final String str) {
7354        return split(str, null, -1);
7355    }
7356
7357    /**
7358     * <p>Splits the provided text into an array, separator specified.
7359     * This is an alternative to using StringTokenizer.</p>
7360     *
7361     * <p>The separator is not included in the returned String array.
7362     * Adjacent separators are treated as one separator.
7363     * For more control over the split use the StrTokenizer class.</p>
7364     *
7365     * <p>A {@code null} input String returns {@code null}.</p>
7366     *
7367     * <pre>
7368     * StringUtils.split(null, *)         = null
7369     * StringUtils.split("", *)           = []
7370     * StringUtils.split("a.b.c", '.')    = ["a", "b", "c"]
7371     * StringUtils.split("a..b.c", '.')   = ["a", "b", "c"]
7372     * StringUtils.split("a:b:c", '.')    = ["a:b:c"]
7373     * StringUtils.split("a b c", ' ')    = ["a", "b", "c"]
7374     * </pre>
7375     *
7376     * @param str  the String to parse, may be null
7377     * @param separatorChar  the character used as the delimiter
7378     * @return an array of parsed Strings, {@code null} if null String input
7379     * @since 2.0
7380     */
7381    public static String[] split(final String str, final char separatorChar) {
7382        return splitWorker(str, separatorChar, false);
7383    }
7384
7385    /**
7386     * <p>Splits the provided text into an array, separators specified.
7387     * This is an alternative to using StringTokenizer.</p>
7388     *
7389     * <p>The separator is not included in the returned String array.
7390     * Adjacent separators are treated as one separator.
7391     * For more control over the split use the StrTokenizer class.</p>
7392     *
7393     * <p>A {@code null} input String returns {@code null}.
7394     * A {@code null} separatorChars splits on whitespace.</p>
7395     *
7396     * <pre>
7397     * StringUtils.split(null, *)         = null
7398     * StringUtils.split("", *)           = []
7399     * StringUtils.split("abc def", null) = ["abc", "def"]
7400     * StringUtils.split("abc def", " ")  = ["abc", "def"]
7401     * StringUtils.split("abc  def", " ") = ["abc", "def"]
7402     * StringUtils.split("ab:cd:ef", ":") = ["ab", "cd", "ef"]
7403     * </pre>
7404     *
7405     * @param str  the String to parse, may be null
7406     * @param separatorChars  the characters used as the delimiters,
7407     *  {@code null} splits on whitespace
7408     * @return an array of parsed Strings, {@code null} if null String input
7409     */
7410    public static String[] split(final String str, final String separatorChars) {
7411        return splitWorker(str, separatorChars, -1, false);
7412    }
7413
7414    /**
7415     * <p>Splits the provided text into an array with a maximum length,
7416     * separators specified.</p>
7417     *
7418     * <p>The separator is not included in the returned String array.
7419     * Adjacent separators are treated as one separator.</p>
7420     *
7421     * <p>A {@code null} input String returns {@code null}.
7422     * A {@code null} separatorChars splits on whitespace.</p>
7423     *
7424     * <p>If more than {@code max} delimited substrings are found, the last
7425     * returned string includes all characters after the first {@code max - 1}
7426     * returned strings (including separator characters).</p>
7427     *
7428     * <pre>
7429     * StringUtils.split(null, *, *)            = null
7430     * StringUtils.split("", *, *)              = []
7431     * StringUtils.split("ab cd ef", null, 0)   = ["ab", "cd", "ef"]
7432     * StringUtils.split("ab   cd ef", null, 0) = ["ab", "cd", "ef"]
7433     * StringUtils.split("ab:cd:ef", ":", 0)    = ["ab", "cd", "ef"]
7434     * StringUtils.split("ab:cd:ef", ":", 2)    = ["ab", "cd:ef"]
7435     * </pre>
7436     *
7437     * @param str  the String to parse, may be null
7438     * @param separatorChars  the characters used as the delimiters,
7439     *  {@code null} splits on whitespace
7440     * @param max  the maximum number of elements to include in the
7441     *  array. A zero or negative value implies no limit
7442     * @return an array of parsed Strings, {@code null} if null String input
7443     */
7444    public static String[] split(final String str, final String separatorChars, final int max) {
7445        return splitWorker(str, separatorChars, max, false);
7446    }
7447
7448    /**
7449     * <p>Splits a String by Character type as returned by
7450     * {@code java.lang.Character.getType(char)}. Groups of contiguous
7451     * characters of the same type are returned as complete tokens.
7452     * <pre>
7453     * StringUtils.splitByCharacterType(null)         = null
7454     * StringUtils.splitByCharacterType("")           = []
7455     * StringUtils.splitByCharacterType("ab de fg")   = ["ab", " ", "de", " ", "fg"]
7456     * StringUtils.splitByCharacterType("ab   de fg") = ["ab", "   ", "de", " ", "fg"]
7457     * StringUtils.splitByCharacterType("ab:cd:ef")   = ["ab", ":", "cd", ":", "ef"]
7458     * StringUtils.splitByCharacterType("number5")    = ["number", "5"]
7459     * StringUtils.splitByCharacterType("fooBar")     = ["foo", "B", "ar"]
7460     * StringUtils.splitByCharacterType("foo200Bar")  = ["foo", "200", "B", "ar"]
7461     * StringUtils.splitByCharacterType("ASFRules")   = ["ASFR", "ules"]
7462     * </pre>
7463     * @param str the String to split, may be {@code null}
7464     * @return an array of parsed Strings, {@code null} if null String input
7465     * @since 2.4
7466     */
7467    public static String[] splitByCharacterType(final String str) {
7468        return splitByCharacterType(str, false);
7469    }
7470
7471    /**
7472     * <p>Splits a String by Character type as returned by
7473     * {@code java.lang.Character.getType(char)}. Groups of contiguous
7474     * characters of the same type are returned as complete tokens, with the
7475     * following exception: if {@code camelCase} is {@code true},
7476     * the character of type {@code Character.UPPERCASE_LETTER}, if any,
7477     * immediately preceding a token of type {@code Character.LOWERCASE_LETTER}
7478     * will belong to the following token rather than to the preceding, if any,
7479     * {@code Character.UPPERCASE_LETTER} token.
7480     * @param str the String to split, may be {@code null}
7481     * @param camelCase whether to use so-called "camel-case" for letter types
7482     * @return an array of parsed Strings, {@code null} if null String input
7483     * @since 2.4
7484     */
7485    private static String[] splitByCharacterType(final String str, final boolean camelCase) {
7486        if (str == null) {
7487            return null;
7488        }
7489        if (str.isEmpty()) {
7490            return ArrayUtils.EMPTY_STRING_ARRAY;
7491        }
7492        final char[] c = str.toCharArray();
7493        final List<String> list = new ArrayList<>();
7494        int tokenStart = 0;
7495        int currentType = Character.getType(c[tokenStart]);
7496        for (int pos = tokenStart + 1; pos < c.length; pos++) {
7497            final int type = Character.getType(c[pos]);
7498            if (type == currentType) {
7499                continue;
7500            }
7501            if (camelCase && type == Character.LOWERCASE_LETTER && currentType == Character.UPPERCASE_LETTER) {
7502                final int newTokenStart = pos - 1;
7503                if (newTokenStart != tokenStart) {
7504                    list.add(new String(c, tokenStart, newTokenStart - tokenStart));
7505                    tokenStart = newTokenStart;
7506                }
7507            } else {
7508                list.add(new String(c, tokenStart, pos - tokenStart));
7509                tokenStart = pos;
7510            }
7511            currentType = type;
7512        }
7513        list.add(new String(c, tokenStart, c.length - tokenStart));
7514        return list.toArray(ArrayUtils.EMPTY_STRING_ARRAY);
7515    }
7516
7517    /**
7518     * <p>Splits a String by Character type as returned by
7519     * {@code java.lang.Character.getType(char)}. Groups of contiguous
7520     * characters of the same type are returned as complete tokens, with the
7521     * following exception: the character of type
7522     * {@code Character.UPPERCASE_LETTER}, if any, immediately
7523     * preceding a token of type {@code Character.LOWERCASE_LETTER}
7524     * will belong to the following token rather than to the preceding, if any,
7525     * {@code Character.UPPERCASE_LETTER} token.
7526     * <pre>
7527     * StringUtils.splitByCharacterTypeCamelCase(null)         = null
7528     * StringUtils.splitByCharacterTypeCamelCase("")           = []
7529     * StringUtils.splitByCharacterTypeCamelCase("ab de fg")   = ["ab", " ", "de", " ", "fg"]
7530     * StringUtils.splitByCharacterTypeCamelCase("ab   de fg") = ["ab", "   ", "de", " ", "fg"]
7531     * StringUtils.splitByCharacterTypeCamelCase("ab:cd:ef")   = ["ab", ":", "cd", ":", "ef"]
7532     * StringUtils.splitByCharacterTypeCamelCase("number5")    = ["number", "5"]
7533     * StringUtils.splitByCharacterTypeCamelCase("fooBar")     = ["foo", "Bar"]
7534     * StringUtils.splitByCharacterTypeCamelCase("foo200Bar")  = ["foo", "200", "Bar"]
7535     * StringUtils.splitByCharacterTypeCamelCase("ASFRules")   = ["ASF", "Rules"]
7536     * </pre>
7537     * @param str the String to split, may be {@code null}
7538     * @return an array of parsed Strings, {@code null} if null String input
7539     * @since 2.4
7540     */
7541    public static String[] splitByCharacterTypeCamelCase(final String str) {
7542        return splitByCharacterType(str, true);
7543    }
7544
7545    /**
7546     * <p>Splits the provided text into an array, separator string specified.</p>
7547     *
7548     * <p>The separator(s) will not be included in the returned String array.
7549     * Adjacent separators are treated as one separator.</p>
7550     *
7551     * <p>A {@code null} input String returns {@code null}.
7552     * A {@code null} separator splits on whitespace.</p>
7553     *
7554     * <pre>
7555     * StringUtils.splitByWholeSeparator(null, *)               = null
7556     * StringUtils.splitByWholeSeparator("", *)                 = []
7557     * StringUtils.splitByWholeSeparator("ab de fg", null)      = ["ab", "de", "fg"]
7558     * StringUtils.splitByWholeSeparator("ab   de fg", null)    = ["ab", "de", "fg"]
7559     * StringUtils.splitByWholeSeparator("ab:cd:ef", ":")       = ["ab", "cd", "ef"]
7560     * StringUtils.splitByWholeSeparator("ab-!-cd-!-ef", "-!-") = ["ab", "cd", "ef"]
7561     * </pre>
7562     *
7563     * @param str  the String to parse, may be null
7564     * @param separator  String containing the String to be used as a delimiter,
7565     *  {@code null} splits on whitespace
7566     * @return an array of parsed Strings, {@code null} if null String was input
7567     */
7568    public static String[] splitByWholeSeparator(final String str, final String separator) {
7569        return splitByWholeSeparatorWorker(str, separator, -1, false);
7570    }
7571
7572    /**
7573     * <p>Splits the provided text into an array, separator string specified.
7574     * Returns a maximum of {@code max} substrings.</p>
7575     *
7576     * <p>The separator(s) will not be included in the returned String array.
7577     * Adjacent separators are treated as one separator.</p>
7578     *
7579     * <p>A {@code null} input String returns {@code null}.
7580     * A {@code null} separator splits on whitespace.</p>
7581     *
7582     * <pre>
7583     * StringUtils.splitByWholeSeparator(null, *, *)               = null
7584     * StringUtils.splitByWholeSeparator("", *, *)                 = []
7585     * StringUtils.splitByWholeSeparator("ab de fg", null, 0)      = ["ab", "de", "fg"]
7586     * StringUtils.splitByWholeSeparator("ab   de fg", null, 0)    = ["ab", "de", "fg"]
7587     * StringUtils.splitByWholeSeparator("ab:cd:ef", ":", 2)       = ["ab", "cd:ef"]
7588     * StringUtils.splitByWholeSeparator("ab-!-cd-!-ef", "-!-", 5) = ["ab", "cd", "ef"]
7589     * StringUtils.splitByWholeSeparator("ab-!-cd-!-ef", "-!-", 2) = ["ab", "cd-!-ef"]
7590     * </pre>
7591     *
7592     * @param str  the String to parse, may be null
7593     * @param separator  String containing the String to be used as a delimiter,
7594     *  {@code null} splits on whitespace
7595     * @param max  the maximum number of elements to include in the returned
7596     *  array. A zero or negative value implies no limit.
7597     * @return an array of parsed Strings, {@code null} if null String was input
7598     */
7599    public static String[] splitByWholeSeparator( final String str, final String separator, final int max) {
7600        return splitByWholeSeparatorWorker(str, separator, max, false);
7601    }
7602
7603    /**
7604     * <p>Splits the provided text into an array, separator string specified. </p>
7605     *
7606     * <p>The separator is not included in the returned String array.
7607     * Adjacent separators are treated as separators for empty tokens.
7608     * For more control over the split use the StrTokenizer class.</p>
7609     *
7610     * <p>A {@code null} input String returns {@code null}.
7611     * A {@code null} separator splits on whitespace.</p>
7612     *
7613     * <pre>
7614     * StringUtils.splitByWholeSeparatorPreserveAllTokens(null, *)               = null
7615     * StringUtils.splitByWholeSeparatorPreserveAllTokens("", *)                 = []
7616     * StringUtils.splitByWholeSeparatorPreserveAllTokens("ab de fg", null)      = ["ab", "de", "fg"]
7617     * StringUtils.splitByWholeSeparatorPreserveAllTokens("ab   de fg", null)    = ["ab", "", "", "de", "fg"]
7618     * StringUtils.splitByWholeSeparatorPreserveAllTokens("ab:cd:ef", ":")       = ["ab", "cd", "ef"]
7619     * StringUtils.splitByWholeSeparatorPreserveAllTokens("ab-!-cd-!-ef", "-!-") = ["ab", "cd", "ef"]
7620     * </pre>
7621     *
7622     * @param str  the String to parse, may be null
7623     * @param separator  String containing the String to be used as a delimiter,
7624     *  {@code null} splits on whitespace
7625     * @return an array of parsed Strings, {@code null} if null String was input
7626     * @since 2.4
7627     */
7628    public static String[] splitByWholeSeparatorPreserveAllTokens(final String str, final String separator) {
7629        return splitByWholeSeparatorWorker(str, separator, -1, true);
7630    }
7631
7632    /**
7633     * <p>Splits the provided text into an array, separator string specified.
7634     * Returns a maximum of {@code max} substrings.</p>
7635     *
7636     * <p>The separator is not included in the returned String array.
7637     * Adjacent separators are treated as separators for empty tokens.
7638     * For more control over the split use the StrTokenizer class.</p>
7639     *
7640     * <p>A {@code null} input String returns {@code null}.
7641     * A {@code null} separator splits on whitespace.</p>
7642     *
7643     * <pre>
7644     * StringUtils.splitByWholeSeparatorPreserveAllTokens(null, *, *)               = null
7645     * StringUtils.splitByWholeSeparatorPreserveAllTokens("", *, *)                 = []
7646     * StringUtils.splitByWholeSeparatorPreserveAllTokens("ab de fg", null, 0)      = ["ab", "de", "fg"]
7647     * StringUtils.splitByWholeSeparatorPreserveAllTokens("ab   de fg", null, 0)    = ["ab", "", "", "de", "fg"]
7648     * StringUtils.splitByWholeSeparatorPreserveAllTokens("ab:cd:ef", ":", 2)       = ["ab", "cd:ef"]
7649     * StringUtils.splitByWholeSeparatorPreserveAllTokens("ab-!-cd-!-ef", "-!-", 5) = ["ab", "cd", "ef"]
7650     * StringUtils.splitByWholeSeparatorPreserveAllTokens("ab-!-cd-!-ef", "-!-", 2) = ["ab", "cd-!-ef"]
7651     * </pre>
7652     *
7653     * @param str  the String to parse, may be null
7654     * @param separator  String containing the String to be used as a delimiter,
7655     *  {@code null} splits on whitespace
7656     * @param max  the maximum number of elements to include in the returned
7657     *  array. A zero or negative value implies no limit.
7658     * @return an array of parsed Strings, {@code null} if null String was input
7659     * @since 2.4
7660     */
7661    public static String[] splitByWholeSeparatorPreserveAllTokens(final String str, final String separator, final int max) {
7662        return splitByWholeSeparatorWorker(str, separator, max, true);
7663    }
7664
7665    /**
7666     * Performs the logic for the {@code splitByWholeSeparatorPreserveAllTokens} methods.
7667     *
7668     * @param str  the String to parse, may be {@code null}
7669     * @param separator  String containing the String to be used as a delimiter,
7670     *  {@code null} splits on whitespace
7671     * @param max  the maximum number of elements to include in the returned
7672     *  array. A zero or negative value implies no limit.
7673     * @param preserveAllTokens if {@code true}, adjacent separators are
7674     * treated as empty token separators; if {@code false}, adjacent
7675     * separators are treated as one separator.
7676     * @return an array of parsed Strings, {@code null} if null String input
7677     * @since 2.4
7678     */
7679    private static String[] splitByWholeSeparatorWorker(
7680            final String str, final String separator, final int max, final boolean preserveAllTokens) {
7681        if (str == null) {
7682            return null;
7683        }
7684
7685        final int len = str.length();
7686
7687        if (len == 0) {
7688            return ArrayUtils.EMPTY_STRING_ARRAY;
7689        }
7690
7691        if (separator == null || EMPTY.equals(separator)) {
7692            // Split on whitespace.
7693            return splitWorker(str, null, max, preserveAllTokens);
7694        }
7695
7696        final int separatorLength = separator.length();
7697
7698        final ArrayList<String> substrings = new ArrayList<>();
7699        int numberOfSubstrings = 0;
7700        int beg = 0;
7701        int end = 0;
7702        while (end < len) {
7703            end = str.indexOf(separator, beg);
7704
7705            if (end > -1) {
7706                if (end > beg) {
7707                    numberOfSubstrings += 1;
7708
7709                    if (numberOfSubstrings == max) {
7710                        end = len;
7711                        substrings.add(str.substring(beg));
7712                    } else {
7713                        // The following is OK, because String.substring( beg, end ) excludes
7714                        // the character at the position 'end'.
7715                        substrings.add(str.substring(beg, end));
7716
7717                        // Set the starting point for the next search.
7718                        // The following is equivalent to beg = end + (separatorLength - 1) + 1,
7719                        // which is the right calculation:
7720                        beg = end + separatorLength;
7721                    }
7722                } else {
7723                    // We found a consecutive occurrence of the separator, so skip it.
7724                    if (preserveAllTokens) {
7725                        numberOfSubstrings += 1;
7726                        if (numberOfSubstrings == max) {
7727                            end = len;
7728                            substrings.add(str.substring(beg));
7729                        } else {
7730                            substrings.add(EMPTY);
7731                        }
7732                    }
7733                    beg = end + separatorLength;
7734                }
7735            } else {
7736                // String.substring( beg ) goes from 'beg' to the end of the String.
7737                substrings.add(str.substring(beg));
7738                end = len;
7739            }
7740        }
7741
7742        return substrings.toArray(ArrayUtils.EMPTY_STRING_ARRAY);
7743    }
7744
7745    // -----------------------------------------------------------------------
7746    /**
7747     * <p>Splits the provided text into an array, using whitespace as the
7748     * separator, preserving all tokens, including empty tokens created by
7749     * adjacent separators. This is an alternative to using StringTokenizer.
7750     * Whitespace is defined by {@link Character#isWhitespace(char)}.</p>
7751     *
7752     * <p>The separator is not included in the returned String array.
7753     * Adjacent separators are treated as separators for empty tokens.
7754     * For more control over the split use the StrTokenizer class.</p>
7755     *
7756     * <p>A {@code null} input String returns {@code null}.</p>
7757     *
7758     * <pre>
7759     * StringUtils.splitPreserveAllTokens(null)       = null
7760     * StringUtils.splitPreserveAllTokens("")         = []
7761     * StringUtils.splitPreserveAllTokens("abc def")  = ["abc", "def"]
7762     * StringUtils.splitPreserveAllTokens("abc  def") = ["abc", "", "def"]
7763     * StringUtils.splitPreserveAllTokens(" abc ")    = ["", "abc", ""]
7764     * </pre>
7765     *
7766     * @param str  the String to parse, may be {@code null}
7767     * @return an array of parsed Strings, {@code null} if null String input
7768     * @since 2.1
7769     */
7770    public static String[] splitPreserveAllTokens(final String str) {
7771        return splitWorker(str, null, -1, true);
7772    }
7773
7774    /**
7775     * <p>Splits the provided text into an array, separator specified,
7776     * preserving all tokens, including empty tokens created by adjacent
7777     * separators. This is an alternative to using StringTokenizer.</p>
7778     *
7779     * <p>The separator is not included in the returned String array.
7780     * Adjacent separators are treated as separators for empty tokens.
7781     * For more control over the split use the StrTokenizer class.</p>
7782     *
7783     * <p>A {@code null} input String returns {@code null}.</p>
7784     *
7785     * <pre>
7786     * StringUtils.splitPreserveAllTokens(null, *)         = null
7787     * StringUtils.splitPreserveAllTokens("", *)           = []
7788     * StringUtils.splitPreserveAllTokens("a.b.c", '.')    = ["a", "b", "c"]
7789     * StringUtils.splitPreserveAllTokens("a..b.c", '.')   = ["a", "", "b", "c"]
7790     * StringUtils.splitPreserveAllTokens("a:b:c", '.')    = ["a:b:c"]
7791     * StringUtils.splitPreserveAllTokens("a\tb\nc", null) = ["a", "b", "c"]
7792     * StringUtils.splitPreserveAllTokens("a b c", ' ')    = ["a", "b", "c"]
7793     * StringUtils.splitPreserveAllTokens("a b c ", ' ')   = ["a", "b", "c", ""]
7794     * StringUtils.splitPreserveAllTokens("a b c  ", ' ')   = ["a", "b", "c", "", ""]
7795     * StringUtils.splitPreserveAllTokens(" a b c", ' ')   = ["", a", "b", "c"]
7796     * StringUtils.splitPreserveAllTokens("  a b c", ' ')  = ["", "", a", "b", "c"]
7797     * StringUtils.splitPreserveAllTokens(" a b c ", ' ')  = ["", a", "b", "c", ""]
7798     * </pre>
7799     *
7800     * @param str  the String to parse, may be {@code null}
7801     * @param separatorChar  the character used as the delimiter,
7802     *  {@code null} splits on whitespace
7803     * @return an array of parsed Strings, {@code null} if null String input
7804     * @since 2.1
7805     */
7806    public static String[] splitPreserveAllTokens(final String str, final char separatorChar) {
7807        return splitWorker(str, separatorChar, true);
7808    }
7809
7810    /**
7811     * <p>Splits the provided text into an array, separators specified,
7812     * preserving all tokens, including empty tokens created by adjacent
7813     * separators. This is an alternative to using StringTokenizer.</p>
7814     *
7815     * <p>The separator is not included in the returned String array.
7816     * Adjacent separators are treated as separators for empty tokens.
7817     * For more control over the split use the StrTokenizer class.</p>
7818     *
7819     * <p>A {@code null} input String returns {@code null}.
7820     * A {@code null} separatorChars splits on whitespace.</p>
7821     *
7822     * <pre>
7823     * StringUtils.splitPreserveAllTokens(null, *)           = null
7824     * StringUtils.splitPreserveAllTokens("", *)             = []
7825     * StringUtils.splitPreserveAllTokens("abc def", null)   = ["abc", "def"]
7826     * StringUtils.splitPreserveAllTokens("abc def", " ")    = ["abc", "def"]
7827     * StringUtils.splitPreserveAllTokens("abc  def", " ")   = ["abc", "", def"]
7828     * StringUtils.splitPreserveAllTokens("ab:cd:ef", ":")   = ["ab", "cd", "ef"]
7829     * StringUtils.splitPreserveAllTokens("ab:cd:ef:", ":")  = ["ab", "cd", "ef", ""]
7830     * StringUtils.splitPreserveAllTokens("ab:cd:ef::", ":") = ["ab", "cd", "ef", "", ""]
7831     * StringUtils.splitPreserveAllTokens("ab::cd:ef", ":")  = ["ab", "", cd", "ef"]
7832     * StringUtils.splitPreserveAllTokens(":cd:ef", ":")     = ["", cd", "ef"]
7833     * StringUtils.splitPreserveAllTokens("::cd:ef", ":")    = ["", "", cd", "ef"]
7834     * StringUtils.splitPreserveAllTokens(":cd:ef:", ":")    = ["", cd", "ef", ""]
7835     * </pre>
7836     *
7837     * @param str  the String to parse, may be {@code null}
7838     * @param separatorChars  the characters used as the delimiters,
7839     *  {@code null} splits on whitespace
7840     * @return an array of parsed Strings, {@code null} if null String input
7841     * @since 2.1
7842     */
7843    public static String[] splitPreserveAllTokens(final String str, final String separatorChars) {
7844        return splitWorker(str, separatorChars, -1, true);
7845    }
7846
7847    /**
7848     * <p>Splits the provided text into an array with a maximum length,
7849     * separators specified, preserving all tokens, including empty tokens
7850     * created by adjacent separators.</p>
7851     *
7852     * <p>The separator is not included in the returned String array.
7853     * Adjacent separators are treated as separators for empty tokens.
7854     * Adjacent separators are treated as one separator.</p>
7855     *
7856     * <p>A {@code null} input String returns {@code null}.
7857     * A {@code null} separatorChars splits on whitespace.</p>
7858     *
7859     * <p>If more than {@code max} delimited substrings are found, the last
7860     * returned string includes all characters after the first {@code max - 1}
7861     * returned strings (including separator characters).</p>
7862     *
7863     * <pre>
7864     * StringUtils.splitPreserveAllTokens(null, *, *)            = null
7865     * StringUtils.splitPreserveAllTokens("", *, *)              = []
7866     * StringUtils.splitPreserveAllTokens("ab de fg", null, 0)   = ["ab", "de", "fg"]
7867     * StringUtils.splitPreserveAllTokens("ab   de fg", null, 0) = ["ab", "", "", "de", "fg"]
7868     * StringUtils.splitPreserveAllTokens("ab:cd:ef", ":", 0)    = ["ab", "cd", "ef"]
7869     * StringUtils.splitPreserveAllTokens("ab:cd:ef", ":", 2)    = ["ab", "cd:ef"]
7870     * StringUtils.splitPreserveAllTokens("ab   de fg", null, 2) = ["ab", "  de fg"]
7871     * StringUtils.splitPreserveAllTokens("ab   de fg", null, 3) = ["ab", "", " de fg"]
7872     * StringUtils.splitPreserveAllTokens("ab   de fg", null, 4) = ["ab", "", "", "de fg"]
7873     * </pre>
7874     *
7875     * @param str  the String to parse, may be {@code null}
7876     * @param separatorChars  the characters used as the delimiters,
7877     *  {@code null} splits on whitespace
7878     * @param max  the maximum number of elements to include in the
7879     *  array. A zero or negative value implies no limit
7880     * @return an array of parsed Strings, {@code null} if null String input
7881     * @since 2.1
7882     */
7883    public static String[] splitPreserveAllTokens(final String str, final String separatorChars, final int max) {
7884        return splitWorker(str, separatorChars, max, true);
7885    }
7886
7887    /**
7888     * Performs the logic for the {@code split} and
7889     * {@code splitPreserveAllTokens} methods that do not return a
7890     * maximum array length.
7891     *
7892     * @param str  the String to parse, may be {@code null}
7893     * @param separatorChar the separate character
7894     * @param preserveAllTokens if {@code true}, adjacent separators are
7895     * treated as empty token separators; if {@code false}, adjacent
7896     * separators are treated as one separator.
7897     * @return an array of parsed Strings, {@code null} if null String input
7898     */
7899    private static String[] splitWorker(final String str, final char separatorChar, final boolean preserveAllTokens) {
7900        // Performance tuned for 2.0 (JDK1.4)
7901
7902        if (str == null) {
7903            return null;
7904        }
7905        final int len = str.length();
7906        if (len == 0) {
7907            return ArrayUtils.EMPTY_STRING_ARRAY;
7908        }
7909        final List<String> list = new ArrayList<>();
7910        int i = 0, start = 0;
7911        boolean match = false;
7912        boolean lastMatch = false;
7913        while (i < len) {
7914            if (str.charAt(i) == separatorChar) {
7915                if (match || preserveAllTokens) {
7916                    list.add(str.substring(start, i));
7917                    match = false;
7918                    lastMatch = true;
7919                }
7920                start = ++i;
7921                continue;
7922            }
7923            lastMatch = false;
7924            match = true;
7925            i++;
7926        }
7927        if (match || preserveAllTokens && lastMatch) {
7928            list.add(str.substring(start, i));
7929        }
7930        return list.toArray(ArrayUtils.EMPTY_STRING_ARRAY);
7931    }
7932
7933    /**
7934     * Performs the logic for the {@code split} and
7935     * {@code splitPreserveAllTokens} methods that return a maximum array
7936     * length.
7937     *
7938     * @param str  the String to parse, may be {@code null}
7939     * @param separatorChars the separate character
7940     * @param max  the maximum number of elements to include in the
7941     *  array. A zero or negative value implies no limit.
7942     * @param preserveAllTokens if {@code true}, adjacent separators are
7943     * treated as empty token separators; if {@code false}, adjacent
7944     * separators are treated as one separator.
7945     * @return an array of parsed Strings, {@code null} if null String input
7946     */
7947    private static String[] splitWorker(final String str, final String separatorChars, final int max, final boolean preserveAllTokens) {
7948        // Performance tuned for 2.0 (JDK1.4)
7949        // Direct code is quicker than StringTokenizer.
7950        // Also, StringTokenizer uses isSpace() not isWhitespace()
7951
7952        if (str == null) {
7953            return null;
7954        }
7955        final int len = str.length();
7956        if (len == 0) {
7957            return ArrayUtils.EMPTY_STRING_ARRAY;
7958        }
7959        final List<String> list = new ArrayList<>();
7960        int sizePlus1 = 1;
7961        int i = 0, start = 0;
7962        boolean match = false;
7963        boolean lastMatch = false;
7964        if (separatorChars == null) {
7965            // Null separator means use whitespace
7966            while (i < len) {
7967                if (Character.isWhitespace(str.charAt(i))) {
7968                    if (match || preserveAllTokens) {
7969                        lastMatch = true;
7970                        if (sizePlus1++ == max) {
7971                            i = len;
7972                            lastMatch = false;
7973                        }
7974                        list.add(str.substring(start, i));
7975                        match = false;
7976                    }
7977                    start = ++i;
7978                    continue;
7979                }
7980                lastMatch = false;
7981                match = true;
7982                i++;
7983            }
7984        } else if (separatorChars.length() == 1) {
7985            // Optimise 1 character case
7986            final char sep = separatorChars.charAt(0);
7987            while (i < len) {
7988                if (str.charAt(i) == sep) {
7989                    if (match || preserveAllTokens) {
7990                        lastMatch = true;
7991                        if (sizePlus1++ == max) {
7992                            i = len;
7993                            lastMatch = false;
7994                        }
7995                        list.add(str.substring(start, i));
7996                        match = false;
7997                    }
7998                    start = ++i;
7999                    continue;
8000                }
8001                lastMatch = false;
8002                match = true;
8003                i++;
8004            }
8005        } else {
8006            // standard case
8007            while (i < len) {
8008                if (separatorChars.indexOf(str.charAt(i)) >= 0) {
8009                    if (match || preserveAllTokens) {
8010                        lastMatch = true;
8011                        if (sizePlus1++ == max) {
8012                            i = len;
8013                            lastMatch = false;
8014                        }
8015                        list.add(str.substring(start, i));
8016                        match = false;
8017                    }
8018                    start = ++i;
8019                    continue;
8020                }
8021                lastMatch = false;
8022                match = true;
8023                i++;
8024            }
8025        }
8026        if (match || preserveAllTokens && lastMatch) {
8027            list.add(str.substring(start, i));
8028        }
8029        return list.toArray(ArrayUtils.EMPTY_STRING_ARRAY);
8030    }
8031
8032    /**
8033     * <p>Check if a CharSequence starts with a specified prefix.</p>
8034     *
8035     * <p>{@code null}s are handled without exceptions. Two {@code null}
8036     * references are considered to be equal. The comparison is case sensitive.</p>
8037     *
8038     * <pre>
8039     * StringUtils.startsWith(null, null)      = true
8040     * StringUtils.startsWith(null, "abc")     = false
8041     * StringUtils.startsWith("abcdef", null)  = false
8042     * StringUtils.startsWith("abcdef", "abc") = true
8043     * StringUtils.startsWith("ABCDEF", "abc") = false
8044     * </pre>
8045     *
8046     * @see java.lang.String#startsWith(String)
8047     * @param str  the CharSequence to check, may be null
8048     * @param prefix the prefix to find, may be null
8049     * @return {@code true} if the CharSequence starts with the prefix, case sensitive, or
8050     *  both {@code null}
8051     * @since 2.4
8052     * @since 3.0 Changed signature from startsWith(String, String) to startsWith(CharSequence, CharSequence)
8053     */
8054    public static boolean startsWith(final CharSequence str, final CharSequence prefix) {
8055        return startsWith(str, prefix, false);
8056    }
8057
8058    /**
8059     * <p>Check if a CharSequence starts with a specified prefix (optionally case insensitive).</p>
8060     *
8061     * @see java.lang.String#startsWith(String)
8062     * @param str  the CharSequence to check, may be null
8063     * @param prefix the prefix to find, may be null
8064     * @param ignoreCase indicates whether the compare should ignore case
8065     *  (case insensitive) or not.
8066     * @return {@code true} if the CharSequence starts with the prefix or
8067     *  both {@code null}
8068     */
8069    private static boolean startsWith(final CharSequence str, final CharSequence prefix, final boolean ignoreCase) {
8070        if (str == null || prefix == null) {
8071            return str == prefix;
8072        }
8073        if (prefix.length() > str.length()) {
8074            return false;
8075        }
8076        return CharSequenceUtils.regionMatches(str, ignoreCase, 0, prefix, 0, prefix.length());
8077    }
8078
8079    /**
8080     * <p>Check if a CharSequence starts with any of the provided case-sensitive prefixes.</p>
8081     *
8082     * <pre>
8083     * StringUtils.startsWithAny(null, null)      = false
8084     * StringUtils.startsWithAny(null, new String[] {"abc"})  = false
8085     * StringUtils.startsWithAny("abcxyz", null)     = false
8086     * StringUtils.startsWithAny("abcxyz", new String[] {""}) = true
8087     * StringUtils.startsWithAny("abcxyz", new String[] {"abc"}) = true
8088     * StringUtils.startsWithAny("abcxyz", new String[] {null, "xyz", "abc"}) = true
8089     * StringUtils.startsWithAny("abcxyz", null, "xyz", "ABCX") = false
8090     * StringUtils.startsWithAny("ABCXYZ", null, "xyz", "abc") = false
8091     * </pre>
8092     *
8093     * @param sequence the CharSequence to check, may be null
8094     * @param searchStrings the case-sensitive CharSequence prefixes, may be empty or contain {@code null}
8095     * @see StringUtils#startsWith(CharSequence, CharSequence)
8096     * @return {@code true} if the input {@code sequence} is {@code null} AND no {@code searchStrings} are provided, or
8097     *   the input {@code sequence} begins with any of the provided case-sensitive {@code searchStrings}.
8098     * @since 2.5
8099     * @since 3.0 Changed signature from startsWithAny(String, String[]) to startsWithAny(CharSequence, CharSequence...)
8100     */
8101    public static boolean startsWithAny(final CharSequence sequence, final CharSequence... searchStrings) {
8102        if (isEmpty(sequence) || ArrayUtils.isEmpty(searchStrings)) {
8103            return false;
8104        }
8105        for (final CharSequence searchString : searchStrings) {
8106            if (startsWith(sequence, searchString)) {
8107                return true;
8108            }
8109        }
8110        return false;
8111    }
8112
8113    /**
8114     * <p>Case insensitive check if a CharSequence starts with a specified prefix.</p>
8115     *
8116     * <p>{@code null}s are handled without exceptions. Two {@code null}
8117     * references are considered to be equal. The comparison is case insensitive.</p>
8118     *
8119     * <pre>
8120     * StringUtils.startsWithIgnoreCase(null, null)      = true
8121     * StringUtils.startsWithIgnoreCase(null, "abc")     = false
8122     * StringUtils.startsWithIgnoreCase("abcdef", null)  = false
8123     * StringUtils.startsWithIgnoreCase("abcdef", "abc") = true
8124     * StringUtils.startsWithIgnoreCase("ABCDEF", "abc") = true
8125     * </pre>
8126     *
8127     * @see java.lang.String#startsWith(String)
8128     * @param str  the CharSequence to check, may be null
8129     * @param prefix the prefix to find, may be null
8130     * @return {@code true} if the CharSequence starts with the prefix, case insensitive, or
8131     *  both {@code null}
8132     * @since 2.4
8133     * @since 3.0 Changed signature from startsWithIgnoreCase(String, String) to startsWithIgnoreCase(CharSequence, CharSequence)
8134     */
8135    public static boolean startsWithIgnoreCase(final CharSequence str, final CharSequence prefix) {
8136        return startsWith(str, prefix, true);
8137    }
8138
8139    // Stripping
8140    //-----------------------------------------------------------------------
8141    /**
8142     * <p>Strips whitespace from the start and end of a String.</p>
8143     *
8144     * <p>This is similar to {@link #trim(String)} but removes whitespace.
8145     * Whitespace is defined by {@link Character#isWhitespace(char)}.</p>
8146     *
8147     * <p>A {@code null} input String returns {@code null}.</p>
8148     *
8149     * <pre>
8150     * StringUtils.strip(null)     = null
8151     * StringUtils.strip("")       = ""
8152     * StringUtils.strip("   ")    = ""
8153     * StringUtils.strip("abc")    = "abc"
8154     * StringUtils.strip("  abc")  = "abc"
8155     * StringUtils.strip("abc  ")  = "abc"
8156     * StringUtils.strip(" abc ")  = "abc"
8157     * StringUtils.strip(" ab c ") = "ab c"
8158     * </pre>
8159     *
8160     * @param str  the String to remove whitespace from, may be null
8161     * @return the stripped String, {@code null} if null String input
8162     */
8163    public static String strip(final String str) {
8164        return strip(str, null);
8165    }
8166
8167    /**
8168     * <p>Strips any of a set of characters from the start and end of a String.
8169     * This is similar to {@link String#trim()} but allows the characters
8170     * to be stripped to be controlled.</p>
8171     *
8172     * <p>A {@code null} input String returns {@code null}.
8173     * An empty string ("") input returns the empty string.</p>
8174     *
8175     * <p>If the stripChars String is {@code null}, whitespace is
8176     * stripped as defined by {@link Character#isWhitespace(char)}.
8177     * Alternatively use {@link #strip(String)}.</p>
8178     *
8179     * <pre>
8180     * StringUtils.strip(null, *)          = null
8181     * StringUtils.strip("", *)            = ""
8182     * StringUtils.strip("abc", null)      = "abc"
8183     * StringUtils.strip("  abc", null)    = "abc"
8184     * StringUtils.strip("abc  ", null)    = "abc"
8185     * StringUtils.strip(" abc ", null)    = "abc"
8186     * StringUtils.strip("  abcyx", "xyz") = "  abc"
8187     * </pre>
8188     *
8189     * @param str  the String to remove characters from, may be null
8190     * @param stripChars  the characters to remove, null treated as whitespace
8191     * @return the stripped String, {@code null} if null String input
8192     */
8193    public static String strip(String str, final String stripChars) {
8194        if (isEmpty(str)) {
8195            return str;
8196        }
8197        str = stripStart(str, stripChars);
8198        return stripEnd(str, stripChars);
8199    }
8200
8201    /**
8202     * <p>Removes diacritics (~= accents) from a string. The case will not be altered.</p>
8203     * <p>For instance, '&agrave;' will be replaced by 'a'.</p>
8204     * <p>Note that ligatures will be left as is.</p>
8205     *
8206     * <pre>
8207     * StringUtils.stripAccents(null)                = null
8208     * StringUtils.stripAccents("")                  = ""
8209     * StringUtils.stripAccents("control")           = "control"
8210     * StringUtils.stripAccents("&eacute;clair")     = "eclair"
8211     * </pre>
8212     *
8213     * @param input String to be stripped
8214     * @return input text with diacritics removed
8215     *
8216     * @since 3.0
8217     */
8218    // 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).
8219    public static String stripAccents(final String input) {
8220        if (input == null) {
8221            return null;
8222        }
8223        final StringBuilder decomposed = new StringBuilder(Normalizer.normalize(input, Normalizer.Form.NFD));
8224        convertRemainingAccentCharacters(decomposed);
8225        // Note that this doesn't correctly remove ligatures...
8226        return STRIP_ACCENTS_PATTERN.matcher(decomposed).replaceAll(EMPTY);
8227    }
8228
8229    // StripAll
8230    //-----------------------------------------------------------------------
8231    /**
8232     * <p>Strips whitespace from the start and end of every String in an array.
8233     * Whitespace is defined by {@link Character#isWhitespace(char)}.</p>
8234     *
8235     * <p>A new array is returned each time, except for length zero.
8236     * A {@code null} array will return {@code null}.
8237     * An empty array will return itself.
8238     * A {@code null} array entry will be ignored.</p>
8239     *
8240     * <pre>
8241     * StringUtils.stripAll(null)             = null
8242     * StringUtils.stripAll([])               = []
8243     * StringUtils.stripAll(["abc", "  abc"]) = ["abc", "abc"]
8244     * StringUtils.stripAll(["abc  ", null])  = ["abc", null]
8245     * </pre>
8246     *
8247     * @param strs  the array to remove whitespace from, may be null
8248     * @return the stripped Strings, {@code null} if null array input
8249     */
8250    public static String[] stripAll(final String... strs) {
8251        return stripAll(strs, null);
8252    }
8253
8254    /**
8255     * <p>Strips any of a set of characters from the start and end of every
8256     * String in an array.</p>
8257     * <p>Whitespace is defined by {@link Character#isWhitespace(char)}.</p>
8258     *
8259     * <p>A new array is returned each time, except for length zero.
8260     * A {@code null} array will return {@code null}.
8261     * An empty array will return itself.
8262     * A {@code null} array entry will be ignored.
8263     * A {@code null} stripChars will strip whitespace as defined by
8264     * {@link Character#isWhitespace(char)}.</p>
8265     *
8266     * <pre>
8267     * StringUtils.stripAll(null, *)                = null
8268     * StringUtils.stripAll([], *)                  = []
8269     * StringUtils.stripAll(["abc", "  abc"], null) = ["abc", "abc"]
8270     * StringUtils.stripAll(["abc  ", null], null)  = ["abc", null]
8271     * StringUtils.stripAll(["abc  ", null], "yz")  = ["abc  ", null]
8272     * StringUtils.stripAll(["yabcz", null], "yz")  = ["abc", null]
8273     * </pre>
8274     *
8275     * @param strs  the array to remove characters from, may be null
8276     * @param stripChars  the characters to remove, null treated as whitespace
8277     * @return the stripped Strings, {@code null} if null array input
8278     */
8279    public static String[] stripAll(final String[] strs, final String stripChars) {
8280        final int strsLen = ArrayUtils.getLength(strs);
8281        if (strsLen == 0) {
8282            return strs;
8283        }
8284        final String[] newArr = new String[strsLen];
8285        for (int i = 0; i < strsLen; i++) {
8286            newArr[i] = strip(strs[i], stripChars);
8287        }
8288        return newArr;
8289    }
8290
8291    /**
8292     * <p>Strips any of a set of characters from the end of a String.</p>
8293     *
8294     * <p>A {@code null} input String returns {@code null}.
8295     * An empty string ("") input returns the empty string.</p>
8296     *
8297     * <p>If the stripChars String is {@code null}, whitespace is
8298     * stripped as defined by {@link Character#isWhitespace(char)}.</p>
8299     *
8300     * <pre>
8301     * StringUtils.stripEnd(null, *)          = null
8302     * StringUtils.stripEnd("", *)            = ""
8303     * StringUtils.stripEnd("abc", "")        = "abc"
8304     * StringUtils.stripEnd("abc", null)      = "abc"
8305     * StringUtils.stripEnd("  abc", null)    = "  abc"
8306     * StringUtils.stripEnd("abc  ", null)    = "abc"
8307     * StringUtils.stripEnd(" abc ", null)    = " abc"
8308     * StringUtils.stripEnd("  abcyx", "xyz") = "  abc"
8309     * StringUtils.stripEnd("120.00", ".0")   = "12"
8310     * </pre>
8311     *
8312     * @param str  the String to remove characters from, may be null
8313     * @param stripChars  the set of characters to remove, null treated as whitespace
8314     * @return the stripped String, {@code null} if null String input
8315     */
8316    public static String stripEnd(final String str, final String stripChars) {
8317        int end = length(str);
8318        if (end == 0) {
8319            return str;
8320        }
8321
8322        if (stripChars == null) {
8323            while (end != 0 && Character.isWhitespace(str.charAt(end - 1))) {
8324                end--;
8325            }
8326        } else if (stripChars.isEmpty()) {
8327            return str;
8328        } else {
8329            while (end != 0 && stripChars.indexOf(str.charAt(end - 1)) != INDEX_NOT_FOUND) {
8330                end--;
8331            }
8332        }
8333        return str.substring(0, end);
8334    }
8335
8336    /**
8337     * <p>Strips any of a set of characters from the start of a String.</p>
8338     *
8339     * <p>A {@code null} input String returns {@code null}.
8340     * An empty string ("") input returns the empty string.</p>
8341     *
8342     * <p>If the stripChars String is {@code null}, whitespace is
8343     * stripped as defined by {@link Character#isWhitespace(char)}.</p>
8344     *
8345     * <pre>
8346     * StringUtils.stripStart(null, *)          = null
8347     * StringUtils.stripStart("", *)            = ""
8348     * StringUtils.stripStart("abc", "")        = "abc"
8349     * StringUtils.stripStart("abc", null)      = "abc"
8350     * StringUtils.stripStart("  abc", null)    = "abc"
8351     * StringUtils.stripStart("abc  ", null)    = "abc  "
8352     * StringUtils.stripStart(" abc ", null)    = "abc "
8353     * StringUtils.stripStart("yxabc  ", "xyz") = "abc  "
8354     * </pre>
8355     *
8356     * @param str  the String to remove characters from, may be null
8357     * @param stripChars  the characters to remove, null treated as whitespace
8358     * @return the stripped String, {@code null} if null String input
8359     */
8360    public static String stripStart(final String str, final String stripChars) {
8361        final int strLen = length(str);
8362        if (strLen == 0) {
8363            return str;
8364        }
8365        int start = 0;
8366        if (stripChars == null) {
8367            while (start != strLen && Character.isWhitespace(str.charAt(start))) {
8368                start++;
8369            }
8370        } else if (stripChars.isEmpty()) {
8371            return str;
8372        } else {
8373            while (start != strLen && stripChars.indexOf(str.charAt(start)) != INDEX_NOT_FOUND) {
8374                start++;
8375            }
8376        }
8377        return str.substring(start);
8378    }
8379
8380    /**
8381     * <p>Strips whitespace from the start and end of a String  returning
8382     * an empty String if {@code null} input.</p>
8383     *
8384     * <p>This is similar to {@link #trimToEmpty(String)} but removes whitespace.
8385     * Whitespace is defined by {@link Character#isWhitespace(char)}.</p>
8386     *
8387     * <pre>
8388     * StringUtils.stripToEmpty(null)     = ""
8389     * StringUtils.stripToEmpty("")       = ""
8390     * StringUtils.stripToEmpty("   ")    = ""
8391     * StringUtils.stripToEmpty("abc")    = "abc"
8392     * StringUtils.stripToEmpty("  abc")  = "abc"
8393     * StringUtils.stripToEmpty("abc  ")  = "abc"
8394     * StringUtils.stripToEmpty(" abc ")  = "abc"
8395     * StringUtils.stripToEmpty(" ab c ") = "ab c"
8396     * </pre>
8397     *
8398     * @param str  the String to be stripped, may be null
8399     * @return the trimmed String, or an empty String if {@code null} input
8400     * @since 2.0
8401     */
8402    public static String stripToEmpty(final String str) {
8403        return str == null ? EMPTY : strip(str, null);
8404    }
8405
8406    /**
8407     * <p>Strips whitespace from the start and end of a String  returning
8408     * {@code null} if the String is empty ("") after the strip.</p>
8409     *
8410     * <p>This is similar to {@link #trimToNull(String)} but removes whitespace.
8411     * Whitespace is defined by {@link Character#isWhitespace(char)}.</p>
8412     *
8413     * <pre>
8414     * StringUtils.stripToNull(null)     = null
8415     * StringUtils.stripToNull("")       = null
8416     * StringUtils.stripToNull("   ")    = null
8417     * StringUtils.stripToNull("abc")    = "abc"
8418     * StringUtils.stripToNull("  abc")  = "abc"
8419     * StringUtils.stripToNull("abc  ")  = "abc"
8420     * StringUtils.stripToNull(" abc ")  = "abc"
8421     * StringUtils.stripToNull(" ab c ") = "ab c"
8422     * </pre>
8423     *
8424     * @param str  the String to be stripped, may be null
8425     * @return the stripped String,
8426     *  {@code null} if whitespace, empty or null String input
8427     * @since 2.0
8428     */
8429    public static String stripToNull(String str) {
8430        if (str == null) {
8431            return null;
8432        }
8433        str = strip(str, null);
8434        return str.isEmpty() ? null : str;
8435    }
8436
8437    // Substring
8438    //-----------------------------------------------------------------------
8439    /**
8440     * <p>Gets a substring from the specified String avoiding exceptions.</p>
8441     *
8442     * <p>A negative start position can be used to start {@code n}
8443     * characters from the end of the String.</p>
8444     *
8445     * <p>A {@code null} String will return {@code null}.
8446     * An empty ("") String will return "".</p>
8447     *
8448     * <pre>
8449     * StringUtils.substring(null, *)   = null
8450     * StringUtils.substring("", *)     = ""
8451     * StringUtils.substring("abc", 0)  = "abc"
8452     * StringUtils.substring("abc", 2)  = "c"
8453     * StringUtils.substring("abc", 4)  = ""
8454     * StringUtils.substring("abc", -2) = "bc"
8455     * StringUtils.substring("abc", -4) = "abc"
8456     * </pre>
8457     *
8458     * @param str  the String to get the substring from, may be null
8459     * @param start  the position to start from, negative means
8460     *  count back from the end of the String by this many characters
8461     * @return substring from start position, {@code null} if null String input
8462     */
8463    public static String substring(final String str, int start) {
8464        if (str == null) {
8465            return null;
8466        }
8467
8468        // handle negatives, which means last n characters
8469        if (start < 0) {
8470            start = str.length() + start; // remember start is negative
8471        }
8472
8473        if (start < 0) {
8474            start = 0;
8475        }
8476        if (start > str.length()) {
8477            return EMPTY;
8478        }
8479
8480        return str.substring(start);
8481    }
8482
8483    /**
8484     * <p>Gets a substring from the specified String avoiding exceptions.</p>
8485     *
8486     * <p>A negative start position can be used to start/end {@code n}
8487     * characters from the end of the String.</p>
8488     *
8489     * <p>The returned substring starts with the character in the {@code start}
8490     * position and ends before the {@code end} position. All position counting is
8491     * zero-based -- i.e., to start at the beginning of the string use
8492     * {@code start = 0}. Negative start and end positions can be used to
8493     * specify offsets relative to the end of the String.</p>
8494     *
8495     * <p>If {@code start} is not strictly to the left of {@code end}, ""
8496     * is returned.</p>
8497     *
8498     * <pre>
8499     * StringUtils.substring(null, *, *)    = null
8500     * StringUtils.substring("", * ,  *)    = "";
8501     * StringUtils.substring("abc", 0, 2)   = "ab"
8502     * StringUtils.substring("abc", 2, 0)   = ""
8503     * StringUtils.substring("abc", 2, 4)   = "c"
8504     * StringUtils.substring("abc", 4, 6)   = ""
8505     * StringUtils.substring("abc", 2, 2)   = ""
8506     * StringUtils.substring("abc", -2, -1) = "b"
8507     * StringUtils.substring("abc", -4, 2)  = "ab"
8508     * </pre>
8509     *
8510     * @param str  the String to get the substring from, may be null
8511     * @param start  the position to start from, negative means
8512     *  count back from the end of the String by this many characters
8513     * @param end  the position to end at (exclusive), negative means
8514     *  count back from the end of the String by this many characters
8515     * @return substring from start position to end position,
8516     *  {@code null} if null String input
8517     */
8518    public static String substring(final String str, int start, int end) {
8519        if (str == null) {
8520            return null;
8521        }
8522
8523        // handle negatives
8524        if (end < 0) {
8525            end = str.length() + end; // remember end is negative
8526        }
8527        if (start < 0) {
8528            start = str.length() + start; // remember start is negative
8529        }
8530
8531        // check length next
8532        if (end > str.length()) {
8533            end = str.length();
8534        }
8535
8536        // if start is greater than end, return ""
8537        if (start > end) {
8538            return EMPTY;
8539        }
8540
8541        if (start < 0) {
8542            start = 0;
8543        }
8544        if (end < 0) {
8545            end = 0;
8546        }
8547
8548        return str.substring(start, end);
8549    }
8550
8551    /**
8552     * <p>Gets the substring after the first occurrence of a separator.
8553     * The separator is not returned.</p>
8554     *
8555     * <p>A {@code null} string input will return {@code null}.
8556     * An empty ("") string input will return the empty string.
8557     *
8558     * <p>If nothing is found, the empty string is returned.</p>
8559     *
8560     * <pre>
8561     * StringUtils.substringAfter(null, *)      = null
8562     * StringUtils.substringAfter("", *)        = ""
8563     * StringUtils.substringAfter("abc", 'a')   = "bc"
8564     * StringUtils.substringAfter("abcba", 'b') = "cba"
8565     * StringUtils.substringAfter("abc", 'c')   = ""
8566     * StringUtils.substringAfter("abc", 'd')   = ""
8567     * StringUtils.substringAfter(" abc", 32)   = "abc"
8568     * </pre>
8569     *
8570     * @param str  the String to get a substring from, may be null
8571     * @param separator  the character to search.
8572     * @return the substring after the first occurrence of the separator,
8573     *  {@code null} if null String input
8574     * @since 3.11
8575     */
8576    public static String substringAfter(final String str, final int separator) {
8577        if (isEmpty(str)) {
8578            return str;
8579        }
8580        final int pos = str.indexOf(separator);
8581        if (pos == INDEX_NOT_FOUND) {
8582            return EMPTY;
8583        }
8584        return str.substring(pos + 1);
8585    }
8586
8587    /**
8588     * <p>Gets the substring after the first occurrence of a separator.
8589     * The separator is not returned.</p>
8590     *
8591     * <p>A {@code null} string input will return {@code null}.
8592     * An empty ("") string input will return the empty string.
8593     * A {@code null} separator will return the empty string if the
8594     * input string is not {@code null}.</p>
8595     *
8596     * <p>If nothing is found, the empty string is returned.</p>
8597     *
8598     * <pre>
8599     * StringUtils.substringAfter(null, *)      = null
8600     * StringUtils.substringAfter("", *)        = ""
8601     * StringUtils.substringAfter(*, null)      = ""
8602     * StringUtils.substringAfter("abc", "a")   = "bc"
8603     * StringUtils.substringAfter("abcba", "b") = "cba"
8604     * StringUtils.substringAfter("abc", "c")   = ""
8605     * StringUtils.substringAfter("abc", "d")   = ""
8606     * StringUtils.substringAfter("abc", "")    = "abc"
8607     * </pre>
8608     *
8609     * @param str  the String to get a substring from, may be null
8610     * @param separator  the String to search for, may be null
8611     * @return the substring after the first occurrence of the separator,
8612     *  {@code null} if null String input
8613     * @since 2.0
8614     */
8615    public static String substringAfter(final String str, final String separator) {
8616        if (isEmpty(str)) {
8617            return str;
8618        }
8619        if (separator == null) {
8620            return EMPTY;
8621        }
8622        final int pos = str.indexOf(separator);
8623        if (pos == INDEX_NOT_FOUND) {
8624            return EMPTY;
8625        }
8626        return str.substring(pos + separator.length());
8627    }
8628
8629    // startsWith
8630    //-----------------------------------------------------------------------
8631
8632    /**
8633     * <p>Gets the substring after the last occurrence of a separator.
8634     * The separator is not returned.</p>
8635     *
8636     * <p>A {@code null} string input will return {@code null}.
8637     * An empty ("") string input will return the empty string.
8638     *
8639     * <p>If nothing is found, the empty string is returned.</p>
8640     *
8641     * <pre>
8642     * StringUtils.substringAfterLast(null, *)      = null
8643     * StringUtils.substringAfterLast("", *)        = ""
8644     * StringUtils.substringAfterLast("abc", 'a')   = "bc"
8645     * StringUtils.substringAfterLast(" bc", 32)    = "bc"
8646     * StringUtils.substringAfterLast("abcba", 'b') = "a"
8647     * StringUtils.substringAfterLast("abc", 'c')   = ""
8648     * StringUtils.substringAfterLast("a", 'a')     = ""
8649     * StringUtils.substringAfterLast("a", 'z')     = ""
8650     * </pre>
8651     *
8652     * @param str  the String to get a substring from, may be null
8653     * @param separator  the String to search for, may be null
8654     * @return the substring after the last occurrence of the separator,
8655     *  {@code null} if null String input
8656     * @since 3.11
8657     */
8658    public static String substringAfterLast(final String str, final int separator) {
8659        if (isEmpty(str)) {
8660            return str;
8661        }
8662        final int pos = str.lastIndexOf(separator);
8663        if (pos == INDEX_NOT_FOUND || pos == str.length() - 1) {
8664            return EMPTY;
8665        }
8666        return str.substring(pos + 1);
8667    }
8668
8669    /**
8670     * <p>Gets the substring after the last occurrence of a separator.
8671     * The separator is not returned.</p>
8672     *
8673     * <p>A {@code null} string input will return {@code null}.
8674     * An empty ("") string input will return the empty string.
8675     * An empty or {@code null} separator will return the empty string if
8676     * the input string is not {@code null}.</p>
8677     *
8678     * <p>If nothing is found, the empty string is returned.</p>
8679     *
8680     * <pre>
8681     * StringUtils.substringAfterLast(null, *)      = null
8682     * StringUtils.substringAfterLast("", *)        = ""
8683     * StringUtils.substringAfterLast(*, "")        = ""
8684     * StringUtils.substringAfterLast(*, null)      = ""
8685     * StringUtils.substringAfterLast("abc", "a")   = "bc"
8686     * StringUtils.substringAfterLast("abcba", "b") = "a"
8687     * StringUtils.substringAfterLast("abc", "c")   = ""
8688     * StringUtils.substringAfterLast("a", "a")     = ""
8689     * StringUtils.substringAfterLast("a", "z")     = ""
8690     * </pre>
8691     *
8692     * @param str  the String to get a substring from, may be null
8693     * @param separator  the String to search for, may be null
8694     * @return the substring after the last occurrence of the separator,
8695     *  {@code null} if null String input
8696     * @since 2.0
8697     */
8698    public static String substringAfterLast(final String str, final String separator) {
8699        if (isEmpty(str)) {
8700            return str;
8701        }
8702        if (isEmpty(separator)) {
8703            return EMPTY;
8704        }
8705        final int pos = str.lastIndexOf(separator);
8706        if (pos == INDEX_NOT_FOUND || pos == str.length() - separator.length()) {
8707            return EMPTY;
8708        }
8709        return str.substring(pos + separator.length());
8710    }
8711
8712    // SubStringAfter/SubStringBefore
8713    //-----------------------------------------------------------------------
8714    /**
8715     * <p>Gets the substring before the first occurrence of a separator.
8716     * The separator is not returned.</p>
8717     *
8718     * <p>A {@code null} string input will return {@code null}.
8719     * An empty ("") string input will return the empty string.
8720     * A {@code null} separator will return the input string.</p>
8721     *
8722     * <p>If nothing is found, the string input is returned.</p>
8723     *
8724     * <pre>
8725     * StringUtils.substringBefore(null, *)      = null
8726     * StringUtils.substringBefore("", *)        = ""
8727     * StringUtils.substringBefore("abc", "a")   = ""
8728     * StringUtils.substringBefore("abcba", "b") = "a"
8729     * StringUtils.substringBefore("abc", "c")   = "ab"
8730     * StringUtils.substringBefore("abc", "d")   = "abc"
8731     * StringUtils.substringBefore("abc", "")    = ""
8732     * StringUtils.substringBefore("abc", null)  = "abc"
8733     * </pre>
8734     *
8735     * @param str  the String to get a substring from, may be null
8736     * @param separator  the String to search for, may be null
8737     * @return the substring before the first occurrence of the separator,
8738     *  {@code null} if null String input
8739     * @since 2.0
8740     */
8741    public static String substringBefore(final String str, final String separator) {
8742        if (isEmpty(str) || separator == null) {
8743            return str;
8744        }
8745        if (separator.isEmpty()) {
8746            return EMPTY;
8747        }
8748        final int pos = str.indexOf(separator);
8749        if (pos == INDEX_NOT_FOUND) {
8750            return str;
8751        }
8752        return str.substring(0, pos);
8753    }
8754
8755    /**
8756     * <p>Gets the substring before the last occurrence of a separator.
8757     * The separator is not returned.</p>
8758     *
8759     * <p>A {@code null} string input will return {@code null}.
8760     * An empty ("") string input will return the empty string.
8761     * An empty or {@code null} separator will return the input string.</p>
8762     *
8763     * <p>If nothing is found, the string input is returned.</p>
8764     *
8765     * <pre>
8766     * StringUtils.substringBeforeLast(null, *)      = null
8767     * StringUtils.substringBeforeLast("", *)        = ""
8768     * StringUtils.substringBeforeLast("abcba", "b") = "abc"
8769     * StringUtils.substringBeforeLast("abc", "c")   = "ab"
8770     * StringUtils.substringBeforeLast("a", "a")     = ""
8771     * StringUtils.substringBeforeLast("a", "z")     = "a"
8772     * StringUtils.substringBeforeLast("a", null)    = "a"
8773     * StringUtils.substringBeforeLast("a", "")      = "a"
8774     * </pre>
8775     *
8776     * @param str  the String to get a substring from, may be null
8777     * @param separator  the String to search for, may be null
8778     * @return the substring before the last occurrence of the separator,
8779     *  {@code null} if null String input
8780     * @since 2.0
8781     */
8782    public static String substringBeforeLast(final String str, final String separator) {
8783        if (isEmpty(str) || isEmpty(separator)) {
8784            return str;
8785        }
8786        final int pos = str.lastIndexOf(separator);
8787        if (pos == INDEX_NOT_FOUND) {
8788            return str;
8789        }
8790        return str.substring(0, pos);
8791    }
8792
8793    // Substring between
8794    //-----------------------------------------------------------------------
8795    /**
8796     * <p>Gets the String that is nested in between two instances of the
8797     * same String.</p>
8798     *
8799     * <p>A {@code null} input String returns {@code null}.
8800     * A {@code null} tag returns {@code null}.</p>
8801     *
8802     * <pre>
8803     * StringUtils.substringBetween(null, *)            = null
8804     * StringUtils.substringBetween("", "")             = ""
8805     * StringUtils.substringBetween("", "tag")          = null
8806     * StringUtils.substringBetween("tagabctag", null)  = null
8807     * StringUtils.substringBetween("tagabctag", "")    = ""
8808     * StringUtils.substringBetween("tagabctag", "tag") = "abc"
8809     * </pre>
8810     *
8811     * @param str  the String containing the substring, may be null
8812     * @param tag  the String before and after the substring, may be null
8813     * @return the substring, {@code null} if no match
8814     * @since 2.0
8815     */
8816    public static String substringBetween(final String str, final String tag) {
8817        return substringBetween(str, tag, tag);
8818    }
8819
8820    // endsWith
8821    //-----------------------------------------------------------------------
8822
8823    /**
8824     * <p>Gets the String that is nested in between two Strings.
8825     * Only the first match is returned.</p>
8826     *
8827     * <p>A {@code null} input String returns {@code null}.
8828     * A {@code null} open/close returns {@code null} (no match).
8829     * An empty ("") open and close returns an empty string.</p>
8830     *
8831     * <pre>
8832     * StringUtils.substringBetween("wx[b]yz", "[", "]") = "b"
8833     * StringUtils.substringBetween(null, *, *)          = null
8834     * StringUtils.substringBetween(*, null, *)          = null
8835     * StringUtils.substringBetween(*, *, null)          = null
8836     * StringUtils.substringBetween("", "", "")          = ""
8837     * StringUtils.substringBetween("", "", "]")         = null
8838     * StringUtils.substringBetween("", "[", "]")        = null
8839     * StringUtils.substringBetween("yabcz", "", "")     = ""
8840     * StringUtils.substringBetween("yabcz", "y", "z")   = "abc"
8841     * StringUtils.substringBetween("yabczyabcz", "y", "z")   = "abc"
8842     * </pre>
8843     *
8844     * @param str  the String containing the substring, may be null
8845     * @param open  the String before the substring, may be null
8846     * @param close  the String after the substring, may be null
8847     * @return the substring, {@code null} if no match
8848     * @since 2.0
8849     */
8850    public static String substringBetween(final String str, final String open, final String close) {
8851        if (!ObjectUtils.allNotNull(str, open, close)) {
8852            return null;
8853        }
8854        final int start = str.indexOf(open);
8855        if (start != INDEX_NOT_FOUND) {
8856            final int end = str.indexOf(close, start + open.length());
8857            if (end != INDEX_NOT_FOUND) {
8858                return str.substring(start + open.length(), end);
8859            }
8860        }
8861        return null;
8862    }
8863
8864    /**
8865     * <p>Searches a String for substrings delimited by a start and end tag,
8866     * returning all matching substrings in an array.</p>
8867     *
8868     * <p>A {@code null} input String returns {@code null}.
8869     * A {@code null} open/close returns {@code null} (no match).
8870     * An empty ("") open/close returns {@code null} (no match).</p>
8871     *
8872     * <pre>
8873     * StringUtils.substringsBetween("[a][b][c]", "[", "]") = ["a","b","c"]
8874     * StringUtils.substringsBetween(null, *, *)            = null
8875     * StringUtils.substringsBetween(*, null, *)            = null
8876     * StringUtils.substringsBetween(*, *, null)            = null
8877     * StringUtils.substringsBetween("", "[", "]")          = []
8878     * </pre>
8879     *
8880     * @param str  the String containing the substrings, null returns null, empty returns empty
8881     * @param open  the String identifying the start of the substring, empty returns null
8882     * @param close  the String identifying the end of the substring, empty returns null
8883     * @return a String Array of substrings, or {@code null} if no match
8884     * @since 2.3
8885     */
8886    public static String[] substringsBetween(final String str, final String open, final String close) {
8887        if (str == null || isEmpty(open) || isEmpty(close)) {
8888            return null;
8889        }
8890        final int strLen = str.length();
8891        if (strLen == 0) {
8892            return ArrayUtils.EMPTY_STRING_ARRAY;
8893        }
8894        final int closeLen = close.length();
8895        final int openLen = open.length();
8896        final List<String> list = new ArrayList<>();
8897        int pos = 0;
8898        while (pos < strLen - closeLen) {
8899            int start = str.indexOf(open, pos);
8900            if (start < 0) {
8901                break;
8902            }
8903            start += openLen;
8904            final int end = str.indexOf(close, start);
8905            if (end < 0) {
8906                break;
8907            }
8908            list.add(str.substring(start, end));
8909            pos = end + closeLen;
8910        }
8911        if (list.isEmpty()) {
8912            return null;
8913        }
8914        return list.toArray(ArrayUtils.EMPTY_STRING_ARRAY);
8915    }
8916
8917    /**
8918     * <p>Swaps the case of a String changing upper and title case to
8919     * lower case, and lower case to upper case.</p>
8920     *
8921     * <ul>
8922     *  <li>Upper case character converts to Lower case</li>
8923     *  <li>Title case character converts to Lower case</li>
8924     *  <li>Lower case character converts to Upper case</li>
8925     * </ul>
8926     *
8927     * <p>For a word based algorithm, see {@link org.apache.commons.lang3.text.WordUtils#swapCase(String)}.
8928     * A {@code null} input String returns {@code null}.</p>
8929     *
8930     * <pre>
8931     * StringUtils.swapCase(null)                 = null
8932     * StringUtils.swapCase("")                   = ""
8933     * StringUtils.swapCase("The dog has a BONE") = "tHE DOG HAS A bone"
8934     * </pre>
8935     *
8936     * <p>NOTE: This method changed in Lang version 2.0.
8937     * It no longer performs a word based algorithm.
8938     * If you only use ASCII, you will notice no change.
8939     * That functionality is available in org.apache.commons.lang3.text.WordUtils.</p>
8940     *
8941     * @param str  the String to swap case, may be null
8942     * @return the changed String, {@code null} if null String input
8943     */
8944    public static String swapCase(final String str) {
8945        if (isEmpty(str)) {
8946            return str;
8947        }
8948
8949        final int strLen = str.length();
8950        final int[] newCodePoints = new int[strLen]; // cannot be longer than the char array
8951        int outOffset = 0;
8952        for (int i = 0; i < strLen; ) {
8953            final int oldCodepoint = str.codePointAt(i);
8954            final int newCodePoint;
8955            if (Character.isUpperCase(oldCodepoint) || Character.isTitleCase(oldCodepoint)) {
8956                newCodePoint = Character.toLowerCase(oldCodepoint);
8957            } else if (Character.isLowerCase(oldCodepoint)) {
8958                newCodePoint = Character.toUpperCase(oldCodepoint);
8959            } else {
8960                newCodePoint = oldCodepoint;
8961            }
8962            newCodePoints[outOffset++] = newCodePoint;
8963            i += Character.charCount(newCodePoint);
8964         }
8965        return new String(newCodePoints, 0, outOffset);
8966    }
8967
8968    /**
8969     * <p>Converts a {@code CharSequence} into an array of code points.</p>
8970     *
8971     * <p>Valid pairs of surrogate code units will be converted into a single supplementary
8972     * code point. Isolated surrogate code units (i.e. a high surrogate not followed by a low surrogate or
8973     * a low surrogate not preceded by a high surrogate) will be returned as-is.</p>
8974     *
8975     * <pre>
8976     * StringUtils.toCodePoints(null)   =  null
8977     * StringUtils.toCodePoints("")     =  []  // empty array
8978     * </pre>
8979     *
8980     * @param str the character sequence to convert
8981     * @return an array of code points
8982     * @since 3.6
8983     */
8984    public static int[] toCodePoints(final CharSequence str) {
8985        if (str == null) {
8986            return null;
8987        }
8988        if (str.length() == 0) {
8989            return ArrayUtils.EMPTY_INT_ARRAY;
8990        }
8991
8992        final String s = str.toString();
8993        final int[] result = new int[s.codePointCount(0, s.length())];
8994        int index = 0;
8995        for (int i = 0; i < result.length; i++) {
8996            result[i] = s.codePointAt(index);
8997            index += Character.charCount(result[i]);
8998        }
8999        return result;
9000    }
9001
9002    /**
9003     * Converts a {@code byte[]} to a String using the specified character encoding.
9004     *
9005     * @param bytes
9006     *            the byte array to read from
9007     * @param charset
9008     *            the encoding to use, if null then use the platform default
9009     * @return a new String
9010     * @throws NullPointerException
9011     *             if {@code bytes} is null
9012     * @since 3.2
9013     * @since 3.3 No longer throws {@link UnsupportedEncodingException}.
9014     */
9015    public static String toEncodedString(final byte[] bytes, final Charset charset) {
9016        return new String(bytes, Charsets.toCharset(charset));
9017    }
9018
9019    /**
9020     * Converts the given source String as a lower-case using the {@link Locale#ROOT} locale in a null-safe manner.
9021     *
9022     * @param source A source String or null.
9023     * @return the given source String as a lower-case using the {@link Locale#ROOT} locale or null.
9024     * @since 3.10
9025     */
9026    public static String toRootLowerCase(final String source) {
9027        return source == null ? null : source.toLowerCase(Locale.ROOT);
9028    }
9029
9030    /**
9031     * Converts the given source String as a upper-case using the {@link Locale#ROOT} locale in a null-safe manner.
9032     *
9033     * @param source A source String or null.
9034     * @return the given source String as a upper-case using the {@link Locale#ROOT} locale or null.
9035     * @since 3.10
9036     */
9037    public static String toRootUpperCase(final String source) {
9038        return source == null ? null : source.toUpperCase(Locale.ROOT);
9039    }
9040
9041    /**
9042     * Converts a {@code byte[]} to a String using the specified character encoding.
9043     *
9044     * @param bytes
9045     *            the byte array to read from
9046     * @param charsetName
9047     *            the encoding to use, if null then use the platform default
9048     * @return a new String
9049     * @throws UnsupportedEncodingException
9050     *             If the named charset is not supported
9051     * @throws NullPointerException
9052     *             if the input is null
9053     * @deprecated use {@link StringUtils#toEncodedString(byte[], Charset)} instead of String constants in your code
9054     * @since 3.1
9055     */
9056    @Deprecated
9057    public static String toString(final byte[] bytes, final String charsetName) throws UnsupportedEncodingException {
9058        return charsetName != null ? new String(bytes, charsetName) : new String(bytes, Charset.defaultCharset());
9059    }
9060
9061    // Trim
9062    //-----------------------------------------------------------------------
9063    /**
9064     * <p>Removes control characters (char &lt;= 32) from both
9065     * ends of this String, handling {@code null} by returning
9066     * {@code null}.</p>
9067     *
9068     * <p>The String is trimmed using {@link String#trim()}.
9069     * Trim removes start and end characters &lt;= 32.
9070     * To strip whitespace use {@link #strip(String)}.</p>
9071     *
9072     * <p>To trim your choice of characters, use the
9073     * {@link #strip(String, String)} methods.</p>
9074     *
9075     * <pre>
9076     * StringUtils.trim(null)          = null
9077     * StringUtils.trim("")            = ""
9078     * StringUtils.trim("     ")       = ""
9079     * StringUtils.trim("abc")         = "abc"
9080     * StringUtils.trim("    abc    ") = "abc"
9081     * </pre>
9082     *
9083     * @param str  the String to be trimmed, may be null
9084     * @return the trimmed string, {@code null} if null String input
9085     */
9086    public static String trim(final String str) {
9087        return str == null ? null : str.trim();
9088    }
9089
9090    /**
9091     * <p>Removes control characters (char &lt;= 32) from both
9092     * ends of this String returning an empty String ("") if the String
9093     * is empty ("") after the trim or if it is {@code null}.
9094     *
9095     * <p>The String is trimmed using {@link String#trim()}.
9096     * Trim removes start and end characters &lt;= 32.
9097     * To strip whitespace use {@link #stripToEmpty(String)}.</p>
9098     *
9099     * <pre>
9100     * StringUtils.trimToEmpty(null)          = ""
9101     * StringUtils.trimToEmpty("")            = ""
9102     * StringUtils.trimToEmpty("     ")       = ""
9103     * StringUtils.trimToEmpty("abc")         = "abc"
9104     * StringUtils.trimToEmpty("    abc    ") = "abc"
9105     * </pre>
9106     *
9107     * @param str  the String to be trimmed, may be null
9108     * @return the trimmed String, or an empty String if {@code null} input
9109     * @since 2.0
9110     */
9111    public static String trimToEmpty(final String str) {
9112        return str == null ? EMPTY : str.trim();
9113    }
9114
9115    /**
9116     * <p>Removes control characters (char &lt;= 32) from both
9117     * ends of this String returning {@code null} if the String is
9118     * empty ("") after the trim or if it is {@code null}.
9119     *
9120     * <p>The String is trimmed using {@link String#trim()}.
9121     * Trim removes start and end characters &lt;= 32.
9122     * To strip whitespace use {@link #stripToNull(String)}.</p>
9123     *
9124     * <pre>
9125     * StringUtils.trimToNull(null)          = null
9126     * StringUtils.trimToNull("")            = null
9127     * StringUtils.trimToNull("     ")       = null
9128     * StringUtils.trimToNull("abc")         = "abc"
9129     * StringUtils.trimToNull("    abc    ") = "abc"
9130     * </pre>
9131     *
9132     * @param str  the String to be trimmed, may be null
9133     * @return the trimmed String,
9134     *  {@code null} if only chars &lt;= 32, empty or null String input
9135     * @since 2.0
9136     */
9137    public static String trimToNull(final String str) {
9138        final String ts = trim(str);
9139        return isEmpty(ts) ? null : ts;
9140    }
9141
9142    /**
9143     * <p>Truncates a String. This will turn
9144     * "Now is the time for all good men" into "Now is the time for".</p>
9145     *
9146     * <p>Specifically:</p>
9147     * <ul>
9148     *   <li>If {@code str} is less than {@code maxWidth} characters
9149     *       long, return it.</li>
9150     *   <li>Else truncate it to {@code substring(str, 0, maxWidth)}.</li>
9151     *   <li>If {@code maxWidth} is less than {@code 0}, throw an
9152     *       {@code IllegalArgumentException}.</li>
9153     *   <li>In no case will it return a String of length greater than
9154     *       {@code maxWidth}.</li>
9155     * </ul>
9156     *
9157     * <pre>
9158     * StringUtils.truncate(null, 0)       = null
9159     * StringUtils.truncate(null, 2)       = null
9160     * StringUtils.truncate("", 4)         = ""
9161     * StringUtils.truncate("abcdefg", 4)  = "abcd"
9162     * StringUtils.truncate("abcdefg", 6)  = "abcdef"
9163     * StringUtils.truncate("abcdefg", 7)  = "abcdefg"
9164     * StringUtils.truncate("abcdefg", 8)  = "abcdefg"
9165     * StringUtils.truncate("abcdefg", -1) = throws an IllegalArgumentException
9166     * </pre>
9167     *
9168     * @param str  the String to truncate, may be null
9169     * @param maxWidth  maximum length of result String, must be positive
9170     * @return truncated String, {@code null} if null String input
9171     * @throws IllegalArgumentException If {@code maxWidth} is less than {@code 0}
9172     * @since 3.5
9173     */
9174    public static String truncate(final String str, final int maxWidth) {
9175        return truncate(str, 0, maxWidth);
9176    }
9177
9178    /**
9179     * <p>Truncates a String. This will turn
9180     * "Now is the time for all good men" into "is the time for all".</p>
9181     *
9182     * <p>Works like {@code truncate(String, int)}, but allows you to specify
9183     * a "left edge" offset.
9184     *
9185     * <p>Specifically:</p>
9186     * <ul>
9187     *   <li>If {@code str} is less than {@code maxWidth} characters
9188     *       long, return it.</li>
9189     *   <li>Else truncate it to {@code substring(str, offset, maxWidth)}.</li>
9190     *   <li>If {@code maxWidth} is less than {@code 0}, throw an
9191     *       {@code IllegalArgumentException}.</li>
9192     *   <li>If {@code offset} is less than {@code 0}, throw an
9193     *       {@code IllegalArgumentException}.</li>
9194     *   <li>In no case will it return a String of length greater than
9195     *       {@code maxWidth}.</li>
9196     * </ul>
9197     *
9198     * <pre>
9199     * StringUtils.truncate(null, 0, 0) = null
9200     * StringUtils.truncate(null, 2, 4) = null
9201     * StringUtils.truncate("", 0, 10) = ""
9202     * StringUtils.truncate("", 2, 10) = ""
9203     * StringUtils.truncate("abcdefghij", 0, 3) = "abc"
9204     * StringUtils.truncate("abcdefghij", 5, 6) = "fghij"
9205     * StringUtils.truncate("raspberry peach", 10, 15) = "peach"
9206     * StringUtils.truncate("abcdefghijklmno", 0, 10) = "abcdefghij"
9207     * StringUtils.truncate("abcdefghijklmno", -1, 10) = throws an IllegalArgumentException
9208     * StringUtils.truncate("abcdefghijklmno", Integer.MIN_VALUE, 10) = throws an IllegalArgumentException
9209     * StringUtils.truncate("abcdefghijklmno", Integer.MIN_VALUE, Integer.MAX_VALUE) = throws an IllegalArgumentException
9210     * StringUtils.truncate("abcdefghijklmno", 0, Integer.MAX_VALUE) = "abcdefghijklmno"
9211     * StringUtils.truncate("abcdefghijklmno", 1, 10) = "bcdefghijk"
9212     * StringUtils.truncate("abcdefghijklmno", 2, 10) = "cdefghijkl"
9213     * StringUtils.truncate("abcdefghijklmno", 3, 10) = "defghijklm"
9214     * StringUtils.truncate("abcdefghijklmno", 4, 10) = "efghijklmn"
9215     * StringUtils.truncate("abcdefghijklmno", 5, 10) = "fghijklmno"
9216     * StringUtils.truncate("abcdefghijklmno", 5, 5) = "fghij"
9217     * StringUtils.truncate("abcdefghijklmno", 5, 3) = "fgh"
9218     * StringUtils.truncate("abcdefghijklmno", 10, 3) = "klm"
9219     * StringUtils.truncate("abcdefghijklmno", 10, Integer.MAX_VALUE) = "klmno"
9220     * StringUtils.truncate("abcdefghijklmno", 13, 1) = "n"
9221     * StringUtils.truncate("abcdefghijklmno", 13, Integer.MAX_VALUE) = "no"
9222     * StringUtils.truncate("abcdefghijklmno", 14, 1) = "o"
9223     * StringUtils.truncate("abcdefghijklmno", 14, Integer.MAX_VALUE) = "o"
9224     * StringUtils.truncate("abcdefghijklmno", 15, 1) = ""
9225     * StringUtils.truncate("abcdefghijklmno", 15, Integer.MAX_VALUE) = ""
9226     * StringUtils.truncate("abcdefghijklmno", Integer.MAX_VALUE, Integer.MAX_VALUE) = ""
9227     * StringUtils.truncate("abcdefghij", 3, -1) = throws an IllegalArgumentException
9228     * StringUtils.truncate("abcdefghij", -2, 4) = throws an IllegalArgumentException
9229     * </pre>
9230     *
9231     * @param str  the String to truncate, may be null
9232     * @param offset  left edge of source String
9233     * @param maxWidth  maximum length of result String, must be positive
9234     * @return truncated String, {@code null} if null String input
9235     * @throws IllegalArgumentException If {@code offset} or {@code maxWidth} is less than {@code 0}
9236     * @since 3.5
9237     */
9238    public static String truncate(final String str, final int offset, final int maxWidth) {
9239        if (offset < 0) {
9240            throw new IllegalArgumentException("offset cannot be negative");
9241        }
9242        if (maxWidth < 0) {
9243            throw new IllegalArgumentException("maxWith cannot be negative");
9244        }
9245        if (str == null) {
9246            return null;
9247        }
9248        if (offset > str.length()) {
9249            return EMPTY;
9250        }
9251        if (str.length() > maxWidth) {
9252            final int ix = Math.min(offset + maxWidth, str.length());
9253            return str.substring(offset, ix);
9254        }
9255        return str.substring(offset);
9256    }
9257
9258    /**
9259     * <p>Uncapitalizes a String, changing the first character to lower case as
9260     * per {@link Character#toLowerCase(int)}. No other characters are changed.</p>
9261     *
9262     * <p>For a word based algorithm, see {@link org.apache.commons.lang3.text.WordUtils#uncapitalize(String)}.
9263     * A {@code null} input String returns {@code null}.</p>
9264     *
9265     * <pre>
9266     * StringUtils.uncapitalize(null)  = null
9267     * StringUtils.uncapitalize("")    = ""
9268     * StringUtils.uncapitalize("cat") = "cat"
9269     * StringUtils.uncapitalize("Cat") = "cat"
9270     * StringUtils.uncapitalize("CAT") = "cAT"
9271     * </pre>
9272     *
9273     * @param str the String to uncapitalize, may be null
9274     * @return the uncapitalized String, {@code null} if null String input
9275     * @see org.apache.commons.lang3.text.WordUtils#uncapitalize(String)
9276     * @see #capitalize(String)
9277     * @since 2.0
9278     */
9279    public static String uncapitalize(final String str) {
9280        final int strLen = length(str);
9281        if (strLen == 0) {
9282            return str;
9283        }
9284
9285        final int firstCodepoint = str.codePointAt(0);
9286        final int newCodePoint = Character.toLowerCase(firstCodepoint);
9287        if (firstCodepoint == newCodePoint) {
9288            // already capitalized
9289            return str;
9290        }
9291
9292        final int[] newCodePoints = new int[strLen]; // cannot be longer than the char array
9293        int outOffset = 0;
9294        newCodePoints[outOffset++] = newCodePoint; // copy the first codepoint
9295        for (int inOffset = Character.charCount(firstCodepoint); inOffset < strLen; ) {
9296            final int codepoint = str.codePointAt(inOffset);
9297            newCodePoints[outOffset++] = codepoint; // copy the remaining ones
9298            inOffset += Character.charCount(codepoint);
9299         }
9300        return new String(newCodePoints, 0, outOffset);
9301    }
9302
9303    /**
9304     * <p>
9305     * Unwraps a given string from a character.
9306     * </p>
9307     *
9308     * <pre>
9309     * StringUtils.unwrap(null, null)         = null
9310     * StringUtils.unwrap(null, '\0')         = null
9311     * StringUtils.unwrap(null, '1')          = null
9312     * StringUtils.unwrap("a", 'a')           = "a"
9313     * StringUtils.unwrap("aa", 'a')           = ""
9314     * StringUtils.unwrap("\'abc\'", '\'')    = "abc"
9315     * StringUtils.unwrap("AABabcBAA", 'A')   = "ABabcBA"
9316     * StringUtils.unwrap("A", '#')           = "A"
9317     * StringUtils.unwrap("#A", '#')          = "#A"
9318     * StringUtils.unwrap("A#", '#')          = "A#"
9319     * </pre>
9320     *
9321     * @param str
9322     *          the String to be unwrapped, can be null
9323     * @param wrapChar
9324     *          the character used to unwrap
9325     * @return unwrapped String or the original string
9326     *          if it is not quoted properly with the wrapChar
9327     * @since 3.6
9328     */
9329    public static String unwrap(final String str, final char wrapChar) {
9330        if (isEmpty(str) || wrapChar == CharUtils.NUL || str.length() == 1) {
9331            return str;
9332        }
9333
9334        if (str.charAt(0) == wrapChar && str.charAt(str.length() - 1) == wrapChar) {
9335            final int startIndex = 0;
9336            final int endIndex = str.length() - 1;
9337
9338            return str.substring(startIndex + 1, endIndex);
9339        }
9340
9341        return str;
9342    }
9343
9344    /**
9345     * <p>
9346     * Unwraps a given string from anther string.
9347     * </p>
9348     *
9349     * <pre>
9350     * StringUtils.unwrap(null, null)         = null
9351     * StringUtils.unwrap(null, "")           = null
9352     * StringUtils.unwrap(null, "1")          = null
9353     * StringUtils.unwrap("a", "a")           = "a"
9354     * StringUtils.unwrap("aa", "a")          = ""
9355     * StringUtils.unwrap("\'abc\'", "\'")    = "abc"
9356     * StringUtils.unwrap("\"abc\"", "\"")    = "abc"
9357     * StringUtils.unwrap("AABabcBAA", "AA")  = "BabcB"
9358     * StringUtils.unwrap("A", "#")           = "A"
9359     * StringUtils.unwrap("#A", "#")          = "#A"
9360     * StringUtils.unwrap("A#", "#")          = "A#"
9361     * </pre>
9362     *
9363     * @param str
9364     *          the String to be unwrapped, can be null
9365     * @param wrapToken
9366     *          the String used to unwrap
9367     * @return unwrapped String or the original string
9368     *          if it is not quoted properly with the wrapToken
9369     * @since 3.6
9370     */
9371    public static String unwrap(final String str, final String wrapToken) {
9372        if (isEmpty(str) || isEmpty(wrapToken) || str.length() == 1) {
9373            return str;
9374        }
9375
9376        if (startsWith(str, wrapToken) && endsWith(str, wrapToken)) {
9377            final int startIndex = str.indexOf(wrapToken);
9378            final int endIndex = str.lastIndexOf(wrapToken);
9379            final int wrapLength = wrapToken.length();
9380
9381            if (startIndex != -1 && endIndex != -1) {
9382                return str.substring(startIndex + wrapLength, endIndex);
9383            }
9384        }
9385
9386        return str;
9387    }
9388
9389    // Case conversion
9390    //-----------------------------------------------------------------------
9391    /**
9392     * <p>Converts a String to upper case as per {@link String#toUpperCase()}.</p>
9393     *
9394     * <p>A {@code null} input String returns {@code null}.</p>
9395     *
9396     * <pre>
9397     * StringUtils.upperCase(null)  = null
9398     * StringUtils.upperCase("")    = ""
9399     * StringUtils.upperCase("aBc") = "ABC"
9400     * </pre>
9401     *
9402     * <p><strong>Note:</strong> As described in the documentation for {@link String#toUpperCase()},
9403     * the result of this method is affected by the current locale.
9404     * For platform-independent case transformations, the method {@link #lowerCase(String, Locale)}
9405     * should be used with a specific locale (e.g. {@link Locale#ENGLISH}).</p>
9406     *
9407     * @param str  the String to upper case, may be null
9408     * @return the upper cased String, {@code null} if null String input
9409     */
9410    public static String upperCase(final String str) {
9411        if (str == null) {
9412            return null;
9413        }
9414        return str.toUpperCase();
9415    }
9416
9417    /**
9418     * <p>Converts a String to upper case as per {@link String#toUpperCase(Locale)}.</p>
9419     *
9420     * <p>A {@code null} input String returns {@code null}.</p>
9421     *
9422     * <pre>
9423     * StringUtils.upperCase(null, Locale.ENGLISH)  = null
9424     * StringUtils.upperCase("", Locale.ENGLISH)    = ""
9425     * StringUtils.upperCase("aBc", Locale.ENGLISH) = "ABC"
9426     * </pre>
9427     *
9428     * @param str  the String to upper case, may be null
9429     * @param locale  the locale that defines the case transformation rules, must not be null
9430     * @return the upper cased String, {@code null} if null String input
9431     * @since 2.5
9432     */
9433    public static String upperCase(final String str, final Locale locale) {
9434        if (str == null) {
9435            return null;
9436        }
9437        return str.toUpperCase(locale);
9438    }
9439
9440    /**
9441     * Returns the string representation of the {@code char} array or null.
9442     *
9443     * @param value the character array.
9444     * @return a String or null
9445     * @see String#valueOf(char[])
9446     * @since 3.9
9447     */
9448    public static String valueOf(final char[] value) {
9449        return value == null ? null : String.valueOf(value);
9450    }
9451
9452    /**
9453     * <p>
9454     * Wraps a string with a char.
9455     * </p>
9456     *
9457     * <pre>
9458     * StringUtils.wrap(null, *)        = null
9459     * StringUtils.wrap("", *)          = ""
9460     * StringUtils.wrap("ab", '\0')     = "ab"
9461     * StringUtils.wrap("ab", 'x')      = "xabx"
9462     * StringUtils.wrap("ab", '\'')     = "'ab'"
9463     * StringUtils.wrap("\"ab\"", '\"') = "\"\"ab\"\""
9464     * </pre>
9465     *
9466     * @param str
9467     *            the string to be wrapped, may be {@code null}
9468     * @param wrapWith
9469     *            the char that will wrap {@code str}
9470     * @return the wrapped string, or {@code null} if {@code str==null}
9471     * @since 3.4
9472     */
9473    public static String wrap(final String str, final char wrapWith) {
9474
9475        if (isEmpty(str) || wrapWith == CharUtils.NUL) {
9476            return str;
9477        }
9478
9479        return wrapWith + str + wrapWith;
9480    }
9481
9482    /**
9483     * <p>
9484     * Wraps a String with another String.
9485     * </p>
9486     *
9487     * <p>
9488     * A {@code null} input String returns {@code null}.
9489     * </p>
9490     *
9491     * <pre>
9492     * StringUtils.wrap(null, *)         = null
9493     * StringUtils.wrap("", *)           = ""
9494     * StringUtils.wrap("ab", null)      = "ab"
9495     * StringUtils.wrap("ab", "x")       = "xabx"
9496     * StringUtils.wrap("ab", "\"")      = "\"ab\""
9497     * StringUtils.wrap("\"ab\"", "\"")  = "\"\"ab\"\""
9498     * StringUtils.wrap("ab", "'")       = "'ab'"
9499     * StringUtils.wrap("'abcd'", "'")   = "''abcd''"
9500     * StringUtils.wrap("\"abcd\"", "'") = "'\"abcd\"'"
9501     * StringUtils.wrap("'abcd'", "\"")  = "\"'abcd'\""
9502     * </pre>
9503     *
9504     * @param str
9505     *            the String to be wrapper, may be null
9506     * @param wrapWith
9507     *            the String that will wrap str
9508     * @return wrapped String, {@code null} if null String input
9509     * @since 3.4
9510     */
9511    public static String wrap(final String str, final String wrapWith) {
9512
9513        if (isEmpty(str) || isEmpty(wrapWith)) {
9514            return str;
9515        }
9516
9517        return wrapWith.concat(str).concat(wrapWith);
9518    }
9519
9520    /**
9521     * <p>
9522     * Wraps a string with a char if that char is missing from the start or end of the given string.
9523     * </p>
9524     *
9525     * <p>A new {@code String} will not be created if {@code str} is already wrapped.</p>
9526     *
9527     * <pre>
9528     * StringUtils.wrapIfMissing(null, *)        = null
9529     * StringUtils.wrapIfMissing("", *)          = ""
9530     * StringUtils.wrapIfMissing("ab", '\0')     = "ab"
9531     * StringUtils.wrapIfMissing("ab", 'x')      = "xabx"
9532     * StringUtils.wrapIfMissing("ab", '\'')     = "'ab'"
9533     * StringUtils.wrapIfMissing("\"ab\"", '\"') = "\"ab\""
9534     * StringUtils.wrapIfMissing("/", '/')  = "/"
9535     * StringUtils.wrapIfMissing("a/b/c", '/')  = "/a/b/c/"
9536     * StringUtils.wrapIfMissing("/a/b/c", '/')  = "/a/b/c/"
9537     * StringUtils.wrapIfMissing("a/b/c/", '/')  = "/a/b/c/"
9538     * </pre>
9539     *
9540     * @param str
9541     *            the string to be wrapped, may be {@code null}
9542     * @param wrapWith
9543     *            the char that will wrap {@code str}
9544     * @return the wrapped string, or {@code null} if {@code str==null}
9545     * @since 3.5
9546     */
9547    public static String wrapIfMissing(final String str, final char wrapWith) {
9548        if (isEmpty(str) || wrapWith == CharUtils.NUL) {
9549            return str;
9550        }
9551        final boolean wrapStart = str.charAt(0) != wrapWith;
9552        final boolean wrapEnd = str.charAt(str.length() - 1) != wrapWith;
9553        if (!wrapStart && !wrapEnd) {
9554            return str;
9555        }
9556
9557        final StringBuilder builder = new StringBuilder(str.length() + 2);
9558        if (wrapStart) {
9559            builder.append(wrapWith);
9560        }
9561        builder.append(str);
9562        if (wrapEnd) {
9563            builder.append(wrapWith);
9564        }
9565        return builder.toString();
9566    }
9567
9568    /**
9569     * <p>
9570     * Wraps a string with a string if that string is missing from the start or end of the given string.
9571     * </p>
9572     *
9573     * <p>A new {@code String} will not be created if {@code str} is already wrapped.</p>
9574     *
9575     * <pre>
9576     * StringUtils.wrapIfMissing(null, *)         = null
9577     * StringUtils.wrapIfMissing("", *)           = ""
9578     * StringUtils.wrapIfMissing("ab", null)      = "ab"
9579     * StringUtils.wrapIfMissing("ab", "x")       = "xabx"
9580     * StringUtils.wrapIfMissing("ab", "\"")      = "\"ab\""
9581     * StringUtils.wrapIfMissing("\"ab\"", "\"")  = "\"ab\""
9582     * StringUtils.wrapIfMissing("ab", "'")       = "'ab'"
9583     * StringUtils.wrapIfMissing("'abcd'", "'")   = "'abcd'"
9584     * StringUtils.wrapIfMissing("\"abcd\"", "'") = "'\"abcd\"'"
9585     * StringUtils.wrapIfMissing("'abcd'", "\"")  = "\"'abcd'\""
9586     * StringUtils.wrapIfMissing("/", "/")  = "/"
9587     * StringUtils.wrapIfMissing("a/b/c", "/")  = "/a/b/c/"
9588     * StringUtils.wrapIfMissing("/a/b/c", "/")  = "/a/b/c/"
9589     * StringUtils.wrapIfMissing("a/b/c/", "/")  = "/a/b/c/"
9590     * </pre>
9591     *
9592     * @param str
9593     *            the string to be wrapped, may be {@code null}
9594     * @param wrapWith
9595     *            the string that will wrap {@code str}
9596     * @return the wrapped string, or {@code null} if {@code str==null}
9597     * @since 3.5
9598     */
9599    public static String wrapIfMissing(final String str, final String wrapWith) {
9600        if (isEmpty(str) || isEmpty(wrapWith)) {
9601            return str;
9602        }
9603
9604        final boolean wrapStart = !str.startsWith(wrapWith);
9605        final boolean wrapEnd = !str.endsWith(wrapWith);
9606        if (!wrapStart && !wrapEnd) {
9607            return str;
9608        }
9609
9610        final StringBuilder builder = new StringBuilder(str.length() + wrapWith.length() + wrapWith.length());
9611        if (wrapStart) {
9612            builder.append(wrapWith);
9613        }
9614        builder.append(str);
9615        if (wrapEnd) {
9616            builder.append(wrapWith);
9617        }
9618        return builder.toString();
9619    }
9620
9621    /**
9622     * <p>{@code StringUtils} instances should NOT be constructed in
9623     * standard programming. Instead, the class should be used as
9624     * {@code StringUtils.trim(" foo ");}.</p>
9625     *
9626     * <p>This constructor is public to permit tools that require a JavaBean
9627     * instance to operate.</p>
9628     */
9629    public StringUtils() {
9630        super();
9631    }
9632
9633}