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.Iterator;
025import java.util.List;
026import java.util.Locale;
027import java.util.Objects;
028import java.util.regex.Pattern;
029
030/**
031 * <p>Operations on {@link java.lang.String} that are
032 * {@code null} safe.</p>
033 *
034 * <ul>
035 *  <li><b>IsEmpty/IsBlank</b>
036 *      - checks if a String contains text</li>
037 *  <li><b>Trim/Strip</b>
038 *      - removes leading and trailing whitespace</li>
039 *  <li><b>Equals/Compare</b>
040 *      - compares two strings null-safe</li>
041 *  <li><b>startsWith</b>
042 *      - check if a String starts with a prefix null-safe</li>
043 *  <li><b>endsWith</b>
044 *      - check if a String ends with a suffix null-safe</li>
045 *  <li><b>IndexOf/LastIndexOf/Contains</b>
046 *      - null-safe index-of checks
047 *  <li><b>IndexOfAny/LastIndexOfAny/IndexOfAnyBut/LastIndexOfAnyBut</b>
048 *      - index-of any of a set of Strings</li>
049 *  <li><b>ContainsOnly/ContainsNone/ContainsAny</b>
050 *      - does String contains only/none/any of these characters</li>
051 *  <li><b>Substring/Left/Right/Mid</b>
052 *      - null-safe substring extractions</li>
053 *  <li><b>SubstringBefore/SubstringAfter/SubstringBetween</b>
054 *      - substring extraction relative to other strings</li>
055 *  <li><b>Split/Join</b>
056 *      - splits a String into an array of substrings and vice versa</li>
057 *  <li><b>Remove/Delete</b>
058 *      - removes part of a String</li>
059 *  <li><b>Replace/Overlay</b>
060 *      - Searches a String and replaces one String with another</li>
061 *  <li><b>Chomp/Chop</b>
062 *      - removes the last part of a String</li>
063 *  <li><b>AppendIfMissing</b>
064 *      - appends a suffix to the end of the String if not present</li>
065 *  <li><b>PrependIfMissing</b>
066 *      - prepends a prefix to the start of the String if not present</li>
067 *  <li><b>LeftPad/RightPad/Center/Repeat</b>
068 *      - pads a String</li>
069 *  <li><b>UpperCase/LowerCase/SwapCase/Capitalize/Uncapitalize</b>
070 *      - changes the case of a String</li>
071 *  <li><b>CountMatches</b>
072 *      - counts the number of occurrences of one String in another</li>
073 *  <li><b>IsAlpha/IsNumeric/IsWhitespace/IsAsciiPrintable</b>
074 *      - checks the characters in a String</li>
075 *  <li><b>DefaultString</b>
076 *      - protects against a null input String</li>
077 *  <li><b>Rotate</b>
078 *      - rotate (circular shift) a String</li>
079 *  <li><b>Reverse/ReverseDelimited</b>
080 *      - reverses a String</li>
081 *  <li><b>Abbreviate</b>
082 *      - abbreviates a string using ellipsis or another given String</li>
083 *  <li><b>Difference</b>
084 *      - compares Strings and reports on their differences</li>
085 *  <li><b>LevenshteinDistance</b>
086 *      - the number of changes needed to change one String into another</li>
087 * </ul>
088 *
089 * <p>The {@code StringUtils} class defines certain words related to
090 * String handling.</p>
091 *
092 * <ul>
093 *  <li>null - {@code null}</li>
094 *  <li>empty - a zero-length string ({@code ""})</li>
095 *  <li>space - the space character ({@code ' '}, char 32)</li>
096 *  <li>whitespace - the characters defined by {@link Character#isWhitespace(char)}</li>
097 *  <li>trim - the characters &lt;= 32 as in {@link String#trim()}</li>
098 * </ul>
099 *
100 * <p>{@code StringUtils} handles {@code null} input Strings quietly.
101 * That is to say that a {@code null} input will return {@code null}.
102 * Where a {@code boolean} or {@code int} is being returned
103 * details vary by method.</p>
104 *
105 * <p>A side effect of the {@code null} handling is that a
106 * {@code NullPointerException} should be considered a bug in
107 * {@code StringUtils}.</p>
108 *
109 * <p>Methods in this class give sample code to explain their operation.
110 * The symbol {@code *} is used to indicate any input including {@code null}.</p>
111 *
112 * <p>#ThreadSafe#</p>
113 * @see java.lang.String
114 * @since 1.0
115 */
116//@Immutable
117public class StringUtils {
118
119    private static final int STRING_BUILDER_SIZE = 256;
120
121    // Performance testing notes (JDK 1.4, Jul03, scolebourne)
122    // Whitespace:
123    // Character.isWhitespace() is faster than WHITESPACE.indexOf()
124    // where WHITESPACE is a string of all whitespace characters
125    //
126    // Character access:
127    // String.charAt(n) versus toCharArray(), then array[n]
128    // String.charAt(n) is about 15% worse for a 10K string
129    // They are about equal for a length 50 string
130    // String.charAt(n) is about 4 times better for a length 3 string
131    // String.charAt(n) is best bet overall
132    //
133    // Append:
134    // String.concat about twice as fast as StringBuffer.append
135    // (not sure who tested this)
136
137    /**
138     * A String for a space character.
139     *
140     * @since 3.2
141     */
142    public static final String SPACE = " ";
143
144    /**
145     * The empty String {@code ""}.
146     * @since 2.0
147     */
148    public static final String EMPTY = "";
149
150    /**
151     * A String for linefeed LF ("\n").
152     *
153     * @see <a href="http://docs.oracle.com/javase/specs/jls/se7/html/jls-3.html#jls-3.10.6">JLF: Escape Sequences
154     *      for Character and String Literals</a>
155     * @since 3.2
156     */
157    public static final String LF = "\n";
158
159    /**
160     * A String for carriage return CR ("\r").
161     *
162     * @see <a href="http://docs.oracle.com/javase/specs/jls/se7/html/jls-3.html#jls-3.10.6">JLF: Escape Sequences
163     *      for Character and String Literals</a>
164     * @since 3.2
165     */
166    public static final String CR = "\r";
167
168    /**
169     * Represents a failed index search.
170     * @since 2.1
171     */
172    public static final int INDEX_NOT_FOUND = -1;
173
174    /**
175     * <p>The maximum size to which the padding constant(s) can expand.</p>
176     */
177    private static final int PAD_LIMIT = 8192;
178
179    /**
180     * <p>{@code StringUtils} instances should NOT be constructed in
181     * standard programming. Instead, the class should be used as
182     * {@code StringUtils.trim(" foo ");}.</p>
183     *
184     * <p>This constructor is public to permit tools that require a JavaBean
185     * instance to operate.</p>
186     */
187    public StringUtils() {
188        super();
189    }
190
191    // Empty checks
192    //-----------------------------------------------------------------------
193    /**
194     * <p>Checks if a CharSequence is empty ("") or null.</p>
195     *
196     * <pre>
197     * StringUtils.isEmpty(null)      = true
198     * StringUtils.isEmpty("")        = true
199     * StringUtils.isEmpty(" ")       = false
200     * StringUtils.isEmpty("bob")     = false
201     * StringUtils.isEmpty("  bob  ") = false
202     * </pre>
203     *
204     * <p>NOTE: This method changed in Lang version 2.0.
205     * It no longer trims the CharSequence.
206     * That functionality is available in isBlank().</p>
207     *
208     * @param cs  the CharSequence to check, may be null
209     * @return {@code true} if the CharSequence is empty or null
210     * @since 3.0 Changed signature from isEmpty(String) to isEmpty(CharSequence)
211     */
212    public static boolean isEmpty(final CharSequence cs) {
213        return cs == null || cs.length() == 0;
214    }
215
216    /**
217     * <p>Checks if a CharSequence is not empty ("") and not null.</p>
218     *
219     * <pre>
220     * StringUtils.isNotEmpty(null)      = false
221     * StringUtils.isNotEmpty("")        = false
222     * StringUtils.isNotEmpty(" ")       = true
223     * StringUtils.isNotEmpty("bob")     = true
224     * StringUtils.isNotEmpty("  bob  ") = true
225     * </pre>
226     *
227     * @param cs  the CharSequence to check, may be null
228     * @return {@code true} if the CharSequence is not empty and not null
229     * @since 3.0 Changed signature from isNotEmpty(String) to isNotEmpty(CharSequence)
230     */
231    public static boolean isNotEmpty(final CharSequence cs) {
232        return !isEmpty(cs);
233    }
234
235    /**
236     * <p>Checks if any of the CharSequences are empty ("") or null.</p>
237     *
238     * <pre>
239     * StringUtils.isAnyEmpty((String) null)    = true
240     * StringUtils.isAnyEmpty((String[]) null)  = false
241     * StringUtils.isAnyEmpty(null, "foo")      = true
242     * StringUtils.isAnyEmpty("", "bar")        = true
243     * StringUtils.isAnyEmpty("bob", "")        = true
244     * StringUtils.isAnyEmpty("  bob  ", null)  = true
245     * StringUtils.isAnyEmpty(" ", "bar")       = false
246     * StringUtils.isAnyEmpty("foo", "bar")     = false
247     * StringUtils.isAnyEmpty(new String[]{})   = false
248     * StringUtils.isAnyEmpty(new String[]{""}) = true
249     * </pre>
250     *
251     * @param css  the CharSequences to check, may be null or empty
252     * @return {@code true} if any of the CharSequences are empty or null
253     * @since 3.2
254     */
255    public static boolean isAnyEmpty(final CharSequence... css) {
256      if (ArrayUtils.isEmpty(css)) {
257        return false;
258      }
259      for (final CharSequence cs : css) {
260        if (isEmpty(cs)) {
261          return true;
262        }
263      }
264      return false;
265    }
266
267    /**
268     * <p>Checks if none of the CharSequences are empty ("") or null.</p>
269     *
270     * <pre>
271     * StringUtils.isNoneEmpty((String) null)    = false
272     * StringUtils.isNoneEmpty((String[]) null)  = true
273     * StringUtils.isNoneEmpty(null, "foo")      = false
274     * StringUtils.isNoneEmpty("", "bar")        = false
275     * StringUtils.isNoneEmpty("bob", "")        = false
276     * StringUtils.isNoneEmpty("  bob  ", null)  = false
277     * StringUtils.isNoneEmpty(new String[] {})  = true
278     * StringUtils.isNoneEmpty(new String[]{""}) = false
279     * StringUtils.isNoneEmpty(" ", "bar")       = true
280     * StringUtils.isNoneEmpty("foo", "bar")     = true
281     * </pre>
282     *
283     * @param css  the CharSequences to check, may be null or empty
284     * @return {@code true} if none of the CharSequences are empty or null
285     * @since 3.2
286     */
287    public static boolean isNoneEmpty(final CharSequence... css) {
288      return !isAnyEmpty(css);
289    }
290
291    /**
292     * <p>Checks if all of the CharSequences are empty ("") or null.</p>
293     *
294     * <pre>
295     * StringUtils.isAllEmpty(null)             = true
296     * StringUtils.isAllEmpty(null, "")         = true
297     * StringUtils.isAllEmpty(new String[] {})  = true
298     * StringUtils.isAllEmpty(null, "foo")      = false
299     * StringUtils.isAllEmpty("", "bar")        = false
300     * StringUtils.isAllEmpty("bob", "")        = false
301     * StringUtils.isAllEmpty("  bob  ", null)  = false
302     * StringUtils.isAllEmpty(" ", "bar")       = false
303     * StringUtils.isAllEmpty("foo", "bar")     = false
304     * </pre>
305     *
306     * @param css  the CharSequences to check, may be null or empty
307     * @return {@code true} if all of the CharSequences are empty or null
308     * @since 3.6
309     */
310    public static boolean isAllEmpty(final CharSequence... css) {
311        if (ArrayUtils.isEmpty(css)) {
312            return true;
313        }
314        for (final CharSequence cs : css) {
315            if (isNotEmpty(cs)) {
316                return false;
317            }
318        }
319        return true;
320    }
321
322    /**
323     * <p>Checks if a CharSequence is empty (""), null or whitespace only.</p>
324     *
325     * <p>Whitespace is defined by {@link Character#isWhitespace(char)}.</p>
326     *
327     * <pre>
328     * StringUtils.isBlank(null)      = true
329     * StringUtils.isBlank("")        = true
330     * StringUtils.isBlank(" ")       = true
331     * StringUtils.isBlank("bob")     = false
332     * StringUtils.isBlank("  bob  ") = false
333     * </pre>
334     *
335     * @param cs  the CharSequence to check, may be null
336     * @return {@code true} if the CharSequence is null, empty or whitespace only
337     * @since 2.0
338     * @since 3.0 Changed signature from isBlank(String) to isBlank(CharSequence)
339     */
340    public static boolean isBlank(final CharSequence cs) {
341        int strLen;
342        if (cs == null || (strLen = cs.length()) == 0) {
343            return true;
344        }
345        for (int i = 0; i < strLen; i++) {
346            if (!Character.isWhitespace(cs.charAt(i))) {
347                return false;
348            }
349        }
350        return true;
351    }
352
353    /**
354     * <p>Checks if a CharSequence is not empty (""), not null and not whitespace only.</p>
355     *
356     * <p>Whitespace is defined by {@link Character#isWhitespace(char)}.</p>
357     *
358     * <pre>
359     * StringUtils.isNotBlank(null)      = false
360     * StringUtils.isNotBlank("")        = false
361     * StringUtils.isNotBlank(" ")       = false
362     * StringUtils.isNotBlank("bob")     = true
363     * StringUtils.isNotBlank("  bob  ") = true
364     * </pre>
365     *
366     * @param cs  the CharSequence to check, may be null
367     * @return {@code true} if the CharSequence is
368     *  not empty and not null and not whitespace only
369     * @since 2.0
370     * @since 3.0 Changed signature from isNotBlank(String) to isNotBlank(CharSequence)
371     */
372    public static boolean isNotBlank(final CharSequence cs) {
373        return !isBlank(cs);
374    }
375
376    /**
377     * <p>Checks if any of the CharSequences are empty ("") or null or whitespace only.</p>
378     *
379     * <p>Whitespace is defined by {@link Character#isWhitespace(char)}.</p>
380     *
381     * <pre>
382     * StringUtils.isAnyBlank((String) null)    = true
383     * StringUtils.isAnyBlank((String[]) null)  = false
384     * StringUtils.isAnyBlank(null, "foo")      = true
385     * StringUtils.isAnyBlank(null, null)       = true
386     * StringUtils.isAnyBlank("", "bar")        = true
387     * StringUtils.isAnyBlank("bob", "")        = true
388     * StringUtils.isAnyBlank("  bob  ", null)  = true
389     * StringUtils.isAnyBlank(" ", "bar")       = true
390     * StringUtils.isAnyBlank(new String[] {})  = false
391     * StringUtils.isAnyBlank(new String[]{""}) = true
392     * StringUtils.isAnyBlank("foo", "bar")     = false
393     * </pre>
394     *
395     * @param css  the CharSequences to check, may be null or empty
396     * @return {@code true} if any of the CharSequences are empty or null or whitespace only
397     * @since 3.2
398     */
399    public static boolean isAnyBlank(final CharSequence... css) {
400      if (ArrayUtils.isEmpty(css)) {
401        return false;
402      }
403      for (final CharSequence cs : css) {
404        if (isBlank(cs)) {
405          return true;
406        }
407      }
408      return false;
409    }
410
411    /**
412     * <p>Checks if none of the CharSequences are empty (""), null or whitespace only.</p>
413     *
414     * <p>Whitespace is defined by {@link Character#isWhitespace(char)}.</p>
415     *
416     * <pre>
417     * StringUtils.isNoneBlank((String) null)    = false
418     * StringUtils.isNoneBlank((String[]) null)  = true
419     * StringUtils.isNoneBlank(null, "foo")      = false
420     * StringUtils.isNoneBlank(null, null)       = false
421     * StringUtils.isNoneBlank("", "bar")        = false
422     * StringUtils.isNoneBlank("bob", "")        = false
423     * StringUtils.isNoneBlank("  bob  ", null)  = false
424     * StringUtils.isNoneBlank(" ", "bar")       = false
425     * StringUtils.isNoneBlank(new String[] {})  = true
426     * StringUtils.isNoneBlank(new String[]{""}) = false
427     * StringUtils.isNoneBlank("foo", "bar")     = true
428     * </pre>
429     *
430     * @param css  the CharSequences to check, may be null or empty
431     * @return {@code true} if none of the CharSequences are empty or null or whitespace only
432     * @since 3.2
433     */
434    public static boolean isNoneBlank(final CharSequence... css) {
435      return !isAnyBlank(css);
436    }
437
438    /**
439     * <p>Checks if all of the CharSequences are empty (""), null or whitespace only.</p>
440     *
441     * <p>Whitespace is defined by {@link Character#isWhitespace(char)}.</p>
442     *
443     * <pre>
444     * StringUtils.isAllBlank(null)             = true
445     * StringUtils.isAllBlank(null, "foo")      = false
446     * StringUtils.isAllBlank(null, null)       = true
447     * StringUtils.isAllBlank("", "bar")        = false
448     * StringUtils.isAllBlank("bob", "")        = false
449     * StringUtils.isAllBlank("  bob  ", null)  = false
450     * StringUtils.isAllBlank(" ", "bar")       = false
451     * StringUtils.isAllBlank("foo", "bar")     = false
452     * StringUtils.isAllBlank(new String[] {})  = true
453     * </pre>
454     *
455     * @param css  the CharSequences to check, may be null or empty
456     * @return {@code true} if all of the CharSequences are empty or null or whitespace only
457     * @since 3.6
458     */
459    public static boolean isAllBlank(final CharSequence... css) {
460        if (ArrayUtils.isEmpty(css)) {
461            return true;
462        }
463        for (final CharSequence cs : css) {
464            if (isNotBlank(cs)) {
465               return false;
466            }
467        }
468        return true;
469    }
470
471    // Trim
472    //-----------------------------------------------------------------------
473    /**
474     * <p>Removes control characters (char &lt;= 32) from both
475     * ends of this String, handling {@code null} by returning
476     * {@code null}.</p>
477     *
478     * <p>The String is trimmed using {@link String#trim()}.
479     * Trim removes start and end characters &lt;= 32.
480     * To strip whitespace use {@link #strip(String)}.</p>
481     *
482     * <p>To trim your choice of characters, use the
483     * {@link #strip(String, String)} methods.</p>
484     *
485     * <pre>
486     * StringUtils.trim(null)          = null
487     * StringUtils.trim("")            = ""
488     * StringUtils.trim("     ")       = ""
489     * StringUtils.trim("abc")         = "abc"
490     * StringUtils.trim("    abc    ") = "abc"
491     * </pre>
492     *
493     * @param str  the String to be trimmed, may be null
494     * @return the trimmed string, {@code null} if null String input
495     */
496    public static String trim(final String str) {
497        return str == null ? null : str.trim();
498    }
499
500    /**
501     * <p>Removes control characters (char &lt;= 32) from both
502     * ends of this String returning {@code null} if the String is
503     * empty ("") after the trim or if it is {@code null}.
504     *
505     * <p>The String is trimmed using {@link String#trim()}.
506     * Trim removes start and end characters &lt;= 32.
507     * To strip whitespace use {@link #stripToNull(String)}.</p>
508     *
509     * <pre>
510     * StringUtils.trimToNull(null)          = null
511     * StringUtils.trimToNull("")            = null
512     * StringUtils.trimToNull("     ")       = null
513     * StringUtils.trimToNull("abc")         = "abc"
514     * StringUtils.trimToNull("    abc    ") = "abc"
515     * </pre>
516     *
517     * @param str  the String to be trimmed, may be null
518     * @return the trimmed String,
519     *  {@code null} if only chars &lt;= 32, empty or null String input
520     * @since 2.0
521     */
522    public static String trimToNull(final String str) {
523        final String ts = trim(str);
524        return isEmpty(ts) ? null : ts;
525    }
526
527    /**
528     * <p>Removes control characters (char &lt;= 32) from both
529     * ends of this String returning an empty String ("") if the String
530     * is empty ("") after the trim or if it is {@code null}.
531     *
532     * <p>The String is trimmed using {@link String#trim()}.
533     * Trim removes start and end characters &lt;= 32.
534     * To strip whitespace use {@link #stripToEmpty(String)}.</p>
535     *
536     * <pre>
537     * StringUtils.trimToEmpty(null)          = ""
538     * StringUtils.trimToEmpty("")            = ""
539     * StringUtils.trimToEmpty("     ")       = ""
540     * StringUtils.trimToEmpty("abc")         = "abc"
541     * StringUtils.trimToEmpty("    abc    ") = "abc"
542     * </pre>
543     *
544     * @param str  the String to be trimmed, may be null
545     * @return the trimmed String, or an empty String if {@code null} input
546     * @since 2.0
547     */
548    public static String trimToEmpty(final String str) {
549        return str == null ? EMPTY : str.trim();
550    }
551
552    /**
553     * <p>Truncates a String. This will turn
554     * "Now is the time for all good men" into "Now is the time for".</p>
555     *
556     * <p>Specifically:</p>
557     * <ul>
558     *   <li>If {@code str} is less than {@code maxWidth} characters
559     *       long, return it.</li>
560     *   <li>Else truncate it to {@code substring(str, 0, maxWidth)}.</li>
561     *   <li>If {@code maxWidth} is less than {@code 0}, throw an
562     *       {@code IllegalArgumentException}.</li>
563     *   <li>In no case will it return a String of length greater than
564     *       {@code maxWidth}.</li>
565     * </ul>
566     *
567     * <pre>
568     * StringUtils.truncate(null, 0)       = null
569     * StringUtils.truncate(null, 2)       = null
570     * StringUtils.truncate("", 4)         = ""
571     * StringUtils.truncate("abcdefg", 4)  = "abcd"
572     * StringUtils.truncate("abcdefg", 6)  = "abcdef"
573     * StringUtils.truncate("abcdefg", 7)  = "abcdefg"
574     * StringUtils.truncate("abcdefg", 8)  = "abcdefg"
575     * StringUtils.truncate("abcdefg", -1) = throws an IllegalArgumentException
576     * </pre>
577     *
578     * @param str  the String to truncate, may be null
579     * @param maxWidth  maximum length of result String, must be positive
580     * @return truncated String, {@code null} if null String input
581     * @since 3.5
582     */
583    public static String truncate(final String str, final int maxWidth) {
584        return truncate(str, 0, maxWidth);
585    }
586
587    /**
588     * <p>Truncates a String. This will turn
589     * "Now is the time for all good men" into "is the time for all".</p>
590     *
591     * <p>Works like {@code truncate(String, int)}, but allows you to specify
592     * a "left edge" offset.
593     *
594     * <p>Specifically:</p>
595     * <ul>
596     *   <li>If {@code str} is less than {@code maxWidth} characters
597     *       long, return it.</li>
598     *   <li>Else truncate it to {@code substring(str, offset, maxWidth)}.</li>
599     *   <li>If {@code maxWidth} is less than {@code 0}, throw an
600     *       {@code IllegalArgumentException}.</li>
601     *   <li>If {@code offset} is less than {@code 0}, throw an
602     *       {@code IllegalArgumentException}.</li>
603     *   <li>In no case will it return a String of length greater than
604     *       {@code maxWidth}.</li>
605     * </ul>
606     *
607     * <pre>
608     * StringUtils.truncate(null, 0, 0) = null
609     * StringUtils.truncate(null, 2, 4) = null
610     * StringUtils.truncate("", 0, 10) = ""
611     * StringUtils.truncate("", 2, 10) = ""
612     * StringUtils.truncate("abcdefghij", 0, 3) = "abc"
613     * StringUtils.truncate("abcdefghij", 5, 6) = "fghij"
614     * StringUtils.truncate("raspberry peach", 10, 15) = "peach"
615     * StringUtils.truncate("abcdefghijklmno", 0, 10) = "abcdefghij"
616     * StringUtils.truncate("abcdefghijklmno", -1, 10) = throws an IllegalArgumentException
617     * StringUtils.truncate("abcdefghijklmno", Integer.MIN_VALUE, 10) = "abcdefghij"
618     * StringUtils.truncate("abcdefghijklmno", Integer.MIN_VALUE, Integer.MAX_VALUE) = "abcdefghijklmno"
619     * StringUtils.truncate("abcdefghijklmno", 0, Integer.MAX_VALUE) = "abcdefghijklmno"
620     * StringUtils.truncate("abcdefghijklmno", 1, 10) = "bcdefghijk"
621     * StringUtils.truncate("abcdefghijklmno", 2, 10) = "cdefghijkl"
622     * StringUtils.truncate("abcdefghijklmno", 3, 10) = "defghijklm"
623     * StringUtils.truncate("abcdefghijklmno", 4, 10) = "efghijklmn"
624     * StringUtils.truncate("abcdefghijklmno", 5, 10) = "fghijklmno"
625     * StringUtils.truncate("abcdefghijklmno", 5, 5) = "fghij"
626     * StringUtils.truncate("abcdefghijklmno", 5, 3) = "fgh"
627     * StringUtils.truncate("abcdefghijklmno", 10, 3) = "klm"
628     * StringUtils.truncate("abcdefghijklmno", 10, Integer.MAX_VALUE) = "klmno"
629     * StringUtils.truncate("abcdefghijklmno", 13, 1) = "n"
630     * StringUtils.truncate("abcdefghijklmno", 13, Integer.MAX_VALUE) = "no"
631     * StringUtils.truncate("abcdefghijklmno", 14, 1) = "o"
632     * StringUtils.truncate("abcdefghijklmno", 14, Integer.MAX_VALUE) = "o"
633     * StringUtils.truncate("abcdefghijklmno", 15, 1) = ""
634     * StringUtils.truncate("abcdefghijklmno", 15, Integer.MAX_VALUE) = ""
635     * StringUtils.truncate("abcdefghijklmno", Integer.MAX_VALUE, Integer.MAX_VALUE) = ""
636     * StringUtils.truncate("abcdefghij", 3, -1) = throws an IllegalArgumentException
637     * StringUtils.truncate("abcdefghij", -2, 4) = throws an IllegalArgumentException
638     * </pre>
639     *
640     * @param str  the String to check, may be null
641     * @param offset  left edge of source String
642     * @param maxWidth  maximum length of result String, must be positive
643     * @return truncated String, {@code null} if null String input
644     * @since 3.5
645     */
646    public static String truncate(final String str, final int offset, final int maxWidth) {
647        if (offset < 0) {
648            throw new IllegalArgumentException("offset cannot be negative");
649        }
650        if (maxWidth < 0) {
651            throw new IllegalArgumentException("maxWith cannot be negative");
652        }
653        if (str == null) {
654            return null;
655        }
656        if (offset > str.length()) {
657            return EMPTY;
658        }
659        if (str.length() > maxWidth) {
660            final int ix = offset + maxWidth > str.length() ? str.length() : offset + maxWidth;
661            return str.substring(offset, ix);
662        }
663        return str.substring(offset);
664    }
665
666    // Stripping
667    //-----------------------------------------------------------------------
668    /**
669     * <p>Strips whitespace from the start and end of a String.</p>
670     *
671     * <p>This is similar to {@link #trim(String)} but removes whitespace.
672     * Whitespace is defined by {@link Character#isWhitespace(char)}.</p>
673     *
674     * <p>A {@code null} input String returns {@code null}.</p>
675     *
676     * <pre>
677     * StringUtils.strip(null)     = null
678     * StringUtils.strip("")       = ""
679     * StringUtils.strip("   ")    = ""
680     * StringUtils.strip("abc")    = "abc"
681     * StringUtils.strip("  abc")  = "abc"
682     * StringUtils.strip("abc  ")  = "abc"
683     * StringUtils.strip(" abc ")  = "abc"
684     * StringUtils.strip(" ab c ") = "ab c"
685     * </pre>
686     *
687     * @param str  the String to remove whitespace from, may be null
688     * @return the stripped String, {@code null} if null String input
689     */
690    public static String strip(final String str) {
691        return strip(str, null);
692    }
693
694    /**
695     * <p>Strips whitespace from the start and end of a String  returning
696     * {@code null} if the String is empty ("") after the strip.</p>
697     *
698     * <p>This is similar to {@link #trimToNull(String)} but removes whitespace.
699     * Whitespace is defined by {@link Character#isWhitespace(char)}.</p>
700     *
701     * <pre>
702     * StringUtils.stripToNull(null)     = null
703     * StringUtils.stripToNull("")       = null
704     * StringUtils.stripToNull("   ")    = null
705     * StringUtils.stripToNull("abc")    = "abc"
706     * StringUtils.stripToNull("  abc")  = "abc"
707     * StringUtils.stripToNull("abc  ")  = "abc"
708     * StringUtils.stripToNull(" abc ")  = "abc"
709     * StringUtils.stripToNull(" ab c ") = "ab c"
710     * </pre>
711     *
712     * @param str  the String to be stripped, may be null
713     * @return the stripped String,
714     *  {@code null} if whitespace, empty or null String input
715     * @since 2.0
716     */
717    public static String stripToNull(String str) {
718        if (str == null) {
719            return null;
720        }
721        str = strip(str, null);
722        return str.isEmpty() ? null : str;
723    }
724
725    /**
726     * <p>Strips whitespace from the start and end of a String  returning
727     * an empty String if {@code null} input.</p>
728     *
729     * <p>This is similar to {@link #trimToEmpty(String)} but removes whitespace.
730     * Whitespace is defined by {@link Character#isWhitespace(char)}.</p>
731     *
732     * <pre>
733     * StringUtils.stripToEmpty(null)     = ""
734     * StringUtils.stripToEmpty("")       = ""
735     * StringUtils.stripToEmpty("   ")    = ""
736     * StringUtils.stripToEmpty("abc")    = "abc"
737     * StringUtils.stripToEmpty("  abc")  = "abc"
738     * StringUtils.stripToEmpty("abc  ")  = "abc"
739     * StringUtils.stripToEmpty(" abc ")  = "abc"
740     * StringUtils.stripToEmpty(" ab c ") = "ab c"
741     * </pre>
742     *
743     * @param str  the String to be stripped, may be null
744     * @return the trimmed String, or an empty String if {@code null} input
745     * @since 2.0
746     */
747    public static String stripToEmpty(final String str) {
748        return str == null ? EMPTY : strip(str, null);
749    }
750
751    /**
752     * <p>Strips any of a set of characters from the start and end of a String.
753     * This is similar to {@link String#trim()} but allows the characters
754     * to be stripped to be controlled.</p>
755     *
756     * <p>A {@code null} input String returns {@code null}.
757     * An empty string ("") input returns the empty string.</p>
758     *
759     * <p>If the stripChars String is {@code null}, whitespace is
760     * stripped as defined by {@link Character#isWhitespace(char)}.
761     * Alternatively use {@link #strip(String)}.</p>
762     *
763     * <pre>
764     * StringUtils.strip(null, *)          = null
765     * StringUtils.strip("", *)            = ""
766     * StringUtils.strip("abc", null)      = "abc"
767     * StringUtils.strip("  abc", null)    = "abc"
768     * StringUtils.strip("abc  ", null)    = "abc"
769     * StringUtils.strip(" abc ", null)    = "abc"
770     * StringUtils.strip("  abcyx", "xyz") = "  abc"
771     * </pre>
772     *
773     * @param str  the String to remove characters from, may be null
774     * @param stripChars  the characters to remove, null treated as whitespace
775     * @return the stripped String, {@code null} if null String input
776     */
777    public static String strip(String str, final String stripChars) {
778        if (isEmpty(str)) {
779            return str;
780        }
781        str = stripStart(str, stripChars);
782        return stripEnd(str, stripChars);
783    }
784
785    /**
786     * <p>Strips any of a set of characters from the start of a String.</p>
787     *
788     * <p>A {@code null} input String returns {@code null}.
789     * An empty string ("") input returns the empty string.</p>
790     *
791     * <p>If the stripChars String is {@code null}, whitespace is
792     * stripped as defined by {@link Character#isWhitespace(char)}.</p>
793     *
794     * <pre>
795     * StringUtils.stripStart(null, *)          = null
796     * StringUtils.stripStart("", *)            = ""
797     * StringUtils.stripStart("abc", "")        = "abc"
798     * StringUtils.stripStart("abc", null)      = "abc"
799     * StringUtils.stripStart("  abc", null)    = "abc"
800     * StringUtils.stripStart("abc  ", null)    = "abc  "
801     * StringUtils.stripStart(" abc ", null)    = "abc "
802     * StringUtils.stripStart("yxabc  ", "xyz") = "abc  "
803     * </pre>
804     *
805     * @param str  the String to remove characters from, may be null
806     * @param stripChars  the characters to remove, null treated as whitespace
807     * @return the stripped String, {@code null} if null String input
808     */
809    public static String stripStart(final String str, final String stripChars) {
810        int strLen;
811        if (str == null || (strLen = str.length()) == 0) {
812            return str;
813        }
814        int start = 0;
815        if (stripChars == null) {
816            while (start != strLen && Character.isWhitespace(str.charAt(start))) {
817                start++;
818            }
819        } else if (stripChars.isEmpty()) {
820            return str;
821        } else {
822            while (start != strLen && stripChars.indexOf(str.charAt(start)) != INDEX_NOT_FOUND) {
823                start++;
824            }
825        }
826        return str.substring(start);
827    }
828
829    /**
830     * <p>Strips any of a set of characters from the end of a String.</p>
831     *
832     * <p>A {@code null} input String returns {@code null}.
833     * An empty string ("") input returns the empty string.</p>
834     *
835     * <p>If the stripChars String is {@code null}, whitespace is
836     * stripped as defined by {@link Character#isWhitespace(char)}.</p>
837     *
838     * <pre>
839     * StringUtils.stripEnd(null, *)          = null
840     * StringUtils.stripEnd("", *)            = ""
841     * StringUtils.stripEnd("abc", "")        = "abc"
842     * StringUtils.stripEnd("abc", null)      = "abc"
843     * StringUtils.stripEnd("  abc", null)    = "  abc"
844     * StringUtils.stripEnd("abc  ", null)    = "abc"
845     * StringUtils.stripEnd(" abc ", null)    = " abc"
846     * StringUtils.stripEnd("  abcyx", "xyz") = "  abc"
847     * StringUtils.stripEnd("120.00", ".0")   = "12"
848     * </pre>
849     *
850     * @param str  the String to remove characters from, may be null
851     * @param stripChars  the set of characters to remove, null treated as whitespace
852     * @return the stripped String, {@code null} if null String input
853     */
854    public static String stripEnd(final String str, final String stripChars) {
855        int end;
856        if (str == null || (end = str.length()) == 0) {
857            return str;
858        }
859
860        if (stripChars == null) {
861            while (end != 0 && Character.isWhitespace(str.charAt(end - 1))) {
862                end--;
863            }
864        } else if (stripChars.isEmpty()) {
865            return str;
866        } else {
867            while (end != 0 && stripChars.indexOf(str.charAt(end - 1)) != INDEX_NOT_FOUND) {
868                end--;
869            }
870        }
871        return str.substring(0, end);
872    }
873
874    // StripAll
875    //-----------------------------------------------------------------------
876    /**
877     * <p>Strips whitespace from the start and end of every String in an array.
878     * Whitespace is defined by {@link Character#isWhitespace(char)}.</p>
879     *
880     * <p>A new array is returned each time, except for length zero.
881     * A {@code null} array will return {@code null}.
882     * An empty array will return itself.
883     * A {@code null} array entry will be ignored.</p>
884     *
885     * <pre>
886     * StringUtils.stripAll(null)             = null
887     * StringUtils.stripAll([])               = []
888     * StringUtils.stripAll(["abc", "  abc"]) = ["abc", "abc"]
889     * StringUtils.stripAll(["abc  ", null])  = ["abc", null]
890     * </pre>
891     *
892     * @param strs  the array to remove whitespace from, may be null
893     * @return the stripped Strings, {@code null} if null array input
894     */
895    public static String[] stripAll(final String... strs) {
896        return stripAll(strs, null);
897    }
898
899    /**
900     * <p>Strips any of a set of characters from the start and end of every
901     * String in an array.</p>
902     * <p>Whitespace is defined by {@link Character#isWhitespace(char)}.</p>
903     *
904     * <p>A new array is returned each time, except for length zero.
905     * A {@code null} array will return {@code null}.
906     * An empty array will return itself.
907     * A {@code null} array entry will be ignored.
908     * A {@code null} stripChars will strip whitespace as defined by
909     * {@link Character#isWhitespace(char)}.</p>
910     *
911     * <pre>
912     * StringUtils.stripAll(null, *)                = null
913     * StringUtils.stripAll([], *)                  = []
914     * StringUtils.stripAll(["abc", "  abc"], null) = ["abc", "abc"]
915     * StringUtils.stripAll(["abc  ", null], null)  = ["abc", null]
916     * StringUtils.stripAll(["abc  ", null], "yz")  = ["abc  ", null]
917     * StringUtils.stripAll(["yabcz", null], "yz")  = ["abc", null]
918     * </pre>
919     *
920     * @param strs  the array to remove characters from, may be null
921     * @param stripChars  the characters to remove, null treated as whitespace
922     * @return the stripped Strings, {@code null} if null array input
923     */
924    public static String[] stripAll(final String[] strs, final String stripChars) {
925        int strsLen;
926        if (strs == null || (strsLen = strs.length) == 0) {
927            return strs;
928        }
929        final String[] newArr = new String[strsLen];
930        for (int i = 0; i < strsLen; i++) {
931            newArr[i] = strip(strs[i], stripChars);
932        }
933        return newArr;
934    }
935
936    /**
937     * <p>Removes diacritics (~= accents) from a string. The case will not be altered.</p>
938     * <p>For instance, '&agrave;' will be replaced by 'a'.</p>
939     * <p>Note that ligatures will be left as is.</p>
940     *
941     * <pre>
942     * StringUtils.stripAccents(null)                = null
943     * StringUtils.stripAccents("")                  = ""
944     * StringUtils.stripAccents("control")           = "control"
945     * StringUtils.stripAccents("&eacute;clair")     = "eclair"
946     * </pre>
947     *
948     * @param input String to be stripped
949     * @return input text with diacritics removed
950     *
951     * @since 3.0
952     */
953    // 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).
954    public static String stripAccents(final String input) {
955        if (input == null) {
956            return null;
957        }
958        final Pattern pattern = Pattern.compile("\\p{InCombiningDiacriticalMarks}+"); //$NON-NLS-1$
959        final StringBuilder decomposed = new StringBuilder(Normalizer.normalize(input, Normalizer.Form.NFD));
960        convertRemainingAccentCharacters(decomposed);
961        // Note that this doesn't correctly remove ligatures...
962        return pattern.matcher(decomposed).replaceAll(EMPTY);
963    }
964
965    private static void convertRemainingAccentCharacters(final StringBuilder decomposed) {
966        for (int i = 0; i < decomposed.length(); i++) {
967            if (decomposed.charAt(i) == '\u0141') {
968                decomposed.deleteCharAt(i);
969                decomposed.insert(i, 'L');
970            } else if (decomposed.charAt(i) == '\u0142') {
971                decomposed.deleteCharAt(i);
972                decomposed.insert(i, 'l');
973            }
974        }
975    }
976
977    // Equals
978    //-----------------------------------------------------------------------
979    /**
980     * <p>Compares two CharSequences, returning {@code true} if they represent
981     * equal sequences of characters.</p>
982     *
983     * <p>{@code null}s are handled without exceptions. Two {@code null}
984     * references are considered to be equal. The comparison is <strong>case sensitive</strong>.</p>
985     *
986     * <pre>
987     * StringUtils.equals(null, null)   = true
988     * StringUtils.equals(null, "abc")  = false
989     * StringUtils.equals("abc", null)  = false
990     * StringUtils.equals("abc", "abc") = true
991     * StringUtils.equals("abc", "ABC") = false
992     * </pre>
993     *
994     * @param cs1  the first CharSequence, may be {@code null}
995     * @param cs2  the second CharSequence, may be {@code null}
996     * @return {@code true} if the CharSequences are equal (case-sensitive), or both {@code null}
997     * @since 3.0 Changed signature from equals(String, String) to equals(CharSequence, CharSequence)
998     * @see Object#equals(Object)
999     * @see #equalsIgnoreCase(CharSequence, CharSequence)
1000     */
1001    public static boolean equals(final CharSequence cs1, final CharSequence cs2) {
1002        if (cs1 == cs2) {
1003            return true;
1004        }
1005        if (cs1 == null || cs2 == null) {
1006            return false;
1007        }
1008        if (cs1.length() != cs2.length()) {
1009            return false;
1010        }
1011        if (cs1 instanceof String && cs2 instanceof String) {
1012            return cs1.equals(cs2);
1013        }
1014        // Step-wise comparison
1015        final int length = cs1.length();
1016        for (int i = 0; i < length; i++) {
1017            if (cs1.charAt(i) != cs2.charAt(i)) {
1018                return false;
1019            }
1020        }
1021        return true;
1022    }
1023
1024    /**
1025     * <p>Compares two CharSequences, returning {@code true} if they represent
1026     * equal sequences of characters, ignoring case.</p>
1027     *
1028     * <p>{@code null}s are handled without exceptions. Two {@code null}
1029     * references are considered equal. The comparison is <strong>case insensitive</strong>.</p>
1030     *
1031     * <pre>
1032     * StringUtils.equalsIgnoreCase(null, null)   = true
1033     * StringUtils.equalsIgnoreCase(null, "abc")  = false
1034     * StringUtils.equalsIgnoreCase("abc", null)  = false
1035     * StringUtils.equalsIgnoreCase("abc", "abc") = true
1036     * StringUtils.equalsIgnoreCase("abc", "ABC") = true
1037     * </pre>
1038     *
1039     * @param cs1  the first CharSequence, may be {@code null}
1040     * @param cs2  the second CharSequence, may be {@code null}
1041     * @return {@code true} if the CharSequences are equal (case-insensitive), or both {@code null}
1042     * @since 3.0 Changed signature from equalsIgnoreCase(String, String) to equalsIgnoreCase(CharSequence, CharSequence)
1043     * @see #equals(CharSequence, CharSequence)
1044     */
1045    public static boolean equalsIgnoreCase(final CharSequence cs1, final CharSequence cs2) {
1046        if (cs1 == cs2) {
1047            return true;
1048        }
1049        if (cs1 == null || cs2 == null) {
1050            return false;
1051        }
1052        if (cs1.length() != cs2.length()) {
1053            return false;
1054        }
1055        return CharSequenceUtils.regionMatches(cs1, true, 0, cs2, 0, cs1.length());
1056    }
1057
1058    // Compare
1059    //-----------------------------------------------------------------------
1060    /**
1061     * <p>Compare two Strings lexicographically, as per {@link String#compareTo(String)}, returning :</p>
1062     * <ul>
1063     *  <li>{@code int = 0}, if {@code str1} is equal to {@code str2} (or both {@code null})</li>
1064     *  <li>{@code int < 0}, if {@code str1} is less than {@code str2}</li>
1065     *  <li>{@code int > 0}, if {@code str1} is greater than {@code str2}</li>
1066     * </ul>
1067     *
1068     * <p>This is a {@code null} safe version of :</p>
1069     * <blockquote><pre>str1.compareTo(str2)</pre></blockquote>
1070     *
1071     * <p>{@code null} value is considered less than non-{@code null} value.
1072     * Two {@code null} references are considered equal.</p>
1073     *
1074     * <pre>
1075     * StringUtils.compare(null, null)   = 0
1076     * StringUtils.compare(null , "a")   &lt; 0
1077     * StringUtils.compare("a", null)    &gt; 0
1078     * StringUtils.compare("abc", "abc") = 0
1079     * StringUtils.compare("a", "b")     &lt; 0
1080     * StringUtils.compare("b", "a")     &gt; 0
1081     * StringUtils.compare("a", "B")     &gt; 0
1082     * StringUtils.compare("ab", "abc")  &lt; 0
1083     * </pre>
1084     *
1085     * @see #compare(String, String, boolean)
1086     * @see String#compareTo(String)
1087     * @param str1  the String to compare from
1088     * @param str2  the String to compare to
1089     * @return &lt; 0, 0, &gt; 0, if {@code str1} is respectively less, equal or greater than {@code str2}
1090     * @since 3.5
1091     */
1092    public static int compare(final String str1, final String str2) {
1093        return compare(str1, str2, true);
1094    }
1095
1096    /**
1097     * <p>Compare two Strings lexicographically, as per {@link String#compareTo(String)}, returning :</p>
1098     * <ul>
1099     *  <li>{@code int = 0}, if {@code str1} is equal to {@code str2} (or both {@code null})</li>
1100     *  <li>{@code int < 0}, if {@code str1} is less than {@code str2}</li>
1101     *  <li>{@code int > 0}, if {@code str1} is greater than {@code str2}</li>
1102     * </ul>
1103     *
1104     * <p>This is a {@code null} safe version of :</p>
1105     * <blockquote><pre>str1.compareTo(str2)</pre></blockquote>
1106     *
1107     * <p>{@code null} inputs are handled according to the {@code nullIsLess} parameter.
1108     * Two {@code null} references are considered equal.</p>
1109     *
1110     * <pre>
1111     * StringUtils.compare(null, null, *)     = 0
1112     * StringUtils.compare(null , "a", true)  &lt; 0
1113     * StringUtils.compare(null , "a", false) &gt; 0
1114     * StringUtils.compare("a", null, true)   &gt; 0
1115     * StringUtils.compare("a", null, false)  &lt; 0
1116     * StringUtils.compare("abc", "abc", *)   = 0
1117     * StringUtils.compare("a", "b", *)       &lt; 0
1118     * StringUtils.compare("b", "a", *)       &gt; 0
1119     * StringUtils.compare("a", "B", *)       &gt; 0
1120     * StringUtils.compare("ab", "abc", *)    &lt; 0
1121     * </pre>
1122     *
1123     * @see String#compareTo(String)
1124     * @param str1  the String to compare from
1125     * @param str2  the String to compare to
1126     * @param nullIsLess  whether consider {@code null} value less than non-{@code null} value
1127     * @return &lt; 0, 0, &gt; 0, if {@code str1} is respectively less, equal ou greater than {@code str2}
1128     * @since 3.5
1129     */
1130    public static int compare(final String str1, final String str2, final boolean nullIsLess) {
1131        if (str1 == str2) {
1132            return 0;
1133        }
1134        if (str1 == null) {
1135            return nullIsLess ? -1 : 1;
1136        }
1137        if (str2 == null) {
1138            return nullIsLess ? 1 : - 1;
1139        }
1140        return str1.compareTo(str2);
1141    }
1142
1143    /**
1144     * <p>Compare two Strings lexicographically, ignoring case differences,
1145     * as per {@link String#compareToIgnoreCase(String)}, returning :</p>
1146     * <ul>
1147     *  <li>{@code int = 0}, if {@code str1} is equal to {@code str2} (or both {@code null})</li>
1148     *  <li>{@code int < 0}, if {@code str1} is less than {@code str2}</li>
1149     *  <li>{@code int > 0}, if {@code str1} is greater than {@code str2}</li>
1150     * </ul>
1151     *
1152     * <p>This is a {@code null} safe version of :</p>
1153     * <blockquote><pre>str1.compareToIgnoreCase(str2)</pre></blockquote>
1154     *
1155     * <p>{@code null} value is considered less than non-{@code null} value.
1156     * Two {@code null} references are considered equal.
1157     * Comparison is case insensitive.</p>
1158     *
1159     * <pre>
1160     * StringUtils.compareIgnoreCase(null, null)   = 0
1161     * StringUtils.compareIgnoreCase(null , "a")   &lt; 0
1162     * StringUtils.compareIgnoreCase("a", null)    &gt; 0
1163     * StringUtils.compareIgnoreCase("abc", "abc") = 0
1164     * StringUtils.compareIgnoreCase("abc", "ABC") = 0
1165     * StringUtils.compareIgnoreCase("a", "b")     &lt; 0
1166     * StringUtils.compareIgnoreCase("b", "a")     &gt; 0
1167     * StringUtils.compareIgnoreCase("a", "B")     &lt; 0
1168     * StringUtils.compareIgnoreCase("A", "b")     &lt; 0
1169     * StringUtils.compareIgnoreCase("ab", "ABC")  &lt; 0
1170     * </pre>
1171     *
1172     * @see #compareIgnoreCase(String, String, boolean)
1173     * @see String#compareToIgnoreCase(String)
1174     * @param str1  the String to compare from
1175     * @param str2  the String to compare to
1176     * @return &lt; 0, 0, &gt; 0, if {@code str1} is respectively less, equal ou greater than {@code str2},
1177     *          ignoring case differences.
1178     * @since 3.5
1179     */
1180    public static int compareIgnoreCase(final String str1, final String str2) {
1181        return compareIgnoreCase(str1, str2, true);
1182    }
1183
1184    /**
1185     * <p>Compare two Strings lexicographically, ignoring case differences,
1186     * as per {@link String#compareToIgnoreCase(String)}, returning :</p>
1187     * <ul>
1188     *  <li>{@code int = 0}, if {@code str1} is equal to {@code str2} (or both {@code null})</li>
1189     *  <li>{@code int < 0}, if {@code str1} is less than {@code str2}</li>
1190     *  <li>{@code int > 0}, if {@code str1} is greater than {@code str2}</li>
1191     * </ul>
1192     *
1193     * <p>This is a {@code null} safe version of :</p>
1194     * <blockquote><pre>str1.compareToIgnoreCase(str2)</pre></blockquote>
1195     *
1196     * <p>{@code null} inputs are handled according to the {@code nullIsLess} parameter.
1197     * Two {@code null} references are considered equal.
1198     * Comparison is case insensitive.</p>
1199     *
1200     * <pre>
1201     * StringUtils.compareIgnoreCase(null, null, *)     = 0
1202     * StringUtils.compareIgnoreCase(null , "a", true)  &lt; 0
1203     * StringUtils.compareIgnoreCase(null , "a", false) &gt; 0
1204     * StringUtils.compareIgnoreCase("a", null, true)   &gt; 0
1205     * StringUtils.compareIgnoreCase("a", null, false)  &lt; 0
1206     * StringUtils.compareIgnoreCase("abc", "abc", *)   = 0
1207     * StringUtils.compareIgnoreCase("abc", "ABC", *)   = 0
1208     * StringUtils.compareIgnoreCase("a", "b", *)       &lt; 0
1209     * StringUtils.compareIgnoreCase("b", "a", *)       &gt; 0
1210     * StringUtils.compareIgnoreCase("a", "B", *)       &lt; 0
1211     * StringUtils.compareIgnoreCase("A", "b", *)       &lt; 0
1212     * StringUtils.compareIgnoreCase("ab", "abc", *)    &lt; 0
1213     * </pre>
1214     *
1215     * @see String#compareToIgnoreCase(String)
1216     * @param str1  the String to compare from
1217     * @param str2  the String to compare to
1218     * @param nullIsLess  whether consider {@code null} value less than non-{@code null} value
1219     * @return &lt; 0, 0, &gt; 0, if {@code str1} is respectively less, equal ou greater than {@code str2},
1220     *          ignoring case differences.
1221     * @since 3.5
1222     */
1223    public static int compareIgnoreCase(final String str1, final String str2, final boolean nullIsLess) {
1224        if (str1 == str2) {
1225            return 0;
1226        }
1227        if (str1 == null) {
1228            return nullIsLess ? -1 : 1;
1229        }
1230        if (str2 == null) {
1231            return nullIsLess ? 1 : - 1;
1232        }
1233        return str1.compareToIgnoreCase(str2);
1234    }
1235
1236    /**
1237     * <p>Compares given <code>string</code> to a CharSequences vararg of <code>searchStrings</code>,
1238     * returning {@code true} if the <code>string</code> is equal to any of the <code>searchStrings</code>.</p>
1239     *
1240     * <pre>
1241     * StringUtils.equalsAny(null, (CharSequence[]) null) = false
1242     * StringUtils.equalsAny(null, null, null)    = true
1243     * StringUtils.equalsAny(null, "abc", "def")  = false
1244     * StringUtils.equalsAny("abc", null, "def")  = false
1245     * StringUtils.equalsAny("abc", "abc", "def") = true
1246     * StringUtils.equalsAny("abc", "ABC", "DEF") = false
1247     * </pre>
1248     *
1249     * @param string to compare, may be {@code null}.
1250     * @param searchStrings a vararg of strings, may be {@code null}.
1251     * @return {@code true} if the string is equal (case-sensitive) to any other element of <code>searchStrings</code>;
1252     * {@code false} if <code>searchStrings</code> is null or contains no matches.
1253     * @since 3.5
1254     */
1255    public static boolean equalsAny(final CharSequence string, final CharSequence... searchStrings) {
1256        if (ArrayUtils.isNotEmpty(searchStrings)) {
1257            for (final CharSequence next : searchStrings) {
1258                if (equals(string, next)) {
1259                    return true;
1260                }
1261            }
1262        }
1263        return false;
1264    }
1265
1266
1267    /**
1268     * <p>Compares given <code>string</code> to a CharSequences vararg of <code>searchStrings</code>,
1269     * returning {@code true} if the <code>string</code> is equal to any of the <code>searchStrings</code>, ignoring case.</p>
1270     *
1271     * <pre>
1272     * StringUtils.equalsAnyIgnoreCase(null, (CharSequence[]) null) = false
1273     * StringUtils.equalsAnyIgnoreCase(null, null, null)    = true
1274     * StringUtils.equalsAnyIgnoreCase(null, "abc", "def")  = false
1275     * StringUtils.equalsAnyIgnoreCase("abc", null, "def")  = false
1276     * StringUtils.equalsAnyIgnoreCase("abc", "abc", "def") = true
1277     * StringUtils.equalsAnyIgnoreCase("abc", "ABC", "DEF") = true
1278     * </pre>
1279     *
1280     * @param string to compare, may be {@code null}.
1281     * @param searchStrings a vararg of strings, may be {@code null}.
1282     * @return {@code true} if the string is equal (case-insensitive) to any other element of <code>searchStrings</code>;
1283     * {@code false} if <code>searchStrings</code> is null or contains no matches.
1284     * @since 3.5
1285     */
1286    public static boolean equalsAnyIgnoreCase(final CharSequence string, final CharSequence...searchStrings) {
1287        if (ArrayUtils.isNotEmpty(searchStrings)) {
1288            for (final CharSequence next : searchStrings) {
1289                if (equalsIgnoreCase(string, next)) {
1290                    return true;
1291                }
1292            }
1293        }
1294        return false;
1295    }
1296
1297    // IndexOf
1298    //-----------------------------------------------------------------------
1299    /**
1300     * Returns the index within <code>seq</code> of the first occurrence of
1301     * the specified character. If a character with value
1302     * <code>searchChar</code> occurs in the character sequence represented by
1303     * <code>seq</code> <code>CharSequence</code> object, then the index (in Unicode
1304     * code units) of the first such occurrence is returned. For
1305     * values of <code>searchChar</code> in the range from 0 to 0xFFFF
1306     * (inclusive), this is the smallest value <i>k</i> such that:
1307     * <blockquote><pre>
1308     * this.charAt(<i>k</i>) == searchChar
1309     * </pre></blockquote>
1310     * is true. For other values of <code>searchChar</code>, it is the
1311     * smallest value <i>k</i> such that:
1312     * <blockquote><pre>
1313     * this.codePointAt(<i>k</i>) == searchChar
1314     * </pre></blockquote>
1315     * is true. In either case, if no such character occurs in <code>seq</code>,
1316     * then {@code INDEX_NOT_FOUND (-1)} is returned.
1317     *
1318     * <p>Furthermore, a {@code null} or empty ("") CharSequence will
1319     * return {@code INDEX_NOT_FOUND (-1)}.</p>
1320     *
1321     * <pre>
1322     * StringUtils.indexOf(null, *)         = -1
1323     * StringUtils.indexOf("", *)           = -1
1324     * StringUtils.indexOf("aabaabaa", 'a') = 0
1325     * StringUtils.indexOf("aabaabaa", 'b') = 2
1326     * </pre>
1327     *
1328     * @param seq  the CharSequence to check, may be null
1329     * @param searchChar  the character to find
1330     * @return the first index of the search character,
1331     *  -1 if no match or {@code null} string input
1332     * @since 2.0
1333     * @since 3.0 Changed signature from indexOf(String, int) to indexOf(CharSequence, int)
1334     * @since 3.6 Updated {@link CharSequenceUtils} call to behave more like <code>String</code>
1335     */
1336    public static int indexOf(final CharSequence seq, final int searchChar) {
1337        if (isEmpty(seq)) {
1338            return INDEX_NOT_FOUND;
1339        }
1340        return CharSequenceUtils.indexOf(seq, searchChar, 0);
1341    }
1342
1343    /**
1344     *
1345     * Returns the index within <code>seq</code> of the first occurrence of the
1346     * specified character, starting the search at the specified index.
1347     * <p>
1348     * If a character with value <code>searchChar</code> occurs in the
1349     * character sequence represented by the <code>seq</code> <code>CharSequence</code>
1350     * object at an index no smaller than <code>startPos</code>, then
1351     * the index of the first such occurrence is returned. For values
1352     * of <code>searchChar</code> in the range from 0 to 0xFFFF (inclusive),
1353     * this is the smallest value <i>k</i> such that:
1354     * <blockquote><pre>
1355     * (this.charAt(<i>k</i>) == searchChar) &amp;&amp; (<i>k</i> &gt;= startPos)
1356     * </pre></blockquote>
1357     * is true. For other values of <code>searchChar</code>, it is the
1358     * smallest value <i>k</i> such that:
1359     * <blockquote><pre>
1360     * (this.codePointAt(<i>k</i>) == searchChar) &amp;&amp; (<i>k</i> &gt;= startPos)
1361     * </pre></blockquote>
1362     * is true. In either case, if no such character occurs in <code>seq</code>
1363     * at or after position <code>startPos</code>, then
1364     * <code>-1</code> is returned.
1365     *
1366     * <p>
1367     * There is no restriction on the value of <code>startPos</code>. If it
1368     * is negative, it has the same effect as if it were zero: this entire
1369     * string may be searched. If it is greater than the length of this
1370     * string, it has the same effect as if it were equal to the length of
1371     * this string: {@code (INDEX_NOT_FOUND) -1} is returned. Furthermore, a
1372     * {@code null} or empty ("") CharSequence will
1373     * return {@code (INDEX_NOT_FOUND) -1}.
1374     *
1375     * <p>All indices are specified in <code>char</code> values
1376     * (Unicode code units).
1377     *
1378     * <pre>
1379     * StringUtils.indexOf(null, *, *)          = -1
1380     * StringUtils.indexOf("", *, *)            = -1
1381     * StringUtils.indexOf("aabaabaa", 'b', 0)  = 2
1382     * StringUtils.indexOf("aabaabaa", 'b', 3)  = 5
1383     * StringUtils.indexOf("aabaabaa", 'b', 9)  = -1
1384     * StringUtils.indexOf("aabaabaa", 'b', -1) = 2
1385     * </pre>
1386     *
1387     * @param seq  the CharSequence to check, may be null
1388     * @param searchChar  the character to find
1389     * @param startPos  the start position, negative treated as zero
1390     * @return the first index of the search character (always &ge; startPos),
1391     *  -1 if no match or {@code null} string input
1392     * @since 2.0
1393     * @since 3.0 Changed signature from indexOf(String, int, int) to indexOf(CharSequence, int, int)
1394     * @since 3.6 Updated {@link CharSequenceUtils} call to behave more like <code>String</code>
1395     */
1396    public static int indexOf(final CharSequence seq, final int searchChar, final int startPos) {
1397        if (isEmpty(seq)) {
1398            return INDEX_NOT_FOUND;
1399        }
1400        return CharSequenceUtils.indexOf(seq, searchChar, startPos);
1401    }
1402
1403    /**
1404     * <p>Finds the first index within a CharSequence, handling {@code null}.
1405     * This method uses {@link String#indexOf(String, int)} if possible.</p>
1406     *
1407     * <p>A {@code null} CharSequence will return {@code -1}.</p>
1408     *
1409     * <pre>
1410     * StringUtils.indexOf(null, *)          = -1
1411     * StringUtils.indexOf(*, null)          = -1
1412     * StringUtils.indexOf("", "")           = 0
1413     * StringUtils.indexOf("", *)            = -1 (except when * = "")
1414     * StringUtils.indexOf("aabaabaa", "a")  = 0
1415     * StringUtils.indexOf("aabaabaa", "b")  = 2
1416     * StringUtils.indexOf("aabaabaa", "ab") = 1
1417     * StringUtils.indexOf("aabaabaa", "")   = 0
1418     * </pre>
1419     *
1420     * @param seq  the CharSequence to check, may be null
1421     * @param searchSeq  the CharSequence to find, may be null
1422     * @return the first index of the search CharSequence,
1423     *  -1 if no match or {@code null} string input
1424     * @since 2.0
1425     * @since 3.0 Changed signature from indexOf(String, String) to indexOf(CharSequence, CharSequence)
1426     */
1427    public static int indexOf(final CharSequence seq, final CharSequence searchSeq) {
1428        if (seq == null || searchSeq == null) {
1429            return INDEX_NOT_FOUND;
1430        }
1431        return CharSequenceUtils.indexOf(seq, searchSeq, 0);
1432    }
1433
1434    /**
1435     * <p>Finds the first index within a CharSequence, handling {@code null}.
1436     * This method uses {@link String#indexOf(String, int)} if possible.</p>
1437     *
1438     * <p>A {@code null} CharSequence will return {@code -1}.
1439     * A negative start position is treated as zero.
1440     * An empty ("") search CharSequence always matches.
1441     * A start position greater than the string length only matches
1442     * an empty search CharSequence.</p>
1443     *
1444     * <pre>
1445     * StringUtils.indexOf(null, *, *)          = -1
1446     * StringUtils.indexOf(*, null, *)          = -1
1447     * StringUtils.indexOf("", "", 0)           = 0
1448     * StringUtils.indexOf("", *, 0)            = -1 (except when * = "")
1449     * StringUtils.indexOf("aabaabaa", "a", 0)  = 0
1450     * StringUtils.indexOf("aabaabaa", "b", 0)  = 2
1451     * StringUtils.indexOf("aabaabaa", "ab", 0) = 1
1452     * StringUtils.indexOf("aabaabaa", "b", 3)  = 5
1453     * StringUtils.indexOf("aabaabaa", "b", 9)  = -1
1454     * StringUtils.indexOf("aabaabaa", "b", -1) = 2
1455     * StringUtils.indexOf("aabaabaa", "", 2)   = 2
1456     * StringUtils.indexOf("abc", "", 9)        = 3
1457     * </pre>
1458     *
1459     * @param seq  the CharSequence to check, may be null
1460     * @param searchSeq  the CharSequence to find, may be null
1461     * @param startPos  the start position, negative treated as zero
1462     * @return the first index of the search CharSequence (always &ge; startPos),
1463     *  -1 if no match or {@code null} string input
1464     * @since 2.0
1465     * @since 3.0 Changed signature from indexOf(String, String, int) to indexOf(CharSequence, CharSequence, int)
1466     */
1467    public static int indexOf(final CharSequence seq, final CharSequence searchSeq, final int startPos) {
1468        if (seq == null || searchSeq == null) {
1469            return INDEX_NOT_FOUND;
1470        }
1471        return CharSequenceUtils.indexOf(seq, searchSeq, startPos);
1472    }
1473
1474    /**
1475     * <p>Finds the n-th index within a CharSequence, handling {@code null}.
1476     * This method uses {@link String#indexOf(String)} if possible.</p>
1477     * <p><b>Note:</b> The code starts looking for a match at the start of the target,
1478     * incrementing the starting index by one after each successful match
1479     * (unless {@code searchStr} is an empty string in which case the position
1480     * is never incremented and {@code 0} is returned immediately).
1481     * This means that matches may overlap.</p>
1482     * <p>A {@code null} CharSequence will return {@code -1}.</p>
1483     *
1484     * <pre>
1485     * StringUtils.ordinalIndexOf(null, *, *)          = -1
1486     * StringUtils.ordinalIndexOf(*, null, *)          = -1
1487     * StringUtils.ordinalIndexOf("", "", *)           = 0
1488     * StringUtils.ordinalIndexOf("aabaabaa", "a", 1)  = 0
1489     * StringUtils.ordinalIndexOf("aabaabaa", "a", 2)  = 1
1490     * StringUtils.ordinalIndexOf("aabaabaa", "b", 1)  = 2
1491     * StringUtils.ordinalIndexOf("aabaabaa", "b", 2)  = 5
1492     * StringUtils.ordinalIndexOf("aabaabaa", "ab", 1) = 1
1493     * StringUtils.ordinalIndexOf("aabaabaa", "ab", 2) = 4
1494     * StringUtils.ordinalIndexOf("aabaabaa", "", 1)   = 0
1495     * StringUtils.ordinalIndexOf("aabaabaa", "", 2)   = 0
1496     * </pre>
1497     *
1498     * <p>Matches may overlap:</p>
1499     * <pre>
1500     * StringUtils.ordinalIndexOf("ababab", "aba", 1)   = 0
1501     * StringUtils.ordinalIndexOf("ababab", "aba", 2)   = 2
1502     * StringUtils.ordinalIndexOf("ababab", "aba", 3)   = -1
1503     *
1504     * StringUtils.ordinalIndexOf("abababab", "abab", 1) = 0
1505     * StringUtils.ordinalIndexOf("abababab", "abab", 2) = 2
1506     * StringUtils.ordinalIndexOf("abababab", "abab", 3) = 4
1507     * StringUtils.ordinalIndexOf("abababab", "abab", 4) = -1
1508     * </pre>
1509     *
1510     * <p>Note that 'head(CharSequence str, int n)' may be implemented as: </p>
1511     *
1512     * <pre>
1513     *   str.substring(0, lastOrdinalIndexOf(str, "\n", n))
1514     * </pre>
1515     *
1516     * @param str  the CharSequence to check, may be null
1517     * @param searchStr  the CharSequence to find, may be null
1518     * @param ordinal  the n-th {@code searchStr} to find
1519     * @return the n-th index of the search CharSequence,
1520     *  {@code -1} ({@code INDEX_NOT_FOUND}) if no match or {@code null} string input
1521     * @since 2.1
1522     * @since 3.0 Changed signature from ordinalIndexOf(String, String, int) to ordinalIndexOf(CharSequence, CharSequence, int)
1523     */
1524    public static int ordinalIndexOf(final CharSequence str, final CharSequence searchStr, final int ordinal) {
1525        return ordinalIndexOf(str, searchStr, ordinal, false);
1526    }
1527
1528    /**
1529     * <p>Finds the n-th index within a String, handling {@code null}.
1530     * This method uses {@link String#indexOf(String)} if possible.</p>
1531     * <p>Note that matches may overlap<p>
1532     *
1533     * <p>A {@code null} CharSequence will return {@code -1}.</p>
1534     *
1535     * @param str  the CharSequence to check, may be null
1536     * @param searchStr  the CharSequence to find, may be null
1537     * @param ordinal  the n-th {@code searchStr} to find, overlapping matches are allowed.
1538     * @param lastIndex true if lastOrdinalIndexOf() otherwise false if ordinalIndexOf()
1539     * @return the n-th index of the search CharSequence,
1540     *  {@code -1} ({@code INDEX_NOT_FOUND}) if no match or {@code null} string input
1541     */
1542    // Shared code between ordinalIndexOf(String, String, int) and lastOrdinalIndexOf(String, String, int)
1543    private static int ordinalIndexOf(final CharSequence str, final CharSequence searchStr, final int ordinal, final boolean lastIndex) {
1544        if (str == null || searchStr == null || ordinal <= 0) {
1545            return INDEX_NOT_FOUND;
1546        }
1547        if (searchStr.length() == 0) {
1548            return lastIndex ? str.length() : 0;
1549        }
1550        int found = 0;
1551        // set the initial index beyond the end of the string
1552        // this is to allow for the initial index decrement/increment
1553        int index = lastIndex ? str.length() : INDEX_NOT_FOUND;
1554        do {
1555            if (lastIndex) {
1556                index = CharSequenceUtils.lastIndexOf(str, searchStr, index - 1); // step backwards thru string
1557            } else {
1558                index = CharSequenceUtils.indexOf(str, searchStr, index + 1); // step forwards through string
1559            }
1560            if (index < 0) {
1561                return index;
1562            }
1563            found++;
1564        } while (found < ordinal);
1565        return index;
1566    }
1567
1568    /**
1569     * <p>Case in-sensitive find of the first index within a CharSequence.</p>
1570     *
1571     * <p>A {@code null} CharSequence will return {@code -1}.
1572     * A negative start position is treated as zero.
1573     * An empty ("") search CharSequence always matches.
1574     * A start position greater than the string length only matches
1575     * an empty search CharSequence.</p>
1576     *
1577     * <pre>
1578     * StringUtils.indexOfIgnoreCase(null, *)          = -1
1579     * StringUtils.indexOfIgnoreCase(*, null)          = -1
1580     * StringUtils.indexOfIgnoreCase("", "")           = 0
1581     * StringUtils.indexOfIgnoreCase("aabaabaa", "a")  = 0
1582     * StringUtils.indexOfIgnoreCase("aabaabaa", "b")  = 2
1583     * StringUtils.indexOfIgnoreCase("aabaabaa", "ab") = 1
1584     * </pre>
1585     *
1586     * @param str  the CharSequence to check, may be null
1587     * @param searchStr  the CharSequence to find, may be null
1588     * @return the first index of the search CharSequence,
1589     *  -1 if no match or {@code null} string input
1590     * @since 2.5
1591     * @since 3.0 Changed signature from indexOfIgnoreCase(String, String) to indexOfIgnoreCase(CharSequence, CharSequence)
1592     */
1593    public static int indexOfIgnoreCase(final CharSequence str, final CharSequence searchStr) {
1594        return indexOfIgnoreCase(str, searchStr, 0);
1595    }
1596
1597    /**
1598     * <p>Case in-sensitive find of the first index within a CharSequence
1599     * from the specified position.</p>
1600     *
1601     * <p>A {@code null} CharSequence will return {@code -1}.
1602     * A negative start position is treated as zero.
1603     * An empty ("") search CharSequence always matches.
1604     * A start position greater than the string length only matches
1605     * an empty search CharSequence.</p>
1606     *
1607     * <pre>
1608     * StringUtils.indexOfIgnoreCase(null, *, *)          = -1
1609     * StringUtils.indexOfIgnoreCase(*, null, *)          = -1
1610     * StringUtils.indexOfIgnoreCase("", "", 0)           = 0
1611     * StringUtils.indexOfIgnoreCase("aabaabaa", "A", 0)  = 0
1612     * StringUtils.indexOfIgnoreCase("aabaabaa", "B", 0)  = 2
1613     * StringUtils.indexOfIgnoreCase("aabaabaa", "AB", 0) = 1
1614     * StringUtils.indexOfIgnoreCase("aabaabaa", "B", 3)  = 5
1615     * StringUtils.indexOfIgnoreCase("aabaabaa", "B", 9)  = -1
1616     * StringUtils.indexOfIgnoreCase("aabaabaa", "B", -1) = 2
1617     * StringUtils.indexOfIgnoreCase("aabaabaa", "", 2)   = 2
1618     * StringUtils.indexOfIgnoreCase("abc", "", 9)        = -1
1619     * </pre>
1620     *
1621     * @param str  the CharSequence to check, may be null
1622     * @param searchStr  the CharSequence to find, may be null
1623     * @param startPos  the start position, negative treated as zero
1624     * @return the first index of the search CharSequence (always &ge; startPos),
1625     *  -1 if no match or {@code null} string input
1626     * @since 2.5
1627     * @since 3.0 Changed signature from indexOfIgnoreCase(String, String, int) to indexOfIgnoreCase(CharSequence, CharSequence, int)
1628     */
1629    public static int indexOfIgnoreCase(final CharSequence str, final CharSequence searchStr, int startPos) {
1630        if (str == null || searchStr == null) {
1631            return INDEX_NOT_FOUND;
1632        }
1633        if (startPos < 0) {
1634            startPos = 0;
1635        }
1636        final int endLimit = str.length() - searchStr.length() + 1;
1637        if (startPos > endLimit) {
1638            return INDEX_NOT_FOUND;
1639        }
1640        if (searchStr.length() == 0) {
1641            return startPos;
1642        }
1643        for (int i = startPos; i < endLimit; i++) {
1644            if (CharSequenceUtils.regionMatches(str, true, i, searchStr, 0, searchStr.length())) {
1645                return i;
1646            }
1647        }
1648        return INDEX_NOT_FOUND;
1649    }
1650
1651    // LastIndexOf
1652    //-----------------------------------------------------------------------
1653    /**
1654     * Returns the index within <code>seq</code> of the last occurrence of
1655     * the specified character. For values of <code>searchChar</code> in the
1656     * range from 0 to 0xFFFF (inclusive), the index (in Unicode code
1657     * units) returned is the largest value <i>k</i> such that:
1658     * <blockquote><pre>
1659     * this.charAt(<i>k</i>) == searchChar
1660     * </pre></blockquote>
1661     * is true. For other values of <code>searchChar</code>, it is the
1662     * largest value <i>k</i> such that:
1663     * <blockquote><pre>
1664     * this.codePointAt(<i>k</i>) == searchChar
1665     * </pre></blockquote>
1666     * is true.  In either case, if no such character occurs in this
1667     * string, then <code>-1</code> is returned. Furthermore, a {@code null} or empty ("")
1668     * <code>CharSequence</code> will return {@code -1}. The
1669     * <code>seq</code> <code>CharSequence</code> object is searched backwards
1670     * starting at the last character.
1671     *
1672     * <pre>
1673     * StringUtils.lastIndexOf(null, *)         = -1
1674     * StringUtils.lastIndexOf("", *)           = -1
1675     * StringUtils.lastIndexOf("aabaabaa", 'a') = 7
1676     * StringUtils.lastIndexOf("aabaabaa", 'b') = 5
1677     * </pre>
1678     *
1679     * @param seq  the <code>CharSequence</code> to check, may be null
1680     * @param searchChar  the character to find
1681     * @return the last index of the search character,
1682     *  -1 if no match or {@code null} string input
1683     * @since 2.0
1684     * @since 3.0 Changed signature from lastIndexOf(String, int) to lastIndexOf(CharSequence, int)
1685     * @since 3.6 Updated {@link CharSequenceUtils} call to behave more like <code>String</code>
1686     */
1687    public static int lastIndexOf(final CharSequence seq, final int searchChar) {
1688        if (isEmpty(seq)) {
1689            return INDEX_NOT_FOUND;
1690        }
1691        return CharSequenceUtils.lastIndexOf(seq, searchChar, seq.length());
1692    }
1693
1694    /**
1695     * Returns the index within <code>seq</code> of the last occurrence of
1696     * the specified character, searching backward starting at the
1697     * specified index. For values of <code>searchChar</code> in the range
1698     * from 0 to 0xFFFF (inclusive), the index returned is the largest
1699     * value <i>k</i> such that:
1700     * <blockquote><pre>
1701     * (this.charAt(<i>k</i>) == searchChar) &amp;&amp; (<i>k</i> &lt;= startPos)
1702     * </pre></blockquote>
1703     * is true. For other values of <code>searchChar</code>, it is the
1704     * largest value <i>k</i> such that:
1705     * <blockquote><pre>
1706     * (this.codePointAt(<i>k</i>) == searchChar) &amp;&amp; (<i>k</i> &lt;= startPos)
1707     * </pre></blockquote>
1708     * is true. In either case, if no such character occurs in <code>seq</code>
1709     * at or before position <code>startPos</code>, then
1710     * <code>-1</code> is returned. Furthermore, a {@code null} or empty ("")
1711     * <code>CharSequence</code> will return {@code -1}. A start position greater
1712     * than the string length searches the whole string.
1713     * The search starts at the <code>startPos</code> and works backwards;
1714     * matches starting after the start position are ignored.
1715     *
1716     * <p>All indices are specified in <code>char</code> values
1717     * (Unicode code units).
1718     *
1719     * <pre>
1720     * StringUtils.lastIndexOf(null, *, *)          = -1
1721     * StringUtils.lastIndexOf("", *,  *)           = -1
1722     * StringUtils.lastIndexOf("aabaabaa", 'b', 8)  = 5
1723     * StringUtils.lastIndexOf("aabaabaa", 'b', 4)  = 2
1724     * StringUtils.lastIndexOf("aabaabaa", 'b', 0)  = -1
1725     * StringUtils.lastIndexOf("aabaabaa", 'b', 9)  = 5
1726     * StringUtils.lastIndexOf("aabaabaa", 'b', -1) = -1
1727     * StringUtils.lastIndexOf("aabaabaa", 'a', 0)  = 0
1728     * </pre>
1729     *
1730     * @param seq  the CharSequence to check, may be null
1731     * @param searchChar  the character to find
1732     * @param startPos  the start position
1733     * @return the last index of the search character (always &le; startPos),
1734     *  -1 if no match or {@code null} string input
1735     * @since 2.0
1736     * @since 3.0 Changed signature from lastIndexOf(String, int, int) to lastIndexOf(CharSequence, int, int)
1737     */
1738    public static int lastIndexOf(final CharSequence seq, final int searchChar, final int startPos) {
1739        if (isEmpty(seq)) {
1740            return INDEX_NOT_FOUND;
1741        }
1742        return CharSequenceUtils.lastIndexOf(seq, searchChar, startPos);
1743    }
1744
1745    /**
1746     * <p>Finds the last index within a CharSequence, handling {@code null}.
1747     * This method uses {@link String#lastIndexOf(String)} if possible.</p>
1748     *
1749     * <p>A {@code null} CharSequence will return {@code -1}.</p>
1750     *
1751     * <pre>
1752     * StringUtils.lastIndexOf(null, *)          = -1
1753     * StringUtils.lastIndexOf(*, null)          = -1
1754     * StringUtils.lastIndexOf("", "")           = 0
1755     * StringUtils.lastIndexOf("aabaabaa", "a")  = 7
1756     * StringUtils.lastIndexOf("aabaabaa", "b")  = 5
1757     * StringUtils.lastIndexOf("aabaabaa", "ab") = 4
1758     * StringUtils.lastIndexOf("aabaabaa", "")   = 8
1759     * </pre>
1760     *
1761     * @param seq  the CharSequence to check, may be null
1762     * @param searchSeq  the CharSequence to find, may be null
1763     * @return the last index of the search String,
1764     *  -1 if no match or {@code null} string input
1765     * @since 2.0
1766     * @since 3.0 Changed signature from lastIndexOf(String, String) to lastIndexOf(CharSequence, CharSequence)
1767     */
1768    public static int lastIndexOf(final CharSequence seq, final CharSequence searchSeq) {
1769        if (seq == null || searchSeq == null) {
1770            return INDEX_NOT_FOUND;
1771        }
1772        return CharSequenceUtils.lastIndexOf(seq, searchSeq, seq.length());
1773    }
1774
1775    /**
1776     * <p>Finds the n-th last index within a String, handling {@code null}.
1777     * This method uses {@link String#lastIndexOf(String)}.</p>
1778     *
1779     * <p>A {@code null} String will return {@code -1}.</p>
1780     *
1781     * <pre>
1782     * StringUtils.lastOrdinalIndexOf(null, *, *)          = -1
1783     * StringUtils.lastOrdinalIndexOf(*, null, *)          = -1
1784     * StringUtils.lastOrdinalIndexOf("", "", *)           = 0
1785     * StringUtils.lastOrdinalIndexOf("aabaabaa", "a", 1)  = 7
1786     * StringUtils.lastOrdinalIndexOf("aabaabaa", "a", 2)  = 6
1787     * StringUtils.lastOrdinalIndexOf("aabaabaa", "b", 1)  = 5
1788     * StringUtils.lastOrdinalIndexOf("aabaabaa", "b", 2)  = 2
1789     * StringUtils.lastOrdinalIndexOf("aabaabaa", "ab", 1) = 4
1790     * StringUtils.lastOrdinalIndexOf("aabaabaa", "ab", 2) = 1
1791     * StringUtils.lastOrdinalIndexOf("aabaabaa", "", 1)   = 8
1792     * StringUtils.lastOrdinalIndexOf("aabaabaa", "", 2)   = 8
1793     * </pre>
1794     *
1795     * <p>Note that 'tail(CharSequence str, int n)' may be implemented as: </p>
1796     *
1797     * <pre>
1798     *   str.substring(lastOrdinalIndexOf(str, "\n", n) + 1)
1799     * </pre>
1800     *
1801     * @param str  the CharSequence to check, may be null
1802     * @param searchStr  the CharSequence to find, may be null
1803     * @param ordinal  the n-th last {@code searchStr} to find
1804     * @return the n-th last index of the search CharSequence,
1805     *  {@code -1} ({@code INDEX_NOT_FOUND}) if no match or {@code null} string input
1806     * @since 2.5
1807     * @since 3.0 Changed signature from lastOrdinalIndexOf(String, String, int) to lastOrdinalIndexOf(CharSequence, CharSequence, int)
1808     */
1809    public static int lastOrdinalIndexOf(final CharSequence str, final CharSequence searchStr, final int ordinal) {
1810        return ordinalIndexOf(str, searchStr, ordinal, true);
1811    }
1812
1813    /**
1814     * <p>Finds the last index within a CharSequence, handling {@code null}.
1815     * This method uses {@link String#lastIndexOf(String, int)} if possible.</p>
1816     *
1817     * <p>A {@code null} CharSequence will return {@code -1}.
1818     * A negative start position returns {@code -1}.
1819     * An empty ("") search CharSequence always matches unless the start position is negative.
1820     * A start position greater than the string length searches the whole string.
1821     * The search starts at the startPos and works backwards; matches starting after the start
1822     * position are ignored.
1823     * </p>
1824     *
1825     * <pre>
1826     * StringUtils.lastIndexOf(null, *, *)          = -1
1827     * StringUtils.lastIndexOf(*, null, *)          = -1
1828     * StringUtils.lastIndexOf("aabaabaa", "a", 8)  = 7
1829     * StringUtils.lastIndexOf("aabaabaa", "b", 8)  = 5
1830     * StringUtils.lastIndexOf("aabaabaa", "ab", 8) = 4
1831     * StringUtils.lastIndexOf("aabaabaa", "b", 9)  = 5
1832     * StringUtils.lastIndexOf("aabaabaa", "b", -1) = -1
1833     * StringUtils.lastIndexOf("aabaabaa", "a", 0)  = 0
1834     * StringUtils.lastIndexOf("aabaabaa", "b", 0)  = -1
1835     * StringUtils.lastIndexOf("aabaabaa", "b", 1)  = -1
1836     * StringUtils.lastIndexOf("aabaabaa", "b", 2)  = 2
1837     * StringUtils.lastIndexOf("aabaabaa", "ba", 2)  = 2
1838     * </pre>
1839     *
1840     * @param seq  the CharSequence to check, may be null
1841     * @param searchSeq  the CharSequence to find, may be null
1842     * @param startPos  the start position, negative treated as zero
1843     * @return the last index of the search CharSequence (always &le; startPos),
1844     *  -1 if no match or {@code null} string input
1845     * @since 2.0
1846     * @since 3.0 Changed signature from lastIndexOf(String, String, int) to lastIndexOf(CharSequence, CharSequence, int)
1847     */
1848    public static int lastIndexOf(final CharSequence seq, final CharSequence searchSeq, final int startPos) {
1849        if (seq == null || searchSeq == null) {
1850            return INDEX_NOT_FOUND;
1851        }
1852        return CharSequenceUtils.lastIndexOf(seq, searchSeq, startPos);
1853    }
1854
1855    /**
1856     * <p>Case in-sensitive find of the last index within a CharSequence.</p>
1857     *
1858     * <p>A {@code null} CharSequence will return {@code -1}.
1859     * A negative start position returns {@code -1}.
1860     * An empty ("") search CharSequence always matches unless the start position is negative.
1861     * A start position greater than the string length searches the whole string.</p>
1862     *
1863     * <pre>
1864     * StringUtils.lastIndexOfIgnoreCase(null, *)          = -1
1865     * StringUtils.lastIndexOfIgnoreCase(*, null)          = -1
1866     * StringUtils.lastIndexOfIgnoreCase("aabaabaa", "A")  = 7
1867     * StringUtils.lastIndexOfIgnoreCase("aabaabaa", "B")  = 5
1868     * StringUtils.lastIndexOfIgnoreCase("aabaabaa", "AB") = 4
1869     * </pre>
1870     *
1871     * @param str  the CharSequence to check, may be null
1872     * @param searchStr  the CharSequence to find, may be null
1873     * @return the first index of the search CharSequence,
1874     *  -1 if no match or {@code null} string input
1875     * @since 2.5
1876     * @since 3.0 Changed signature from lastIndexOfIgnoreCase(String, String) to lastIndexOfIgnoreCase(CharSequence, CharSequence)
1877     */
1878    public static int lastIndexOfIgnoreCase(final CharSequence str, final CharSequence searchStr) {
1879        if (str == null || searchStr == null) {
1880            return INDEX_NOT_FOUND;
1881        }
1882        return lastIndexOfIgnoreCase(str, searchStr, str.length());
1883    }
1884
1885    /**
1886     * <p>Case in-sensitive find of the last index within a CharSequence
1887     * from the specified position.</p>
1888     *
1889     * <p>A {@code null} CharSequence will return {@code -1}.
1890     * A negative start position returns {@code -1}.
1891     * An empty ("") search CharSequence always matches unless the start position is negative.
1892     * A start position greater than the string length searches the whole string.
1893     * The search starts at the startPos and works backwards; matches starting after the start
1894     * position are ignored.
1895     * </p>
1896     *
1897     * <pre>
1898     * StringUtils.lastIndexOfIgnoreCase(null, *, *)          = -1
1899     * StringUtils.lastIndexOfIgnoreCase(*, null, *)          = -1
1900     * StringUtils.lastIndexOfIgnoreCase("aabaabaa", "A", 8)  = 7
1901     * StringUtils.lastIndexOfIgnoreCase("aabaabaa", "B", 8)  = 5
1902     * StringUtils.lastIndexOfIgnoreCase("aabaabaa", "AB", 8) = 4
1903     * StringUtils.lastIndexOfIgnoreCase("aabaabaa", "B", 9)  = 5
1904     * StringUtils.lastIndexOfIgnoreCase("aabaabaa", "B", -1) = -1
1905     * StringUtils.lastIndexOfIgnoreCase("aabaabaa", "A", 0)  = 0
1906     * StringUtils.lastIndexOfIgnoreCase("aabaabaa", "B", 0)  = -1
1907     * </pre>
1908     *
1909     * @param str  the CharSequence to check, may be null
1910     * @param searchStr  the CharSequence to find, may be null
1911     * @param startPos  the start position
1912     * @return the last index of the search CharSequence (always &le; startPos),
1913     *  -1 if no match or {@code null} input
1914     * @since 2.5
1915     * @since 3.0 Changed signature from lastIndexOfIgnoreCase(String, String, int) to lastIndexOfIgnoreCase(CharSequence, CharSequence, int)
1916     */
1917    public static int lastIndexOfIgnoreCase(final CharSequence str, final CharSequence searchStr, int startPos) {
1918        if (str == null || searchStr == null) {
1919            return INDEX_NOT_FOUND;
1920        }
1921        if (startPos > str.length() - searchStr.length()) {
1922            startPos = str.length() - searchStr.length();
1923        }
1924        if (startPos < 0) {
1925            return INDEX_NOT_FOUND;
1926        }
1927        if (searchStr.length() == 0) {
1928            return startPos;
1929        }
1930
1931        for (int i = startPos; i >= 0; i--) {
1932            if (CharSequenceUtils.regionMatches(str, true, i, searchStr, 0, searchStr.length())) {
1933                return i;
1934            }
1935        }
1936        return INDEX_NOT_FOUND;
1937    }
1938
1939    // Contains
1940    //-----------------------------------------------------------------------
1941    /**
1942     * <p>Checks if CharSequence contains a search character, handling {@code null}.
1943     * This method uses {@link String#indexOf(int)} if possible.</p>
1944     *
1945     * <p>A {@code null} or empty ("") CharSequence will return {@code false}.</p>
1946     *
1947     * <pre>
1948     * StringUtils.contains(null, *)    = false
1949     * StringUtils.contains("", *)      = false
1950     * StringUtils.contains("abc", 'a') = true
1951     * StringUtils.contains("abc", 'z') = false
1952     * </pre>
1953     *
1954     * @param seq  the CharSequence to check, may be null
1955     * @param searchChar  the character to find
1956     * @return true if the CharSequence contains the search character,
1957     *  false if not or {@code null} string input
1958     * @since 2.0
1959     * @since 3.0 Changed signature from contains(String, int) to contains(CharSequence, int)
1960     */
1961    public static boolean contains(final CharSequence seq, final int searchChar) {
1962        if (isEmpty(seq)) {
1963            return false;
1964        }
1965        return CharSequenceUtils.indexOf(seq, searchChar, 0) >= 0;
1966    }
1967
1968    /**
1969     * <p>Checks if CharSequence contains a search CharSequence, handling {@code null}.
1970     * This method uses {@link String#indexOf(String)} if possible.</p>
1971     *
1972     * <p>A {@code null} CharSequence will return {@code false}.</p>
1973     *
1974     * <pre>
1975     * StringUtils.contains(null, *)     = false
1976     * StringUtils.contains(*, null)     = false
1977     * StringUtils.contains("", "")      = true
1978     * StringUtils.contains("abc", "")   = true
1979     * StringUtils.contains("abc", "a")  = true
1980     * StringUtils.contains("abc", "z")  = false
1981     * </pre>
1982     *
1983     * @param seq  the CharSequence to check, may be null
1984     * @param searchSeq  the CharSequence to find, may be null
1985     * @return true if the CharSequence contains the search CharSequence,
1986     *  false if not or {@code null} string input
1987     * @since 2.0
1988     * @since 3.0 Changed signature from contains(String, String) to contains(CharSequence, CharSequence)
1989     */
1990    public static boolean contains(final CharSequence seq, final CharSequence searchSeq) {
1991        if (seq == null || searchSeq == null) {
1992            return false;
1993        }
1994        return CharSequenceUtils.indexOf(seq, searchSeq, 0) >= 0;
1995    }
1996
1997    /**
1998     * <p>Checks if CharSequence contains a search CharSequence irrespective of case,
1999     * handling {@code null}. Case-insensitivity is defined as by
2000     * {@link String#equalsIgnoreCase(String)}.
2001     *
2002     * <p>A {@code null} CharSequence will return {@code false}.</p>
2003     *
2004     * <pre>
2005     * StringUtils.containsIgnoreCase(null, *) = false
2006     * StringUtils.containsIgnoreCase(*, null) = false
2007     * StringUtils.containsIgnoreCase("", "") = true
2008     * StringUtils.containsIgnoreCase("abc", "") = true
2009     * StringUtils.containsIgnoreCase("abc", "a") = true
2010     * StringUtils.containsIgnoreCase("abc", "z") = false
2011     * StringUtils.containsIgnoreCase("abc", "A") = true
2012     * StringUtils.containsIgnoreCase("abc", "Z") = false
2013     * </pre>
2014     *
2015     * @param str  the CharSequence to check, may be null
2016     * @param searchStr  the CharSequence to find, may be null
2017     * @return true if the CharSequence contains the search CharSequence irrespective of
2018     * case or false if not or {@code null} string input
2019     * @since 3.0 Changed signature from containsIgnoreCase(String, String) to containsIgnoreCase(CharSequence, CharSequence)
2020     */
2021    public static boolean containsIgnoreCase(final CharSequence str, final CharSequence searchStr) {
2022        if (str == null || searchStr == null) {
2023            return false;
2024        }
2025        final int len = searchStr.length();
2026        final int max = str.length() - len;
2027        for (int i = 0; i <= max; i++) {
2028            if (CharSequenceUtils.regionMatches(str, true, i, searchStr, 0, len)) {
2029                return true;
2030            }
2031        }
2032        return false;
2033    }
2034
2035    /**
2036     * <p>Check whether the given CharSequence contains any whitespace characters.</p>
2037     *
2038     * <p>Whitespace is defined by {@link Character#isWhitespace(char)}.</p>
2039     *
2040     * @param seq the CharSequence to check (may be {@code null})
2041     * @return {@code true} if the CharSequence is not empty and
2042     * contains at least 1 (breaking) whitespace character
2043     * @since 3.0
2044     */
2045    // From org.springframework.util.StringUtils, under Apache License 2.0
2046    public static boolean containsWhitespace(final CharSequence seq) {
2047        if (isEmpty(seq)) {
2048            return false;
2049        }
2050        final int strLen = seq.length();
2051        for (int i = 0; i < strLen; i++) {
2052            if (Character.isWhitespace(seq.charAt(i))) {
2053                return true;
2054            }
2055        }
2056        return false;
2057    }
2058
2059    // IndexOfAny chars
2060    //-----------------------------------------------------------------------
2061    /**
2062     * <p>Search a CharSequence to find the first index of any
2063     * character in the given set of characters.</p>
2064     *
2065     * <p>A {@code null} String will return {@code -1}.
2066     * A {@code null} or zero length search array will return {@code -1}.</p>
2067     *
2068     * <pre>
2069     * StringUtils.indexOfAny(null, *)                  = -1
2070     * StringUtils.indexOfAny("", *)                    = -1
2071     * StringUtils.indexOfAny(*, null)                  = -1
2072     * StringUtils.indexOfAny(*, [])                    = -1
2073     * StringUtils.indexOfAny("zzabyycdxx", ['z', 'a']) = 0
2074     * StringUtils.indexOfAny("zzabyycdxx", ['b', 'y']) = 3
2075     * StringUtils.indexOfAny("aba", ['z'])             = -1
2076     * </pre>
2077     *
2078     * @param cs  the CharSequence to check, may be null
2079     * @param searchChars  the chars to search for, may be null
2080     * @return the index of any of the chars, -1 if no match or null input
2081     * @since 2.0
2082     * @since 3.0 Changed signature from indexOfAny(String, char[]) to indexOfAny(CharSequence, char...)
2083     */
2084    public static int indexOfAny(final CharSequence cs, final char... searchChars) {
2085        if (isEmpty(cs) || ArrayUtils.isEmpty(searchChars)) {
2086            return INDEX_NOT_FOUND;
2087        }
2088        final int csLen = cs.length();
2089        final int csLast = csLen - 1;
2090        final int searchLen = searchChars.length;
2091        final int searchLast = searchLen - 1;
2092        for (int i = 0; i < csLen; i++) {
2093            final char ch = cs.charAt(i);
2094            for (int j = 0; j < searchLen; j++) {
2095                if (searchChars[j] == ch) {
2096                    if (i < csLast && j < searchLast && Character.isHighSurrogate(ch)) {
2097                        // ch is a supplementary character
2098                        if (searchChars[j + 1] == cs.charAt(i + 1)) {
2099                            return i;
2100                        }
2101                    } else {
2102                        return i;
2103                    }
2104                }
2105            }
2106        }
2107        return INDEX_NOT_FOUND;
2108    }
2109
2110    /**
2111     * <p>Search a CharSequence to find the first index of any
2112     * character in the given set of characters.</p>
2113     *
2114     * <p>A {@code null} String will return {@code -1}.
2115     * A {@code null} search string will return {@code -1}.</p>
2116     *
2117     * <pre>
2118     * StringUtils.indexOfAny(null, *)            = -1
2119     * StringUtils.indexOfAny("", *)              = -1
2120     * StringUtils.indexOfAny(*, null)            = -1
2121     * StringUtils.indexOfAny(*, "")              = -1
2122     * StringUtils.indexOfAny("zzabyycdxx", "za") = 0
2123     * StringUtils.indexOfAny("zzabyycdxx", "by") = 3
2124     * StringUtils.indexOfAny("aba", "z")         = -1
2125     * </pre>
2126     *
2127     * @param cs  the CharSequence to check, may be null
2128     * @param searchChars  the chars to search for, may be null
2129     * @return the index of any of the chars, -1 if no match or null input
2130     * @since 2.0
2131     * @since 3.0 Changed signature from indexOfAny(String, String) to indexOfAny(CharSequence, String)
2132     */
2133    public static int indexOfAny(final CharSequence cs, final String searchChars) {
2134        if (isEmpty(cs) || isEmpty(searchChars)) {
2135            return INDEX_NOT_FOUND;
2136        }
2137        return indexOfAny(cs, searchChars.toCharArray());
2138    }
2139
2140    // ContainsAny
2141    //-----------------------------------------------------------------------
2142    /**
2143     * <p>Checks if the CharSequence contains any character in the given
2144     * set of characters.</p>
2145     *
2146     * <p>A {@code null} CharSequence will return {@code false}.
2147     * A {@code null} or zero length search array will return {@code false}.</p>
2148     *
2149     * <pre>
2150     * StringUtils.containsAny(null, *)                  = false
2151     * StringUtils.containsAny("", *)                    = false
2152     * StringUtils.containsAny(*, null)                  = false
2153     * StringUtils.containsAny(*, [])                    = false
2154     * StringUtils.containsAny("zzabyycdxx", ['z', 'a']) = true
2155     * StringUtils.containsAny("zzabyycdxx", ['b', 'y']) = true
2156     * StringUtils.containsAny("zzabyycdxx", ['z', 'y']) = true
2157     * StringUtils.containsAny("aba", ['z'])             = false
2158     * </pre>
2159     *
2160     * @param cs  the CharSequence to check, may be null
2161     * @param searchChars  the chars to search for, may be null
2162     * @return the {@code true} if any of the chars are found,
2163     * {@code false} if no match or null input
2164     * @since 2.4
2165     * @since 3.0 Changed signature from containsAny(String, char[]) to containsAny(CharSequence, char...)
2166     */
2167    public static boolean containsAny(final CharSequence cs, final char... searchChars) {
2168        if (isEmpty(cs) || ArrayUtils.isEmpty(searchChars)) {
2169            return false;
2170        }
2171        final int csLength = cs.length();
2172        final int searchLength = searchChars.length;
2173        final int csLast = csLength - 1;
2174        final int searchLast = searchLength - 1;
2175        for (int i = 0; i < csLength; i++) {
2176            final char ch = cs.charAt(i);
2177            for (int j = 0; j < searchLength; j++) {
2178                if (searchChars[j] == ch) {
2179                    if (Character.isHighSurrogate(ch)) {
2180                        if (j == searchLast) {
2181                            // missing low surrogate, fine, like String.indexOf(String)
2182                            return true;
2183                        }
2184                        if (i < csLast && searchChars[j + 1] == cs.charAt(i + 1)) {
2185                            return true;
2186                        }
2187                    } else {
2188                        // ch is in the Basic Multilingual Plane
2189                        return true;
2190                    }
2191                }
2192            }
2193        }
2194        return false;
2195    }
2196
2197    /**
2198     * <p>
2199     * Checks if the CharSequence contains any character in the given set of characters.
2200     * </p>
2201     *
2202     * <p>
2203     * A {@code null} CharSequence will return {@code false}. A {@code null} search CharSequence will return
2204     * {@code false}.
2205     * </p>
2206     *
2207     * <pre>
2208     * StringUtils.containsAny(null, *)               = false
2209     * StringUtils.containsAny("", *)                 = false
2210     * StringUtils.containsAny(*, null)               = false
2211     * StringUtils.containsAny(*, "")                 = false
2212     * StringUtils.containsAny("zzabyycdxx", "za")    = true
2213     * StringUtils.containsAny("zzabyycdxx", "by")    = true
2214     * StringUtils.containsAny("zzabyycdxx", "zy")    = true
2215     * StringUtils.containsAny("zzabyycdxx", "\tx")   = true
2216     * StringUtils.containsAny("zzabyycdxx", "$.#yF") = true
2217     * StringUtils.containsAny("aba", "z")            = false
2218     * </pre>
2219     *
2220     * @param cs
2221     *            the CharSequence to check, may be null
2222     * @param searchChars
2223     *            the chars to search for, may be null
2224     * @return the {@code true} if any of the chars are found, {@code false} if no match or null input
2225     * @since 2.4
2226     * @since 3.0 Changed signature from containsAny(String, String) to containsAny(CharSequence, CharSequence)
2227     */
2228    public static boolean containsAny(final CharSequence cs, final CharSequence searchChars) {
2229        if (searchChars == null) {
2230            return false;
2231        }
2232        return containsAny(cs, CharSequenceUtils.toCharArray(searchChars));
2233    }
2234
2235    /**
2236     * <p>Checks if the CharSequence contains any of the CharSequences in the given array.</p>
2237     *
2238     * <p>
2239     * A {@code null} {@code cs} CharSequence will return {@code false}. A {@code null} or zero
2240     * length search array will return {@code false}.
2241     * </p>
2242     *
2243     * <pre>
2244     * StringUtils.containsAny(null, *)            = false
2245     * StringUtils.containsAny("", *)              = false
2246     * StringUtils.containsAny(*, null)            = false
2247     * StringUtils.containsAny(*, [])              = false
2248     * StringUtils.containsAny("abcd", "ab", null) = true
2249     * StringUtils.containsAny("abcd", "ab", "cd") = true
2250     * StringUtils.containsAny("abc", "d", "abc")  = true
2251     * </pre>
2252     *
2253     *
2254     * @param cs The CharSequence to check, may be null
2255     * @param searchCharSequences The array of CharSequences to search for, may be null.
2256     * Individual CharSequences may be null as well.
2257     * @return {@code true} if any of the search CharSequences are found, {@code false} otherwise
2258     * @since 3.4
2259     */
2260    public static boolean containsAny(final CharSequence cs, final CharSequence... searchCharSequences) {
2261        if (isEmpty(cs) || ArrayUtils.isEmpty(searchCharSequences)) {
2262            return false;
2263        }
2264        for (final CharSequence searchCharSequence : searchCharSequences) {
2265            if (contains(cs, searchCharSequence)) {
2266                return true;
2267            }
2268        }
2269        return false;
2270    }
2271
2272    // IndexOfAnyBut chars
2273    //-----------------------------------------------------------------------
2274    /**
2275     * <p>Searches a CharSequence to find the first index of any
2276     * character not in the given set of characters.</p>
2277     *
2278     * <p>A {@code null} CharSequence will return {@code -1}.
2279     * A {@code null} or zero length search array will return {@code -1}.</p>
2280     *
2281     * <pre>
2282     * StringUtils.indexOfAnyBut(null, *)                              = -1
2283     * StringUtils.indexOfAnyBut("", *)                                = -1
2284     * StringUtils.indexOfAnyBut(*, null)                              = -1
2285     * StringUtils.indexOfAnyBut(*, [])                                = -1
2286     * StringUtils.indexOfAnyBut("zzabyycdxx", new char[] {'z', 'a'} ) = 3
2287     * StringUtils.indexOfAnyBut("aba", new char[] {'z'} )             = 0
2288     * StringUtils.indexOfAnyBut("aba", new char[] {'a', 'b'} )        = -1
2289
2290     * </pre>
2291     *
2292     * @param cs  the CharSequence to check, may be null
2293     * @param searchChars  the chars to search for, may be null
2294     * @return the index of any of the chars, -1 if no match or null input
2295     * @since 2.0
2296     * @since 3.0 Changed signature from indexOfAnyBut(String, char[]) to indexOfAnyBut(CharSequence, char...)
2297     */
2298    public static int indexOfAnyBut(final CharSequence cs, final char... searchChars) {
2299        if (isEmpty(cs) || ArrayUtils.isEmpty(searchChars)) {
2300            return INDEX_NOT_FOUND;
2301        }
2302        final int csLen = cs.length();
2303        final int csLast = csLen - 1;
2304        final int searchLen = searchChars.length;
2305        final int searchLast = searchLen - 1;
2306        outer:
2307        for (int i = 0; i < csLen; i++) {
2308            final char ch = cs.charAt(i);
2309            for (int j = 0; j < searchLen; j++) {
2310                if (searchChars[j] == ch) {
2311                    if (i < csLast && j < searchLast && Character.isHighSurrogate(ch)) {
2312                        if (searchChars[j + 1] == cs.charAt(i + 1)) {
2313                            continue outer;
2314                        }
2315                    } else {
2316                        continue outer;
2317                    }
2318                }
2319            }
2320            return i;
2321        }
2322        return INDEX_NOT_FOUND;
2323    }
2324
2325    /**
2326     * <p>Search a CharSequence to find the first index of any
2327     * character not in the given set of characters.</p>
2328     *
2329     * <p>A {@code null} CharSequence will return {@code -1}.
2330     * A {@code null} or empty search string will return {@code -1}.</p>
2331     *
2332     * <pre>
2333     * StringUtils.indexOfAnyBut(null, *)            = -1
2334     * StringUtils.indexOfAnyBut("", *)              = -1
2335     * StringUtils.indexOfAnyBut(*, null)            = -1
2336     * StringUtils.indexOfAnyBut(*, "")              = -1
2337     * StringUtils.indexOfAnyBut("zzabyycdxx", "za") = 3
2338     * StringUtils.indexOfAnyBut("zzabyycdxx", "")   = -1
2339     * StringUtils.indexOfAnyBut("aba", "ab")        = -1
2340     * </pre>
2341     *
2342     * @param seq  the CharSequence to check, may be null
2343     * @param searchChars  the chars to search for, may be null
2344     * @return the index of any of the chars, -1 if no match or null input
2345     * @since 2.0
2346     * @since 3.0 Changed signature from indexOfAnyBut(String, String) to indexOfAnyBut(CharSequence, CharSequence)
2347     */
2348    public static int indexOfAnyBut(final CharSequence seq, final CharSequence searchChars) {
2349        if (isEmpty(seq) || isEmpty(searchChars)) {
2350            return INDEX_NOT_FOUND;
2351        }
2352        final int strLen = seq.length();
2353        for (int i = 0; i < strLen; i++) {
2354            final char ch = seq.charAt(i);
2355            final boolean chFound = CharSequenceUtils.indexOf(searchChars, ch, 0) >= 0;
2356            if (i + 1 < strLen && Character.isHighSurrogate(ch)) {
2357                final char ch2 = seq.charAt(i + 1);
2358                if (chFound && CharSequenceUtils.indexOf(searchChars, ch2, 0) < 0) {
2359                    return i;
2360                }
2361            } else {
2362                if (!chFound) {
2363                    return i;
2364                }
2365            }
2366        }
2367        return INDEX_NOT_FOUND;
2368    }
2369
2370    // ContainsOnly
2371    //-----------------------------------------------------------------------
2372    /**
2373     * <p>Checks if the CharSequence contains only certain characters.</p>
2374     *
2375     * <p>A {@code null} CharSequence will return {@code false}.
2376     * A {@code null} valid character array will return {@code false}.
2377     * An empty CharSequence (length()=0) always returns {@code true}.</p>
2378     *
2379     * <pre>
2380     * StringUtils.containsOnly(null, *)       = false
2381     * StringUtils.containsOnly(*, null)       = false
2382     * StringUtils.containsOnly("", *)         = true
2383     * StringUtils.containsOnly("ab", '')      = false
2384     * StringUtils.containsOnly("abab", 'abc') = true
2385     * StringUtils.containsOnly("ab1", 'abc')  = false
2386     * StringUtils.containsOnly("abz", 'abc')  = false
2387     * </pre>
2388     *
2389     * @param cs  the String to check, may be null
2390     * @param valid  an array of valid chars, may be null
2391     * @return true if it only contains valid chars and is non-null
2392     * @since 3.0 Changed signature from containsOnly(String, char[]) to containsOnly(CharSequence, char...)
2393     */
2394    public static boolean containsOnly(final CharSequence cs, final char... valid) {
2395        // All these pre-checks are to maintain API with an older version
2396        if (valid == null || cs == null) {
2397            return false;
2398        }
2399        if (cs.length() == 0) {
2400            return true;
2401        }
2402        if (valid.length == 0) {
2403            return false;
2404        }
2405        return indexOfAnyBut(cs, valid) == INDEX_NOT_FOUND;
2406    }
2407
2408    /**
2409     * <p>Checks if the CharSequence contains only certain characters.</p>
2410     *
2411     * <p>A {@code null} CharSequence will return {@code false}.
2412     * A {@code null} valid character String will return {@code false}.
2413     * An empty String (length()=0) always returns {@code true}.</p>
2414     *
2415     * <pre>
2416     * StringUtils.containsOnly(null, *)       = false
2417     * StringUtils.containsOnly(*, null)       = false
2418     * StringUtils.containsOnly("", *)         = true
2419     * StringUtils.containsOnly("ab", "")      = false
2420     * StringUtils.containsOnly("abab", "abc") = true
2421     * StringUtils.containsOnly("ab1", "abc")  = false
2422     * StringUtils.containsOnly("abz", "abc")  = false
2423     * </pre>
2424     *
2425     * @param cs  the CharSequence to check, may be null
2426     * @param validChars  a String of valid chars, may be null
2427     * @return true if it only contains valid chars and is non-null
2428     * @since 2.0
2429     * @since 3.0 Changed signature from containsOnly(String, String) to containsOnly(CharSequence, String)
2430     */
2431    public static boolean containsOnly(final CharSequence cs, final String validChars) {
2432        if (cs == null || validChars == null) {
2433            return false;
2434        }
2435        return containsOnly(cs, validChars.toCharArray());
2436    }
2437
2438    // ContainsNone
2439    //-----------------------------------------------------------------------
2440    /**
2441     * <p>Checks that the CharSequence does not contain certain characters.</p>
2442     *
2443     * <p>A {@code null} CharSequence will return {@code true}.
2444     * A {@code null} invalid character array will return {@code true}.
2445     * An empty CharSequence (length()=0) always returns true.</p>
2446     *
2447     * <pre>
2448     * StringUtils.containsNone(null, *)       = true
2449     * StringUtils.containsNone(*, null)       = true
2450     * StringUtils.containsNone("", *)         = true
2451     * StringUtils.containsNone("ab", '')      = true
2452     * StringUtils.containsNone("abab", 'xyz') = true
2453     * StringUtils.containsNone("ab1", 'xyz')  = true
2454     * StringUtils.containsNone("abz", 'xyz')  = false
2455     * </pre>
2456     *
2457     * @param cs  the CharSequence to check, may be null
2458     * @param searchChars  an array of invalid chars, may be null
2459     * @return true if it contains none of the invalid chars, or is null
2460     * @since 2.0
2461     * @since 3.0 Changed signature from containsNone(String, char[]) to containsNone(CharSequence, char...)
2462     */
2463    public static boolean containsNone(final CharSequence cs, final char... searchChars) {
2464        if (cs == null || searchChars == null) {
2465            return true;
2466        }
2467        final int csLen = cs.length();
2468        final int csLast = csLen - 1;
2469        final int searchLen = searchChars.length;
2470        final int searchLast = searchLen - 1;
2471        for (int i = 0; i < csLen; i++) {
2472            final char ch = cs.charAt(i);
2473            for (int j = 0; j < searchLen; j++) {
2474                if (searchChars[j] == ch) {
2475                    if (Character.isHighSurrogate(ch)) {
2476                        if (j == searchLast) {
2477                            // missing low surrogate, fine, like String.indexOf(String)
2478                            return false;
2479                        }
2480                        if (i < csLast && searchChars[j + 1] == cs.charAt(i + 1)) {
2481                            return false;
2482                        }
2483                    } else {
2484                        // ch is in the Basic Multilingual Plane
2485                        return false;
2486                    }
2487                }
2488            }
2489        }
2490        return true;
2491    }
2492
2493    /**
2494     * <p>Checks that the CharSequence does not contain certain characters.</p>
2495     *
2496     * <p>A {@code null} CharSequence will return {@code true}.
2497     * A {@code null} invalid character array will return {@code true}.
2498     * An empty String ("") always returns true.</p>
2499     *
2500     * <pre>
2501     * StringUtils.containsNone(null, *)       = true
2502     * StringUtils.containsNone(*, null)       = true
2503     * StringUtils.containsNone("", *)         = true
2504     * StringUtils.containsNone("ab", "")      = true
2505     * StringUtils.containsNone("abab", "xyz") = true
2506     * StringUtils.containsNone("ab1", "xyz")  = true
2507     * StringUtils.containsNone("abz", "xyz")  = false
2508     * </pre>
2509     *
2510     * @param cs  the CharSequence to check, may be null
2511     * @param invalidChars  a String of invalid chars, may be null
2512     * @return true if it contains none of the invalid chars, or is null
2513     * @since 2.0
2514     * @since 3.0 Changed signature from containsNone(String, String) to containsNone(CharSequence, String)
2515     */
2516    public static boolean containsNone(final CharSequence cs, final String invalidChars) {
2517        if (cs == null || invalidChars == null) {
2518            return true;
2519        }
2520        return containsNone(cs, invalidChars.toCharArray());
2521    }
2522
2523    // IndexOfAny strings
2524    //-----------------------------------------------------------------------
2525    /**
2526     * <p>Find the first index of any of a set of potential substrings.</p>
2527     *
2528     * <p>A {@code null} CharSequence will return {@code -1}.
2529     * A {@code null} or zero length search array will return {@code -1}.
2530     * A {@code null} search array entry will be ignored, but a search
2531     * array containing "" will return {@code 0} if {@code str} is not
2532     * null. This method uses {@link String#indexOf(String)} if possible.</p>
2533     *
2534     * <pre>
2535     * StringUtils.indexOfAny(null, *)                      = -1
2536     * StringUtils.indexOfAny(*, null)                      = -1
2537     * StringUtils.indexOfAny(*, [])                        = -1
2538     * StringUtils.indexOfAny("zzabyycdxx", ["ab", "cd"])   = 2
2539     * StringUtils.indexOfAny("zzabyycdxx", ["cd", "ab"])   = 2
2540     * StringUtils.indexOfAny("zzabyycdxx", ["mn", "op"])   = -1
2541     * StringUtils.indexOfAny("zzabyycdxx", ["zab", "aby"]) = 1
2542     * StringUtils.indexOfAny("zzabyycdxx", [""])           = 0
2543     * StringUtils.indexOfAny("", [""])                     = 0
2544     * StringUtils.indexOfAny("", ["a"])                    = -1
2545     * </pre>
2546     *
2547     * @param str  the CharSequence to check, may be null
2548     * @param searchStrs  the CharSequences to search for, may be null
2549     * @return the first index of any of the searchStrs in str, -1 if no match
2550     * @since 3.0 Changed signature from indexOfAny(String, String[]) to indexOfAny(CharSequence, CharSequence...)
2551     */
2552    public static int indexOfAny(final CharSequence str, final CharSequence... searchStrs) {
2553        if (str == null || searchStrs == null) {
2554            return INDEX_NOT_FOUND;
2555        }
2556
2557        // String's can't have a MAX_VALUEth index.
2558        int ret = Integer.MAX_VALUE;
2559
2560        int tmp = 0;
2561        for (final CharSequence search : searchStrs) {
2562            if (search == null) {
2563                continue;
2564            }
2565            tmp = CharSequenceUtils.indexOf(str, search, 0);
2566            if (tmp == INDEX_NOT_FOUND) {
2567                continue;
2568            }
2569
2570            if (tmp < ret) {
2571                ret = tmp;
2572            }
2573        }
2574
2575        return ret == Integer.MAX_VALUE ? INDEX_NOT_FOUND : ret;
2576    }
2577
2578    /**
2579     * <p>Find the latest index of any of a set of potential substrings.</p>
2580     *
2581     * <p>A {@code null} CharSequence will return {@code -1}.
2582     * A {@code null} search array will return {@code -1}.
2583     * A {@code null} or zero length search array entry will be ignored,
2584     * but a search array containing "" will return the length of {@code str}
2585     * if {@code str} is not null. This method uses {@link String#indexOf(String)} if possible</p>
2586     *
2587     * <pre>
2588     * StringUtils.lastIndexOfAny(null, *)                    = -1
2589     * StringUtils.lastIndexOfAny(*, null)                    = -1
2590     * StringUtils.lastIndexOfAny(*, [])                      = -1
2591     * StringUtils.lastIndexOfAny(*, [null])                  = -1
2592     * StringUtils.lastIndexOfAny("zzabyycdxx", ["ab", "cd"]) = 6
2593     * StringUtils.lastIndexOfAny("zzabyycdxx", ["cd", "ab"]) = 6
2594     * StringUtils.lastIndexOfAny("zzabyycdxx", ["mn", "op"]) = -1
2595     * StringUtils.lastIndexOfAny("zzabyycdxx", ["mn", "op"]) = -1
2596     * StringUtils.lastIndexOfAny("zzabyycdxx", ["mn", ""])   = 10
2597     * </pre>
2598     *
2599     * @param str  the CharSequence to check, may be null
2600     * @param searchStrs  the CharSequences to search for, may be null
2601     * @return the last index of any of the CharSequences, -1 if no match
2602     * @since 3.0 Changed signature from lastIndexOfAny(String, String[]) to lastIndexOfAny(CharSequence, CharSequence)
2603     */
2604    public static int lastIndexOfAny(final CharSequence str, final CharSequence... searchStrs) {
2605        if (str == null || searchStrs == null) {
2606            return INDEX_NOT_FOUND;
2607        }
2608        int ret = INDEX_NOT_FOUND;
2609        int tmp = 0;
2610        for (final CharSequence search : searchStrs) {
2611            if (search == null) {
2612                continue;
2613            }
2614            tmp = CharSequenceUtils.lastIndexOf(str, search, str.length());
2615            if (tmp > ret) {
2616                ret = tmp;
2617            }
2618        }
2619        return ret;
2620    }
2621
2622    // Substring
2623    //-----------------------------------------------------------------------
2624    /**
2625     * <p>Gets a substring from the specified String avoiding exceptions.</p>
2626     *
2627     * <p>A negative start position can be used to start {@code n}
2628     * characters from the end of the String.</p>
2629     *
2630     * <p>A {@code null} String will return {@code null}.
2631     * An empty ("") String will return "".</p>
2632     *
2633     * <pre>
2634     * StringUtils.substring(null, *)   = null
2635     * StringUtils.substring("", *)     = ""
2636     * StringUtils.substring("abc", 0)  = "abc"
2637     * StringUtils.substring("abc", 2)  = "c"
2638     * StringUtils.substring("abc", 4)  = ""
2639     * StringUtils.substring("abc", -2) = "bc"
2640     * StringUtils.substring("abc", -4) = "abc"
2641     * </pre>
2642     *
2643     * @param str  the String to get the substring from, may be null
2644     * @param start  the position to start from, negative means
2645     *  count back from the end of the String by this many characters
2646     * @return substring from start position, {@code null} if null String input
2647     */
2648    public static String substring(final String str, int start) {
2649        if (str == null) {
2650            return null;
2651        }
2652
2653        // handle negatives, which means last n characters
2654        if (start < 0) {
2655            start = str.length() + start; // remember start is negative
2656        }
2657
2658        if (start < 0) {
2659            start = 0;
2660        }
2661        if (start > str.length()) {
2662            return EMPTY;
2663        }
2664
2665        return str.substring(start);
2666    }
2667
2668    /**
2669     * <p>Gets a substring from the specified String avoiding exceptions.</p>
2670     *
2671     * <p>A negative start position can be used to start/end {@code n}
2672     * characters from the end of the String.</p>
2673     *
2674     * <p>The returned substring starts with the character in the {@code start}
2675     * position and ends before the {@code end} position. All position counting is
2676     * zero-based -- i.e., to start at the beginning of the string use
2677     * {@code start = 0}. Negative start and end positions can be used to
2678     * specify offsets relative to the end of the String.</p>
2679     *
2680     * <p>If {@code start} is not strictly to the left of {@code end}, ""
2681     * is returned.</p>
2682     *
2683     * <pre>
2684     * StringUtils.substring(null, *, *)    = null
2685     * StringUtils.substring("", * ,  *)    = "";
2686     * StringUtils.substring("abc", 0, 2)   = "ab"
2687     * StringUtils.substring("abc", 2, 0)   = ""
2688     * StringUtils.substring("abc", 2, 4)   = "c"
2689     * StringUtils.substring("abc", 4, 6)   = ""
2690     * StringUtils.substring("abc", 2, 2)   = ""
2691     * StringUtils.substring("abc", -2, -1) = "b"
2692     * StringUtils.substring("abc", -4, 2)  = "ab"
2693     * </pre>
2694     *
2695     * @param str  the String to get the substring from, may be null
2696     * @param start  the position to start from, negative means
2697     *  count back from the end of the String by this many characters
2698     * @param end  the position to end at (exclusive), negative means
2699     *  count back from the end of the String by this many characters
2700     * @return substring from start position to end position,
2701     *  {@code null} if null String input
2702     */
2703    public static String substring(final String str, int start, int end) {
2704        if (str == null) {
2705            return null;
2706        }
2707
2708        // handle negatives
2709        if (end < 0) {
2710            end = str.length() + end; // remember end is negative
2711        }
2712        if (start < 0) {
2713            start = str.length() + start; // remember start is negative
2714        }
2715
2716        // check length next
2717        if (end > str.length()) {
2718            end = str.length();
2719        }
2720
2721        // if start is greater than end, return ""
2722        if (start > end) {
2723            return EMPTY;
2724        }
2725
2726        if (start < 0) {
2727            start = 0;
2728        }
2729        if (end < 0) {
2730            end = 0;
2731        }
2732
2733        return str.substring(start, end);
2734    }
2735
2736    // Left/Right/Mid
2737    //-----------------------------------------------------------------------
2738    /**
2739     * <p>Gets the leftmost {@code len} characters of a String.</p>
2740     *
2741     * <p>If {@code len} characters are not available, or the
2742     * String is {@code null}, the String will be returned without
2743     * an exception. An empty String is returned if len is negative.</p>
2744     *
2745     * <pre>
2746     * StringUtils.left(null, *)    = null
2747     * StringUtils.left(*, -ve)     = ""
2748     * StringUtils.left("", *)      = ""
2749     * StringUtils.left("abc", 0)   = ""
2750     * StringUtils.left("abc", 2)   = "ab"
2751     * StringUtils.left("abc", 4)   = "abc"
2752     * </pre>
2753     *
2754     * @param str  the String to get the leftmost characters from, may be null
2755     * @param len  the length of the required String
2756     * @return the leftmost characters, {@code null} if null String input
2757     */
2758    public static String left(final String str, final int len) {
2759        if (str == null) {
2760            return null;
2761        }
2762        if (len < 0) {
2763            return EMPTY;
2764        }
2765        if (str.length() <= len) {
2766            return str;
2767        }
2768        return str.substring(0, len);
2769    }
2770
2771    /**
2772     * <p>Gets the rightmost {@code len} characters of a String.</p>
2773     *
2774     * <p>If {@code len} characters are not available, or the String
2775     * is {@code null}, the String will be returned without an
2776     * an exception. An empty String is returned if len is negative.</p>
2777     *
2778     * <pre>
2779     * StringUtils.right(null, *)    = null
2780     * StringUtils.right(*, -ve)     = ""
2781     * StringUtils.right("", *)      = ""
2782     * StringUtils.right("abc", 0)   = ""
2783     * StringUtils.right("abc", 2)   = "bc"
2784     * StringUtils.right("abc", 4)   = "abc"
2785     * </pre>
2786     *
2787     * @param str  the String to get the rightmost characters from, may be null
2788     * @param len  the length of the required String
2789     * @return the rightmost characters, {@code null} if null String input
2790     */
2791    public static String right(final String str, final int len) {
2792        if (str == null) {
2793            return null;
2794        }
2795        if (len < 0) {
2796            return EMPTY;
2797        }
2798        if (str.length() <= len) {
2799            return str;
2800        }
2801        return str.substring(str.length() - len);
2802    }
2803
2804    /**
2805     * <p>Gets {@code len} characters from the middle of a String.</p>
2806     *
2807     * <p>If {@code len} characters are not available, the remainder
2808     * of the String will be returned without an exception. If the
2809     * String is {@code null}, {@code null} will be returned.
2810     * An empty String is returned if len is negative or exceeds the
2811     * length of {@code str}.</p>
2812     *
2813     * <pre>
2814     * StringUtils.mid(null, *, *)    = null
2815     * StringUtils.mid(*, *, -ve)     = ""
2816     * StringUtils.mid("", 0, *)      = ""
2817     * StringUtils.mid("abc", 0, 2)   = "ab"
2818     * StringUtils.mid("abc", 0, 4)   = "abc"
2819     * StringUtils.mid("abc", 2, 4)   = "c"
2820     * StringUtils.mid("abc", 4, 2)   = ""
2821     * StringUtils.mid("abc", -2, 2)  = "ab"
2822     * </pre>
2823     *
2824     * @param str  the String to get the characters from, may be null
2825     * @param pos  the position to start from, negative treated as zero
2826     * @param len  the length of the required String
2827     * @return the middle characters, {@code null} if null String input
2828     */
2829    public static String mid(final String str, int pos, final int len) {
2830        if (str == null) {
2831            return null;
2832        }
2833        if (len < 0 || pos > str.length()) {
2834            return EMPTY;
2835        }
2836        if (pos < 0) {
2837            pos = 0;
2838        }
2839        if (str.length() <= pos + len) {
2840            return str.substring(pos);
2841        }
2842        return str.substring(pos, pos + len);
2843    }
2844
2845    private static StringBuilder newStringBuilder(final int noOfItems) {
2846        return new StringBuilder(noOfItems * 16);
2847    }
2848
2849    // SubStringAfter/SubStringBefore
2850    //-----------------------------------------------------------------------
2851    /**
2852     * <p>Gets the substring before the first occurrence of a separator.
2853     * The separator is not returned.</p>
2854     *
2855     * <p>A {@code null} string input will return {@code null}.
2856     * An empty ("") string input will return the empty string.
2857     * A {@code null} separator will return the input string.</p>
2858     *
2859     * <p>If nothing is found, the string input is returned.</p>
2860     *
2861     * <pre>
2862     * StringUtils.substringBefore(null, *)      = null
2863     * StringUtils.substringBefore("", *)        = ""
2864     * StringUtils.substringBefore("abc", "a")   = ""
2865     * StringUtils.substringBefore("abcba", "b") = "a"
2866     * StringUtils.substringBefore("abc", "c")   = "ab"
2867     * StringUtils.substringBefore("abc", "d")   = "abc"
2868     * StringUtils.substringBefore("abc", "")    = ""
2869     * StringUtils.substringBefore("abc", null)  = "abc"
2870     * </pre>
2871     *
2872     * @param str  the String to get a substring from, may be null
2873     * @param separator  the String to search for, may be null
2874     * @return the substring before the first occurrence of the separator,
2875     *  {@code null} if null String input
2876     * @since 2.0
2877     */
2878    public static String substringBefore(final String str, final String separator) {
2879        if (isEmpty(str) || separator == null) {
2880            return str;
2881        }
2882        if (separator.isEmpty()) {
2883            return EMPTY;
2884        }
2885        final int pos = str.indexOf(separator);
2886        if (pos == INDEX_NOT_FOUND) {
2887            return str;
2888        }
2889        return str.substring(0, pos);
2890    }
2891
2892    /**
2893     * <p>Gets the substring after the first occurrence of a separator.
2894     * The separator is not returned.</p>
2895     *
2896     * <p>A {@code null} string input will return {@code null}.
2897     * An empty ("") string input will return the empty string.
2898     * A {@code null} separator will return the empty string if the
2899     * input string is not {@code null}.</p>
2900     *
2901     * <p>If nothing is found, the empty string is returned.</p>
2902     *
2903     * <pre>
2904     * StringUtils.substringAfter(null, *)      = null
2905     * StringUtils.substringAfter("", *)        = ""
2906     * StringUtils.substringAfter(*, null)      = ""
2907     * StringUtils.substringAfter("abc", "a")   = "bc"
2908     * StringUtils.substringAfter("abcba", "b") = "cba"
2909     * StringUtils.substringAfter("abc", "c")   = ""
2910     * StringUtils.substringAfter("abc", "d")   = ""
2911     * StringUtils.substringAfter("abc", "")    = "abc"
2912     * </pre>
2913     *
2914     * @param str  the String to get a substring from, may be null
2915     * @param separator  the String to search for, may be null
2916     * @return the substring after the first occurrence of the separator,
2917     *  {@code null} if null String input
2918     * @since 2.0
2919     */
2920    public static String substringAfter(final String str, final String separator) {
2921        if (isEmpty(str)) {
2922            return str;
2923        }
2924        if (separator == null) {
2925            return EMPTY;
2926        }
2927        final int pos = str.indexOf(separator);
2928        if (pos == INDEX_NOT_FOUND) {
2929            return EMPTY;
2930        }
2931        return str.substring(pos + separator.length());
2932    }
2933
2934    /**
2935     * <p>Gets the substring before the last occurrence of a separator.
2936     * The separator is not returned.</p>
2937     *
2938     * <p>A {@code null} string input will return {@code null}.
2939     * An empty ("") string input will return the empty string.
2940     * An empty or {@code null} separator will return the input string.</p>
2941     *
2942     * <p>If nothing is found, the string input is returned.</p>
2943     *
2944     * <pre>
2945     * StringUtils.substringBeforeLast(null, *)      = null
2946     * StringUtils.substringBeforeLast("", *)        = ""
2947     * StringUtils.substringBeforeLast("abcba", "b") = "abc"
2948     * StringUtils.substringBeforeLast("abc", "c")   = "ab"
2949     * StringUtils.substringBeforeLast("a", "a")     = ""
2950     * StringUtils.substringBeforeLast("a", "z")     = "a"
2951     * StringUtils.substringBeforeLast("a", null)    = "a"
2952     * StringUtils.substringBeforeLast("a", "")      = "a"
2953     * </pre>
2954     *
2955     * @param str  the String to get a substring from, may be null
2956     * @param separator  the String to search for, may be null
2957     * @return the substring before the last occurrence of the separator,
2958     *  {@code null} if null String input
2959     * @since 2.0
2960     */
2961    public static String substringBeforeLast(final String str, final String separator) {
2962        if (isEmpty(str) || isEmpty(separator)) {
2963            return str;
2964        }
2965        final int pos = str.lastIndexOf(separator);
2966        if (pos == INDEX_NOT_FOUND) {
2967            return str;
2968        }
2969        return str.substring(0, pos);
2970    }
2971
2972    /**
2973     * <p>Gets the substring after the last occurrence of a separator.
2974     * The separator is not returned.</p>
2975     *
2976     * <p>A {@code null} string input will return {@code null}.
2977     * An empty ("") string input will return the empty string.
2978     * An empty or {@code null} separator will return the empty string if
2979     * the input string is not {@code null}.</p>
2980     *
2981     * <p>If nothing is found, the empty string is returned.</p>
2982     *
2983     * <pre>
2984     * StringUtils.substringAfterLast(null, *)      = null
2985     * StringUtils.substringAfterLast("", *)        = ""
2986     * StringUtils.substringAfterLast(*, "")        = ""
2987     * StringUtils.substringAfterLast(*, null)      = ""
2988     * StringUtils.substringAfterLast("abc", "a")   = "bc"
2989     * StringUtils.substringAfterLast("abcba", "b") = "a"
2990     * StringUtils.substringAfterLast("abc", "c")   = ""
2991     * StringUtils.substringAfterLast("a", "a")     = ""
2992     * StringUtils.substringAfterLast("a", "z")     = ""
2993     * </pre>
2994     *
2995     * @param str  the String to get a substring from, may be null
2996     * @param separator  the String to search for, may be null
2997     * @return the substring after the last occurrence of the separator,
2998     *  {@code null} if null String input
2999     * @since 2.0
3000     */
3001    public static String substringAfterLast(final String str, final String separator) {
3002        if (isEmpty(str)) {
3003            return str;
3004        }
3005        if (isEmpty(separator)) {
3006            return EMPTY;
3007        }
3008        final int pos = str.lastIndexOf(separator);
3009        if (pos == INDEX_NOT_FOUND || pos == str.length() - separator.length()) {
3010            return EMPTY;
3011        }
3012        return str.substring(pos + separator.length());
3013    }
3014
3015    // Substring between
3016    //-----------------------------------------------------------------------
3017    /**
3018     * <p>Gets the String that is nested in between two instances of the
3019     * same String.</p>
3020     *
3021     * <p>A {@code null} input String returns {@code null}.
3022     * A {@code null} tag returns {@code null}.</p>
3023     *
3024     * <pre>
3025     * StringUtils.substringBetween(null, *)            = null
3026     * StringUtils.substringBetween("", "")             = ""
3027     * StringUtils.substringBetween("", "tag")          = null
3028     * StringUtils.substringBetween("tagabctag", null)  = null
3029     * StringUtils.substringBetween("tagabctag", "")    = ""
3030     * StringUtils.substringBetween("tagabctag", "tag") = "abc"
3031     * </pre>
3032     *
3033     * @param str  the String containing the substring, may be null
3034     * @param tag  the String before and after the substring, may be null
3035     * @return the substring, {@code null} if no match
3036     * @since 2.0
3037     */
3038    public static String substringBetween(final String str, final String tag) {
3039        return substringBetween(str, tag, tag);
3040    }
3041
3042    /**
3043     * <p>Gets the String that is nested in between two Strings.
3044     * Only the first match is returned.</p>
3045     *
3046     * <p>A {@code null} input String returns {@code null}.
3047     * A {@code null} open/close returns {@code null} (no match).
3048     * An empty ("") open and close returns an empty string.</p>
3049     *
3050     * <pre>
3051     * StringUtils.substringBetween("wx[b]yz", "[", "]") = "b"
3052     * StringUtils.substringBetween(null, *, *)          = null
3053     * StringUtils.substringBetween(*, null, *)          = null
3054     * StringUtils.substringBetween(*, *, null)          = null
3055     * StringUtils.substringBetween("", "", "")          = ""
3056     * StringUtils.substringBetween("", "", "]")         = null
3057     * StringUtils.substringBetween("", "[", "]")        = null
3058     * StringUtils.substringBetween("yabcz", "", "")     = ""
3059     * StringUtils.substringBetween("yabcz", "y", "z")   = "abc"
3060     * StringUtils.substringBetween("yabczyabcz", "y", "z")   = "abc"
3061     * </pre>
3062     *
3063     * @param str  the String containing the substring, may be null
3064     * @param open  the String before the substring, may be null
3065     * @param close  the String after the substring, may be null
3066     * @return the substring, {@code null} if no match
3067     * @since 2.0
3068     */
3069    public static String substringBetween(final String str, final String open, final String close) {
3070        if (str == null || open == null || close == null) {
3071            return null;
3072        }
3073        final int start = str.indexOf(open);
3074        if (start != INDEX_NOT_FOUND) {
3075            final int end = str.indexOf(close, start + open.length());
3076            if (end != INDEX_NOT_FOUND) {
3077                return str.substring(start + open.length(), end);
3078            }
3079        }
3080        return null;
3081    }
3082
3083    /**
3084     * <p>Searches a String for substrings delimited by a start and end tag,
3085     * returning all matching substrings in an array.</p>
3086     *
3087     * <p>A {@code null} input String returns {@code null}.
3088     * A {@code null} open/close returns {@code null} (no match).
3089     * An empty ("") open/close returns {@code null} (no match).</p>
3090     *
3091     * <pre>
3092     * StringUtils.substringsBetween("[a][b][c]", "[", "]") = ["a","b","c"]
3093     * StringUtils.substringsBetween(null, *, *)            = null
3094     * StringUtils.substringsBetween(*, null, *)            = null
3095     * StringUtils.substringsBetween(*, *, null)            = null
3096     * StringUtils.substringsBetween("", "[", "]")          = []
3097     * </pre>
3098     *
3099     * @param str  the String containing the substrings, null returns null, empty returns empty
3100     * @param open  the String identifying the start of the substring, empty returns null
3101     * @param close  the String identifying the end of the substring, empty returns null
3102     * @return a String Array of substrings, or {@code null} if no match
3103     * @since 2.3
3104     */
3105    public static String[] substringsBetween(final String str, final String open, final String close) {
3106        if (str == null || isEmpty(open) || isEmpty(close)) {
3107            return null;
3108        }
3109        final int strLen = str.length();
3110        if (strLen == 0) {
3111            return ArrayUtils.EMPTY_STRING_ARRAY;
3112        }
3113        final int closeLen = close.length();
3114        final int openLen = open.length();
3115        final List<String> list = new ArrayList<>();
3116        int pos = 0;
3117        while (pos < strLen - closeLen) {
3118            int start = str.indexOf(open, pos);
3119            if (start < 0) {
3120                break;
3121            }
3122            start += openLen;
3123            final int end = str.indexOf(close, start);
3124            if (end < 0) {
3125                break;
3126            }
3127            list.add(str.substring(start, end));
3128            pos = end + closeLen;
3129        }
3130        if (list.isEmpty()) {
3131            return null;
3132        }
3133        return list.toArray(new String [list.size()]);
3134    }
3135
3136    // Nested extraction
3137    //-----------------------------------------------------------------------
3138
3139    // Splitting
3140    //-----------------------------------------------------------------------
3141    /**
3142     * <p>Splits the provided text into an array, using whitespace as the
3143     * separator.
3144     * Whitespace is defined by {@link Character#isWhitespace(char)}.</p>
3145     *
3146     * <p>The separator is not included in the returned String array.
3147     * Adjacent separators are treated as one separator.
3148     * For more control over the split use the StrTokenizer class.</p>
3149     *
3150     * <p>A {@code null} input String returns {@code null}.</p>
3151     *
3152     * <pre>
3153     * StringUtils.split(null)       = null
3154     * StringUtils.split("")         = []
3155     * StringUtils.split("abc def")  = ["abc", "def"]
3156     * StringUtils.split("abc  def") = ["abc", "def"]
3157     * StringUtils.split(" abc ")    = ["abc"]
3158     * </pre>
3159     *
3160     * @param str  the String to parse, may be null
3161     * @return an array of parsed Strings, {@code null} if null String input
3162     */
3163    public static String[] split(final String str) {
3164        return split(str, null, -1);
3165    }
3166
3167    /**
3168     * <p>Splits the provided text into an array, separator specified.
3169     * This is an alternative to using StringTokenizer.</p>
3170     *
3171     * <p>The separator is not included in the returned String array.
3172     * Adjacent separators are treated as one separator.
3173     * For more control over the split use the StrTokenizer class.</p>
3174     *
3175     * <p>A {@code null} input String returns {@code null}.</p>
3176     *
3177     * <pre>
3178     * StringUtils.split(null, *)         = null
3179     * StringUtils.split("", *)           = []
3180     * StringUtils.split("a.b.c", '.')    = ["a", "b", "c"]
3181     * StringUtils.split("a..b.c", '.')   = ["a", "b", "c"]
3182     * StringUtils.split("a:b:c", '.')    = ["a:b:c"]
3183     * StringUtils.split("a b c", ' ')    = ["a", "b", "c"]
3184     * </pre>
3185     *
3186     * @param str  the String to parse, may be null
3187     * @param separatorChar  the character used as the delimiter
3188     * @return an array of parsed Strings, {@code null} if null String input
3189     * @since 2.0
3190     */
3191    public static String[] split(final String str, final char separatorChar) {
3192        return splitWorker(str, separatorChar, false);
3193    }
3194
3195    /**
3196     * <p>Splits the provided text into an array, separators specified.
3197     * This is an alternative to using StringTokenizer.</p>
3198     *
3199     * <p>The separator is not included in the returned String array.
3200     * Adjacent separators are treated as one separator.
3201     * For more control over the split use the StrTokenizer class.</p>
3202     *
3203     * <p>A {@code null} input String returns {@code null}.
3204     * A {@code null} separatorChars splits on whitespace.</p>
3205     *
3206     * <pre>
3207     * StringUtils.split(null, *)         = null
3208     * StringUtils.split("", *)           = []
3209     * StringUtils.split("abc def", null) = ["abc", "def"]
3210     * StringUtils.split("abc def", " ")  = ["abc", "def"]
3211     * StringUtils.split("abc  def", " ") = ["abc", "def"]
3212     * StringUtils.split("ab:cd:ef", ":") = ["ab", "cd", "ef"]
3213     * </pre>
3214     *
3215     * @param str  the String to parse, may be null
3216     * @param separatorChars  the characters used as the delimiters,
3217     *  {@code null} splits on whitespace
3218     * @return an array of parsed Strings, {@code null} if null String input
3219     */
3220    public static String[] split(final String str, final String separatorChars) {
3221        return splitWorker(str, separatorChars, -1, false);
3222    }
3223
3224    /**
3225     * <p>Splits the provided text into an array with a maximum length,
3226     * separators specified.</p>
3227     *
3228     * <p>The separator is not included in the returned String array.
3229     * Adjacent separators are treated as one separator.</p>
3230     *
3231     * <p>A {@code null} input String returns {@code null}.
3232     * A {@code null} separatorChars splits on whitespace.</p>
3233     *
3234     * <p>If more than {@code max} delimited substrings are found, the last
3235     * returned string includes all characters after the first {@code max - 1}
3236     * returned strings (including separator characters).</p>
3237     *
3238     * <pre>
3239     * StringUtils.split(null, *, *)            = null
3240     * StringUtils.split("", *, *)              = []
3241     * StringUtils.split("ab cd ef", null, 0)   = ["ab", "cd", "ef"]
3242     * StringUtils.split("ab   cd ef", null, 0) = ["ab", "cd", "ef"]
3243     * StringUtils.split("ab:cd:ef", ":", 0)    = ["ab", "cd", "ef"]
3244     * StringUtils.split("ab:cd:ef", ":", 2)    = ["ab", "cd:ef"]
3245     * </pre>
3246     *
3247     * @param str  the String to parse, may be null
3248     * @param separatorChars  the characters used as the delimiters,
3249     *  {@code null} splits on whitespace
3250     * @param max  the maximum number of elements to include in the
3251     *  array. A zero or negative value implies no limit
3252     * @return an array of parsed Strings, {@code null} if null String input
3253     */
3254    public static String[] split(final String str, final String separatorChars, final int max) {
3255        return splitWorker(str, separatorChars, max, false);
3256    }
3257
3258    /**
3259     * <p>Splits the provided text into an array, separator string specified.</p>
3260     *
3261     * <p>The separator(s) will not be included in the returned String array.
3262     * Adjacent separators are treated as one separator.</p>
3263     *
3264     * <p>A {@code null} input String returns {@code null}.
3265     * A {@code null} separator splits on whitespace.</p>
3266     *
3267     * <pre>
3268     * StringUtils.splitByWholeSeparator(null, *)               = null
3269     * StringUtils.splitByWholeSeparator("", *)                 = []
3270     * StringUtils.splitByWholeSeparator("ab de fg", null)      = ["ab", "de", "fg"]
3271     * StringUtils.splitByWholeSeparator("ab   de fg", null)    = ["ab", "de", "fg"]
3272     * StringUtils.splitByWholeSeparator("ab:cd:ef", ":")       = ["ab", "cd", "ef"]
3273     * StringUtils.splitByWholeSeparator("ab-!-cd-!-ef", "-!-") = ["ab", "cd", "ef"]
3274     * </pre>
3275     *
3276     * @param str  the String to parse, may be null
3277     * @param separator  String containing the String to be used as a delimiter,
3278     *  {@code null} splits on whitespace
3279     * @return an array of parsed Strings, {@code null} if null String was input
3280     */
3281    public static String[] splitByWholeSeparator(final String str, final String separator) {
3282        return splitByWholeSeparatorWorker(str, separator, -1, false);
3283    }
3284
3285    /**
3286     * <p>Splits the provided text into an array, separator string specified.
3287     * Returns a maximum of {@code max} substrings.</p>
3288     *
3289     * <p>The separator(s) will not be included in the returned String array.
3290     * Adjacent separators are treated as one separator.</p>
3291     *
3292     * <p>A {@code null} input String returns {@code null}.
3293     * A {@code null} separator splits on whitespace.</p>
3294     *
3295     * <pre>
3296     * StringUtils.splitByWholeSeparator(null, *, *)               = null
3297     * StringUtils.splitByWholeSeparator("", *, *)                 = []
3298     * StringUtils.splitByWholeSeparator("ab de fg", null, 0)      = ["ab", "de", "fg"]
3299     * StringUtils.splitByWholeSeparator("ab   de fg", null, 0)    = ["ab", "de", "fg"]
3300     * StringUtils.splitByWholeSeparator("ab:cd:ef", ":", 2)       = ["ab", "cd:ef"]
3301     * StringUtils.splitByWholeSeparator("ab-!-cd-!-ef", "-!-", 5) = ["ab", "cd", "ef"]
3302     * StringUtils.splitByWholeSeparator("ab-!-cd-!-ef", "-!-", 2) = ["ab", "cd-!-ef"]
3303     * </pre>
3304     *
3305     * @param str  the String to parse, may be null
3306     * @param separator  String containing the String to be used as a delimiter,
3307     *  {@code null} splits on whitespace
3308     * @param max  the maximum number of elements to include in the returned
3309     *  array. A zero or negative value implies no limit.
3310     * @return an array of parsed Strings, {@code null} if null String was input
3311     */
3312    public static String[] splitByWholeSeparator( final String str, final String separator, final int max) {
3313        return splitByWholeSeparatorWorker(str, separator, max, false);
3314    }
3315
3316    /**
3317     * <p>Splits the provided text into an array, separator string specified. </p>
3318     *
3319     * <p>The separator is not included in the returned String array.
3320     * Adjacent separators are treated as separators for empty tokens.
3321     * For more control over the split use the StrTokenizer class.</p>
3322     *
3323     * <p>A {@code null} input String returns {@code null}.
3324     * A {@code null} separator splits on whitespace.</p>
3325     *
3326     * <pre>
3327     * StringUtils.splitByWholeSeparatorPreserveAllTokens(null, *)               = null
3328     * StringUtils.splitByWholeSeparatorPreserveAllTokens("", *)                 = []
3329     * StringUtils.splitByWholeSeparatorPreserveAllTokens("ab de fg", null)      = ["ab", "de", "fg"]
3330     * StringUtils.splitByWholeSeparatorPreserveAllTokens("ab   de fg", null)    = ["ab", "", "", "de", "fg"]
3331     * StringUtils.splitByWholeSeparatorPreserveAllTokens("ab:cd:ef", ":")       = ["ab", "cd", "ef"]
3332     * StringUtils.splitByWholeSeparatorPreserveAllTokens("ab-!-cd-!-ef", "-!-") = ["ab", "cd", "ef"]
3333     * </pre>
3334     *
3335     * @param str  the String to parse, may be null
3336     * @param separator  String containing the String to be used as a delimiter,
3337     *  {@code null} splits on whitespace
3338     * @return an array of parsed Strings, {@code null} if null String was input
3339     * @since 2.4
3340     */
3341    public static String[] splitByWholeSeparatorPreserveAllTokens(final String str, final String separator) {
3342        return splitByWholeSeparatorWorker(str, separator, -1, true);
3343    }
3344
3345    /**
3346     * <p>Splits the provided text into an array, separator string specified.
3347     * Returns a maximum of {@code max} substrings.</p>
3348     *
3349     * <p>The separator is not included in the returned String array.
3350     * Adjacent separators are treated as separators for empty tokens.
3351     * For more control over the split use the StrTokenizer class.</p>
3352     *
3353     * <p>A {@code null} input String returns {@code null}.
3354     * A {@code null} separator splits on whitespace.</p>
3355     *
3356     * <pre>
3357     * StringUtils.splitByWholeSeparatorPreserveAllTokens(null, *, *)               = null
3358     * StringUtils.splitByWholeSeparatorPreserveAllTokens("", *, *)                 = []
3359     * StringUtils.splitByWholeSeparatorPreserveAllTokens("ab de fg", null, 0)      = ["ab", "de", "fg"]
3360     * StringUtils.splitByWholeSeparatorPreserveAllTokens("ab   de fg", null, 0)    = ["ab", "", "", "de", "fg"]
3361     * StringUtils.splitByWholeSeparatorPreserveAllTokens("ab:cd:ef", ":", 2)       = ["ab", "cd:ef"]
3362     * StringUtils.splitByWholeSeparatorPreserveAllTokens("ab-!-cd-!-ef", "-!-", 5) = ["ab", "cd", "ef"]
3363     * StringUtils.splitByWholeSeparatorPreserveAllTokens("ab-!-cd-!-ef", "-!-", 2) = ["ab", "cd-!-ef"]
3364     * </pre>
3365     *
3366     * @param str  the String to parse, may be null
3367     * @param separator  String containing the String to be used as a delimiter,
3368     *  {@code null} splits on whitespace
3369     * @param max  the maximum number of elements to include in the returned
3370     *  array. A zero or negative value implies no limit.
3371     * @return an array of parsed Strings, {@code null} if null String was input
3372     * @since 2.4
3373     */
3374    public static String[] splitByWholeSeparatorPreserveAllTokens(final String str, final String separator, final int max) {
3375        return splitByWholeSeparatorWorker(str, separator, max, true);
3376    }
3377
3378    /**
3379     * Performs the logic for the {@code splitByWholeSeparatorPreserveAllTokens} methods.
3380     *
3381     * @param str  the String to parse, may be {@code null}
3382     * @param separator  String containing the String to be used as a delimiter,
3383     *  {@code null} splits on whitespace
3384     * @param max  the maximum number of elements to include in the returned
3385     *  array. A zero or negative value implies no limit.
3386     * @param preserveAllTokens if {@code true}, adjacent separators are
3387     * treated as empty token separators; if {@code false}, adjacent
3388     * separators are treated as one separator.
3389     * @return an array of parsed Strings, {@code null} if null String input
3390     * @since 2.4
3391     */
3392    private static String[] splitByWholeSeparatorWorker(
3393            final String str, final String separator, final int max, final boolean preserveAllTokens) {
3394        if (str == null) {
3395            return null;
3396        }
3397
3398        final int len = str.length();
3399
3400        if (len == 0) {
3401            return ArrayUtils.EMPTY_STRING_ARRAY;
3402        }
3403
3404        if (separator == null || EMPTY.equals(separator)) {
3405            // Split on whitespace.
3406            return splitWorker(str, null, max, preserveAllTokens);
3407        }
3408
3409        final int separatorLength = separator.length();
3410
3411        final ArrayList<String> substrings = new ArrayList<>();
3412        int numberOfSubstrings = 0;
3413        int beg = 0;
3414        int end = 0;
3415        while (end < len) {
3416            end = str.indexOf(separator, beg);
3417
3418            if (end > -1) {
3419                if (end > beg) {
3420                    numberOfSubstrings += 1;
3421
3422                    if (numberOfSubstrings == max) {
3423                        end = len;
3424                        substrings.add(str.substring(beg));
3425                    } else {
3426                        // The following is OK, because String.substring( beg, end ) excludes
3427                        // the character at the position 'end'.
3428                        substrings.add(str.substring(beg, end));
3429
3430                        // Set the starting point for the next search.
3431                        // The following is equivalent to beg = end + (separatorLength - 1) + 1,
3432                        // which is the right calculation:
3433                        beg = end + separatorLength;
3434                    }
3435                } else {
3436                    // We found a consecutive occurrence of the separator, so skip it.
3437                    if (preserveAllTokens) {
3438                        numberOfSubstrings += 1;
3439                        if (numberOfSubstrings == max) {
3440                            end = len;
3441                            substrings.add(str.substring(beg));
3442                        } else {
3443                            substrings.add(EMPTY);
3444                        }
3445                    }
3446                    beg = end + separatorLength;
3447                }
3448            } else {
3449                // String.substring( beg ) goes from 'beg' to the end of the String.
3450                substrings.add(str.substring(beg));
3451                end = len;
3452            }
3453        }
3454
3455        return substrings.toArray(new String[substrings.size()]);
3456    }
3457
3458    // -----------------------------------------------------------------------
3459    /**
3460     * <p>Splits the provided text into an array, using whitespace as the
3461     * separator, preserving all tokens, including empty tokens created by
3462     * adjacent separators. This is an alternative to using StringTokenizer.
3463     * Whitespace is defined by {@link Character#isWhitespace(char)}.</p>
3464     *
3465     * <p>The separator is not included in the returned String array.
3466     * Adjacent separators are treated as separators for empty tokens.
3467     * For more control over the split use the StrTokenizer class.</p>
3468     *
3469     * <p>A {@code null} input String returns {@code null}.</p>
3470     *
3471     * <pre>
3472     * StringUtils.splitPreserveAllTokens(null)       = null
3473     * StringUtils.splitPreserveAllTokens("")         = []
3474     * StringUtils.splitPreserveAllTokens("abc def")  = ["abc", "def"]
3475     * StringUtils.splitPreserveAllTokens("abc  def") = ["abc", "", "def"]
3476     * StringUtils.splitPreserveAllTokens(" abc ")    = ["", "abc", ""]
3477     * </pre>
3478     *
3479     * @param str  the String to parse, may be {@code null}
3480     * @return an array of parsed Strings, {@code null} if null String input
3481     * @since 2.1
3482     */
3483    public static String[] splitPreserveAllTokens(final String str) {
3484        return splitWorker(str, null, -1, true);
3485    }
3486
3487    /**
3488     * <p>Splits the provided text into an array, separator specified,
3489     * preserving all tokens, including empty tokens created by adjacent
3490     * separators. This is an alternative to using StringTokenizer.</p>
3491     *
3492     * <p>The separator is not included in the returned String array.
3493     * Adjacent separators are treated as separators for empty tokens.
3494     * For more control over the split use the StrTokenizer class.</p>
3495     *
3496     * <p>A {@code null} input String returns {@code null}.</p>
3497     *
3498     * <pre>
3499     * StringUtils.splitPreserveAllTokens(null, *)         = null
3500     * StringUtils.splitPreserveAllTokens("", *)           = []
3501     * StringUtils.splitPreserveAllTokens("a.b.c", '.')    = ["a", "b", "c"]
3502     * StringUtils.splitPreserveAllTokens("a..b.c", '.')   = ["a", "", "b", "c"]
3503     * StringUtils.splitPreserveAllTokens("a:b:c", '.')    = ["a:b:c"]
3504     * StringUtils.splitPreserveAllTokens("a\tb\nc", null) = ["a", "b", "c"]
3505     * StringUtils.splitPreserveAllTokens("a b c", ' ')    = ["a", "b", "c"]
3506     * StringUtils.splitPreserveAllTokens("a b c ", ' ')   = ["a", "b", "c", ""]
3507     * StringUtils.splitPreserveAllTokens("a b c  ", ' ')   = ["a", "b", "c", "", ""]
3508     * StringUtils.splitPreserveAllTokens(" a b c", ' ')   = ["", a", "b", "c"]
3509     * StringUtils.splitPreserveAllTokens("  a b c", ' ')  = ["", "", a", "b", "c"]
3510     * StringUtils.splitPreserveAllTokens(" a b c ", ' ')  = ["", a", "b", "c", ""]
3511     * </pre>
3512     *
3513     * @param str  the String to parse, may be {@code null}
3514     * @param separatorChar  the character used as the delimiter,
3515     *  {@code null} splits on whitespace
3516     * @return an array of parsed Strings, {@code null} if null String input
3517     * @since 2.1
3518     */
3519    public static String[] splitPreserveAllTokens(final String str, final char separatorChar) {
3520        return splitWorker(str, separatorChar, true);
3521    }
3522
3523    /**
3524     * Performs the logic for the {@code split} and
3525     * {@code splitPreserveAllTokens} methods that do not return a
3526     * maximum array length.
3527     *
3528     * @param str  the String to parse, may be {@code null}
3529     * @param separatorChar the separate character
3530     * @param preserveAllTokens if {@code true}, adjacent separators are
3531     * treated as empty token separators; if {@code false}, adjacent
3532     * separators are treated as one separator.
3533     * @return an array of parsed Strings, {@code null} if null String input
3534     */
3535    private static String[] splitWorker(final String str, final char separatorChar, final boolean preserveAllTokens) {
3536        // Performance tuned for 2.0 (JDK1.4)
3537
3538        if (str == null) {
3539            return null;
3540        }
3541        final int len = str.length();
3542        if (len == 0) {
3543            return ArrayUtils.EMPTY_STRING_ARRAY;
3544        }
3545        final List<String> list = new ArrayList<>();
3546        int i = 0, start = 0;
3547        boolean match = false;
3548        boolean lastMatch = false;
3549        while (i < len) {
3550            if (str.charAt(i) == separatorChar) {
3551                if (match || preserveAllTokens) {
3552                    list.add(str.substring(start, i));
3553                    match = false;
3554                    lastMatch = true;
3555                }
3556                start = ++i;
3557                continue;
3558            }
3559            lastMatch = false;
3560            match = true;
3561            i++;
3562        }
3563        if (match || preserveAllTokens && lastMatch) {
3564            list.add(str.substring(start, i));
3565        }
3566        return list.toArray(new String[list.size()]);
3567    }
3568
3569    /**
3570     * <p>Splits the provided text into an array, separators specified,
3571     * preserving all tokens, including empty tokens created by adjacent
3572     * separators. This is an alternative to using StringTokenizer.</p>
3573     *
3574     * <p>The separator is not included in the returned String array.
3575     * Adjacent separators are treated as separators for empty tokens.
3576     * For more control over the split use the StrTokenizer class.</p>
3577     *
3578     * <p>A {@code null} input String returns {@code null}.
3579     * A {@code null} separatorChars splits on whitespace.</p>
3580     *
3581     * <pre>
3582     * StringUtils.splitPreserveAllTokens(null, *)           = null
3583     * StringUtils.splitPreserveAllTokens("", *)             = []
3584     * StringUtils.splitPreserveAllTokens("abc def", null)   = ["abc", "def"]
3585     * StringUtils.splitPreserveAllTokens("abc def", " ")    = ["abc", "def"]
3586     * StringUtils.splitPreserveAllTokens("abc  def", " ")   = ["abc", "", def"]
3587     * StringUtils.splitPreserveAllTokens("ab:cd:ef", ":")   = ["ab", "cd", "ef"]
3588     * StringUtils.splitPreserveAllTokens("ab:cd:ef:", ":")  = ["ab", "cd", "ef", ""]
3589     * StringUtils.splitPreserveAllTokens("ab:cd:ef::", ":") = ["ab", "cd", "ef", "", ""]
3590     * StringUtils.splitPreserveAllTokens("ab::cd:ef", ":")  = ["ab", "", cd", "ef"]
3591     * StringUtils.splitPreserveAllTokens(":cd:ef", ":")     = ["", cd", "ef"]
3592     * StringUtils.splitPreserveAllTokens("::cd:ef", ":")    = ["", "", cd", "ef"]
3593     * StringUtils.splitPreserveAllTokens(":cd:ef:", ":")    = ["", cd", "ef", ""]
3594     * </pre>
3595     *
3596     * @param str  the String to parse, may be {@code null}
3597     * @param separatorChars  the characters used as the delimiters,
3598     *  {@code null} splits on whitespace
3599     * @return an array of parsed Strings, {@code null} if null String input
3600     * @since 2.1
3601     */
3602    public static String[] splitPreserveAllTokens(final String str, final String separatorChars) {
3603        return splitWorker(str, separatorChars, -1, true);
3604    }
3605
3606    /**
3607     * <p>Splits the provided text into an array with a maximum length,
3608     * separators specified, preserving all tokens, including empty tokens
3609     * created by adjacent separators.</p>
3610     *
3611     * <p>The separator is not included in the returned String array.
3612     * Adjacent separators are treated as separators for empty tokens.
3613     * Adjacent separators are treated as one separator.</p>
3614     *
3615     * <p>A {@code null} input String returns {@code null}.
3616     * A {@code null} separatorChars splits on whitespace.</p>
3617     *
3618     * <p>If more than {@code max} delimited substrings are found, the last
3619     * returned string includes all characters after the first {@code max - 1}
3620     * returned strings (including separator characters).</p>
3621     *
3622     * <pre>
3623     * StringUtils.splitPreserveAllTokens(null, *, *)            = null
3624     * StringUtils.splitPreserveAllTokens("", *, *)              = []
3625     * StringUtils.splitPreserveAllTokens("ab de fg", null, 0)   = ["ab", "cd", "ef"]
3626     * StringUtils.splitPreserveAllTokens("ab   de fg", null, 0) = ["ab", "cd", "ef"]
3627     * StringUtils.splitPreserveAllTokens("ab:cd:ef", ":", 0)    = ["ab", "cd", "ef"]
3628     * StringUtils.splitPreserveAllTokens("ab:cd:ef", ":", 2)    = ["ab", "cd:ef"]
3629     * StringUtils.splitPreserveAllTokens("ab   de fg", null, 2) = ["ab", "  de fg"]
3630     * StringUtils.splitPreserveAllTokens("ab   de fg", null, 3) = ["ab", "", " de fg"]
3631     * StringUtils.splitPreserveAllTokens("ab   de fg", null, 4) = ["ab", "", "", "de fg"]
3632     * </pre>
3633     *
3634     * @param str  the String to parse, may be {@code null}
3635     * @param separatorChars  the characters used as the delimiters,
3636     *  {@code null} splits on whitespace
3637     * @param max  the maximum number of elements to include in the
3638     *  array. A zero or negative value implies no limit
3639     * @return an array of parsed Strings, {@code null} if null String input
3640     * @since 2.1
3641     */
3642    public static String[] splitPreserveAllTokens(final String str, final String separatorChars, final int max) {
3643        return splitWorker(str, separatorChars, max, true);
3644    }
3645
3646    /**
3647     * Performs the logic for the {@code split} and
3648     * {@code splitPreserveAllTokens} methods that return a maximum array
3649     * length.
3650     *
3651     * @param str  the String to parse, may be {@code null}
3652     * @param separatorChars the separate character
3653     * @param max  the maximum number of elements to include in the
3654     *  array. A zero or negative value implies no limit.
3655     * @param preserveAllTokens if {@code true}, adjacent separators are
3656     * treated as empty token separators; if {@code false}, adjacent
3657     * separators are treated as one separator.
3658     * @return an array of parsed Strings, {@code null} if null String input
3659     */
3660    private static String[] splitWorker(final String str, final String separatorChars, final int max, final boolean preserveAllTokens) {
3661        // Performance tuned for 2.0 (JDK1.4)
3662        // Direct code is quicker than StringTokenizer.
3663        // Also, StringTokenizer uses isSpace() not isWhitespace()
3664
3665        if (str == null) {
3666            return null;
3667        }
3668        final int len = str.length();
3669        if (len == 0) {
3670            return ArrayUtils.EMPTY_STRING_ARRAY;
3671        }
3672        final List<String> list = new ArrayList<>();
3673        int sizePlus1 = 1;
3674        int i = 0, start = 0;
3675        boolean match = false;
3676        boolean lastMatch = false;
3677        if (separatorChars == null) {
3678            // Null separator means use whitespace
3679            while (i < len) {
3680                if (Character.isWhitespace(str.charAt(i))) {
3681                    if (match || preserveAllTokens) {
3682                        lastMatch = true;
3683                        if (sizePlus1++ == max) {
3684                            i = len;
3685                            lastMatch = false;
3686                        }
3687                        list.add(str.substring(start, i));
3688                        match = false;
3689                    }
3690                    start = ++i;
3691                    continue;
3692                }
3693                lastMatch = false;
3694                match = true;
3695                i++;
3696            }
3697        } else if (separatorChars.length() == 1) {
3698            // Optimise 1 character case
3699            final char sep = separatorChars.charAt(0);
3700            while (i < len) {
3701                if (str.charAt(i) == sep) {
3702                    if (match || preserveAllTokens) {
3703                        lastMatch = true;
3704                        if (sizePlus1++ == max) {
3705                            i = len;
3706                            lastMatch = false;
3707                        }
3708                        list.add(str.substring(start, i));
3709                        match = false;
3710                    }
3711                    start = ++i;
3712                    continue;
3713                }
3714                lastMatch = false;
3715                match = true;
3716                i++;
3717            }
3718        } else {
3719            // standard case
3720            while (i < len) {
3721                if (separatorChars.indexOf(str.charAt(i)) >= 0) {
3722                    if (match || preserveAllTokens) {
3723                        lastMatch = true;
3724                        if (sizePlus1++ == max) {
3725                            i = len;
3726                            lastMatch = false;
3727                        }
3728                        list.add(str.substring(start, i));
3729                        match = false;
3730                    }
3731                    start = ++i;
3732                    continue;
3733                }
3734                lastMatch = false;
3735                match = true;
3736                i++;
3737            }
3738        }
3739        if (match || preserveAllTokens && lastMatch) {
3740            list.add(str.substring(start, i));
3741        }
3742        return list.toArray(new String[list.size()]);
3743    }
3744
3745    /**
3746     * <p>Splits a String by Character type as returned by
3747     * {@code java.lang.Character.getType(char)}. Groups of contiguous
3748     * characters of the same type are returned as complete tokens.
3749     * <pre>
3750     * StringUtils.splitByCharacterType(null)         = null
3751     * StringUtils.splitByCharacterType("")           = []
3752     * StringUtils.splitByCharacterType("ab de fg")   = ["ab", " ", "de", " ", "fg"]
3753     * StringUtils.splitByCharacterType("ab   de fg") = ["ab", "   ", "de", " ", "fg"]
3754     * StringUtils.splitByCharacterType("ab:cd:ef")   = ["ab", ":", "cd", ":", "ef"]
3755     * StringUtils.splitByCharacterType("number5")    = ["number", "5"]
3756     * StringUtils.splitByCharacterType("fooBar")     = ["foo", "B", "ar"]
3757     * StringUtils.splitByCharacterType("foo200Bar")  = ["foo", "200", "B", "ar"]
3758     * StringUtils.splitByCharacterType("ASFRules")   = ["ASFR", "ules"]
3759     * </pre>
3760     * @param str the String to split, may be {@code null}
3761     * @return an array of parsed Strings, {@code null} if null String input
3762     * @since 2.4
3763     */
3764    public static String[] splitByCharacterType(final String str) {
3765        return splitByCharacterType(str, false);
3766    }
3767
3768    /**
3769     * <p>Splits a String by Character type as returned by
3770     * {@code java.lang.Character.getType(char)}. Groups of contiguous
3771     * characters of the same type are returned as complete tokens, with the
3772     * following exception: the character of type
3773     * {@code Character.UPPERCASE_LETTER}, if any, immediately
3774     * preceding a token of type {@code Character.LOWERCASE_LETTER}
3775     * will belong to the following token rather than to the preceding, if any,
3776     * {@code Character.UPPERCASE_LETTER} token.
3777     * <pre>
3778     * StringUtils.splitByCharacterTypeCamelCase(null)         = null
3779     * StringUtils.splitByCharacterTypeCamelCase("")           = []
3780     * StringUtils.splitByCharacterTypeCamelCase("ab de fg")   = ["ab", " ", "de", " ", "fg"]
3781     * StringUtils.splitByCharacterTypeCamelCase("ab   de fg") = ["ab", "   ", "de", " ", "fg"]
3782     * StringUtils.splitByCharacterTypeCamelCase("ab:cd:ef")   = ["ab", ":", "cd", ":", "ef"]
3783     * StringUtils.splitByCharacterTypeCamelCase("number5")    = ["number", "5"]
3784     * StringUtils.splitByCharacterTypeCamelCase("fooBar")     = ["foo", "Bar"]
3785     * StringUtils.splitByCharacterTypeCamelCase("foo200Bar")  = ["foo", "200", "Bar"]
3786     * StringUtils.splitByCharacterTypeCamelCase("ASFRules")   = ["ASF", "Rules"]
3787     * </pre>
3788     * @param str the String to split, may be {@code null}
3789     * @return an array of parsed Strings, {@code null} if null String input
3790     * @since 2.4
3791     */
3792    public static String[] splitByCharacterTypeCamelCase(final String str) {
3793        return splitByCharacterType(str, true);
3794    }
3795
3796    /**
3797     * <p>Splits a String by Character type as returned by
3798     * {@code java.lang.Character.getType(char)}. Groups of contiguous
3799     * characters of the same type are returned as complete tokens, with the
3800     * following exception: if {@code camelCase} is {@code true},
3801     * the character of type {@code Character.UPPERCASE_LETTER}, if any,
3802     * immediately preceding a token of type {@code Character.LOWERCASE_LETTER}
3803     * will belong to the following token rather than to the preceding, if any,
3804     * {@code Character.UPPERCASE_LETTER} token.
3805     * @param str the String to split, may be {@code null}
3806     * @param camelCase whether to use so-called "camel-case" for letter types
3807     * @return an array of parsed Strings, {@code null} if null String input
3808     * @since 2.4
3809     */
3810    private static String[] splitByCharacterType(final String str, final boolean camelCase) {
3811        if (str == null) {
3812            return null;
3813        }
3814        if (str.isEmpty()) {
3815            return ArrayUtils.EMPTY_STRING_ARRAY;
3816        }
3817        final char[] c = str.toCharArray();
3818        final List<String> list = new ArrayList<>();
3819        int tokenStart = 0;
3820        int currentType = Character.getType(c[tokenStart]);
3821        for (int pos = tokenStart + 1; pos < c.length; pos++) {
3822            final int type = Character.getType(c[pos]);
3823            if (type == currentType) {
3824                continue;
3825            }
3826            if (camelCase && type == Character.LOWERCASE_LETTER && currentType == Character.UPPERCASE_LETTER) {
3827                final int newTokenStart = pos - 1;
3828                if (newTokenStart != tokenStart) {
3829                    list.add(new String(c, tokenStart, newTokenStart - tokenStart));
3830                    tokenStart = newTokenStart;
3831                }
3832            } else {
3833                list.add(new String(c, tokenStart, pos - tokenStart));
3834                tokenStart = pos;
3835            }
3836            currentType = type;
3837        }
3838        list.add(new String(c, tokenStart, c.length - tokenStart));
3839        return list.toArray(new String[list.size()]);
3840    }
3841
3842    // Joining
3843    //-----------------------------------------------------------------------
3844    /**
3845     * <p>Joins the elements of the provided array into a single String
3846     * containing the provided list of elements.</p>
3847     *
3848     * <p>No separator is added to the joined String.
3849     * Null objects or empty strings within the array are represented by
3850     * empty strings.</p>
3851     *
3852     * <pre>
3853     * StringUtils.join(null)            = null
3854     * StringUtils.join([])              = ""
3855     * StringUtils.join([null])          = ""
3856     * StringUtils.join(["a", "b", "c"]) = "abc"
3857     * StringUtils.join([null, "", "a"]) = "a"
3858     * </pre>
3859     *
3860     * @param <T> the specific type of values to join together
3861     * @param elements  the values to join together, may be null
3862     * @return the joined String, {@code null} if null array input
3863     * @since 2.0
3864     * @since 3.0 Changed signature to use varargs
3865     */
3866    @SafeVarargs
3867    public static <T> String join(final T... elements) {
3868        return join(elements, null);
3869    }
3870
3871    /**
3872     * <p>Joins the elements of the provided array into a single String
3873     * containing the provided list of elements.</p>
3874     *
3875     * <p>No delimiter is added before or after the list.
3876     * Null objects or empty strings within the array are represented by
3877     * empty strings.</p>
3878     *
3879     * <pre>
3880     * StringUtils.join(null, *)               = null
3881     * StringUtils.join([], *)                 = ""
3882     * StringUtils.join([null], *)             = ""
3883     * StringUtils.join(["a", "b", "c"], ';')  = "a;b;c"
3884     * StringUtils.join(["a", "b", "c"], null) = "abc"
3885     * StringUtils.join([null, "", "a"], ';')  = ";;a"
3886     * </pre>
3887     *
3888     * @param array  the array of values to join together, may be null
3889     * @param separator  the separator character to use
3890     * @return the joined String, {@code null} if null array input
3891     * @since 2.0
3892     */
3893    public static String join(final Object[] array, final char separator) {
3894        if (array == null) {
3895            return null;
3896        }
3897        return join(array, separator, 0, array.length);
3898    }
3899
3900    /**
3901     * <p>
3902     * Joins the elements of the provided array into a single String containing the provided list of elements.
3903     * </p>
3904     *
3905     * <p>
3906     * No delimiter is added before or after the list. Null objects or empty strings within the array are represented
3907     * by empty strings.
3908     * </p>
3909     *
3910     * <pre>
3911     * StringUtils.join(null, *)               = null
3912     * StringUtils.join([], *)                 = ""
3913     * StringUtils.join([null], *)             = ""
3914     * StringUtils.join([1, 2, 3], ';')  = "1;2;3"
3915     * StringUtils.join([1, 2, 3], null) = "123"
3916     * </pre>
3917     *
3918     * @param array
3919     *            the array of values to join together, may be null
3920     * @param separator
3921     *            the separator character to use
3922     * @return the joined String, {@code null} if null array input
3923     * @since 3.2
3924     */
3925    public static String join(final long[] array, final char separator) {
3926        if (array == null) {
3927            return null;
3928        }
3929        return join(array, separator, 0, array.length);
3930    }
3931
3932    /**
3933     * <p>
3934     * Joins the elements of the provided array into a single String containing the provided list of elements.
3935     * </p>
3936     *
3937     * <p>
3938     * No delimiter is added before or after the list. Null objects or empty strings within the array are represented
3939     * by empty strings.
3940     * </p>
3941     *
3942     * <pre>
3943     * StringUtils.join(null, *)               = null
3944     * StringUtils.join([], *)                 = ""
3945     * StringUtils.join([null], *)             = ""
3946     * StringUtils.join([1, 2, 3], ';')  = "1;2;3"
3947     * StringUtils.join([1, 2, 3], null) = "123"
3948     * </pre>
3949     *
3950     * @param array
3951     *            the array of values to join together, may be null
3952     * @param separator
3953     *            the separator character to use
3954     * @return the joined String, {@code null} if null array input
3955     * @since 3.2
3956     */
3957    public static String join(final int[] array, final char separator) {
3958        if (array == null) {
3959            return null;
3960        }
3961        return join(array, separator, 0, array.length);
3962    }
3963
3964    /**
3965     * <p>
3966     * Joins the elements of the provided array into a single String containing the provided list of elements.
3967     * </p>
3968     *
3969     * <p>
3970     * No delimiter is added before or after the list. Null objects or empty strings within the array are represented
3971     * by empty strings.
3972     * </p>
3973     *
3974     * <pre>
3975     * StringUtils.join(null, *)               = null
3976     * StringUtils.join([], *)                 = ""
3977     * StringUtils.join([null], *)             = ""
3978     * StringUtils.join([1, 2, 3], ';')  = "1;2;3"
3979     * StringUtils.join([1, 2, 3], null) = "123"
3980     * </pre>
3981     *
3982     * @param array
3983     *            the array of values to join together, may be null
3984     * @param separator
3985     *            the separator character to use
3986     * @return the joined String, {@code null} if null array input
3987     * @since 3.2
3988     */
3989    public static String join(final short[] array, final char separator) {
3990        if (array == null) {
3991            return null;
3992        }
3993        return join(array, separator, 0, array.length);
3994    }
3995
3996    /**
3997     * <p>
3998     * Joins the elements of the provided array into a single String containing the provided list of elements.
3999     * </p>
4000     *
4001     * <p>
4002     * No delimiter is added before or after the list. Null objects or empty strings within the array are represented
4003     * by empty strings.
4004     * </p>
4005     *
4006     * <pre>
4007     * StringUtils.join(null, *)               = null
4008     * StringUtils.join([], *)                 = ""
4009     * StringUtils.join([null], *)             = ""
4010     * StringUtils.join([1, 2, 3], ';')  = "1;2;3"
4011     * StringUtils.join([1, 2, 3], null) = "123"
4012     * </pre>
4013     *
4014     * @param array
4015     *            the array of values to join together, may be null
4016     * @param separator
4017     *            the separator character to use
4018     * @return the joined String, {@code null} if null array input
4019     * @since 3.2
4020     */
4021    public static String join(final byte[] array, final char separator) {
4022        if (array == null) {
4023            return null;
4024        }
4025        return join(array, separator, 0, array.length);
4026    }
4027
4028    /**
4029     * <p>
4030     * Joins the elements of the provided array into a single String containing the provided list of elements.
4031     * </p>
4032     *
4033     * <p>
4034     * No delimiter is added before or after the list. Null objects or empty strings within the array are represented
4035     * by empty strings.
4036     * </p>
4037     *
4038     * <pre>
4039     * StringUtils.join(null, *)               = null
4040     * StringUtils.join([], *)                 = ""
4041     * StringUtils.join([null], *)             = ""
4042     * StringUtils.join([1, 2, 3], ';')  = "1;2;3"
4043     * StringUtils.join([1, 2, 3], null) = "123"
4044     * </pre>
4045     *
4046     * @param array
4047     *            the array of values to join together, may be null
4048     * @param separator
4049     *            the separator character to use
4050     * @return the joined String, {@code null} if null array input
4051     * @since 3.2
4052     */
4053    public static String join(final char[] array, final char separator) {
4054        if (array == null) {
4055            return null;
4056        }
4057        return join(array, separator, 0, array.length);
4058    }
4059
4060    /**
4061     * <p>
4062     * Joins the elements of the provided array into a single String containing the provided list of elements.
4063     * </p>
4064     *
4065     * <p>
4066     * No delimiter is added before or after the list. Null objects or empty strings within the array are represented
4067     * by empty strings.
4068     * </p>
4069     *
4070     * <pre>
4071     * StringUtils.join(null, *)               = null
4072     * StringUtils.join([], *)                 = ""
4073     * StringUtils.join([null], *)             = ""
4074     * StringUtils.join([1, 2, 3], ';')  = "1;2;3"
4075     * StringUtils.join([1, 2, 3], null) = "123"
4076     * </pre>
4077     *
4078     * @param array
4079     *            the array of values to join together, may be null
4080     * @param separator
4081     *            the separator character to use
4082     * @return the joined String, {@code null} if null array input
4083     * @since 3.2
4084     */
4085    public static String join(final float[] array, final char separator) {
4086        if (array == null) {
4087            return null;
4088        }
4089        return join(array, separator, 0, array.length);
4090    }
4091
4092    /**
4093     * <p>
4094     * Joins the elements of the provided array into a single String containing the provided list of elements.
4095     * </p>
4096     *
4097     * <p>
4098     * No delimiter is added before or after the list. Null objects or empty strings within the array are represented
4099     * by empty strings.
4100     * </p>
4101     *
4102     * <pre>
4103     * StringUtils.join(null, *)               = null
4104     * StringUtils.join([], *)                 = ""
4105     * StringUtils.join([null], *)             = ""
4106     * StringUtils.join([1, 2, 3], ';')  = "1;2;3"
4107     * StringUtils.join([1, 2, 3], null) = "123"
4108     * </pre>
4109     *
4110     * @param array
4111     *            the array of values to join together, may be null
4112     * @param separator
4113     *            the separator character to use
4114     * @return the joined String, {@code null} if null array input
4115     * @since 3.2
4116     */
4117    public static String join(final double[] array, final char separator) {
4118        if (array == null) {
4119            return null;
4120        }
4121        return join(array, separator, 0, array.length);
4122    }
4123
4124
4125    /**
4126     * <p>Joins the elements of the provided array into a single String
4127     * containing the provided list of elements.</p>
4128     *
4129     * <p>No delimiter is added before or after the list.
4130     * Null objects or empty strings within the array are represented by
4131     * empty strings.</p>
4132     *
4133     * <pre>
4134     * StringUtils.join(null, *)               = null
4135     * StringUtils.join([], *)                 = ""
4136     * StringUtils.join([null], *)             = ""
4137     * StringUtils.join(["a", "b", "c"], ';')  = "a;b;c"
4138     * StringUtils.join(["a", "b", "c"], null) = "abc"
4139     * StringUtils.join([null, "", "a"], ';')  = ";;a"
4140     * </pre>
4141     *
4142     * @param array  the array of values to join together, may be null
4143     * @param separator  the separator character to use
4144     * @param startIndex the first index to start joining from.  It is
4145     * an error to pass in a start index past the end of the array
4146     * @param endIndex the index to stop joining from (exclusive). It is
4147     * an error to pass in an end index past the end of the array
4148     * @return the joined String, {@code null} if null array input
4149     * @since 2.0
4150     */
4151    public static String join(final Object[] array, final char separator, final int startIndex, final int endIndex) {
4152        if (array == null) {
4153            return null;
4154        }
4155        final int noOfItems = endIndex - startIndex;
4156        if (noOfItems <= 0) {
4157            return EMPTY;
4158        }
4159        final StringBuilder buf = newStringBuilder(noOfItems);
4160        for (int i = startIndex; i < endIndex; i++) {
4161            if (i > startIndex) {
4162                buf.append(separator);
4163            }
4164            if (array[i] != null) {
4165                buf.append(array[i]);
4166            }
4167        }
4168        return buf.toString();
4169    }
4170
4171    /**
4172     * <p>
4173     * Joins the elements of the provided array into a single String containing the provided list of elements.
4174     * </p>
4175     *
4176     * <p>
4177     * No delimiter is added before or after the list. Null objects or empty strings within the array are represented
4178     * by empty strings.
4179     * </p>
4180     *
4181     * <pre>
4182     * StringUtils.join(null, *)               = null
4183     * StringUtils.join([], *)                 = ""
4184     * StringUtils.join([null], *)             = ""
4185     * StringUtils.join([1, 2, 3], ';')  = "1;2;3"
4186     * StringUtils.join([1, 2, 3], null) = "123"
4187     * </pre>
4188     *
4189     * @param array
4190     *            the array of values to join together, may be null
4191     * @param separator
4192     *            the separator character to use
4193     * @param startIndex
4194     *            the first index to start joining from. It is an error to pass in a start index past the end of the
4195     *            array
4196     * @param endIndex
4197     *            the index to stop joining from (exclusive). It is an error to pass in an end index past the end of
4198     *            the array
4199     * @return the joined String, {@code null} if null array input
4200     * @since 3.2
4201     */
4202    public static String join(final long[] array, final char separator, final int startIndex, final int endIndex) {
4203        if (array == null) {
4204            return null;
4205        }
4206        final int noOfItems = endIndex - startIndex;
4207        if (noOfItems <= 0) {
4208            return EMPTY;
4209        }
4210        final StringBuilder buf = newStringBuilder(noOfItems);
4211        for (int i = startIndex; i < endIndex; i++) {
4212            if (i > startIndex) {
4213                buf.append(separator);
4214            }
4215            buf.append(array[i]);
4216        }
4217        return buf.toString();
4218    }
4219
4220    /**
4221     * <p>
4222     * Joins the elements of the provided array into a single String containing the provided list of elements.
4223     * </p>
4224     *
4225     * <p>
4226     * No delimiter is added before or after the list. Null objects or empty strings within the array are represented
4227     * by empty strings.
4228     * </p>
4229     *
4230     * <pre>
4231     * StringUtils.join(null, *)               = null
4232     * StringUtils.join([], *)                 = ""
4233     * StringUtils.join([null], *)             = ""
4234     * StringUtils.join([1, 2, 3], ';')  = "1;2;3"
4235     * StringUtils.join([1, 2, 3], null) = "123"
4236     * </pre>
4237     *
4238     * @param array
4239     *            the array of values to join together, may be null
4240     * @param separator
4241     *            the separator character to use
4242     * @param startIndex
4243     *            the first index to start joining from. It is an error to pass in a start index past the end of the
4244     *            array
4245     * @param endIndex
4246     *            the index to stop joining from (exclusive). It is an error to pass in an end index past the end of
4247     *            the array
4248     * @return the joined String, {@code null} if null array input
4249     * @since 3.2
4250     */
4251    public static String join(final int[] array, final char separator, final int startIndex, final int endIndex) {
4252        if (array == null) {
4253            return null;
4254        }
4255        final int noOfItems = endIndex - startIndex;
4256        if (noOfItems <= 0) {
4257            return EMPTY;
4258        }
4259        final StringBuilder buf = newStringBuilder(noOfItems);
4260        for (int i = startIndex; i < endIndex; i++) {
4261            if (i > startIndex) {
4262                buf.append(separator);
4263            }
4264            buf.append(array[i]);
4265        }
4266        return buf.toString();
4267    }
4268
4269    /**
4270     * <p>
4271     * Joins the elements of the provided array into a single String containing the provided list of elements.
4272     * </p>
4273     *
4274     * <p>
4275     * No delimiter is added before or after the list. Null objects or empty strings within the array are represented
4276     * by empty strings.
4277     * </p>
4278     *
4279     * <pre>
4280     * StringUtils.join(null, *)               = null
4281     * StringUtils.join([], *)                 = ""
4282     * StringUtils.join([null], *)             = ""
4283     * StringUtils.join([1, 2, 3], ';')  = "1;2;3"
4284     * StringUtils.join([1, 2, 3], null) = "123"
4285     * </pre>
4286     *
4287     * @param array
4288     *            the array of values to join together, may be null
4289     * @param separator
4290     *            the separator character to use
4291     * @param startIndex
4292     *            the first index to start joining from. It is an error to pass in a start index past the end of the
4293     *            array
4294     * @param endIndex
4295     *            the index to stop joining from (exclusive). It is an error to pass in an end index past the end of
4296     *            the array
4297     * @return the joined String, {@code null} if null array input
4298     * @since 3.2
4299     */
4300    public static String join(final byte[] array, final char separator, final int startIndex, final int endIndex) {
4301        if (array == null) {
4302            return null;
4303        }
4304        final int noOfItems = endIndex - startIndex;
4305        if (noOfItems <= 0) {
4306            return EMPTY;
4307        }
4308        final StringBuilder buf = newStringBuilder(noOfItems);
4309        for (int i = startIndex; i < endIndex; i++) {
4310            if (i > startIndex) {
4311                buf.append(separator);
4312            }
4313            buf.append(array[i]);
4314        }
4315        return buf.toString();
4316    }
4317
4318    /**
4319     * <p>
4320     * Joins the elements of the provided array into a single String containing the provided list of elements.
4321     * </p>
4322     *
4323     * <p>
4324     * No delimiter is added before or after the list. Null objects or empty strings within the array are represented
4325     * by empty strings.
4326     * </p>
4327     *
4328     * <pre>
4329     * StringUtils.join(null, *)               = null
4330     * StringUtils.join([], *)                 = ""
4331     * StringUtils.join([null], *)             = ""
4332     * StringUtils.join([1, 2, 3], ';')  = "1;2;3"
4333     * StringUtils.join([1, 2, 3], null) = "123"
4334     * </pre>
4335     *
4336     * @param array
4337     *            the array of values to join together, may be null
4338     * @param separator
4339     *            the separator character to use
4340     * @param startIndex
4341     *            the first index to start joining from. It is an error to pass in a start index past the end of the
4342     *            array
4343     * @param endIndex
4344     *            the index to stop joining from (exclusive). It is an error to pass in an end index past the end of
4345     *            the array
4346     * @return the joined String, {@code null} if null array input
4347     * @since 3.2
4348     */
4349    public static String join(final short[] array, final char separator, final int startIndex, final int endIndex) {
4350        if (array == null) {
4351            return null;
4352        }
4353        final int noOfItems = endIndex - startIndex;
4354        if (noOfItems <= 0) {
4355            return EMPTY;
4356        }
4357        final StringBuilder buf = newStringBuilder(noOfItems);
4358        for (int i = startIndex; i < endIndex; i++) {
4359            if (i > startIndex) {
4360                buf.append(separator);
4361            }
4362            buf.append(array[i]);
4363        }
4364        return buf.toString();
4365    }
4366
4367    /**
4368     * <p>
4369     * Joins the elements of the provided array into a single String containing the provided list of elements.
4370     * </p>
4371     *
4372     * <p>
4373     * No delimiter is added before or after the list. Null objects or empty strings within the array are represented
4374     * by empty strings.
4375     * </p>
4376     *
4377     * <pre>
4378     * StringUtils.join(null, *)               = null
4379     * StringUtils.join([], *)                 = ""
4380     * StringUtils.join([null], *)             = ""
4381     * StringUtils.join([1, 2, 3], ';')  = "1;2;3"
4382     * StringUtils.join([1, 2, 3], null) = "123"
4383     * </pre>
4384     *
4385     * @param array
4386     *            the array of values to join together, may be null
4387     * @param separator
4388     *            the separator character to use
4389     * @param startIndex
4390     *            the first index to start joining from. It is an error to pass in a start index past the end of the
4391     *            array
4392     * @param endIndex
4393     *            the index to stop joining from (exclusive). It is an error to pass in an end index past the end of
4394     *            the array
4395     * @return the joined String, {@code null} if null array input
4396     * @since 3.2
4397     */
4398    public static String join(final char[] array, final char separator, final int startIndex, final int endIndex) {
4399        if (array == null) {
4400            return null;
4401        }
4402        final int noOfItems = endIndex - startIndex;
4403        if (noOfItems <= 0) {
4404            return EMPTY;
4405        }
4406        final StringBuilder buf = newStringBuilder(noOfItems);
4407        for (int i = startIndex; i < endIndex; i++) {
4408            if (i > startIndex) {
4409                buf.append(separator);
4410            }
4411            buf.append(array[i]);
4412        }
4413        return buf.toString();
4414    }
4415
4416    /**
4417     * <p>
4418     * Joins the elements of the provided array into a single String containing the provided list of elements.
4419     * </p>
4420     *
4421     * <p>
4422     * No delimiter is added before or after the list. Null objects or empty strings within the array are represented
4423     * by empty strings.
4424     * </p>
4425     *
4426     * <pre>
4427     * StringUtils.join(null, *)               = null
4428     * StringUtils.join([], *)                 = ""
4429     * StringUtils.join([null], *)             = ""
4430     * StringUtils.join([1, 2, 3], ';')  = "1;2;3"
4431     * StringUtils.join([1, 2, 3], null) = "123"
4432     * </pre>
4433     *
4434     * @param array
4435     *            the array of values to join together, may be null
4436     * @param separator
4437     *            the separator character to use
4438     * @param startIndex
4439     *            the first index to start joining from. It is an error to pass in a start index past the end of the
4440     *            array
4441     * @param endIndex
4442     *            the index to stop joining from (exclusive). It is an error to pass in an end index past the end of
4443     *            the array
4444     * @return the joined String, {@code null} if null array input
4445     * @since 3.2
4446     */
4447    public static String join(final double[] array, final char separator, final int startIndex, final int endIndex) {
4448        if (array == null) {
4449            return null;
4450        }
4451        final int noOfItems = endIndex - startIndex;
4452        if (noOfItems <= 0) {
4453            return EMPTY;
4454        }
4455        final StringBuilder buf = newStringBuilder(noOfItems);
4456        for (int i = startIndex; i < endIndex; i++) {
4457            if (i > startIndex) {
4458                buf.append(separator);
4459            }
4460            buf.append(array[i]);
4461        }
4462        return buf.toString();
4463    }
4464
4465    /**
4466     * <p>
4467     * Joins the elements of the provided array into a single String containing the provided list of elements.
4468     * </p>
4469     *
4470     * <p>
4471     * No delimiter is added before or after the list. Null objects or empty strings within the array are represented
4472     * by empty strings.
4473     * </p>
4474     *
4475     * <pre>
4476     * StringUtils.join(null, *)               = null
4477     * StringUtils.join([], *)                 = ""
4478     * StringUtils.join([null], *)             = ""
4479     * StringUtils.join([1, 2, 3], ';')  = "1;2;3"
4480     * StringUtils.join([1, 2, 3], null) = "123"
4481     * </pre>
4482     *
4483     * @param array
4484     *            the array of values to join together, may be null
4485     * @param separator
4486     *            the separator character to use
4487     * @param startIndex
4488     *            the first index to start joining from. It is an error to pass in a start index past the end of the
4489     *            array
4490     * @param endIndex
4491     *            the index to stop joining from (exclusive). It is an error to pass in an end index past the end of
4492     *            the array
4493     * @return the joined String, {@code null} if null array input
4494     * @since 3.2
4495     */
4496    public static String join(final float[] array, final char separator, final int startIndex, final int endIndex) {
4497        if (array == null) {
4498            return null;
4499        }
4500        final int noOfItems = endIndex - startIndex;
4501        if (noOfItems <= 0) {
4502            return EMPTY;
4503        }
4504        final StringBuilder buf = newStringBuilder(noOfItems);
4505        for (int i = startIndex; i < endIndex; i++) {
4506            if (i > startIndex) {
4507                buf.append(separator);
4508            }
4509            buf.append(array[i]);
4510        }
4511        return buf.toString();
4512    }
4513
4514
4515    /**
4516     * <p>Joins the elements of the provided array into a single String
4517     * containing the provided list of elements.</p>
4518     *
4519     * <p>No delimiter is added before or after the list.
4520     * A {@code null} separator is the same as an empty String ("").
4521     * Null objects or empty strings within the array are represented by
4522     * empty strings.</p>
4523     *
4524     * <pre>
4525     * StringUtils.join(null, *)                = null
4526     * StringUtils.join([], *)                  = ""
4527     * StringUtils.join([null], *)              = ""
4528     * StringUtils.join(["a", "b", "c"], "--")  = "a--b--c"
4529     * StringUtils.join(["a", "b", "c"], null)  = "abc"
4530     * StringUtils.join(["a", "b", "c"], "")    = "abc"
4531     * StringUtils.join([null, "", "a"], ',')   = ",,a"
4532     * </pre>
4533     *
4534     * @param array  the array of values to join together, may be null
4535     * @param separator  the separator character to use, null treated as ""
4536     * @return the joined String, {@code null} if null array input
4537     */
4538    public static String join(final Object[] array, final String separator) {
4539        if (array == null) {
4540            return null;
4541        }
4542        return join(array, separator, 0, array.length);
4543    }
4544
4545    /**
4546     * <p>Joins the elements of the provided array into a single String
4547     * containing the provided list of elements.</p>
4548     *
4549     * <p>No delimiter is added before or after the list.
4550     * A {@code null} separator is the same as an empty String ("").
4551     * Null objects or empty strings within the array are represented by
4552     * empty strings.</p>
4553     *
4554     * <pre>
4555     * StringUtils.join(null, *, *, *)                = null
4556     * StringUtils.join([], *, *, *)                  = ""
4557     * StringUtils.join([null], *, *, *)              = ""
4558     * StringUtils.join(["a", "b", "c"], "--", 0, 3)  = "a--b--c"
4559     * StringUtils.join(["a", "b", "c"], "--", 1, 3)  = "b--c"
4560     * StringUtils.join(["a", "b", "c"], "--", 2, 3)  = "c"
4561     * StringUtils.join(["a", "b", "c"], "--", 2, 2)  = ""
4562     * StringUtils.join(["a", "b", "c"], null, 0, 3)  = "abc"
4563     * StringUtils.join(["a", "b", "c"], "", 0, 3)    = "abc"
4564     * StringUtils.join([null, "", "a"], ',', 0, 3)   = ",,a"
4565     * </pre>
4566     *
4567     * @param array  the array of values to join together, may be null
4568     * @param separator  the separator character to use, null treated as ""
4569     * @param startIndex the first index to start joining from.
4570     * @param endIndex the index to stop joining from (exclusive).
4571     * @return the joined String, {@code null} if null array input; or the empty string
4572     * if {@code endIndex - startIndex <= 0}. The number of joined entries is given by
4573     * {@code endIndex - startIndex}
4574     * @throws ArrayIndexOutOfBoundsException ife<br>
4575     * {@code startIndex < 0} or <br>
4576     * {@code startIndex >= array.length()} or <br>
4577     * {@code endIndex < 0} or <br>
4578     * {@code endIndex > array.length()}
4579     */
4580    public static String join(final Object[] array, String separator, final int startIndex, final int endIndex) {
4581        if (array == null) {
4582            return null;
4583        }
4584        if (separator == null) {
4585            separator = EMPTY;
4586        }
4587
4588        // endIndex - startIndex > 0:   Len = NofStrings *(len(firstString) + len(separator))
4589        //           (Assuming that all Strings are roughly equally long)
4590        final int noOfItems = endIndex - startIndex;
4591        if (noOfItems <= 0) {
4592            return EMPTY;
4593        }
4594
4595        final StringBuilder buf = newStringBuilder(noOfItems);
4596
4597        for (int i = startIndex; i < endIndex; i++) {
4598            if (i > startIndex) {
4599                buf.append(separator);
4600            }
4601            if (array[i] != null) {
4602                buf.append(array[i]);
4603            }
4604        }
4605        return buf.toString();
4606    }
4607
4608    /**
4609     * <p>Joins the elements of the provided {@code Iterator} into
4610     * a single String containing the provided elements.</p>
4611     *
4612     * <p>No delimiter is added before or after the list. Null objects or empty
4613     * strings within the iteration are represented by empty strings.</p>
4614     *
4615     * <p>See the examples here: {@link #join(Object[],char)}. </p>
4616     *
4617     * @param iterator  the {@code Iterator} of values to join together, may be null
4618     * @param separator  the separator character to use
4619     * @return the joined String, {@code null} if null iterator input
4620     * @since 2.0
4621     */
4622    public static String join(final Iterator<?> iterator, final char separator) {
4623
4624        // handle null, zero and one elements before building a buffer
4625        if (iterator == null) {
4626            return null;
4627        }
4628        if (!iterator.hasNext()) {
4629            return EMPTY;
4630        }
4631        final Object first = iterator.next();
4632        if (!iterator.hasNext()) {
4633            return Objects.toString(first, EMPTY);
4634        }
4635
4636        // two or more elements
4637        final StringBuilder buf = new StringBuilder(STRING_BUILDER_SIZE); // Java default is 16, probably too small
4638        if (first != null) {
4639            buf.append(first);
4640        }
4641
4642        while (iterator.hasNext()) {
4643            buf.append(separator);
4644            final Object obj = iterator.next();
4645            if (obj != null) {
4646                buf.append(obj);
4647            }
4648        }
4649
4650        return buf.toString();
4651    }
4652
4653    /**
4654     * <p>Joins the elements of the provided {@code Iterator} into
4655     * a single String containing the provided elements.</p>
4656     *
4657     * <p>No delimiter is added before or after the list.
4658     * A {@code null} separator is the same as an empty String ("").</p>
4659     *
4660     * <p>See the examples here: {@link #join(Object[],String)}. </p>
4661     *
4662     * @param iterator  the {@code Iterator} of values to join together, may be null
4663     * @param separator  the separator character to use, null treated as ""
4664     * @return the joined String, {@code null} if null iterator input
4665     */
4666    public static String join(final Iterator<?> iterator, final String separator) {
4667
4668        // handle null, zero and one elements before building a buffer
4669        if (iterator == null) {
4670            return null;
4671        }
4672        if (!iterator.hasNext()) {
4673            return EMPTY;
4674        }
4675        final Object first = iterator.next();
4676        if (!iterator.hasNext()) {
4677            return Objects.toString(first, "");
4678        }
4679
4680        // two or more elements
4681        final StringBuilder buf = new StringBuilder(STRING_BUILDER_SIZE); // Java default is 16, probably too small
4682        if (first != null) {
4683            buf.append(first);
4684        }
4685
4686        while (iterator.hasNext()) {
4687            if (separator != null) {
4688                buf.append(separator);
4689            }
4690            final Object obj = iterator.next();
4691            if (obj != null) {
4692                buf.append(obj);
4693            }
4694        }
4695        return buf.toString();
4696    }
4697
4698    /**
4699     * <p>Joins the elements of the provided {@code Iterable} into
4700     * a single String containing the provided elements.</p>
4701     *
4702     * <p>No delimiter is added before or after the list. Null objects or empty
4703     * strings within the iteration are represented by empty strings.</p>
4704     *
4705     * <p>See the examples here: {@link #join(Object[],char)}. </p>
4706     *
4707     * @param iterable  the {@code Iterable} providing the values to join together, may be null
4708     * @param separator  the separator character to use
4709     * @return the joined String, {@code null} if null iterator input
4710     * @since 2.3
4711     */
4712    public static String join(final Iterable<?> iterable, final char separator) {
4713        if (iterable == null) {
4714            return null;
4715        }
4716        return join(iterable.iterator(), separator);
4717    }
4718
4719    /**
4720     * <p>Joins the elements of the provided {@code Iterable} into
4721     * a single String containing the provided elements.</p>
4722     *
4723     * <p>No delimiter is added before or after the list.
4724     * A {@code null} separator is the same as an empty String ("").</p>
4725     *
4726     * <p>See the examples here: {@link #join(Object[],String)}. </p>
4727     *
4728     * @param iterable  the {@code Iterable} providing the values to join together, may be null
4729     * @param separator  the separator character to use, null treated as ""
4730     * @return the joined String, {@code null} if null iterator input
4731     * @since 2.3
4732     */
4733    public static String join(final Iterable<?> iterable, final String separator) {
4734        if (iterable == null) {
4735            return null;
4736        }
4737        return join(iterable.iterator(), separator);
4738    }
4739
4740    /**
4741     * <p>Joins the elements of the provided {@code List} into a single String
4742     * containing the provided list of elements.</p>
4743     *
4744     * <p>No delimiter is added before or after the list.
4745     * Null objects or empty strings within the array are represented by
4746     * empty strings.</p>
4747     *
4748     * <pre>
4749     * StringUtils.join(null, *)               = null
4750     * StringUtils.join([], *)                 = ""
4751     * StringUtils.join([null], *)             = ""
4752     * StringUtils.join(["a", "b", "c"], ';')  = "a;b;c"
4753     * StringUtils.join(["a", "b", "c"], null) = "abc"
4754     * StringUtils.join([null, "", "a"], ';')  = ";;a"
4755     * </pre>
4756     *
4757     * @param list  the {@code List} of values to join together, may be null
4758     * @param separator  the separator character to use
4759     * @param startIndex the first index to start joining from.  It is
4760     * an error to pass in a start index past the end of the list
4761     * @param endIndex the index to stop joining from (exclusive). It is
4762     * an error to pass in an end index past the end of the list
4763     * @return the joined String, {@code null} if null list input
4764     * @since 3.8
4765     */
4766    public static String join(final List<?> list, final char separator, final int startIndex, final int endIndex) {
4767        if (list == null) {
4768            return null;
4769        }
4770        final int noOfItems = endIndex - startIndex;
4771        if (noOfItems <= 0) {
4772            return EMPTY;
4773        }
4774        final List<?> subList = list.subList(startIndex, endIndex);
4775        return join(subList.iterator(), separator);
4776    }
4777
4778    /**
4779     * <p>Joins the elements of the provided {@code List} into a single String
4780     * containing the provided list of elements.</p>
4781     *
4782     * <p>No delimiter is added before or after the list.
4783     * Null objects or empty strings within the array are represented by
4784     * empty strings.</p>
4785     *
4786     * <pre>
4787     * StringUtils.join(null, *)               = null
4788     * StringUtils.join([], *)                 = ""
4789     * StringUtils.join([null], *)             = ""
4790     * StringUtils.join(["a", "b", "c"], ';')  = "a;b;c"
4791     * StringUtils.join(["a", "b", "c"], null) = "abc"
4792     * StringUtils.join([null, "", "a"], ';')  = ";;a"
4793     * </pre>
4794     *
4795     * @param list  the {@code List} of values to join together, may be null
4796     * @param separator  the separator character to use
4797     * @param startIndex the first index to start joining from.  It is
4798     * an error to pass in a start index past the end of the list
4799     * @param endIndex the index to stop joining from (exclusive). It is
4800     * an error to pass in an end index past the end of the list
4801     * @return the joined String, {@code null} if null list input
4802     * @since 3.8
4803     */
4804    public static String join(final List<?> list, final String separator, final int startIndex, final int endIndex) {
4805        if (list == null) {
4806            return null;
4807        }
4808        final int noOfItems = endIndex - startIndex;
4809        if (noOfItems <= 0) {
4810            return EMPTY;
4811        }
4812        final List<?> subList = list.subList(startIndex, endIndex);
4813        return join(subList.iterator(), separator);
4814    }
4815
4816    /**
4817     * <p>Joins the elements of the provided varargs into a
4818     * single String containing the provided elements.</p>
4819     *
4820     * <p>No delimiter is added before or after the list.
4821     * {@code null} elements and separator are treated as empty Strings ("").</p>
4822     *
4823     * <pre>
4824     * StringUtils.joinWith(",", {"a", "b"})        = "a,b"
4825     * StringUtils.joinWith(",", {"a", "b",""})     = "a,b,"
4826     * StringUtils.joinWith(",", {"a", null, "b"})  = "a,,b"
4827     * StringUtils.joinWith(null, {"a", "b"})       = "ab"
4828     * </pre>
4829     *
4830     * @param separator the separator character to use, null treated as ""
4831     * @param objects the varargs providing the values to join together. {@code null} elements are treated as ""
4832     * @return the joined String.
4833     * @throws java.lang.IllegalArgumentException if a null varargs is provided
4834     * @since 3.5
4835     */
4836    public static String joinWith(final String separator, final Object... objects) {
4837        if (objects == null) {
4838            throw new IllegalArgumentException("Object varargs must not be null");
4839        }
4840
4841        final String sanitizedSeparator = defaultString(separator);
4842
4843        final StringBuilder result = new StringBuilder();
4844
4845        final Iterator<Object> iterator = Arrays.asList(objects).iterator();
4846        while (iterator.hasNext()) {
4847            final String value = Objects.toString(iterator.next(), "");
4848            result.append(value);
4849
4850            if (iterator.hasNext()) {
4851                result.append(sanitizedSeparator);
4852            }
4853        }
4854
4855        return result.toString();
4856    }
4857
4858    // Delete
4859    //-----------------------------------------------------------------------
4860    /**
4861     * <p>Deletes all whitespaces from a String as defined by
4862     * {@link Character#isWhitespace(char)}.</p>
4863     *
4864     * <pre>
4865     * StringUtils.deleteWhitespace(null)         = null
4866     * StringUtils.deleteWhitespace("")           = ""
4867     * StringUtils.deleteWhitespace("abc")        = "abc"
4868     * StringUtils.deleteWhitespace("   ab  c  ") = "abc"
4869     * </pre>
4870     *
4871     * @param str  the String to delete whitespace from, may be null
4872     * @return the String without whitespaces, {@code null} if null String input
4873     */
4874    public static String deleteWhitespace(final String str) {
4875        if (isEmpty(str)) {
4876            return str;
4877        }
4878        final int sz = str.length();
4879        final char[] chs = new char[sz];
4880        int count = 0;
4881        for (int i = 0; i < sz; i++) {
4882            if (!Character.isWhitespace(str.charAt(i))) {
4883                chs[count++] = str.charAt(i);
4884            }
4885        }
4886        if (count == sz) {
4887            return str;
4888        }
4889        return new String(chs, 0, count);
4890    }
4891
4892    // Remove
4893    //-----------------------------------------------------------------------
4894    /**
4895     * <p>Removes a substring only if it is at the beginning of a source string,
4896     * otherwise returns the source string.</p>
4897     *
4898     * <p>A {@code null} source string will return {@code null}.
4899     * An empty ("") source string will return the empty string.
4900     * A {@code null} search string will return the source string.</p>
4901     *
4902     * <pre>
4903     * StringUtils.removeStart(null, *)      = null
4904     * StringUtils.removeStart("", *)        = ""
4905     * StringUtils.removeStart(*, null)      = *
4906     * StringUtils.removeStart("www.domain.com", "www.")   = "domain.com"
4907     * StringUtils.removeStart("domain.com", "www.")       = "domain.com"
4908     * StringUtils.removeStart("www.domain.com", "domain") = "www.domain.com"
4909     * StringUtils.removeStart("abc", "")    = "abc"
4910     * </pre>
4911     *
4912     * @param str  the source String to search, may be null
4913     * @param remove  the String to search for and remove, may be null
4914     * @return the substring with the string removed if found,
4915     *  {@code null} if null String input
4916     * @since 2.1
4917     */
4918    public static String removeStart(final String str, final String remove) {
4919        if (isEmpty(str) || isEmpty(remove)) {
4920            return str;
4921        }
4922        if (str.startsWith(remove)) {
4923            return str.substring(remove.length());
4924        }
4925        return str;
4926    }
4927
4928    /**
4929     * <p>Case insensitive removal of a substring if it is at the beginning of a source string,
4930     * otherwise returns the source string.</p>
4931     *
4932     * <p>A {@code null} source string will return {@code null}.
4933     * An empty ("") source string will return the empty string.
4934     * A {@code null} search string will return the source string.</p>
4935     *
4936     * <pre>
4937     * StringUtils.removeStartIgnoreCase(null, *)      = null
4938     * StringUtils.removeStartIgnoreCase("", *)        = ""
4939     * StringUtils.removeStartIgnoreCase(*, null)      = *
4940     * StringUtils.removeStartIgnoreCase("www.domain.com", "www.")   = "domain.com"
4941     * StringUtils.removeStartIgnoreCase("www.domain.com", "WWW.")   = "domain.com"
4942     * StringUtils.removeStartIgnoreCase("domain.com", "www.")       = "domain.com"
4943     * StringUtils.removeStartIgnoreCase("www.domain.com", "domain") = "www.domain.com"
4944     * StringUtils.removeStartIgnoreCase("abc", "")    = "abc"
4945     * </pre>
4946     *
4947     * @param str  the source String to search, may be null
4948     * @param remove  the String to search for (case insensitive) and remove, may be null
4949     * @return the substring with the string removed if found,
4950     *  {@code null} if null String input
4951     * @since 2.4
4952     */
4953    public static String removeStartIgnoreCase(final String str, final String remove) {
4954        if (isEmpty(str) || isEmpty(remove)) {
4955            return str;
4956        }
4957        if (startsWithIgnoreCase(str, remove)) {
4958            return str.substring(remove.length());
4959        }
4960        return str;
4961    }
4962
4963    /**
4964     * <p>Removes a substring only if it is at the end of a source string,
4965     * otherwise returns the source string.</p>
4966     *
4967     * <p>A {@code null} source string will return {@code null}.
4968     * An empty ("") source string will return the empty string.
4969     * A {@code null} search string will return the source string.</p>
4970     *
4971     * <pre>
4972     * StringUtils.removeEnd(null, *)      = null
4973     * StringUtils.removeEnd("", *)        = ""
4974     * StringUtils.removeEnd(*, null)      = *
4975     * StringUtils.removeEnd("www.domain.com", ".com.")  = "www.domain.com"
4976     * StringUtils.removeEnd("www.domain.com", ".com")   = "www.domain"
4977     * StringUtils.removeEnd("www.domain.com", "domain") = "www.domain.com"
4978     * StringUtils.removeEnd("abc", "")    = "abc"
4979     * </pre>
4980     *
4981     * @param str  the source String to search, may be null
4982     * @param remove  the String to search for and remove, may be null
4983     * @return the substring with the string removed if found,
4984     *  {@code null} if null String input
4985     * @since 2.1
4986     */
4987    public static String removeEnd(final String str, final String remove) {
4988        if (isEmpty(str) || isEmpty(remove)) {
4989            return str;
4990        }
4991        if (str.endsWith(remove)) {
4992            return str.substring(0, str.length() - remove.length());
4993        }
4994        return str;
4995    }
4996
4997    /**
4998     * <p>Case insensitive removal of a substring if it is at the end of a source string,
4999     * otherwise returns the source string.</p>
5000     *
5001     * <p>A {@code null} source string will return {@code null}.
5002     * An empty ("") source string will return the empty string.
5003     * A {@code null} search string will return the source string.</p>
5004     *
5005     * <pre>
5006     * StringUtils.removeEndIgnoreCase(null, *)      = null
5007     * StringUtils.removeEndIgnoreCase("", *)        = ""
5008     * StringUtils.removeEndIgnoreCase(*, null)      = *
5009     * StringUtils.removeEndIgnoreCase("www.domain.com", ".com.")  = "www.domain.com"
5010     * StringUtils.removeEndIgnoreCase("www.domain.com", ".com")   = "www.domain"
5011     * StringUtils.removeEndIgnoreCase("www.domain.com", "domain") = "www.domain.com"
5012     * StringUtils.removeEndIgnoreCase("abc", "")    = "abc"
5013     * StringUtils.removeEndIgnoreCase("www.domain.com", ".COM") = "www.domain")
5014     * StringUtils.removeEndIgnoreCase("www.domain.COM", ".com") = "www.domain")
5015     * </pre>
5016     *
5017     * @param str  the source String to search, may be null
5018     * @param remove  the String to search for (case insensitive) and remove, may be null
5019     * @return the substring with the string removed if found,
5020     *  {@code null} if null String input
5021     * @since 2.4
5022     */
5023    public static String removeEndIgnoreCase(final String str, final String remove) {
5024        if (isEmpty(str) || isEmpty(remove)) {
5025            return str;
5026        }
5027        if (endsWithIgnoreCase(str, remove)) {
5028            return str.substring(0, str.length() - remove.length());
5029        }
5030        return str;
5031    }
5032
5033    /**
5034     * <p>Removes all occurrences of a substring from within the source string.</p>
5035     *
5036     * <p>A {@code null} source string will return {@code null}.
5037     * An empty ("") source string will return the empty string.
5038     * A {@code null} remove string will return the source string.
5039     * An empty ("") remove string will return the source string.</p>
5040     *
5041     * <pre>
5042     * StringUtils.remove(null, *)        = null
5043     * StringUtils.remove("", *)          = ""
5044     * StringUtils.remove(*, null)        = *
5045     * StringUtils.remove(*, "")          = *
5046     * StringUtils.remove("queued", "ue") = "qd"
5047     * StringUtils.remove("queued", "zz") = "queued"
5048     * </pre>
5049     *
5050     * @param str  the source String to search, may be null
5051     * @param remove  the String to search for and remove, may be null
5052     * @return the substring with the string removed if found,
5053     *  {@code null} if null String input
5054     * @since 2.1
5055     */
5056    public static String remove(final String str, final String remove) {
5057        if (isEmpty(str) || isEmpty(remove)) {
5058            return str;
5059        }
5060        return replace(str, remove, EMPTY, -1);
5061    }
5062
5063    /**
5064     * <p>
5065     * Case insensitive removal of all occurrences of a substring from within
5066     * the source string.
5067     * </p>
5068     *
5069     * <p>
5070     * A {@code null} source string will return {@code null}. An empty ("")
5071     * source string will return the empty string. A {@code null} remove string
5072     * will return the source string. An empty ("") remove string will return
5073     * the source string.
5074     * </p>
5075     *
5076     * <pre>
5077     * StringUtils.removeIgnoreCase(null, *)        = null
5078     * StringUtils.removeIgnoreCase("", *)          = ""
5079     * StringUtils.removeIgnoreCase(*, null)        = *
5080     * StringUtils.removeIgnoreCase(*, "")          = *
5081     * StringUtils.removeIgnoreCase("queued", "ue") = "qd"
5082     * StringUtils.removeIgnoreCase("queued", "zz") = "queued"
5083     * StringUtils.removeIgnoreCase("quEUed", "UE") = "qd"
5084     * StringUtils.removeIgnoreCase("queued", "zZ") = "queued"
5085     * </pre>
5086     *
5087     * @param str
5088     *            the source String to search, may be null
5089     * @param remove
5090     *            the String to search for (case insensitive) and remove, may be
5091     *            null
5092     * @return the substring with the string removed if found, {@code null} if
5093     *         null String input
5094     * @since 3.5
5095     */
5096    public static String removeIgnoreCase(final String str, final String remove) {
5097        if (isEmpty(str) || isEmpty(remove)) {
5098            return str;
5099        }
5100        return replaceIgnoreCase(str, remove, EMPTY, -1);
5101    }
5102
5103    /**
5104     * <p>Removes all occurrences of a character from within the source string.</p>
5105     *
5106     * <p>A {@code null} source string will return {@code null}.
5107     * An empty ("") source string will return the empty string.</p>
5108     *
5109     * <pre>
5110     * StringUtils.remove(null, *)       = null
5111     * StringUtils.remove("", *)         = ""
5112     * StringUtils.remove("queued", 'u') = "qeed"
5113     * StringUtils.remove("queued", 'z') = "queued"
5114     * </pre>
5115     *
5116     * @param str  the source String to search, may be null
5117     * @param remove  the char to search for and remove, may be null
5118     * @return the substring with the char removed if found,
5119     *  {@code null} if null String input
5120     * @since 2.1
5121     */
5122    public static String remove(final String str, final char remove) {
5123        if (isEmpty(str) || str.indexOf(remove) == INDEX_NOT_FOUND) {
5124            return str;
5125        }
5126        final char[] chars = str.toCharArray();
5127        int pos = 0;
5128        for (int i = 0; i < chars.length; i++) {
5129            if (chars[i] != remove) {
5130                chars[pos++] = chars[i];
5131            }
5132        }
5133        return new String(chars, 0, pos);
5134    }
5135
5136    /**
5137     * <p>Removes each substring of the text String that matches the given regular expression.</p>
5138     *
5139     * This method is a {@code null} safe equivalent to:
5140     * <ul>
5141     *  <li>{@code text.replaceAll(regex, StringUtils.EMPTY)}</li>
5142     *  <li>{@code Pattern.compile(regex).matcher(text).replaceAll(StringUtils.EMPTY)}</li>
5143     * </ul>
5144     *
5145     * <p>A {@code null} reference passed to this method is a no-op.</p>
5146     *
5147     * <p>Unlike in the {@link #removePattern(String, String)} method, the {@link Pattern#DOTALL} option
5148     * is NOT automatically added.
5149     * To use the DOTALL option prepend <code>"(?s)"</code> to the regex.
5150     * DOTALL is also known as single-line mode in Perl.</p>
5151     *
5152     * <pre>
5153     * StringUtils.removeAll(null, *)      = null
5154     * StringUtils.removeAll("any", (String) null)  = "any"
5155     * StringUtils.removeAll("any", "")    = "any"
5156     * StringUtils.removeAll("any", ".*")  = ""
5157     * StringUtils.removeAll("any", ".+")  = ""
5158     * StringUtils.removeAll("abc", ".?")  = ""
5159     * StringUtils.removeAll("A&lt;__&gt;\n&lt;__&gt;B", "&lt;.*&gt;")      = "A\nB"
5160     * StringUtils.removeAll("A&lt;__&gt;\n&lt;__&gt;B", "(?s)&lt;.*&gt;")  = "AB"
5161     * StringUtils.removeAll("ABCabc123abc", "[a-z]")     = "ABC123"
5162     * </pre>
5163     *
5164     * @param text  text to remove from, may be null
5165     * @param regex  the regular expression to which this string is to be matched
5166     * @return  the text with any removes processed,
5167     *              {@code null} if null String input
5168     *
5169     * @throws  java.util.regex.PatternSyntaxException
5170     *              if the regular expression's syntax is invalid
5171     *
5172     * @see #replaceAll(String, String, String)
5173     * @see #removePattern(String, String)
5174     * @see String#replaceAll(String, String)
5175     * @see java.util.regex.Pattern
5176     * @see java.util.regex.Pattern#DOTALL
5177     * @since 3.5
5178     *
5179     * @deprecated Moved to RegExUtils.
5180     */
5181    @Deprecated
5182    public static String removeAll(final String text, final String regex) {
5183        return RegExUtils.removeAll(text, regex);
5184    }
5185
5186    /**
5187     * <p>Removes the first substring of the text string that matches the given regular expression.</p>
5188     *
5189     * This method is a {@code null} safe equivalent to:
5190     * <ul>
5191     *  <li>{@code text.replaceFirst(regex, StringUtils.EMPTY)}</li>
5192     *  <li>{@code Pattern.compile(regex).matcher(text).replaceFirst(StringUtils.EMPTY)}</li>
5193     * </ul>
5194     *
5195     * <p>A {@code null} reference passed to this method is a no-op.</p>
5196     *
5197     * <p>The {@link Pattern#DOTALL} option is NOT automatically added.
5198     * To use the DOTALL option prepend <code>"(?s)"</code> to the regex.
5199     * DOTALL is also known as single-line mode in Perl.</p>
5200     *
5201     * <pre>
5202     * StringUtils.removeFirst(null, *)      = null
5203     * StringUtils.removeFirst("any", (String) null)  = "any"
5204     * StringUtils.removeFirst("any", "")    = "any"
5205     * StringUtils.removeFirst("any", ".*")  = ""
5206     * StringUtils.removeFirst("any", ".+")  = ""
5207     * StringUtils.removeFirst("abc", ".?")  = "bc"
5208     * StringUtils.removeFirst("A&lt;__&gt;\n&lt;__&gt;B", "&lt;.*&gt;")      = "A\n&lt;__&gt;B"
5209     * StringUtils.removeFirst("A&lt;__&gt;\n&lt;__&gt;B", "(?s)&lt;.*&gt;")  = "AB"
5210     * StringUtils.removeFirst("ABCabc123", "[a-z]")          = "ABCbc123"
5211     * StringUtils.removeFirst("ABCabc123abc", "[a-z]+")      = "ABC123abc"
5212     * </pre>
5213     *
5214     * @param text  text to remove from, may be null
5215     * @param regex  the regular expression to which this string is to be matched
5216     * @return  the text with the first replacement processed,
5217     *              {@code null} if null String input
5218     *
5219     * @throws  java.util.regex.PatternSyntaxException
5220     *              if the regular expression's syntax is invalid
5221     *
5222     * @see #replaceFirst(String, String, String)
5223     * @see String#replaceFirst(String, String)
5224     * @see java.util.regex.Pattern
5225     * @see java.util.regex.Pattern#DOTALL
5226     * @since 3.5
5227     *
5228     * @deprecated Moved to RegExUtils.
5229     */
5230    @Deprecated
5231    public static String removeFirst(final String text, final String regex) {
5232        return replaceFirst(text, regex, EMPTY);
5233    }
5234
5235    // Replacing
5236    //-----------------------------------------------------------------------
5237    /**
5238     * <p>Replaces a String with another String inside a larger String, once.</p>
5239     *
5240     * <p>A {@code null} reference passed to this method is a no-op.</p>
5241     *
5242     * <pre>
5243     * StringUtils.replaceOnce(null, *, *)        = null
5244     * StringUtils.replaceOnce("", *, *)          = ""
5245     * StringUtils.replaceOnce("any", null, *)    = "any"
5246     * StringUtils.replaceOnce("any", *, null)    = "any"
5247     * StringUtils.replaceOnce("any", "", *)      = "any"
5248     * StringUtils.replaceOnce("aba", "a", null)  = "aba"
5249     * StringUtils.replaceOnce("aba", "a", "")    = "ba"
5250     * StringUtils.replaceOnce("aba", "a", "z")   = "zba"
5251     * </pre>
5252     *
5253     * @see #replace(String text, String searchString, String replacement, int max)
5254     * @param text  text to search and replace in, may be null
5255     * @param searchString  the String to search for, may be null
5256     * @param replacement  the String to replace with, may be null
5257     * @return the text with any replacements processed,
5258     *  {@code null} if null String input
5259     */
5260    public static String replaceOnce(final String text, final String searchString, final String replacement) {
5261        return replace(text, searchString, replacement, 1);
5262    }
5263
5264    /**
5265     * <p>Case insensitively replaces a String with another String inside a larger String, once.</p>
5266     *
5267     * <p>A {@code null} reference passed to this method is a no-op.</p>
5268     *
5269     * <pre>
5270     * StringUtils.replaceOnceIgnoreCase(null, *, *)        = null
5271     * StringUtils.replaceOnceIgnoreCase("", *, *)          = ""
5272     * StringUtils.replaceOnceIgnoreCase("any", null, *)    = "any"
5273     * StringUtils.replaceOnceIgnoreCase("any", *, null)    = "any"
5274     * StringUtils.replaceOnceIgnoreCase("any", "", *)      = "any"
5275     * StringUtils.replaceOnceIgnoreCase("aba", "a", null)  = "aba"
5276     * StringUtils.replaceOnceIgnoreCase("aba", "a", "")    = "ba"
5277     * StringUtils.replaceOnceIgnoreCase("aba", "a", "z")   = "zba"
5278     * StringUtils.replaceOnceIgnoreCase("FoOFoofoo", "foo", "") = "Foofoo"
5279     * </pre>
5280     *
5281     * @see #replaceIgnoreCase(String text, String searchString, String replacement, int max)
5282     * @param text  text to search and replace in, may be null
5283     * @param searchString  the String to search for (case insensitive), may be null
5284     * @param replacement  the String to replace with, may be null
5285     * @return the text with any replacements processed,
5286     *  {@code null} if null String input
5287     * @since 3.5
5288     */
5289    public static String replaceOnceIgnoreCase(final String text, final String searchString, final String replacement) {
5290        return replaceIgnoreCase(text, searchString, replacement, 1);
5291    }
5292
5293    /**
5294     * <p>Replaces each substring of the source String that matches the given regular expression with the given
5295     * replacement using the {@link Pattern#DOTALL} option. DOTALL is also known as single-line mode in Perl.</p>
5296     *
5297     * This call is a {@code null} safe equivalent to:
5298     * <ul>
5299     * <li>{@code source.replaceAll(&quot;(?s)&quot; + regex, replacement)}</li>
5300     * <li>{@code Pattern.compile(regex, Pattern.DOTALL).matcher(source).replaceAll(replacement)}</li>
5301     * </ul>
5302     *
5303     * <p>A {@code null} reference passed to this method is a no-op.</p>
5304     *
5305     * <pre>
5306     * StringUtils.replacePattern(null, *, *)       = null
5307     * StringUtils.replacePattern("any", (String) null, *)   = "any"
5308     * StringUtils.replacePattern("any", *, null)   = "any"
5309     * StringUtils.replacePattern("", "", "zzz")    = "zzz"
5310     * StringUtils.replacePattern("", ".*", "zzz")  = "zzz"
5311     * StringUtils.replacePattern("", ".+", "zzz")  = ""
5312     * StringUtils.replacePattern("&lt;__&gt;\n&lt;__&gt;", "&lt;.*&gt;", "z")       = "z"
5313     * StringUtils.replacePattern("ABCabc123", "[a-z]", "_")       = "ABC___123"
5314     * StringUtils.replacePattern("ABCabc123", "[^A-Z0-9]+", "_")  = "ABC_123"
5315     * StringUtils.replacePattern("ABCabc123", "[^A-Z0-9]+", "")   = "ABC123"
5316     * StringUtils.replacePattern("Lorem ipsum  dolor   sit", "( +)([a-z]+)", "_$2")  = "Lorem_ipsum_dolor_sit"
5317     * </pre>
5318     *
5319     * @param source
5320     *            the source string
5321     * @param regex
5322     *            the regular expression to which this string is to be matched
5323     * @param replacement
5324     *            the string to be substituted for each match
5325     * @return The resulting {@code String}
5326     * @see #replaceAll(String, String, String)
5327     * @see String#replaceAll(String, String)
5328     * @see Pattern#DOTALL
5329     * @since 3.2
5330     * @since 3.5 Changed {@code null} reference passed to this method is a no-op.
5331     *
5332     * @deprecated Moved to RegExUtils.
5333     */
5334    @Deprecated
5335    public static String replacePattern(final String source, final String regex, final String replacement) {
5336        return RegExUtils.replacePattern(source, regex, replacement);
5337    }
5338
5339    /**
5340     * <p>Removes each substring of the source String that matches the given regular expression using the DOTALL option.
5341     * </p>
5342     *
5343     * This call is a {@code null} safe equivalent to:
5344     * <ul>
5345     * <li>{@code source.replaceAll(&quot;(?s)&quot; + regex, StringUtils.EMPTY)}</li>
5346     * <li>{@code Pattern.compile(regex, Pattern.DOTALL).matcher(source).replaceAll(StringUtils.EMPTY)}</li>
5347     * </ul>
5348     *
5349     * <p>A {@code null} reference passed to this method is a no-op.</p>
5350     *
5351     * <pre>
5352     * StringUtils.removePattern(null, *)       = null
5353     * StringUtils.removePattern("any", (String) null)   = "any"
5354     * StringUtils.removePattern("A&lt;__&gt;\n&lt;__&gt;B", "&lt;.*&gt;")  = "AB"
5355     * StringUtils.removePattern("ABCabc123", "[a-z]")    = "ABC123"
5356     * </pre>
5357     *
5358     * @param source
5359     *            the source string
5360     * @param regex
5361     *            the regular expression to which this string is to be matched
5362     * @return The resulting {@code String}
5363     * @see #replacePattern(String, String, String)
5364     * @see String#replaceAll(String, String)
5365     * @see Pattern#DOTALL
5366     * @since 3.2
5367     * @since 3.5 Changed {@code null} reference passed to this method is a no-op.
5368     *
5369     * @deprecated Moved to RegExUtils.
5370     */
5371    @Deprecated
5372    public static String removePattern(final String source, final String regex) {
5373        return RegExUtils.removePattern(source, regex);
5374    }
5375
5376    /**
5377     * <p>Replaces each substring of the text String that matches the given regular expression
5378     * with the given replacement.</p>
5379     *
5380     * This method is a {@code null} safe equivalent to:
5381     * <ul>
5382     *  <li>{@code text.replaceAll(regex, replacement)}</li>
5383     *  <li>{@code Pattern.compile(regex).matcher(text).replaceAll(replacement)}</li>
5384     * </ul>
5385     *
5386     * <p>A {@code null} reference passed to this method is a no-op.</p>
5387     *
5388     * <p>Unlike in the {@link #replacePattern(String, String, String)} method, the {@link Pattern#DOTALL} option
5389     * is NOT automatically added.
5390     * To use the DOTALL option prepend <code>"(?s)"</code> to the regex.
5391     * DOTALL is also known as single-line mode in Perl.</p>
5392     *
5393     * <pre>
5394     * StringUtils.replaceAll(null, *, *)       = null
5395     * StringUtils.replaceAll("any", (String) null, *)   = "any"
5396     * StringUtils.replaceAll("any", *, null)   = "any"
5397     * StringUtils.replaceAll("", "", "zzz")    = "zzz"
5398     * StringUtils.replaceAll("", ".*", "zzz")  = "zzz"
5399     * StringUtils.replaceAll("", ".+", "zzz")  = ""
5400     * StringUtils.replaceAll("abc", "", "ZZ")  = "ZZaZZbZZcZZ"
5401     * StringUtils.replaceAll("&lt;__&gt;\n&lt;__&gt;", "&lt;.*&gt;", "z")      = "z\nz"
5402     * StringUtils.replaceAll("&lt;__&gt;\n&lt;__&gt;", "(?s)&lt;.*&gt;", "z")  = "z"
5403     * StringUtils.replaceAll("ABCabc123", "[a-z]", "_")       = "ABC___123"
5404     * StringUtils.replaceAll("ABCabc123", "[^A-Z0-9]+", "_")  = "ABC_123"
5405     * StringUtils.replaceAll("ABCabc123", "[^A-Z0-9]+", "")   = "ABC123"
5406     * StringUtils.replaceAll("Lorem ipsum  dolor   sit", "( +)([a-z]+)", "_$2")  = "Lorem_ipsum_dolor_sit"
5407     * </pre>
5408     *
5409     * @param text  text to search and replace in, may be null
5410     * @param regex  the regular expression to which this string is to be matched
5411     * @param replacement  the string to be substituted for each match
5412     * @return  the text with any replacements processed,
5413     *              {@code null} if null String input
5414     *
5415     * @throws  java.util.regex.PatternSyntaxException
5416     *              if the regular expression's syntax is invalid
5417     *
5418     * @see #replacePattern(String, String, String)
5419     * @see String#replaceAll(String, String)
5420     * @see java.util.regex.Pattern
5421     * @see java.util.regex.Pattern#DOTALL
5422     * @since 3.5
5423     *
5424     * @deprecated Moved to RegExUtils.
5425     */
5426    @Deprecated
5427    public static String replaceAll(final String text, final String regex, final String replacement) {
5428        return RegExUtils.replaceAll(text, regex, replacement);
5429    }
5430
5431    /**
5432     * <p>Replaces the first substring of the text string that matches the given regular expression
5433     * with the given replacement.</p>
5434     *
5435     * This method is a {@code null} safe equivalent to:
5436     * <ul>
5437     *  <li>{@code text.replaceFirst(regex, replacement)}</li>
5438     *  <li>{@code Pattern.compile(regex).matcher(text).replaceFirst(replacement)}</li>
5439     * </ul>
5440     *
5441     * <p>A {@code null} reference passed to this method is a no-op.</p>
5442     *
5443     * <p>The {@link Pattern#DOTALL} option is NOT automatically added.
5444     * To use the DOTALL option prepend <code>"(?s)"</code> to the regex.
5445     * DOTALL is also known as single-line mode in Perl.</p>
5446     *
5447     * <pre>
5448     * StringUtils.replaceFirst(null, *, *)       = null
5449     * StringUtils.replaceFirst("any", (String) null, *)   = "any"
5450     * StringUtils.replaceFirst("any", *, null)   = "any"
5451     * StringUtils.replaceFirst("", "", "zzz")    = "zzz"
5452     * StringUtils.replaceFirst("", ".*", "zzz")  = "zzz"
5453     * StringUtils.replaceFirst("", ".+", "zzz")  = ""
5454     * StringUtils.replaceFirst("abc", "", "ZZ")  = "ZZabc"
5455     * StringUtils.replaceFirst("&lt;__&gt;\n&lt;__&gt;", "&lt;.*&gt;", "z")      = "z\n&lt;__&gt;"
5456     * StringUtils.replaceFirst("&lt;__&gt;\n&lt;__&gt;", "(?s)&lt;.*&gt;", "z")  = "z"
5457     * StringUtils.replaceFirst("ABCabc123", "[a-z]", "_")          = "ABC_bc123"
5458     * StringUtils.replaceFirst("ABCabc123abc", "[^A-Z0-9]+", "_")  = "ABC_123abc"
5459     * StringUtils.replaceFirst("ABCabc123abc", "[^A-Z0-9]+", "")   = "ABC123abc"
5460     * StringUtils.replaceFirst("Lorem ipsum  dolor   sit", "( +)([a-z]+)", "_$2")  = "Lorem_ipsum  dolor   sit"
5461     * </pre>
5462     *
5463     * @param text  text to search and replace in, may be null
5464     * @param regex  the regular expression to which this string is to be matched
5465     * @param replacement  the string to be substituted for the first match
5466     * @return  the text with the first replacement processed,
5467     *              {@code null} if null String input
5468     *
5469     * @throws  java.util.regex.PatternSyntaxException
5470     *              if the regular expression's syntax is invalid
5471     *
5472     * @see String#replaceFirst(String, String)
5473     * @see java.util.regex.Pattern
5474     * @see java.util.regex.Pattern#DOTALL
5475     * @since 3.5
5476     *
5477     * @deprecated Moved to RegExUtils.
5478     */
5479    @Deprecated
5480    public static String replaceFirst(final String text, final String regex, final String replacement) {
5481        return RegExUtils.replaceFirst(text, regex, replacement);
5482    }
5483
5484    /**
5485     * <p>Replaces all occurrences of a String within another String.</p>
5486     *
5487     * <p>A {@code null} reference passed to this method is a no-op.</p>
5488     *
5489     * <pre>
5490     * StringUtils.replace(null, *, *)        = null
5491     * StringUtils.replace("", *, *)          = ""
5492     * StringUtils.replace("any", null, *)    = "any"
5493     * StringUtils.replace("any", *, null)    = "any"
5494     * StringUtils.replace("any", "", *)      = "any"
5495     * StringUtils.replace("aba", "a", null)  = "aba"
5496     * StringUtils.replace("aba", "a", "")    = "b"
5497     * StringUtils.replace("aba", "a", "z")   = "zbz"
5498     * </pre>
5499     *
5500     * @see #replace(String text, String searchString, String replacement, int max)
5501     * @param text  text to search and replace in, may be null
5502     * @param searchString  the String to search for, may be null
5503     * @param replacement  the String to replace it with, may be null
5504     * @return the text with any replacements processed,
5505     *  {@code null} if null String input
5506     */
5507    public static String replace(final String text, final String searchString, final String replacement) {
5508        return replace(text, searchString, replacement, -1);
5509    }
5510
5511    /**
5512    * <p>Case insensitively replaces all occurrences of a String within another String.</p>
5513    *
5514    * <p>A {@code null} reference passed to this method is a no-op.</p>
5515    *
5516    * <pre>
5517    * StringUtils.replaceIgnoreCase(null, *, *)        = null
5518    * StringUtils.replaceIgnoreCase("", *, *)          = ""
5519    * StringUtils.replaceIgnoreCase("any", null, *)    = "any"
5520    * StringUtils.replaceIgnoreCase("any", *, null)    = "any"
5521    * StringUtils.replaceIgnoreCase("any", "", *)      = "any"
5522    * StringUtils.replaceIgnoreCase("aba", "a", null)  = "aba"
5523    * StringUtils.replaceIgnoreCase("abA", "A", "")    = "b"
5524    * StringUtils.replaceIgnoreCase("aba", "A", "z")   = "zbz"
5525    * </pre>
5526    *
5527    * @see #replaceIgnoreCase(String text, String searchString, String replacement, int max)
5528    * @param text  text to search and replace in, may be null
5529    * @param searchString  the String to search for (case insensitive), may be null
5530    * @param replacement  the String to replace it with, may be null
5531    * @return the text with any replacements processed,
5532    *  {@code null} if null String input
5533    * @since 3.5
5534    */
5535   public static String replaceIgnoreCase(final String text, final String searchString, final String replacement) {
5536       return replaceIgnoreCase(text, searchString, replacement, -1);
5537   }
5538
5539    /**
5540     * <p>Replaces a String with another String inside a larger String,
5541     * for the first {@code max} values of the search String.</p>
5542     *
5543     * <p>A {@code null} reference passed to this method is a no-op.</p>
5544     *
5545     * <pre>
5546     * StringUtils.replace(null, *, *, *)         = null
5547     * StringUtils.replace("", *, *, *)           = ""
5548     * StringUtils.replace("any", null, *, *)     = "any"
5549     * StringUtils.replace("any", *, null, *)     = "any"
5550     * StringUtils.replace("any", "", *, *)       = "any"
5551     * StringUtils.replace("any", *, *, 0)        = "any"
5552     * StringUtils.replace("abaa", "a", null, -1) = "abaa"
5553     * StringUtils.replace("abaa", "a", "", -1)   = "b"
5554     * StringUtils.replace("abaa", "a", "z", 0)   = "abaa"
5555     * StringUtils.replace("abaa", "a", "z", 1)   = "zbaa"
5556     * StringUtils.replace("abaa", "a", "z", 2)   = "zbza"
5557     * StringUtils.replace("abaa", "a", "z", -1)  = "zbzz"
5558     * </pre>
5559     *
5560     * @param text  text to search and replace in, may be null
5561     * @param searchString  the String to search for, may be null
5562     * @param replacement  the String to replace it with, may be null
5563     * @param max  maximum number of values to replace, or {@code -1} if no maximum
5564     * @return the text with any replacements processed,
5565     *  {@code null} if null String input
5566     */
5567    public static String replace(final String text, final String searchString, final String replacement, final int max) {
5568        return replace(text, searchString, replacement, max, false);
5569    }
5570
5571    /**
5572     * <p>Replaces a String with another String inside a larger String,
5573     * for the first {@code max} values of the search String,
5574     * case sensitively/insensisitively based on {@code ignoreCase} value.</p>
5575     *
5576     * <p>A {@code null} reference passed to this method is a no-op.</p>
5577     *
5578     * <pre>
5579     * StringUtils.replace(null, *, *, *, false)         = null
5580     * StringUtils.replace("", *, *, *, false)           = ""
5581     * StringUtils.replace("any", null, *, *, false)     = "any"
5582     * StringUtils.replace("any", *, null, *, false)     = "any"
5583     * StringUtils.replace("any", "", *, *, false)       = "any"
5584     * StringUtils.replace("any", *, *, 0, false)        = "any"
5585     * StringUtils.replace("abaa", "a", null, -1, false) = "abaa"
5586     * StringUtils.replace("abaa", "a", "", -1, false)   = "b"
5587     * StringUtils.replace("abaa", "a", "z", 0, false)   = "abaa"
5588     * StringUtils.replace("abaa", "A", "z", 1, false)   = "abaa"
5589     * StringUtils.replace("abaa", "A", "z", 1, true)   = "zbaa"
5590     * StringUtils.replace("abAa", "a", "z", 2, true)   = "zbza"
5591     * StringUtils.replace("abAa", "a", "z", -1, true)  = "zbzz"
5592     * </pre>
5593     *
5594     * @param text  text to search and replace in, may be null
5595     * @param searchString  the String to search for (case insensitive), may be null
5596     * @param replacement  the String to replace it with, may be null
5597     * @param max  maximum number of values to replace, or {@code -1} if no maximum
5598     * @param ignoreCase if true replace is case insensitive, otherwise case sensitive
5599     * @return the text with any replacements processed,
5600     *  {@code null} if null String input
5601     */
5602     private static String replace(final String text, String searchString, final String replacement, int max, final boolean ignoreCase) {
5603         if (isEmpty(text) || isEmpty(searchString) || replacement == null || max == 0) {
5604             return text;
5605         }
5606         String searchText = text;
5607         if (ignoreCase) {
5608             searchText = text.toLowerCase();
5609             searchString = searchString.toLowerCase();
5610         }
5611         int start = 0;
5612         int end = searchText.indexOf(searchString, start);
5613         if (end == INDEX_NOT_FOUND) {
5614             return text;
5615         }
5616         final int replLength = searchString.length();
5617         int increase = replacement.length() - replLength;
5618         increase = increase < 0 ? 0 : increase;
5619         increase *= max < 0 ? 16 : max > 64 ? 64 : max;
5620         final StringBuilder buf = new StringBuilder(text.length() + increase);
5621         while (end != INDEX_NOT_FOUND) {
5622             buf.append(text, start, end).append(replacement);
5623             start = end + replLength;
5624             if (--max == 0) {
5625                 break;
5626             }
5627             end = searchText.indexOf(searchString, start);
5628         }
5629         buf.append(text, start, text.length());
5630         return buf.toString();
5631     }
5632
5633    /**
5634     * <p>Case insensitively replaces a String with another String inside a larger String,
5635     * for the first {@code max} values of the search String.</p>
5636     *
5637     * <p>A {@code null} reference passed to this method is a no-op.</p>
5638     *
5639     * <pre>
5640     * StringUtils.replaceIgnoreCase(null, *, *, *)         = null
5641     * StringUtils.replaceIgnoreCase("", *, *, *)           = ""
5642     * StringUtils.replaceIgnoreCase("any", null, *, *)     = "any"
5643     * StringUtils.replaceIgnoreCase("any", *, null, *)     = "any"
5644     * StringUtils.replaceIgnoreCase("any", "", *, *)       = "any"
5645     * StringUtils.replaceIgnoreCase("any", *, *, 0)        = "any"
5646     * StringUtils.replaceIgnoreCase("abaa", "a", null, -1) = "abaa"
5647     * StringUtils.replaceIgnoreCase("abaa", "a", "", -1)   = "b"
5648     * StringUtils.replaceIgnoreCase("abaa", "a", "z", 0)   = "abaa"
5649     * StringUtils.replaceIgnoreCase("abaa", "A", "z", 1)   = "zbaa"
5650     * StringUtils.replaceIgnoreCase("abAa", "a", "z", 2)   = "zbza"
5651     * StringUtils.replaceIgnoreCase("abAa", "a", "z", -1)  = "zbzz"
5652     * </pre>
5653     *
5654     * @param text  text to search and replace in, may be null
5655     * @param searchString  the String to search for (case insensitive), may be null
5656     * @param replacement  the String to replace it with, may be null
5657     * @param max  maximum number of values to replace, or {@code -1} if no maximum
5658     * @return the text with any replacements processed,
5659     *  {@code null} if null String input
5660     * @since 3.5
5661     */
5662    public static String replaceIgnoreCase(final String text, final String searchString, final String replacement, final int max) {
5663        return replace(text, searchString, replacement, max, true);
5664    }
5665
5666    /**
5667     * <p>
5668     * Replaces all occurrences of Strings within another String.
5669     * </p>
5670     *
5671     * <p>
5672     * A {@code null} reference passed to this method is a no-op, or if
5673     * any "search string" or "string to replace" is null, that replace will be
5674     * ignored. This will not repeat. For repeating replaces, call the
5675     * overloaded method.
5676     * </p>
5677     *
5678     * <pre>
5679     *  StringUtils.replaceEach(null, *, *)        = null
5680     *  StringUtils.replaceEach("", *, *)          = ""
5681     *  StringUtils.replaceEach("aba", null, null) = "aba"
5682     *  StringUtils.replaceEach("aba", new String[0], null) = "aba"
5683     *  StringUtils.replaceEach("aba", null, new String[0]) = "aba"
5684     *  StringUtils.replaceEach("aba", new String[]{"a"}, null)  = "aba"
5685     *  StringUtils.replaceEach("aba", new String[]{"a"}, new String[]{""})  = "b"
5686     *  StringUtils.replaceEach("aba", new String[]{null}, new String[]{"a"})  = "aba"
5687     *  StringUtils.replaceEach("abcde", new String[]{"ab", "d"}, new String[]{"w", "t"})  = "wcte"
5688     *  (example of how it does not repeat)
5689     *  StringUtils.replaceEach("abcde", new String[]{"ab", "d"}, new String[]{"d", "t"})  = "dcte"
5690     * </pre>
5691     *
5692     * @param text
5693     *            text to search and replace in, no-op if null
5694     * @param searchList
5695     *            the Strings to search for, no-op if null
5696     * @param replacementList
5697     *            the Strings to replace them with, no-op if null
5698     * @return the text with any replacements processed, {@code null} if
5699     *         null String input
5700     * @throws IllegalArgumentException
5701     *             if the lengths of the arrays are not the same (null is ok,
5702     *             and/or size 0)
5703     * @since 2.4
5704     */
5705    public static String replaceEach(final String text, final String[] searchList, final String[] replacementList) {
5706        return replaceEach(text, searchList, replacementList, false, 0);
5707    }
5708
5709    /**
5710     * <p>
5711     * Replaces all occurrences of Strings within another String.
5712     * </p>
5713     *
5714     * <p>
5715     * A {@code null} reference passed to this method is a no-op, or if
5716     * any "search string" or "string to replace" is null, that replace will be
5717     * ignored.
5718     * </p>
5719     *
5720     * <pre>
5721     *  StringUtils.replaceEachRepeatedly(null, *, *) = null
5722     *  StringUtils.replaceEachRepeatedly("", *, *) = ""
5723     *  StringUtils.replaceEachRepeatedly("aba", null, null) = "aba"
5724     *  StringUtils.replaceEachRepeatedly("aba", new String[0], null) = "aba"
5725     *  StringUtils.replaceEachRepeatedly("aba", null, new String[0]) = "aba"
5726     *  StringUtils.replaceEachRepeatedly("aba", new String[]{"a"}, null) = "aba"
5727     *  StringUtils.replaceEachRepeatedly("aba", new String[]{"a"}, new String[]{""}) = "b"
5728     *  StringUtils.replaceEachRepeatedly("aba", new String[]{null}, new String[]{"a"}) = "aba"
5729     *  StringUtils.replaceEachRepeatedly("abcde", new String[]{"ab", "d"}, new String[]{"w", "t"}) = "wcte"
5730     *  (example of how it repeats)
5731     *  StringUtils.replaceEachRepeatedly("abcde", new String[]{"ab", "d"}, new String[]{"d", "t"}) = "tcte"
5732     *  StringUtils.replaceEachRepeatedly("abcde", new String[]{"ab", "d"}, new String[]{"d", "ab"}) = IllegalStateException
5733     * </pre>
5734     *
5735     * @param text
5736     *            text to search and replace in, no-op if null
5737     * @param searchList
5738     *            the Strings to search for, no-op if null
5739     * @param replacementList
5740     *            the Strings to replace them with, no-op if null
5741     * @return the text with any replacements processed, {@code null} if
5742     *         null String input
5743     * @throws IllegalStateException
5744     *             if the search is repeating and there is an endless loop due
5745     *             to outputs of one being inputs to another
5746     * @throws IllegalArgumentException
5747     *             if the lengths of the arrays are not the same (null is ok,
5748     *             and/or size 0)
5749     * @since 2.4
5750     */
5751    public static String replaceEachRepeatedly(final String text, final String[] searchList, final String[] replacementList) {
5752        // timeToLive should be 0 if not used or nothing to replace, else it's
5753        // the length of the replace array
5754        final int timeToLive = searchList == null ? 0 : searchList.length;
5755        return replaceEach(text, searchList, replacementList, true, timeToLive);
5756    }
5757
5758    /**
5759     * <p>
5760     * Replace all occurrences of Strings within another String.
5761     * This is a private recursive helper method for {@link #replaceEachRepeatedly(String, String[], String[])} and
5762     * {@link #replaceEach(String, String[], String[])}
5763     * </p>
5764     *
5765     * <p>
5766     * A {@code null} reference passed to this method is a no-op, or if
5767     * any "search string" or "string to replace" is null, that replace will be
5768     * ignored.
5769     * </p>
5770     *
5771     * <pre>
5772     *  StringUtils.replaceEach(null, *, *, *, *) = null
5773     *  StringUtils.replaceEach("", *, *, *, *) = ""
5774     *  StringUtils.replaceEach("aba", null, null, *, *) = "aba"
5775     *  StringUtils.replaceEach("aba", new String[0], null, *, *) = "aba"
5776     *  StringUtils.replaceEach("aba", null, new String[0], *, *) = "aba"
5777     *  StringUtils.replaceEach("aba", new String[]{"a"}, null, *, *) = "aba"
5778     *  StringUtils.replaceEach("aba", new String[]{"a"}, new String[]{""}, *, >=0) = "b"
5779     *  StringUtils.replaceEach("aba", new String[]{null}, new String[]{"a"}, *, >=0) = "aba"
5780     *  StringUtils.replaceEach("abcde", new String[]{"ab", "d"}, new String[]{"w", "t"}, *, >=0) = "wcte"
5781     *  (example of how it repeats)
5782     *  StringUtils.replaceEach("abcde", new String[]{"ab", "d"}, new String[]{"d", "t"}, false, >=0) = "dcte"
5783     *  StringUtils.replaceEach("abcde", new String[]{"ab", "d"}, new String[]{"d", "t"}, true, >=2) = "tcte"
5784     *  StringUtils.replaceEach("abcde", new String[]{"ab", "d"}, new String[]{"d", "ab"}, *, *) = IllegalStateException
5785     * </pre>
5786     *
5787     * @param text
5788     *            text to search and replace in, no-op if null
5789     * @param searchList
5790     *            the Strings to search for, no-op if null
5791     * @param replacementList
5792     *            the Strings to replace them with, no-op if null
5793     * @param repeat if true, then replace repeatedly
5794     *       until there are no more possible replacements or timeToLive < 0
5795     * @param timeToLive
5796     *            if less than 0 then there is a circular reference and endless
5797     *            loop
5798     * @return the text with any replacements processed, {@code null} if
5799     *         null String input
5800     * @throws IllegalStateException
5801     *             if the search is repeating and there is an endless loop due
5802     *             to outputs of one being inputs to another
5803     * @throws IllegalArgumentException
5804     *             if the lengths of the arrays are not the same (null is ok,
5805     *             and/or size 0)
5806     * @since 2.4
5807     */
5808    private static String replaceEach(
5809            final String text, final String[] searchList, final String[] replacementList, final boolean repeat, final int timeToLive) {
5810
5811        // mchyzer Performance note: This creates very few new objects (one major goal)
5812        // let me know if there are performance requests, we can create a harness to measure
5813
5814        if (text == null || text.isEmpty() || searchList == null ||
5815                searchList.length == 0 || replacementList == null || replacementList.length == 0) {
5816            return text;
5817        }
5818
5819        // if recursing, this shouldn't be less than 0
5820        if (timeToLive < 0) {
5821            throw new IllegalStateException("Aborting to protect against StackOverflowError - " +
5822                                            "output of one loop is the input of another");
5823        }
5824
5825        final int searchLength = searchList.length;
5826        final int replacementLength = replacementList.length;
5827
5828        // make sure lengths are ok, these need to be equal
5829        if (searchLength != replacementLength) {
5830            throw new IllegalArgumentException("Search and Replace array lengths don't match: "
5831                + searchLength
5832                + " vs "
5833                + replacementLength);
5834        }
5835
5836        // keep track of which still have matches
5837        final boolean[] noMoreMatchesForReplIndex = new boolean[searchLength];
5838
5839        // index on index that the match was found
5840        int textIndex = -1;
5841        int replaceIndex = -1;
5842        int tempIndex = -1;
5843
5844        // index of replace array that will replace the search string found
5845        // NOTE: logic duplicated below START
5846        for (int i = 0; i < searchLength; i++) {
5847            if (noMoreMatchesForReplIndex[i] || searchList[i] == null ||
5848                    searchList[i].isEmpty() || replacementList[i] == null) {
5849                continue;
5850            }
5851            tempIndex = text.indexOf(searchList[i]);
5852
5853            // see if we need to keep searching for this
5854            if (tempIndex == -1) {
5855                noMoreMatchesForReplIndex[i] = true;
5856            } else {
5857                if (textIndex == -1 || tempIndex < textIndex) {
5858                    textIndex = tempIndex;
5859                    replaceIndex = i;
5860                }
5861            }
5862        }
5863        // NOTE: logic mostly below END
5864
5865        // no search strings found, we are done
5866        if (textIndex == -1) {
5867            return text;
5868        }
5869
5870        int start = 0;
5871
5872        // get a good guess on the size of the result buffer so it doesn't have to double if it goes over a bit
5873        int increase = 0;
5874
5875        // count the replacement text elements that are larger than their corresponding text being replaced
5876        for (int i = 0; i < searchList.length; i++) {
5877            if (searchList[i] == null || replacementList[i] == null) {
5878                continue;
5879            }
5880            final int greater = replacementList[i].length() - searchList[i].length();
5881            if (greater > 0) {
5882                increase += 3 * greater; // assume 3 matches
5883            }
5884        }
5885        // have upper-bound at 20% increase, then let Java take over
5886        increase = Math.min(increase, text.length() / 5);
5887
5888        final StringBuilder buf = new StringBuilder(text.length() + increase);
5889
5890        while (textIndex != -1) {
5891
5892            for (int i = start; i < textIndex; i++) {
5893                buf.append(text.charAt(i));
5894            }
5895            buf.append(replacementList[replaceIndex]);
5896
5897            start = textIndex + searchList[replaceIndex].length();
5898
5899            textIndex = -1;
5900            replaceIndex = -1;
5901            tempIndex = -1;
5902            // find the next earliest match
5903            // NOTE: logic mostly duplicated above START
5904            for (int i = 0; i < searchLength; i++) {
5905                if (noMoreMatchesForReplIndex[i] || searchList[i] == null ||
5906                        searchList[i].isEmpty() || replacementList[i] == null) {
5907                    continue;
5908                }
5909                tempIndex = text.indexOf(searchList[i], start);
5910
5911                // see if we need to keep searching for this
5912                if (tempIndex == -1) {
5913                    noMoreMatchesForReplIndex[i] = true;
5914                } else {
5915                    if (textIndex == -1 || tempIndex < textIndex) {
5916                        textIndex = tempIndex;
5917                        replaceIndex = i;
5918                    }
5919                }
5920            }
5921            // NOTE: logic duplicated above END
5922
5923        }
5924        final int textLength = text.length();
5925        for (int i = start; i < textLength; i++) {
5926            buf.append(text.charAt(i));
5927        }
5928        final String result = buf.toString();
5929        if (!repeat) {
5930            return result;
5931        }
5932
5933        return replaceEach(result, searchList, replacementList, repeat, timeToLive - 1);
5934    }
5935
5936    // Replace, character based
5937    //-----------------------------------------------------------------------
5938    /**
5939     * <p>Replaces all occurrences of a character in a String with another.
5940     * This is a null-safe version of {@link String#replace(char, char)}.</p>
5941     *
5942     * <p>A {@code null} string input returns {@code null}.
5943     * An empty ("") string input returns an empty string.</p>
5944     *
5945     * <pre>
5946     * StringUtils.replaceChars(null, *, *)        = null
5947     * StringUtils.replaceChars("", *, *)          = ""
5948     * StringUtils.replaceChars("abcba", 'b', 'y') = "aycya"
5949     * StringUtils.replaceChars("abcba", 'z', 'y') = "abcba"
5950     * </pre>
5951     *
5952     * @param str  String to replace characters in, may be null
5953     * @param searchChar  the character to search for, may be null
5954     * @param replaceChar  the character to replace, may be null
5955     * @return modified String, {@code null} if null string input
5956     * @since 2.0
5957     */
5958    public static String replaceChars(final String str, final char searchChar, final char replaceChar) {
5959        if (str == null) {
5960            return null;
5961        }
5962        return str.replace(searchChar, replaceChar);
5963    }
5964
5965    /**
5966     * <p>Replaces multiple characters in a String in one go.
5967     * This method can also be used to delete characters.</p>
5968     *
5969     * <p>For example:<br>
5970     * <code>replaceChars(&quot;hello&quot;, &quot;ho&quot;, &quot;jy&quot;) = jelly</code>.</p>
5971     *
5972     * <p>A {@code null} string input returns {@code null}.
5973     * An empty ("") string input returns an empty string.
5974     * A null or empty set of search characters returns the input string.</p>
5975     *
5976     * <p>The length of the search characters should normally equal the length
5977     * of the replace characters.
5978     * If the search characters is longer, then the extra search characters
5979     * are deleted.
5980     * If the search characters is shorter, then the extra replace characters
5981     * are ignored.</p>
5982     *
5983     * <pre>
5984     * StringUtils.replaceChars(null, *, *)           = null
5985     * StringUtils.replaceChars("", *, *)             = ""
5986     * StringUtils.replaceChars("abc", null, *)       = "abc"
5987     * StringUtils.replaceChars("abc", "", *)         = "abc"
5988     * StringUtils.replaceChars("abc", "b", null)     = "ac"
5989     * StringUtils.replaceChars("abc", "b", "")       = "ac"
5990     * StringUtils.replaceChars("abcba", "bc", "yz")  = "ayzya"
5991     * StringUtils.replaceChars("abcba", "bc", "y")   = "ayya"
5992     * StringUtils.replaceChars("abcba", "bc", "yzx") = "ayzya"
5993     * </pre>
5994     *
5995     * @param str  String to replace characters in, may be null
5996     * @param searchChars  a set of characters to search for, may be null
5997     * @param replaceChars  a set of characters to replace, may be null
5998     * @return modified String, {@code null} if null string input
5999     * @since 2.0
6000     */
6001    public static String replaceChars(final String str, final String searchChars, String replaceChars) {
6002        if (isEmpty(str) || isEmpty(searchChars)) {
6003            return str;
6004        }
6005        if (replaceChars == null) {
6006            replaceChars = EMPTY;
6007        }
6008        boolean modified = false;
6009        final int replaceCharsLength = replaceChars.length();
6010        final int strLength = str.length();
6011        final StringBuilder buf = new StringBuilder(strLength);
6012        for (int i = 0; i < strLength; i++) {
6013            final char ch = str.charAt(i);
6014            final int index = searchChars.indexOf(ch);
6015            if (index >= 0) {
6016                modified = true;
6017                if (index < replaceCharsLength) {
6018                    buf.append(replaceChars.charAt(index));
6019                }
6020            } else {
6021                buf.append(ch);
6022            }
6023        }
6024        if (modified) {
6025            return buf.toString();
6026        }
6027        return str;
6028    }
6029
6030    // Overlay
6031    //-----------------------------------------------------------------------
6032    /**
6033     * <p>Overlays part of a String with another String.</p>
6034     *
6035     * <p>A {@code null} string input returns {@code null}.
6036     * A negative index is treated as zero.
6037     * An index greater than the string length is treated as the string length.
6038     * The start index is always the smaller of the two indices.</p>
6039     *
6040     * <pre>
6041     * StringUtils.overlay(null, *, *, *)            = null
6042     * StringUtils.overlay("", "abc", 0, 0)          = "abc"
6043     * StringUtils.overlay("abcdef", null, 2, 4)     = "abef"
6044     * StringUtils.overlay("abcdef", "", 2, 4)       = "abef"
6045     * StringUtils.overlay("abcdef", "", 4, 2)       = "abef"
6046     * StringUtils.overlay("abcdef", "zzzz", 2, 4)   = "abzzzzef"
6047     * StringUtils.overlay("abcdef", "zzzz", 4, 2)   = "abzzzzef"
6048     * StringUtils.overlay("abcdef", "zzzz", -1, 4)  = "zzzzef"
6049     * StringUtils.overlay("abcdef", "zzzz", 2, 8)   = "abzzzz"
6050     * StringUtils.overlay("abcdef", "zzzz", -2, -3) = "zzzzabcdef"
6051     * StringUtils.overlay("abcdef", "zzzz", 8, 10)  = "abcdefzzzz"
6052     * </pre>
6053     *
6054     * @param str  the String to do overlaying in, may be null
6055     * @param overlay  the String to overlay, may be null
6056     * @param start  the position to start overlaying at
6057     * @param end  the position to stop overlaying before
6058     * @return overlayed String, {@code null} if null String input
6059     * @since 2.0
6060     */
6061    public static String overlay(final String str, String overlay, int start, int end) {
6062        if (str == null) {
6063            return null;
6064        }
6065        if (overlay == null) {
6066            overlay = EMPTY;
6067        }
6068        final int len = str.length();
6069        if (start < 0) {
6070            start = 0;
6071        }
6072        if (start > len) {
6073            start = len;
6074        }
6075        if (end < 0) {
6076            end = 0;
6077        }
6078        if (end > len) {
6079            end = len;
6080        }
6081        if (start > end) {
6082            final int temp = start;
6083            start = end;
6084            end = temp;
6085        }
6086        return str.substring(0, start) +
6087            overlay +
6088            str.substring(end);
6089    }
6090
6091    // Chomping
6092    //-----------------------------------------------------------------------
6093    /**
6094     * <p>Removes one newline from end of a String if it's there,
6095     * otherwise leave it alone.  A newline is &quot;{@code \n}&quot;,
6096     * &quot;{@code \r}&quot;, or &quot;{@code \r\n}&quot;.</p>
6097     *
6098     * <p>NOTE: This method changed in 2.0.
6099     * It now more closely matches Perl chomp.</p>
6100     *
6101     * <pre>
6102     * StringUtils.chomp(null)          = null
6103     * StringUtils.chomp("")            = ""
6104     * StringUtils.chomp("abc \r")      = "abc "
6105     * StringUtils.chomp("abc\n")       = "abc"
6106     * StringUtils.chomp("abc\r\n")     = "abc"
6107     * StringUtils.chomp("abc\r\n\r\n") = "abc\r\n"
6108     * StringUtils.chomp("abc\n\r")     = "abc\n"
6109     * StringUtils.chomp("abc\n\rabc")  = "abc\n\rabc"
6110     * StringUtils.chomp("\r")          = ""
6111     * StringUtils.chomp("\n")          = ""
6112     * StringUtils.chomp("\r\n")        = ""
6113     * </pre>
6114     *
6115     * @param str  the String to chomp a newline from, may be null
6116     * @return String without newline, {@code null} if null String input
6117     */
6118    public static String chomp(final String str) {
6119        if (isEmpty(str)) {
6120            return str;
6121        }
6122
6123        if (str.length() == 1) {
6124            final char ch = str.charAt(0);
6125            if (ch == CharUtils.CR || ch == CharUtils.LF) {
6126                return EMPTY;
6127            }
6128            return str;
6129        }
6130
6131        int lastIdx = str.length() - 1;
6132        final char last = str.charAt(lastIdx);
6133
6134        if (last == CharUtils.LF) {
6135            if (str.charAt(lastIdx - 1) == CharUtils.CR) {
6136                lastIdx--;
6137            }
6138        } else if (last != CharUtils.CR) {
6139            lastIdx++;
6140        }
6141        return str.substring(0, lastIdx);
6142    }
6143
6144    /**
6145     * <p>Removes {@code separator} from the end of
6146     * {@code str} if it's there, otherwise leave it alone.</p>
6147     *
6148     * <p>NOTE: This method changed in version 2.0.
6149     * It now more closely matches Perl chomp.
6150     * For the previous behavior, use {@link #substringBeforeLast(String, String)}.
6151     * This method uses {@link String#endsWith(String)}.</p>
6152     *
6153     * <pre>
6154     * StringUtils.chomp(null, *)         = null
6155     * StringUtils.chomp("", *)           = ""
6156     * StringUtils.chomp("foobar", "bar") = "foo"
6157     * StringUtils.chomp("foobar", "baz") = "foobar"
6158     * StringUtils.chomp("foo", "foo")    = ""
6159     * StringUtils.chomp("foo ", "foo")   = "foo "
6160     * StringUtils.chomp(" foo", "foo")   = " "
6161     * StringUtils.chomp("foo", "foooo")  = "foo"
6162     * StringUtils.chomp("foo", "")       = "foo"
6163     * StringUtils.chomp("foo", null)     = "foo"
6164     * </pre>
6165     *
6166     * @param str  the String to chomp from, may be null
6167     * @param separator  separator String, may be null
6168     * @return String without trailing separator, {@code null} if null String input
6169     * @deprecated This feature will be removed in Lang 4.0, use {@link StringUtils#removeEnd(String, String)} instead
6170     */
6171    @Deprecated
6172    public static String chomp(final String str, final String separator) {
6173        return removeEnd(str, separator);
6174    }
6175
6176    // Chopping
6177    //-----------------------------------------------------------------------
6178    /**
6179     * <p>Remove the last character from a String.</p>
6180     *
6181     * <p>If the String ends in {@code \r\n}, then remove both
6182     * of them.</p>
6183     *
6184     * <pre>
6185     * StringUtils.chop(null)          = null
6186     * StringUtils.chop("")            = ""
6187     * StringUtils.chop("abc \r")      = "abc "
6188     * StringUtils.chop("abc\n")       = "abc"
6189     * StringUtils.chop("abc\r\n")     = "abc"
6190     * StringUtils.chop("abc")         = "ab"
6191     * StringUtils.chop("abc\nabc")    = "abc\nab"
6192     * StringUtils.chop("a")           = ""
6193     * StringUtils.chop("\r")          = ""
6194     * StringUtils.chop("\n")          = ""
6195     * StringUtils.chop("\r\n")        = ""
6196     * </pre>
6197     *
6198     * @param str  the String to chop last character from, may be null
6199     * @return String without last character, {@code null} if null String input
6200     */
6201    public static String chop(final String str) {
6202        if (str == null) {
6203            return null;
6204        }
6205        final int strLen = str.length();
6206        if (strLen < 2) {
6207            return EMPTY;
6208        }
6209        final int lastIdx = strLen - 1;
6210        final String ret = str.substring(0, lastIdx);
6211        final char last = str.charAt(lastIdx);
6212        if (last == CharUtils.LF && ret.charAt(lastIdx - 1) == CharUtils.CR) {
6213            return ret.substring(0, lastIdx - 1);
6214        }
6215        return ret;
6216    }
6217
6218    // Conversion
6219    //-----------------------------------------------------------------------
6220
6221    // Padding
6222    //-----------------------------------------------------------------------
6223    /**
6224     * <p>Repeat a String {@code repeat} times to form a
6225     * new String.</p>
6226     *
6227     * <pre>
6228     * StringUtils.repeat(null, 2) = null
6229     * StringUtils.repeat("", 0)   = ""
6230     * StringUtils.repeat("", 2)   = ""
6231     * StringUtils.repeat("a", 3)  = "aaa"
6232     * StringUtils.repeat("ab", 2) = "abab"
6233     * StringUtils.repeat("a", -2) = ""
6234     * </pre>
6235     *
6236     * @param str  the String to repeat, may be null
6237     * @param repeat  number of times to repeat str, negative treated as zero
6238     * @return a new String consisting of the original String repeated,
6239     *  {@code null} if null String input
6240     */
6241    public static String repeat(final String str, final int repeat) {
6242        // Performance tuned for 2.0 (JDK1.4)
6243
6244        if (str == null) {
6245            return null;
6246        }
6247        if (repeat <= 0) {
6248            return EMPTY;
6249        }
6250        final int inputLength = str.length();
6251        if (repeat == 1 || inputLength == 0) {
6252            return str;
6253        }
6254        if (inputLength == 1 && repeat <= PAD_LIMIT) {
6255            return repeat(str.charAt(0), repeat);
6256        }
6257
6258        final int outputLength = inputLength * repeat;
6259        switch (inputLength) {
6260            case 1 :
6261                return repeat(str.charAt(0), repeat);
6262            case 2 :
6263                final char ch0 = str.charAt(0);
6264                final char ch1 = str.charAt(1);
6265                final char[] output2 = new char[outputLength];
6266                for (int i = repeat * 2 - 2; i >= 0; i--, i--) {
6267                    output2[i] = ch0;
6268                    output2[i + 1] = ch1;
6269                }
6270                return new String(output2);
6271            default :
6272                final StringBuilder buf = new StringBuilder(outputLength);
6273                for (int i = 0; i < repeat; i++) {
6274                    buf.append(str);
6275                }
6276                return buf.toString();
6277        }
6278    }
6279
6280    /**
6281     * <p>Repeat a String {@code repeat} times to form a
6282     * new String, with a String separator injected each time. </p>
6283     *
6284     * <pre>
6285     * StringUtils.repeat(null, null, 2) = null
6286     * StringUtils.repeat(null, "x", 2)  = null
6287     * StringUtils.repeat("", null, 0)   = ""
6288     * StringUtils.repeat("", "", 2)     = ""
6289     * StringUtils.repeat("", "x", 3)    = "xxx"
6290     * StringUtils.repeat("?", ", ", 3)  = "?, ?, ?"
6291     * </pre>
6292     *
6293     * @param str        the String to repeat, may be null
6294     * @param separator  the String to inject, may be null
6295     * @param repeat     number of times to repeat str, negative treated as zero
6296     * @return a new String consisting of the original String repeated,
6297     *  {@code null} if null String input
6298     * @since 2.5
6299     */
6300    public static String repeat(final String str, final String separator, final int repeat) {
6301        if (str == null || separator == null) {
6302            return repeat(str, repeat);
6303        }
6304        // given that repeat(String, int) is quite optimized, better to rely on it than try and splice this into it
6305        final String result = repeat(str + separator, repeat);
6306        return removeEnd(result, separator);
6307    }
6308
6309    /**
6310     * <p>Returns padding using the specified delimiter repeated
6311     * to a given length.</p>
6312     *
6313     * <pre>
6314     * StringUtils.repeat('e', 0)  = ""
6315     * StringUtils.repeat('e', 3)  = "eee"
6316     * StringUtils.repeat('e', -2) = ""
6317     * </pre>
6318     *
6319     * <p>Note: this method does not support padding with
6320     * <a href="http://www.unicode.org/glossary/#supplementary_character">Unicode Supplementary Characters</a>
6321     * as they require a pair of {@code char}s to be represented.
6322     * If you are needing to support full I18N of your applications
6323     * consider using {@link #repeat(String, int)} instead.
6324     * </p>
6325     *
6326     * @param ch  character to repeat
6327     * @param repeat  number of times to repeat char, negative treated as zero
6328     * @return String with repeated character
6329     * @see #repeat(String, int)
6330     */
6331    public static String repeat(final char ch, final int repeat) {
6332        if (repeat <= 0) {
6333            return EMPTY;
6334        }
6335        final char[] buf = new char[repeat];
6336        for (int i = repeat - 1; i >= 0; i--) {
6337            buf[i] = ch;
6338        }
6339        return new String(buf);
6340    }
6341
6342    /**
6343     * <p>Right pad a String with spaces (' ').</p>
6344     *
6345     * <p>The String is padded to the size of {@code size}.</p>
6346     *
6347     * <pre>
6348     * StringUtils.rightPad(null, *)   = null
6349     * StringUtils.rightPad("", 3)     = "   "
6350     * StringUtils.rightPad("bat", 3)  = "bat"
6351     * StringUtils.rightPad("bat", 5)  = "bat  "
6352     * StringUtils.rightPad("bat", 1)  = "bat"
6353     * StringUtils.rightPad("bat", -1) = "bat"
6354     * </pre>
6355     *
6356     * @param str  the String to pad out, may be null
6357     * @param size  the size to pad to
6358     * @return right padded String or original String if no padding is necessary,
6359     *  {@code null} if null String input
6360     */
6361    public static String rightPad(final String str, final int size) {
6362        return rightPad(str, size, ' ');
6363    }
6364
6365    /**
6366     * <p>Right pad a String with a specified character.</p>
6367     *
6368     * <p>The String is padded to the size of {@code size}.</p>
6369     *
6370     * <pre>
6371     * StringUtils.rightPad(null, *, *)     = null
6372     * StringUtils.rightPad("", 3, 'z')     = "zzz"
6373     * StringUtils.rightPad("bat", 3, 'z')  = "bat"
6374     * StringUtils.rightPad("bat", 5, 'z')  = "batzz"
6375     * StringUtils.rightPad("bat", 1, 'z')  = "bat"
6376     * StringUtils.rightPad("bat", -1, 'z') = "bat"
6377     * </pre>
6378     *
6379     * @param str  the String to pad out, may be null
6380     * @param size  the size to pad to
6381     * @param padChar  the character to pad with
6382     * @return right padded String or original String if no padding is necessary,
6383     *  {@code null} if null String input
6384     * @since 2.0
6385     */
6386    public static String rightPad(final String str, final int size, final char padChar) {
6387        if (str == null) {
6388            return null;
6389        }
6390        final int pads = size - str.length();
6391        if (pads <= 0) {
6392            return str; // returns original String when possible
6393        }
6394        if (pads > PAD_LIMIT) {
6395            return rightPad(str, size, String.valueOf(padChar));
6396        }
6397        return str.concat(repeat(padChar, pads));
6398    }
6399
6400    /**
6401     * <p>Right pad a String with a specified String.</p>
6402     *
6403     * <p>The String is padded to the size of {@code size}.</p>
6404     *
6405     * <pre>
6406     * StringUtils.rightPad(null, *, *)      = null
6407     * StringUtils.rightPad("", 3, "z")      = "zzz"
6408     * StringUtils.rightPad("bat", 3, "yz")  = "bat"
6409     * StringUtils.rightPad("bat", 5, "yz")  = "batyz"
6410     * StringUtils.rightPad("bat", 8, "yz")  = "batyzyzy"
6411     * StringUtils.rightPad("bat", 1, "yz")  = "bat"
6412     * StringUtils.rightPad("bat", -1, "yz") = "bat"
6413     * StringUtils.rightPad("bat", 5, null)  = "bat  "
6414     * StringUtils.rightPad("bat", 5, "")    = "bat  "
6415     * </pre>
6416     *
6417     * @param str  the String to pad out, may be null
6418     * @param size  the size to pad to
6419     * @param padStr  the String to pad with, null or empty treated as single space
6420     * @return right padded String or original String if no padding is necessary,
6421     *  {@code null} if null String input
6422     */
6423    public static String rightPad(final String str, final int size, String padStr) {
6424        if (str == null) {
6425            return null;
6426        }
6427        if (isEmpty(padStr)) {
6428            padStr = SPACE;
6429        }
6430        final int padLen = padStr.length();
6431        final int strLen = str.length();
6432        final int pads = size - strLen;
6433        if (pads <= 0) {
6434            return str; // returns original String when possible
6435        }
6436        if (padLen == 1 && pads <= PAD_LIMIT) {
6437            return rightPad(str, size, padStr.charAt(0));
6438        }
6439
6440        if (pads == padLen) {
6441            return str.concat(padStr);
6442        } else if (pads < padLen) {
6443            return str.concat(padStr.substring(0, pads));
6444        } else {
6445            final char[] padding = new char[pads];
6446            final char[] padChars = padStr.toCharArray();
6447            for (int i = 0; i < pads; i++) {
6448                padding[i] = padChars[i % padLen];
6449            }
6450            return str.concat(new String(padding));
6451        }
6452    }
6453
6454    /**
6455     * <p>Left pad a String with spaces (' ').</p>
6456     *
6457     * <p>The String is padded to the size of {@code size}.</p>
6458     *
6459     * <pre>
6460     * StringUtils.leftPad(null, *)   = null
6461     * StringUtils.leftPad("", 3)     = "   "
6462     * StringUtils.leftPad("bat", 3)  = "bat"
6463     * StringUtils.leftPad("bat", 5)  = "  bat"
6464     * StringUtils.leftPad("bat", 1)  = "bat"
6465     * StringUtils.leftPad("bat", -1) = "bat"
6466     * </pre>
6467     *
6468     * @param str  the String to pad out, may be null
6469     * @param size  the size to pad to
6470     * @return left padded String or original String if no padding is necessary,
6471     *  {@code null} if null String input
6472     */
6473    public static String leftPad(final String str, final int size) {
6474        return leftPad(str, size, ' ');
6475    }
6476
6477    /**
6478     * <p>Left pad a String with a specified character.</p>
6479     *
6480     * <p>Pad to a size of {@code size}.</p>
6481     *
6482     * <pre>
6483     * StringUtils.leftPad(null, *, *)     = null
6484     * StringUtils.leftPad("", 3, 'z')     = "zzz"
6485     * StringUtils.leftPad("bat", 3, 'z')  = "bat"
6486     * StringUtils.leftPad("bat", 5, 'z')  = "zzbat"
6487     * StringUtils.leftPad("bat", 1, 'z')  = "bat"
6488     * StringUtils.leftPad("bat", -1, 'z') = "bat"
6489     * </pre>
6490     *
6491     * @param str  the String to pad out, may be null
6492     * @param size  the size to pad to
6493     * @param padChar  the character to pad with
6494     * @return left padded String or original String if no padding is necessary,
6495     *  {@code null} if null String input
6496     * @since 2.0
6497     */
6498    public static String leftPad(final String str, final int size, final char padChar) {
6499        if (str == null) {
6500            return null;
6501        }
6502        final int pads = size - str.length();
6503        if (pads <= 0) {
6504            return str; // returns original String when possible
6505        }
6506        if (pads > PAD_LIMIT) {
6507            return leftPad(str, size, String.valueOf(padChar));
6508        }
6509        return repeat(padChar, pads).concat(str);
6510    }
6511
6512    /**
6513     * <p>Left pad a String with a specified String.</p>
6514     *
6515     * <p>Pad to a size of {@code size}.</p>
6516     *
6517     * <pre>
6518     * StringUtils.leftPad(null, *, *)      = null
6519     * StringUtils.leftPad("", 3, "z")      = "zzz"
6520     * StringUtils.leftPad("bat", 3, "yz")  = "bat"
6521     * StringUtils.leftPad("bat", 5, "yz")  = "yzbat"
6522     * StringUtils.leftPad("bat", 8, "yz")  = "yzyzybat"
6523     * StringUtils.leftPad("bat", 1, "yz")  = "bat"
6524     * StringUtils.leftPad("bat", -1, "yz") = "bat"
6525     * StringUtils.leftPad("bat", 5, null)  = "  bat"
6526     * StringUtils.leftPad("bat", 5, "")    = "  bat"
6527     * </pre>
6528     *
6529     * @param str  the String to pad out, may be null
6530     * @param size  the size to pad to
6531     * @param padStr  the String to pad with, null or empty treated as single space
6532     * @return left padded String or original String if no padding is necessary,
6533     *  {@code null} if null String input
6534     */
6535    public static String leftPad(final String str, final int size, String padStr) {
6536        if (str == null) {
6537            return null;
6538        }
6539        if (isEmpty(padStr)) {
6540            padStr = SPACE;
6541        }
6542        final int padLen = padStr.length();
6543        final int strLen = str.length();
6544        final int pads = size - strLen;
6545        if (pads <= 0) {
6546            return str; // returns original String when possible
6547        }
6548        if (padLen == 1 && pads <= PAD_LIMIT) {
6549            return leftPad(str, size, padStr.charAt(0));
6550        }
6551
6552        if (pads == padLen) {
6553            return padStr.concat(str);
6554        } else if (pads < padLen) {
6555            return padStr.substring(0, pads).concat(str);
6556        } else {
6557            final char[] padding = new char[pads];
6558            final char[] padChars = padStr.toCharArray();
6559            for (int i = 0; i < pads; i++) {
6560                padding[i] = padChars[i % padLen];
6561            }
6562            return new String(padding).concat(str);
6563        }
6564    }
6565
6566    /**
6567     * Gets a CharSequence length or {@code 0} if the CharSequence is
6568     * {@code null}.
6569     *
6570     * @param cs
6571     *            a CharSequence or {@code null}
6572     * @return CharSequence length or {@code 0} if the CharSequence is
6573     *         {@code null}.
6574     * @since 2.4
6575     * @since 3.0 Changed signature from length(String) to length(CharSequence)
6576     */
6577    public static int length(final CharSequence cs) {
6578        return cs == null ? 0 : cs.length();
6579    }
6580
6581    // Centering
6582    //-----------------------------------------------------------------------
6583    /**
6584     * <p>Centers a String in a larger String of size {@code size}
6585     * using the space character (' ').</p>
6586     *
6587     * <p>If the size is less than the String length, the String is returned.
6588     * A {@code null} String returns {@code null}.
6589     * A negative size is treated as zero.</p>
6590     *
6591     * <p>Equivalent to {@code center(str, size, " ")}.</p>
6592     *
6593     * <pre>
6594     * StringUtils.center(null, *)   = null
6595     * StringUtils.center("", 4)     = "    "
6596     * StringUtils.center("ab", -1)  = "ab"
6597     * StringUtils.center("ab", 4)   = " ab "
6598     * StringUtils.center("abcd", 2) = "abcd"
6599     * StringUtils.center("a", 4)    = " a  "
6600     * </pre>
6601     *
6602     * @param str  the String to center, may be null
6603     * @param size  the int size of new String, negative treated as zero
6604     * @return centered String, {@code null} if null String input
6605     */
6606    public static String center(final String str, final int size) {
6607        return center(str, size, ' ');
6608    }
6609
6610    /**
6611     * <p>Centers a String in a larger String of size {@code size}.
6612     * Uses a supplied character as the value to pad the String with.</p>
6613     *
6614     * <p>If the size is less than the String length, the String is returned.
6615     * A {@code null} String returns {@code null}.
6616     * A negative size is treated as zero.</p>
6617     *
6618     * <pre>
6619     * StringUtils.center(null, *, *)     = null
6620     * StringUtils.center("", 4, ' ')     = "    "
6621     * StringUtils.center("ab", -1, ' ')  = "ab"
6622     * StringUtils.center("ab", 4, ' ')   = " ab "
6623     * StringUtils.center("abcd", 2, ' ') = "abcd"
6624     * StringUtils.center("a", 4, ' ')    = " a  "
6625     * StringUtils.center("a", 4, 'y')    = "yayy"
6626     * </pre>
6627     *
6628     * @param str  the String to center, may be null
6629     * @param size  the int size of new String, negative treated as zero
6630     * @param padChar  the character to pad the new String with
6631     * @return centered String, {@code null} if null String input
6632     * @since 2.0
6633     */
6634    public static String center(String str, final int size, final char padChar) {
6635        if (str == null || size <= 0) {
6636            return str;
6637        }
6638        final int strLen = str.length();
6639        final int pads = size - strLen;
6640        if (pads <= 0) {
6641            return str;
6642        }
6643        str = leftPad(str, strLen + pads / 2, padChar);
6644        str = rightPad(str, size, padChar);
6645        return str;
6646    }
6647
6648    /**
6649     * <p>Centers a String in a larger String of size {@code size}.
6650     * Uses a supplied String as the value to pad the String with.</p>
6651     *
6652     * <p>If the size is less than the String length, the String is returned.
6653     * A {@code null} String returns {@code null}.
6654     * A negative size is treated as zero.</p>
6655     *
6656     * <pre>
6657     * StringUtils.center(null, *, *)     = null
6658     * StringUtils.center("", 4, " ")     = "    "
6659     * StringUtils.center("ab", -1, " ")  = "ab"
6660     * StringUtils.center("ab", 4, " ")   = " ab "
6661     * StringUtils.center("abcd", 2, " ") = "abcd"
6662     * StringUtils.center("a", 4, " ")    = " a  "
6663     * StringUtils.center("a", 4, "yz")   = "yayz"
6664     * StringUtils.center("abc", 7, null) = "  abc  "
6665     * StringUtils.center("abc", 7, "")   = "  abc  "
6666     * </pre>
6667     *
6668     * @param str  the String to center, may be null
6669     * @param size  the int size of new String, negative treated as zero
6670     * @param padStr  the String to pad the new String with, must not be null or empty
6671     * @return centered String, {@code null} if null String input
6672     * @throws IllegalArgumentException if padStr is {@code null} or empty
6673     */
6674    public static String center(String str, final int size, String padStr) {
6675        if (str == null || size <= 0) {
6676            return str;
6677        }
6678        if (isEmpty(padStr)) {
6679            padStr = SPACE;
6680        }
6681        final int strLen = str.length();
6682        final int pads = size - strLen;
6683        if (pads <= 0) {
6684            return str;
6685        }
6686        str = leftPad(str, strLen + pads / 2, padStr);
6687        str = rightPad(str, size, padStr);
6688        return str;
6689    }
6690
6691    // Case conversion
6692    //-----------------------------------------------------------------------
6693    /**
6694     * <p>Converts a String to upper case as per {@link String#toUpperCase()}.</p>
6695     *
6696     * <p>A {@code null} input String returns {@code null}.</p>
6697     *
6698     * <pre>
6699     * StringUtils.upperCase(null)  = null
6700     * StringUtils.upperCase("")    = ""
6701     * StringUtils.upperCase("aBc") = "ABC"
6702     * </pre>
6703     *
6704     * <p><strong>Note:</strong> As described in the documentation for {@link String#toUpperCase()},
6705     * the result of this method is affected by the current locale.
6706     * For platform-independent case transformations, the method {@link #lowerCase(String, Locale)}
6707     * should be used with a specific locale (e.g. {@link Locale#ENGLISH}).</p>
6708     *
6709     * @param str  the String to upper case, may be null
6710     * @return the upper cased String, {@code null} if null String input
6711     */
6712    public static String upperCase(final String str) {
6713        if (str == null) {
6714            return null;
6715        }
6716        return str.toUpperCase();
6717    }
6718
6719    /**
6720     * <p>Converts a String to upper case as per {@link String#toUpperCase(Locale)}.</p>
6721     *
6722     * <p>A {@code null} input String returns {@code null}.</p>
6723     *
6724     * <pre>
6725     * StringUtils.upperCase(null, Locale.ENGLISH)  = null
6726     * StringUtils.upperCase("", Locale.ENGLISH)    = ""
6727     * StringUtils.upperCase("aBc", Locale.ENGLISH) = "ABC"
6728     * </pre>
6729     *
6730     * @param str  the String to upper case, may be null
6731     * @param locale  the locale that defines the case transformation rules, must not be null
6732     * @return the upper cased String, {@code null} if null String input
6733     * @since 2.5
6734     */
6735    public static String upperCase(final String str, final Locale locale) {
6736        if (str == null) {
6737            return null;
6738        }
6739        return str.toUpperCase(locale);
6740    }
6741
6742    /**
6743     * <p>Converts a String to lower case as per {@link String#toLowerCase()}.</p>
6744     *
6745     * <p>A {@code null} input String returns {@code null}.</p>
6746     *
6747     * <pre>
6748     * StringUtils.lowerCase(null)  = null
6749     * StringUtils.lowerCase("")    = ""
6750     * StringUtils.lowerCase("aBc") = "abc"
6751     * </pre>
6752     *
6753     * <p><strong>Note:</strong> As described in the documentation for {@link String#toLowerCase()},
6754     * the result of this method is affected by the current locale.
6755     * For platform-independent case transformations, the method {@link #lowerCase(String, Locale)}
6756     * should be used with a specific locale (e.g. {@link Locale#ENGLISH}).</p>
6757     *
6758     * @param str  the String to lower case, may be null
6759     * @return the lower cased String, {@code null} if null String input
6760     */
6761    public static String lowerCase(final String str) {
6762        if (str == null) {
6763            return null;
6764        }
6765        return str.toLowerCase();
6766    }
6767
6768    /**
6769     * <p>Converts a String to lower case as per {@link String#toLowerCase(Locale)}.</p>
6770     *
6771     * <p>A {@code null} input String returns {@code null}.</p>
6772     *
6773     * <pre>
6774     * StringUtils.lowerCase(null, Locale.ENGLISH)  = null
6775     * StringUtils.lowerCase("", Locale.ENGLISH)    = ""
6776     * StringUtils.lowerCase("aBc", Locale.ENGLISH) = "abc"
6777     * </pre>
6778     *
6779     * @param str  the String to lower case, may be null
6780     * @param locale  the locale that defines the case transformation rules, must not be null
6781     * @return the lower cased String, {@code null} if null String input
6782     * @since 2.5
6783     */
6784    public static String lowerCase(final String str, final Locale locale) {
6785        if (str == null) {
6786            return null;
6787        }
6788        return str.toLowerCase(locale);
6789    }
6790
6791    /**
6792     * <p>Capitalizes a String changing the first character to title case as
6793     * per {@link Character#toTitleCase(int)}. No other characters are changed.</p>
6794     *
6795     * <p>For a word based algorithm, see {@link org.apache.commons.lang3.text.WordUtils#capitalize(String)}.
6796     * A {@code null} input String returns {@code null}.</p>
6797     *
6798     * <pre>
6799     * StringUtils.capitalize(null)  = null
6800     * StringUtils.capitalize("")    = ""
6801     * StringUtils.capitalize("cat") = "Cat"
6802     * StringUtils.capitalize("cAt") = "CAt"
6803     * StringUtils.capitalize("'cat'") = "'cat'"
6804     * </pre>
6805     *
6806     * @param str the String to capitalize, may be null
6807     * @return the capitalized String, {@code null} if null String input
6808     * @see org.apache.commons.lang3.text.WordUtils#capitalize(String)
6809     * @see #uncapitalize(String)
6810     * @since 2.0
6811     */
6812    public static String capitalize(final String str) {
6813        int strLen;
6814        if (str == null || (strLen = str.length()) == 0) {
6815            return str;
6816        }
6817
6818        final int firstCodepoint = str.codePointAt(0);
6819        final int newCodePoint = Character.toTitleCase(firstCodepoint);
6820        if (firstCodepoint == newCodePoint) {
6821            // already capitalized
6822            return str;
6823        }
6824
6825        final int newCodePoints[] = new int[strLen]; // cannot be longer than the char array
6826        int outOffset = 0;
6827        newCodePoints[outOffset++] = newCodePoint; // copy the first codepoint
6828        for (int inOffset = Character.charCount(firstCodepoint); inOffset < strLen; ) {
6829            final int codepoint = str.codePointAt(inOffset);
6830            newCodePoints[outOffset++] = codepoint; // copy the remaining ones
6831            inOffset += Character.charCount(codepoint);
6832         }
6833        return new String(newCodePoints, 0, outOffset);
6834    }
6835
6836    /**
6837     * <p>Uncapitalizes a String, changing the first character to lower case as
6838     * per {@link Character#toLowerCase(int)}. No other characters are changed.</p>
6839     *
6840     * <p>For a word based algorithm, see {@link org.apache.commons.lang3.text.WordUtils#uncapitalize(String)}.
6841     * A {@code null} input String returns {@code null}.</p>
6842     *
6843     * <pre>
6844     * StringUtils.uncapitalize(null)  = null
6845     * StringUtils.uncapitalize("")    = ""
6846     * StringUtils.uncapitalize("cat") = "cat"
6847     * StringUtils.uncapitalize("Cat") = "cat"
6848     * StringUtils.uncapitalize("CAT") = "cAT"
6849     * </pre>
6850     *
6851     * @param str the String to uncapitalize, may be null
6852     * @return the uncapitalized String, {@code null} if null String input
6853     * @see org.apache.commons.lang3.text.WordUtils#uncapitalize(String)
6854     * @see #capitalize(String)
6855     * @since 2.0
6856     */
6857    public static String uncapitalize(final String str) {
6858        int strLen;
6859        if (str == null || (strLen = str.length()) == 0) {
6860            return str;
6861        }
6862
6863        final int firstCodepoint = str.codePointAt(0);
6864        final int newCodePoint = Character.toLowerCase(firstCodepoint);
6865        if (firstCodepoint == newCodePoint) {
6866            // already capitalized
6867            return str;
6868        }
6869
6870        final int newCodePoints[] = new int[strLen]; // cannot be longer than the char array
6871        int outOffset = 0;
6872        newCodePoints[outOffset++] = newCodePoint; // copy the first codepoint
6873        for (int inOffset = Character.charCount(firstCodepoint); inOffset < strLen; ) {
6874            final int codepoint = str.codePointAt(inOffset);
6875            newCodePoints[outOffset++] = codepoint; // copy the remaining ones
6876            inOffset += Character.charCount(codepoint);
6877         }
6878        return new String(newCodePoints, 0, outOffset);
6879    }
6880
6881    /**
6882     * <p>Swaps the case of a String changing upper and title case to
6883     * lower case, and lower case to upper case.</p>
6884     *
6885     * <ul>
6886     *  <li>Upper case character converts to Lower case</li>
6887     *  <li>Title case character converts to Lower case</li>
6888     *  <li>Lower case character converts to Upper case</li>
6889     * </ul>
6890     *
6891     * <p>For a word based algorithm, see {@link org.apache.commons.lang3.text.WordUtils#swapCase(String)}.
6892     * A {@code null} input String returns {@code null}.</p>
6893     *
6894     * <pre>
6895     * StringUtils.swapCase(null)                 = null
6896     * StringUtils.swapCase("")                   = ""
6897     * StringUtils.swapCase("The dog has a BONE") = "tHE DOG HAS A bone"
6898     * </pre>
6899     *
6900     * <p>NOTE: This method changed in Lang version 2.0.
6901     * It no longer performs a word based algorithm.
6902     * If you only use ASCII, you will notice no change.
6903     * That functionality is available in org.apache.commons.lang3.text.WordUtils.</p>
6904     *
6905     * @param str  the String to swap case, may be null
6906     * @return the changed String, {@code null} if null String input
6907     */
6908    public static String swapCase(final String str) {
6909        if (isEmpty(str)) {
6910            return str;
6911        }
6912
6913        final int strLen = str.length();
6914        final int newCodePoints[] = new int[strLen]; // cannot be longer than the char array
6915        int outOffset = 0;
6916        for (int i = 0; i < strLen; ) {
6917            final int oldCodepoint = str.codePointAt(i);
6918            final int newCodePoint;
6919            if (Character.isUpperCase(oldCodepoint)) {
6920                newCodePoint = Character.toLowerCase(oldCodepoint);
6921            } else if (Character.isTitleCase(oldCodepoint)) {
6922                newCodePoint = Character.toLowerCase(oldCodepoint);
6923            } else if (Character.isLowerCase(oldCodepoint)) {
6924                newCodePoint = Character.toUpperCase(oldCodepoint);
6925            } else {
6926                newCodePoint = oldCodepoint;
6927            }
6928            newCodePoints[outOffset++] = newCodePoint;
6929            i += Character.charCount(newCodePoint);
6930         }
6931        return new String(newCodePoints, 0, outOffset);
6932    }
6933
6934    // Count matches
6935    //-----------------------------------------------------------------------
6936    /**
6937     * <p>Counts how many times the substring appears in the larger string.</p>
6938     *
6939     * <p>A {@code null} or empty ("") String input returns {@code 0}.</p>
6940     *
6941     * <pre>
6942     * StringUtils.countMatches(null, *)       = 0
6943     * StringUtils.countMatches("", *)         = 0
6944     * StringUtils.countMatches("abba", null)  = 0
6945     * StringUtils.countMatches("abba", "")    = 0
6946     * StringUtils.countMatches("abba", "a")   = 2
6947     * StringUtils.countMatches("abba", "ab")  = 1
6948     * StringUtils.countMatches("abba", "xxx") = 0
6949     * </pre>
6950     *
6951     * @param str  the CharSequence to check, may be null
6952     * @param sub  the substring to count, may be null
6953     * @return the number of occurrences, 0 if either CharSequence is {@code null}
6954     * @since 3.0 Changed signature from countMatches(String, String) to countMatches(CharSequence, CharSequence)
6955     */
6956    public static int countMatches(final CharSequence str, final CharSequence sub) {
6957        if (isEmpty(str) || isEmpty(sub)) {
6958            return 0;
6959        }
6960        int count = 0;
6961        int idx = 0;
6962        while ((idx = CharSequenceUtils.indexOf(str, sub, idx)) != INDEX_NOT_FOUND) {
6963            count++;
6964            idx += sub.length();
6965        }
6966        return count;
6967    }
6968
6969    /**
6970     * <p>Counts how many times the char appears in the given string.</p>
6971     *
6972     * <p>A {@code null} or empty ("") String input returns {@code 0}.</p>
6973     *
6974     * <pre>
6975     * StringUtils.countMatches(null, *)       = 0
6976     * StringUtils.countMatches("", *)         = 0
6977     * StringUtils.countMatches("abba", 0)  = 0
6978     * StringUtils.countMatches("abba", 'a')   = 2
6979     * StringUtils.countMatches("abba", 'b')  = 2
6980     * StringUtils.countMatches("abba", 'x') = 0
6981     * </pre>
6982     *
6983     * @param str  the CharSequence to check, may be null
6984     * @param ch  the char to count
6985     * @return the number of occurrences, 0 if the CharSequence is {@code null}
6986     * @since 3.4
6987     */
6988    public static int countMatches(final CharSequence str, final char ch) {
6989        if (isEmpty(str)) {
6990            return 0;
6991        }
6992        int count = 0;
6993        // We could also call str.toCharArray() for faster look ups but that would generate more garbage.
6994        for (int i = 0; i < str.length(); i++) {
6995            if (ch == str.charAt(i)) {
6996                count++;
6997            }
6998        }
6999        return count;
7000    }
7001
7002    // Character Tests
7003    //-----------------------------------------------------------------------
7004    /**
7005     * <p>Checks if the CharSequence contains only Unicode letters.</p>
7006     *
7007     * <p>{@code null} will return {@code false}.
7008     * An empty CharSequence (length()=0) will return {@code false}.</p>
7009     *
7010     * <pre>
7011     * StringUtils.isAlpha(null)   = false
7012     * StringUtils.isAlpha("")     = false
7013     * StringUtils.isAlpha("  ")   = false
7014     * StringUtils.isAlpha("abc")  = true
7015     * StringUtils.isAlpha("ab2c") = false
7016     * StringUtils.isAlpha("ab-c") = false
7017     * </pre>
7018     *
7019     * @param cs  the CharSequence to check, may be null
7020     * @return {@code true} if only contains letters, and is non-null
7021     * @since 3.0 Changed signature from isAlpha(String) to isAlpha(CharSequence)
7022     * @since 3.0 Changed "" to return false and not true
7023     */
7024    public static boolean isAlpha(final CharSequence cs) {
7025        if (isEmpty(cs)) {
7026            return false;
7027        }
7028        final int sz = cs.length();
7029        for (int i = 0; i < sz; i++) {
7030            if (!Character.isLetter(cs.charAt(i))) {
7031                return false;
7032            }
7033        }
7034        return true;
7035    }
7036
7037    /**
7038     * <p>Checks if the CharSequence contains only Unicode letters and
7039     * space (' ').</p>
7040     *
7041     * <p>{@code null} will return {@code false}
7042     * An empty CharSequence (length()=0) will return {@code true}.</p>
7043     *
7044     * <pre>
7045     * StringUtils.isAlphaSpace(null)   = false
7046     * StringUtils.isAlphaSpace("")     = true
7047     * StringUtils.isAlphaSpace("  ")   = true
7048     * StringUtils.isAlphaSpace("abc")  = true
7049     * StringUtils.isAlphaSpace("ab c") = true
7050     * StringUtils.isAlphaSpace("ab2c") = false
7051     * StringUtils.isAlphaSpace("ab-c") = false
7052     * </pre>
7053     *
7054     * @param cs  the CharSequence to check, may be null
7055     * @return {@code true} if only contains letters and space,
7056     *  and is non-null
7057     * @since 3.0 Changed signature from isAlphaSpace(String) to isAlphaSpace(CharSequence)
7058     */
7059    public static boolean isAlphaSpace(final CharSequence cs) {
7060        if (cs == null) {
7061            return false;
7062        }
7063        final int sz = cs.length();
7064        for (int i = 0; i < sz; i++) {
7065            if (!Character.isLetter(cs.charAt(i)) && cs.charAt(i) != ' ') {
7066                return false;
7067            }
7068        }
7069        return true;
7070    }
7071
7072    /**
7073     * <p>Checks if the CharSequence contains only Unicode letters or digits.</p>
7074     *
7075     * <p>{@code null} will return {@code false}.
7076     * An empty CharSequence (length()=0) will return {@code false}.</p>
7077     *
7078     * <pre>
7079     * StringUtils.isAlphanumeric(null)   = false
7080     * StringUtils.isAlphanumeric("")     = false
7081     * StringUtils.isAlphanumeric("  ")   = false
7082     * StringUtils.isAlphanumeric("abc")  = true
7083     * StringUtils.isAlphanumeric("ab c") = false
7084     * StringUtils.isAlphanumeric("ab2c") = true
7085     * StringUtils.isAlphanumeric("ab-c") = false
7086     * </pre>
7087     *
7088     * @param cs  the CharSequence to check, may be null
7089     * @return {@code true} if only contains letters or digits,
7090     *  and is non-null
7091     * @since 3.0 Changed signature from isAlphanumeric(String) to isAlphanumeric(CharSequence)
7092     * @since 3.0 Changed "" to return false and not true
7093     */
7094    public static boolean isAlphanumeric(final CharSequence cs) {
7095        if (isEmpty(cs)) {
7096            return false;
7097        }
7098        final int sz = cs.length();
7099        for (int i = 0; i < sz; i++) {
7100            if (!Character.isLetterOrDigit(cs.charAt(i))) {
7101                return false;
7102            }
7103        }
7104        return true;
7105    }
7106
7107    /**
7108     * <p>Checks if the CharSequence contains only Unicode letters, digits
7109     * or space ({@code ' '}).</p>
7110     *
7111     * <p>{@code null} will return {@code false}.
7112     * An empty CharSequence (length()=0) will return {@code true}.</p>
7113     *
7114     * <pre>
7115     * StringUtils.isAlphanumericSpace(null)   = false
7116     * StringUtils.isAlphanumericSpace("")     = true
7117     * StringUtils.isAlphanumericSpace("  ")   = true
7118     * StringUtils.isAlphanumericSpace("abc")  = true
7119     * StringUtils.isAlphanumericSpace("ab c") = true
7120     * StringUtils.isAlphanumericSpace("ab2c") = true
7121     * StringUtils.isAlphanumericSpace("ab-c") = false
7122     * </pre>
7123     *
7124     * @param cs  the CharSequence to check, may be null
7125     * @return {@code true} if only contains letters, digits or space,
7126     *  and is non-null
7127     * @since 3.0 Changed signature from isAlphanumericSpace(String) to isAlphanumericSpace(CharSequence)
7128     */
7129    public static boolean isAlphanumericSpace(final CharSequence cs) {
7130        if (cs == null) {
7131            return false;
7132        }
7133        final int sz = cs.length();
7134        for (int i = 0; i < sz; i++) {
7135            if (!Character.isLetterOrDigit(cs.charAt(i)) && cs.charAt(i) != ' ') {
7136                return false;
7137            }
7138        }
7139        return true;
7140    }
7141
7142    /**
7143     * <p>Checks if the CharSequence contains only ASCII printable characters.</p>
7144     *
7145     * <p>{@code null} will return {@code false}.
7146     * An empty CharSequence (length()=0) will return {@code true}.</p>
7147     *
7148     * <pre>
7149     * StringUtils.isAsciiPrintable(null)     = false
7150     * StringUtils.isAsciiPrintable("")       = true
7151     * StringUtils.isAsciiPrintable(" ")      = true
7152     * StringUtils.isAsciiPrintable("Ceki")   = true
7153     * StringUtils.isAsciiPrintable("ab2c")   = true
7154     * StringUtils.isAsciiPrintable("!ab-c~") = true
7155     * StringUtils.isAsciiPrintable("\u0020") = true
7156     * StringUtils.isAsciiPrintable("\u0021") = true
7157     * StringUtils.isAsciiPrintable("\u007e") = true
7158     * StringUtils.isAsciiPrintable("\u007f") = false
7159     * StringUtils.isAsciiPrintable("Ceki G\u00fclc\u00fc") = false
7160     * </pre>
7161     *
7162     * @param cs the CharSequence to check, may be null
7163     * @return {@code true} if every character is in the range
7164     *  32 thru 126
7165     * @since 2.1
7166     * @since 3.0 Changed signature from isAsciiPrintable(String) to isAsciiPrintable(CharSequence)
7167     */
7168    public static boolean isAsciiPrintable(final CharSequence cs) {
7169        if (cs == null) {
7170            return false;
7171        }
7172        final int sz = cs.length();
7173        for (int i = 0; i < sz; i++) {
7174            if (!CharUtils.isAsciiPrintable(cs.charAt(i))) {
7175                return false;
7176            }
7177        }
7178        return true;
7179    }
7180
7181    /**
7182     * <p>Checks if the CharSequence contains only Unicode digits.
7183     * A decimal point is not a Unicode digit and returns false.</p>
7184     *
7185     * <p>{@code null} will return {@code false}.
7186     * An empty CharSequence (length()=0) will return {@code false}.</p>
7187     *
7188     * <p>Note that the method does not allow for a leading sign, either positive or negative.
7189     * Also, if a String passes the numeric test, it may still generate a NumberFormatException
7190     * when parsed by Integer.parseInt or Long.parseLong, e.g. if the value is outside the range
7191     * for int or long respectively.</p>
7192     *
7193     * <pre>
7194     * StringUtils.isNumeric(null)   = false
7195     * StringUtils.isNumeric("")     = false
7196     * StringUtils.isNumeric("  ")   = false
7197     * StringUtils.isNumeric("123")  = true
7198     * StringUtils.isNumeric("\u0967\u0968\u0969")  = true
7199     * StringUtils.isNumeric("12 3") = false
7200     * StringUtils.isNumeric("ab2c") = false
7201     * StringUtils.isNumeric("12-3") = false
7202     * StringUtils.isNumeric("12.3") = false
7203     * StringUtils.isNumeric("-123") = false
7204     * StringUtils.isNumeric("+123") = false
7205     * </pre>
7206     *
7207     * @param cs  the CharSequence to check, may be null
7208     * @return {@code true} if only contains digits, and is non-null
7209     * @since 3.0 Changed signature from isNumeric(String) to isNumeric(CharSequence)
7210     * @since 3.0 Changed "" to return false and not true
7211     */
7212    public static boolean isNumeric(final CharSequence cs) {
7213        if (isEmpty(cs)) {
7214            return false;
7215        }
7216        final int sz = cs.length();
7217        for (int i = 0; i < sz; i++) {
7218            if (!Character.isDigit(cs.charAt(i))) {
7219                return false;
7220            }
7221        }
7222        return true;
7223    }
7224
7225    /**
7226     * <p>Checks if the CharSequence contains only Unicode digits or space
7227     * ({@code ' '}).
7228     * A decimal point is not a Unicode digit and returns false.</p>
7229     *
7230     * <p>{@code null} will return {@code false}.
7231     * An empty CharSequence (length()=0) will return {@code true}.</p>
7232     *
7233     * <pre>
7234     * StringUtils.isNumericSpace(null)   = false
7235     * StringUtils.isNumericSpace("")     = true
7236     * StringUtils.isNumericSpace("  ")   = true
7237     * StringUtils.isNumericSpace("123")  = true
7238     * StringUtils.isNumericSpace("12 3") = true
7239     * StringUtils.isNumeric("\u0967\u0968\u0969")  = true
7240     * StringUtils.isNumeric("\u0967\u0968 \u0969")  = true
7241     * StringUtils.isNumericSpace("ab2c") = false
7242     * StringUtils.isNumericSpace("12-3") = false
7243     * StringUtils.isNumericSpace("12.3") = false
7244     * </pre>
7245     *
7246     * @param cs  the CharSequence to check, may be null
7247     * @return {@code true} if only contains digits or space,
7248     *  and is non-null
7249     * @since 3.0 Changed signature from isNumericSpace(String) to isNumericSpace(CharSequence)
7250     */
7251    public static boolean isNumericSpace(final CharSequence cs) {
7252        if (cs == null) {
7253            return false;
7254        }
7255        final int sz = cs.length();
7256        for (int i = 0; i < sz; i++) {
7257            if (!Character.isDigit(cs.charAt(i)) && cs.charAt(i) != ' ') {
7258                return false;
7259            }
7260        }
7261        return true;
7262    }
7263
7264    /**
7265     * <p>Checks if a String {@code str} contains Unicode digits,
7266     * if yes then concatenate all the digits in {@code str} and return it as a String.</p>
7267     *
7268     * <p>An empty ("") String will be returned if no digits found in {@code str}.</p>
7269     *
7270     * <pre>
7271     * StringUtils.getDigits(null)  = null
7272     * StringUtils.getDigits("")    = ""
7273     * StringUtils.getDigits("abc") = ""
7274     * StringUtils.getDigits("1000$") = "1000"
7275     * StringUtils.getDigits("1123~45") = "112345"
7276     * StringUtils.getDigits("(541) 754-3010") = "5417543010"
7277     * StringUtils.getDigits("\u0967\u0968\u0969") = "\u0967\u0968\u0969"
7278     * </pre>
7279     *
7280     * @param str the String to extract digits from, may be null
7281     * @return String with only digits,
7282     *           or an empty ("") String if no digits found,
7283     *           or {@code null} String if {@code str} is null
7284     * @since 3.6
7285     */
7286    public static String getDigits(final String str) {
7287        if (isEmpty(str)) {
7288            return str;
7289        }
7290        final int sz = str.length();
7291        final StringBuilder strDigits = new StringBuilder(sz);
7292        for (int i = 0; i < sz; i++) {
7293            final char tempChar = str.charAt(i);
7294            if (Character.isDigit(tempChar)) {
7295                strDigits.append(tempChar);
7296            }
7297        }
7298        return strDigits.toString();
7299    }
7300
7301    /**
7302     * <p>Checks if the CharSequence contains only whitespace.</p>
7303     *
7304     * <p>Whitespace is defined by {@link Character#isWhitespace(char)}.</p>
7305     *
7306     * <p>{@code null} will return {@code false}.
7307     * An empty CharSequence (length()=0) will return {@code true}.</p>
7308     *
7309     * <pre>
7310     * StringUtils.isWhitespace(null)   = false
7311     * StringUtils.isWhitespace("")     = true
7312     * StringUtils.isWhitespace("  ")   = true
7313     * StringUtils.isWhitespace("abc")  = false
7314     * StringUtils.isWhitespace("ab2c") = false
7315     * StringUtils.isWhitespace("ab-c") = false
7316     * </pre>
7317     *
7318     * @param cs  the CharSequence to check, may be null
7319     * @return {@code true} if only contains whitespace, and is non-null
7320     * @since 2.0
7321     * @since 3.0 Changed signature from isWhitespace(String) to isWhitespace(CharSequence)
7322     */
7323    public static boolean isWhitespace(final CharSequence cs) {
7324        if (cs == null) {
7325            return false;
7326        }
7327        final int sz = cs.length();
7328        for (int i = 0; i < sz; i++) {
7329            if (!Character.isWhitespace(cs.charAt(i))) {
7330                return false;
7331            }
7332        }
7333        return true;
7334    }
7335
7336    /**
7337     * <p>Checks if the CharSequence contains only lowercase characters.</p>
7338     *
7339     * <p>{@code null} will return {@code false}.
7340     * An empty CharSequence (length()=0) will return {@code false}.</p>
7341     *
7342     * <pre>
7343     * StringUtils.isAllLowerCase(null)   = false
7344     * StringUtils.isAllLowerCase("")     = false
7345     * StringUtils.isAllLowerCase("  ")   = false
7346     * StringUtils.isAllLowerCase("abc")  = true
7347     * StringUtils.isAllLowerCase("abC")  = false
7348     * StringUtils.isAllLowerCase("ab c") = false
7349     * StringUtils.isAllLowerCase("ab1c") = false
7350     * StringUtils.isAllLowerCase("ab/c") = false
7351     * </pre>
7352     *
7353     * @param cs  the CharSequence to check, may be null
7354     * @return {@code true} if only contains lowercase characters, and is non-null
7355     * @since 2.5
7356     * @since 3.0 Changed signature from isAllLowerCase(String) to isAllLowerCase(CharSequence)
7357     */
7358    public static boolean isAllLowerCase(final CharSequence cs) {
7359        if (cs == null || isEmpty(cs)) {
7360            return false;
7361        }
7362        final int sz = cs.length();
7363        for (int i = 0; i < sz; i++) {
7364            if (!Character.isLowerCase(cs.charAt(i))) {
7365                return false;
7366            }
7367        }
7368        return true;
7369    }
7370
7371    /**
7372     * <p>Checks if the CharSequence contains only uppercase characters.</p>
7373     *
7374     * <p>{@code null} will return {@code false}.
7375     * An empty String (length()=0) will return {@code false}.</p>
7376     *
7377     * <pre>
7378     * StringUtils.isAllUpperCase(null)   = false
7379     * StringUtils.isAllUpperCase("")     = false
7380     * StringUtils.isAllUpperCase("  ")   = false
7381     * StringUtils.isAllUpperCase("ABC")  = true
7382     * StringUtils.isAllUpperCase("aBC")  = false
7383     * StringUtils.isAllUpperCase("A C")  = false
7384     * StringUtils.isAllUpperCase("A1C")  = false
7385     * StringUtils.isAllUpperCase("A/C")  = false
7386     * </pre>
7387     *
7388     * @param cs the CharSequence to check, may be null
7389     * @return {@code true} if only contains uppercase characters, and is non-null
7390     * @since 2.5
7391     * @since 3.0 Changed signature from isAllUpperCase(String) to isAllUpperCase(CharSequence)
7392     */
7393    public static boolean isAllUpperCase(final CharSequence cs) {
7394        if (cs == null || isEmpty(cs)) {
7395            return false;
7396        }
7397        final int sz = cs.length();
7398        for (int i = 0; i < sz; i++) {
7399            if (!Character.isUpperCase(cs.charAt(i))) {
7400                return false;
7401            }
7402        }
7403        return true;
7404    }
7405
7406    /**
7407     * <p>Checks if the CharSequence contains mixed casing of both uppercase and lowercase characters.</p>
7408     *
7409     * <p>{@code null} will return {@code false}. An empty CharSequence ({@code length()=0}) will return
7410     * {@code false}.</p>
7411     *
7412     * <pre>
7413     * StringUtils.isMixedCase(null)    = false
7414     * StringUtils.isMixedCase("")      = false
7415     * StringUtils.isMixedCase("ABC")   = false
7416     * StringUtils.isMixedCase("abc")   = false
7417     * StringUtils.isMixedCase("aBc")   = true
7418     * StringUtils.isMixedCase("A c")   = true
7419     * StringUtils.isMixedCase("A1c")   = true
7420     * StringUtils.isMixedCase("a/C")   = true
7421     * StringUtils.isMixedCase("aC\t")  = true
7422     * </pre>
7423     *
7424     * @param cs the CharSequence to check, may be null
7425     * @return {@code true} if the CharSequence contains both uppercase and lowercase characters
7426     * @since 3.5
7427     */
7428    public static boolean isMixedCase(final CharSequence cs) {
7429        if (isEmpty(cs) || cs.length() == 1) {
7430            return false;
7431        }
7432        boolean containsUppercase = false;
7433        boolean containsLowercase = false;
7434        final int sz = cs.length();
7435        for (int i = 0; i < sz; i++) {
7436            if (containsUppercase && containsLowercase) {
7437                return true;
7438            } else if (Character.isUpperCase(cs.charAt(i))) {
7439                containsUppercase = true;
7440            } else if (Character.isLowerCase(cs.charAt(i))) {
7441                containsLowercase = true;
7442            }
7443        }
7444        return containsUppercase && containsLowercase;
7445    }
7446
7447    // Defaults
7448    //-----------------------------------------------------------------------
7449    /**
7450     * <p>Returns either the passed in String,
7451     * or if the String is {@code null}, an empty String ("").</p>
7452     *
7453     * <pre>
7454     * StringUtils.defaultString(null)  = ""
7455     * StringUtils.defaultString("")    = ""
7456     * StringUtils.defaultString("bat") = "bat"
7457     * </pre>
7458     *
7459     * @see ObjectUtils#toString(Object)
7460     * @see String#valueOf(Object)
7461     * @param str  the String to check, may be null
7462     * @return the passed in String, or the empty String if it
7463     *  was {@code null}
7464     */
7465    public static String defaultString(final String str) {
7466        return defaultString(str, EMPTY);
7467    }
7468
7469    /**
7470     * <p>Returns either the passed in String, or if the String is
7471     * {@code null}, the value of {@code defaultStr}.</p>
7472     *
7473     * <pre>
7474     * StringUtils.defaultString(null, "NULL")  = "NULL"
7475     * StringUtils.defaultString("", "NULL")    = ""
7476     * StringUtils.defaultString("bat", "NULL") = "bat"
7477     * </pre>
7478     *
7479     * @see ObjectUtils#toString(Object,String)
7480     * @see String#valueOf(Object)
7481     * @param str  the String to check, may be null
7482     * @param defaultStr  the default String to return
7483     *  if the input is {@code null}, may be null
7484     * @return the passed in String, or the default if it was {@code null}
7485     */
7486    public static String defaultString(final String str, final String defaultStr) {
7487        return str == null ? defaultStr : str;
7488    }
7489
7490    /**
7491     * <p>Returns the first value in the array which is not empty (""),
7492     * {@code null} or whitespace only.</p>
7493     *
7494     * <p>Whitespace is defined by {@link Character#isWhitespace(char)}.</p>
7495     *
7496     * <p>If all values are blank or the array is {@code null}
7497     * or empty then {@code null} is returned.</p>
7498     *
7499     * <pre>
7500     * StringUtils.firstNonBlank(null, null, null)     = null
7501     * StringUtils.firstNonBlank(null, "", " ")        = null
7502     * StringUtils.firstNonBlank("abc")                = "abc"
7503     * StringUtils.firstNonBlank(null, "xyz")          = "xyz"
7504     * StringUtils.firstNonBlank(null, "", " ", "xyz") = "xyz"
7505     * StringUtils.firstNonBlank(null, "xyz", "abc")   = "xyz"
7506     * StringUtils.firstNonBlank()                     = null
7507     * </pre>
7508     *
7509     * @param <T> the specific kind of CharSequence
7510     * @param values  the values to test, may be {@code null} or empty
7511     * @return the first value from {@code values} which is not blank,
7512     *  or {@code null} if there are no non-blank values
7513     * @since 3.8
7514     */
7515    @SafeVarargs
7516    public static <T extends CharSequence> T firstNonBlank(final T... values) {
7517        if (values != null) {
7518            for (final T val : values) {
7519                if (isNotBlank(val)) {
7520                    return val;
7521                }
7522            }
7523        }
7524        return null;
7525    }
7526
7527    /**
7528     * <p>Returns the first value in the array which is not empty.</p>
7529     *
7530     * <p>If all values are empty or the array is {@code null}
7531     * or empty then {@code null} is returned.</p>
7532     *
7533     * <pre>
7534     * StringUtils.firstNonEmpty(null, null, null)   = null
7535     * StringUtils.firstNonEmpty(null, null, "")     = null
7536     * StringUtils.firstNonEmpty(null, "", " ")      = " "
7537     * StringUtils.firstNonEmpty("abc")              = "abc"
7538     * StringUtils.firstNonEmpty(null, "xyz")        = "xyz"
7539     * StringUtils.firstNonEmpty("", "xyz")          = "xyz"
7540     * StringUtils.firstNonEmpty(null, "xyz", "abc") = "xyz"
7541     * StringUtils.firstNonEmpty()                   = null
7542     * </pre>
7543     *
7544     * @param <T> the specific kind of CharSequence
7545     * @param values  the values to test, may be {@code null} or empty
7546     * @return the first value from {@code values} which is not empty,
7547     *  or {@code null} if there are no non-empty values
7548     * @since 3.8
7549     */
7550    @SafeVarargs
7551    public static <T extends CharSequence> T firstNonEmpty(final T... values) {
7552        if (values != null) {
7553            for (final T val : values) {
7554                if (isNotEmpty(val)) {
7555                    return val;
7556                }
7557            }
7558        }
7559        return null;
7560    }
7561
7562    /**
7563     * <p>Returns either the passed in CharSequence, or if the CharSequence is
7564     * whitespace, empty ("") or {@code null}, the value of {@code defaultStr}.</p>
7565     *
7566     * <p>Whitespace is defined by {@link Character#isWhitespace(char)}.</p>
7567     *
7568     * <pre>
7569     * StringUtils.defaultIfBlank(null, "NULL")  = "NULL"
7570     * StringUtils.defaultIfBlank("", "NULL")    = "NULL"
7571     * StringUtils.defaultIfBlank(" ", "NULL")   = "NULL"
7572     * StringUtils.defaultIfBlank("bat", "NULL") = "bat"
7573     * StringUtils.defaultIfBlank("", null)      = null
7574     * </pre>
7575     * @param <T> the specific kind of CharSequence
7576     * @param str the CharSequence to check, may be null
7577     * @param defaultStr  the default CharSequence to return
7578     *  if the input is whitespace, empty ("") or {@code null}, may be null
7579     * @return the passed in CharSequence, or the default
7580     * @see StringUtils#defaultString(String, String)
7581     */
7582    public static <T extends CharSequence> T defaultIfBlank(final T str, final T defaultStr) {
7583        return isBlank(str) ? defaultStr : str;
7584    }
7585
7586    /**
7587     * <p>Returns either the passed in CharSequence, or if the CharSequence is
7588     * empty or {@code null}, the value of {@code defaultStr}.</p>
7589     *
7590     * <pre>
7591     * StringUtils.defaultIfEmpty(null, "NULL")  = "NULL"
7592     * StringUtils.defaultIfEmpty("", "NULL")    = "NULL"
7593     * StringUtils.defaultIfEmpty(" ", "NULL")   = " "
7594     * StringUtils.defaultIfEmpty("bat", "NULL") = "bat"
7595     * StringUtils.defaultIfEmpty("", null)      = null
7596     * </pre>
7597     * @param <T> the specific kind of CharSequence
7598     * @param str  the CharSequence to check, may be null
7599     * @param defaultStr  the default CharSequence to return
7600     *  if the input is empty ("") or {@code null}, may be null
7601     * @return the passed in CharSequence, or the default
7602     * @see StringUtils#defaultString(String, String)
7603     */
7604    public static <T extends CharSequence> T defaultIfEmpty(final T str, final T defaultStr) {
7605        return isEmpty(str) ? defaultStr : str;
7606    }
7607
7608    // Rotating (circular shift)
7609    //-----------------------------------------------------------------------
7610    /**
7611     * <p>Rotate (circular shift) a String of {@code shift} characters.</p>
7612     * <ul>
7613     *  <li>If {@code shift > 0}, right circular shift (ex : ABCDEF =&gt; FABCDE)</li>
7614     *  <li>If {@code shift < 0}, left circular shift (ex : ABCDEF =&gt; BCDEFA)</li>
7615     * </ul>
7616     *
7617     * <pre>
7618     * StringUtils.rotate(null, *)        = null
7619     * StringUtils.rotate("", *)          = ""
7620     * StringUtils.rotate("abcdefg", 0)   = "abcdefg"
7621     * StringUtils.rotate("abcdefg", 2)   = "fgabcde"
7622     * StringUtils.rotate("abcdefg", -2)  = "cdefgab"
7623     * StringUtils.rotate("abcdefg", 7)   = "abcdefg"
7624     * StringUtils.rotate("abcdefg", -7)  = "abcdefg"
7625     * StringUtils.rotate("abcdefg", 9)   = "fgabcde"
7626     * StringUtils.rotate("abcdefg", -9)  = "cdefgab"
7627     * </pre>
7628     *
7629     * @param str  the String to rotate, may be null
7630     * @param shift  number of time to shift (positive : right shift, negative : left shift)
7631     * @return the rotated String,
7632     *          or the original String if {@code shift == 0},
7633     *          or {@code null} if null String input
7634     * @since 3.5
7635     */
7636    public static String rotate(final String str, final int shift) {
7637        if (str == null) {
7638            return null;
7639        }
7640
7641        final int strLen = str.length();
7642        if (shift == 0 || strLen == 0 || shift % strLen == 0) {
7643            return str;
7644        }
7645
7646        final StringBuilder builder = new StringBuilder(strLen);
7647        final int offset = - (shift % strLen);
7648        builder.append(substring(str, offset));
7649        builder.append(substring(str, 0, offset));
7650        return builder.toString();
7651    }
7652
7653    // Reversing
7654    //-----------------------------------------------------------------------
7655    /**
7656     * <p>Reverses a String as per {@link StringBuilder#reverse()}.</p>
7657     *
7658     * <p>A {@code null} String returns {@code null}.</p>
7659     *
7660     * <pre>
7661     * StringUtils.reverse(null)  = null
7662     * StringUtils.reverse("")    = ""
7663     * StringUtils.reverse("bat") = "tab"
7664     * </pre>
7665     *
7666     * @param str  the String to reverse, may be null
7667     * @return the reversed String, {@code null} if null String input
7668     */
7669    public static String reverse(final String str) {
7670        if (str == null) {
7671            return null;
7672        }
7673        return new StringBuilder(str).reverse().toString();
7674    }
7675
7676    /**
7677     * <p>Reverses a String that is delimited by a specific character.</p>
7678     *
7679     * <p>The Strings between the delimiters are not reversed.
7680     * Thus java.lang.String becomes String.lang.java (if the delimiter
7681     * is {@code '.'}).</p>
7682     *
7683     * <pre>
7684     * StringUtils.reverseDelimited(null, *)      = null
7685     * StringUtils.reverseDelimited("", *)        = ""
7686     * StringUtils.reverseDelimited("a.b.c", 'x') = "a.b.c"
7687     * StringUtils.reverseDelimited("a.b.c", ".") = "c.b.a"
7688     * </pre>
7689     *
7690     * @param str  the String to reverse, may be null
7691     * @param separatorChar  the separator character to use
7692     * @return the reversed String, {@code null} if null String input
7693     * @since 2.0
7694     */
7695    public static String reverseDelimited(final String str, final char separatorChar) {
7696        if (str == null) {
7697            return null;
7698        }
7699        // could implement manually, but simple way is to reuse other,
7700        // probably slower, methods.
7701        final String[] strs = split(str, separatorChar);
7702        ArrayUtils.reverse(strs);
7703        return join(strs, separatorChar);
7704    }
7705
7706    // Abbreviating
7707    //-----------------------------------------------------------------------
7708    /**
7709     * <p>Abbreviates a String using ellipses. This will turn
7710     * "Now is the time for all good men" into "Now is the time for..."</p>
7711     *
7712     * <p>Specifically:</p>
7713     * <ul>
7714     *   <li>If the number of characters in {@code str} is less than or equal to
7715     *       {@code maxWidth}, return {@code str}.</li>
7716     *   <li>Else abbreviate it to {@code (substring(str, 0, max-3) + "...")}.</li>
7717     *   <li>If {@code maxWidth} is less than {@code 4}, throw an
7718     *       {@code IllegalArgumentException}.</li>
7719     *   <li>In no case will it return a String of length greater than
7720     *       {@code maxWidth}.</li>
7721     * </ul>
7722     *
7723     * <pre>
7724     * StringUtils.abbreviate(null, *)      = null
7725     * StringUtils.abbreviate("", 4)        = ""
7726     * StringUtils.abbreviate("abcdefg", 6) = "abc..."
7727     * StringUtils.abbreviate("abcdefg", 7) = "abcdefg"
7728     * StringUtils.abbreviate("abcdefg", 8) = "abcdefg"
7729     * StringUtils.abbreviate("abcdefg", 4) = "a..."
7730     * StringUtils.abbreviate("abcdefg", 3) = IllegalArgumentException
7731     * </pre>
7732     *
7733     * @param str  the String to check, may be null
7734     * @param maxWidth  maximum length of result String, must be at least 4
7735     * @return abbreviated String, {@code null} if null String input
7736     * @throws IllegalArgumentException if the width is too small
7737     * @since 2.0
7738     */
7739    public static String abbreviate(final String str, final int maxWidth) {
7740        final String defaultAbbrevMarker = "...";
7741        return abbreviate(str, defaultAbbrevMarker, 0, maxWidth);
7742    }
7743
7744    /**
7745     * <p>Abbreviates a String using ellipses. This will turn
7746     * "Now is the time for all good men" into "...is the time for..."</p>
7747     *
7748     * <p>Works like {@code abbreviate(String, int)}, but allows you to specify
7749     * a "left edge" offset.  Note that this left edge is not necessarily going to
7750     * be the leftmost character in the result, or the first character following the
7751     * ellipses, but it will appear somewhere in the result.
7752     *
7753     * <p>In no case will it return a String of length greater than
7754     * {@code maxWidth}.</p>
7755     *
7756     * <pre>
7757     * StringUtils.abbreviate(null, *, *)                = null
7758     * StringUtils.abbreviate("", 0, 4)                  = ""
7759     * StringUtils.abbreviate("abcdefghijklmno", -1, 10) = "abcdefg..."
7760     * StringUtils.abbreviate("abcdefghijklmno", 0, 10)  = "abcdefg..."
7761     * StringUtils.abbreviate("abcdefghijklmno", 1, 10)  = "abcdefg..."
7762     * StringUtils.abbreviate("abcdefghijklmno", 4, 10)  = "abcdefg..."
7763     * StringUtils.abbreviate("abcdefghijklmno", 5, 10)  = "...fghi..."
7764     * StringUtils.abbreviate("abcdefghijklmno", 6, 10)  = "...ghij..."
7765     * StringUtils.abbreviate("abcdefghijklmno", 8, 10)  = "...ijklmno"
7766     * StringUtils.abbreviate("abcdefghijklmno", 10, 10) = "...ijklmno"
7767     * StringUtils.abbreviate("abcdefghijklmno", 12, 10) = "...ijklmno"
7768     * StringUtils.abbreviate("abcdefghij", 0, 3)        = IllegalArgumentException
7769     * StringUtils.abbreviate("abcdefghij", 5, 6)        = IllegalArgumentException
7770     * </pre>
7771     *
7772     * @param str  the String to check, may be null
7773     * @param offset  left edge of source String
7774     * @param maxWidth  maximum length of result String, must be at least 4
7775     * @return abbreviated String, {@code null} if null String input
7776     * @throws IllegalArgumentException if the width is too small
7777     * @since 2.0
7778     */
7779    public static String abbreviate(final String str, final int offset, final int maxWidth) {
7780        final String defaultAbbrevMarker = "...";
7781        return abbreviate(str, defaultAbbrevMarker, offset, maxWidth);
7782    }
7783
7784    /**
7785     * <p>Abbreviates a String using another given String as replacement marker. This will turn
7786     * "Now is the time for all good men" into "Now is the time for..." if "..." was defined
7787     * as the replacement marker.</p>
7788     *
7789     * <p>Specifically:</p>
7790     * <ul>
7791     *   <li>If the number of characters in {@code str} is less than or equal to
7792     *       {@code maxWidth}, return {@code str}.</li>
7793     *   <li>Else abbreviate it to {@code (substring(str, 0, max-abbrevMarker.length) + abbrevMarker)}.</li>
7794     *   <li>If {@code maxWidth} is less than {@code abbrevMarker.length + 1}, throw an
7795     *       {@code IllegalArgumentException}.</li>
7796     *   <li>In no case will it return a String of length greater than
7797     *       {@code maxWidth}.</li>
7798     * </ul>
7799     *
7800     * <pre>
7801     * StringUtils.abbreviate(null, "...", *)      = null
7802     * StringUtils.abbreviate("abcdefg", null, *)  = "abcdefg"
7803     * StringUtils.abbreviate("", "...", 4)        = ""
7804     * StringUtils.abbreviate("abcdefg", ".", 5)   = "abcd."
7805     * StringUtils.abbreviate("abcdefg", ".", 7)   = "abcdefg"
7806     * StringUtils.abbreviate("abcdefg", ".", 8)   = "abcdefg"
7807     * StringUtils.abbreviate("abcdefg", "..", 4)  = "ab.."
7808     * StringUtils.abbreviate("abcdefg", "..", 3)  = "a.."
7809     * StringUtils.abbreviate("abcdefg", "..", 2)  = IllegalArgumentException
7810     * StringUtils.abbreviate("abcdefg", "...", 3) = IllegalArgumentException
7811     * </pre>
7812     *
7813     * @param str  the String to check, may be null
7814     * @param abbrevMarker  the String used as replacement marker
7815     * @param maxWidth  maximum length of result String, must be at least {@code abbrevMarker.length + 1}
7816     * @return abbreviated String, {@code null} if null String input
7817     * @throws IllegalArgumentException if the width is too small
7818     * @since 3.6
7819     */
7820    public static String abbreviate(final String str, final String abbrevMarker, final int maxWidth) {
7821        return abbreviate(str, abbrevMarker, 0, maxWidth);
7822    }
7823
7824    /**
7825     * <p>Abbreviates a String using a given replacement marker. This will turn
7826     * "Now is the time for all good men" into "...is the time for..." if "..." was defined
7827     * as the replacement marker.</p>
7828     *
7829     * <p>Works like {@code abbreviate(String, String, int)}, but allows you to specify
7830     * a "left edge" offset.  Note that this left edge is not necessarily going to
7831     * be the leftmost character in the result, or the first character following the
7832     * replacement marker, but it will appear somewhere in the result.
7833     *
7834     * <p>In no case will it return a String of length greater than {@code maxWidth}.</p>
7835     *
7836     * <pre>
7837     * StringUtils.abbreviate(null, null, *, *)                 = null
7838     * StringUtils.abbreviate("abcdefghijklmno", null, *, *)    = "abcdefghijklmno"
7839     * StringUtils.abbreviate("", "...", 0, 4)                  = ""
7840     * StringUtils.abbreviate("abcdefghijklmno", "---", -1, 10) = "abcdefg---"
7841     * StringUtils.abbreviate("abcdefghijklmno", ",", 0, 10)    = "abcdefghi,"
7842     * StringUtils.abbreviate("abcdefghijklmno", ",", 1, 10)    = "abcdefghi,"
7843     * StringUtils.abbreviate("abcdefghijklmno", ",", 2, 10)    = "abcdefghi,"
7844     * StringUtils.abbreviate("abcdefghijklmno", "::", 4, 10)   = "::efghij::"
7845     * StringUtils.abbreviate("abcdefghijklmno", "...", 6, 10)  = "...ghij..."
7846     * StringUtils.abbreviate("abcdefghijklmno", "*", 9, 10)    = "*ghijklmno"
7847     * StringUtils.abbreviate("abcdefghijklmno", "'", 10, 10)   = "'ghijklmno"
7848     * StringUtils.abbreviate("abcdefghijklmno", "!", 12, 10)   = "!ghijklmno"
7849     * StringUtils.abbreviate("abcdefghij", "abra", 0, 4)       = IllegalArgumentException
7850     * StringUtils.abbreviate("abcdefghij", "...", 5, 6)        = IllegalArgumentException
7851     * </pre>
7852     *
7853     * @param str  the String to check, may be null
7854     * @param abbrevMarker  the String used as replacement marker
7855     * @param offset  left edge of source String
7856     * @param maxWidth  maximum length of result String, must be at least 4
7857     * @return abbreviated String, {@code null} if null String input
7858     * @throws IllegalArgumentException if the width is too small
7859     * @since 3.6
7860     */
7861    public static String abbreviate(final String str, final String abbrevMarker, int offset, final int maxWidth) {
7862        if (isEmpty(str) || isEmpty(abbrevMarker)) {
7863            return str;
7864        }
7865
7866        final int abbrevMarkerLength = abbrevMarker.length();
7867        final int minAbbrevWidth = abbrevMarkerLength + 1;
7868        final int minAbbrevWidthOffset = abbrevMarkerLength + abbrevMarkerLength + 1;
7869
7870        if (maxWidth < minAbbrevWidth) {
7871            throw new IllegalArgumentException(String.format("Minimum abbreviation width is %d", minAbbrevWidth));
7872        }
7873        if (str.length() <= maxWidth) {
7874            return str;
7875        }
7876        if (offset > str.length()) {
7877            offset = str.length();
7878        }
7879        if (str.length() - offset < maxWidth - abbrevMarkerLength) {
7880            offset = str.length() - (maxWidth - abbrevMarkerLength);
7881        }
7882        if (offset <= abbrevMarkerLength+1) {
7883            return str.substring(0, maxWidth - abbrevMarkerLength) + abbrevMarker;
7884        }
7885        if (maxWidth < minAbbrevWidthOffset) {
7886            throw new IllegalArgumentException(String.format("Minimum abbreviation width with offset is %d", minAbbrevWidthOffset));
7887        }
7888        if (offset + maxWidth - abbrevMarkerLength < str.length()) {
7889            return abbrevMarker + abbreviate(str.substring(offset), abbrevMarker, maxWidth - abbrevMarkerLength);
7890        }
7891        return abbrevMarker + str.substring(str.length() - (maxWidth - abbrevMarkerLength));
7892    }
7893
7894    /**
7895     * <p>Abbreviates a String to the length passed, replacing the middle characters with the supplied
7896     * replacement String.</p>
7897     *
7898     * <p>This abbreviation only occurs if the following criteria is met:</p>
7899     * <ul>
7900     * <li>Neither the String for abbreviation nor the replacement String are null or empty </li>
7901     * <li>The length to truncate to is less than the length of the supplied String</li>
7902     * <li>The length to truncate to is greater than 0</li>
7903     * <li>The abbreviated String will have enough room for the length supplied replacement String
7904     * and the first and last characters of the supplied String for abbreviation</li>
7905     * </ul>
7906     * <p>Otherwise, the returned String will be the same as the supplied String for abbreviation.
7907     * </p>
7908     *
7909     * <pre>
7910     * StringUtils.abbreviateMiddle(null, null, 0)      = null
7911     * StringUtils.abbreviateMiddle("abc", null, 0)      = "abc"
7912     * StringUtils.abbreviateMiddle("abc", ".", 0)      = "abc"
7913     * StringUtils.abbreviateMiddle("abc", ".", 3)      = "abc"
7914     * StringUtils.abbreviateMiddle("abcdef", ".", 4)     = "ab.f"
7915     * </pre>
7916     *
7917     * @param str  the String to abbreviate, may be null
7918     * @param middle the String to replace the middle characters with, may be null
7919     * @param length the length to abbreviate {@code str} to.
7920     * @return the abbreviated String if the above criteria is met, or the original String supplied for abbreviation.
7921     * @since 2.5
7922     */
7923    public static String abbreviateMiddle(final String str, final String middle, final int length) {
7924        if (isEmpty(str) || isEmpty(middle)) {
7925            return str;
7926        }
7927
7928        if (length >= str.length() || length < middle.length()+2) {
7929            return str;
7930        }
7931
7932        final int targetSting = length-middle.length();
7933        final int startOffset = targetSting/2+targetSting%2;
7934        final int endOffset = str.length()-targetSting/2;
7935
7936        return str.substring(0, startOffset) +
7937            middle +
7938            str.substring(endOffset);
7939    }
7940
7941    // Difference
7942    //-----------------------------------------------------------------------
7943    /**
7944     * <p>Compares two Strings, and returns the portion where they differ.
7945     * More precisely, return the remainder of the second String,
7946     * starting from where it's different from the first. This means that
7947     * the difference between "abc" and "ab" is the empty String and not "c". </p>
7948     *
7949     * <p>For example,
7950     * {@code difference("i am a machine", "i am a robot") -> "robot"}.</p>
7951     *
7952     * <pre>
7953     * StringUtils.difference(null, null) = null
7954     * StringUtils.difference("", "") = ""
7955     * StringUtils.difference("", "abc") = "abc"
7956     * StringUtils.difference("abc", "") = ""
7957     * StringUtils.difference("abc", "abc") = ""
7958     * StringUtils.difference("abc", "ab") = ""
7959     * StringUtils.difference("ab", "abxyz") = "xyz"
7960     * StringUtils.difference("abcde", "abxyz") = "xyz"
7961     * StringUtils.difference("abcde", "xyz") = "xyz"
7962     * </pre>
7963     *
7964     * @param str1  the first String, may be null
7965     * @param str2  the second String, may be null
7966     * @return the portion of str2 where it differs from str1; returns the
7967     * empty String if they are equal
7968     * @see #indexOfDifference(CharSequence,CharSequence)
7969     * @since 2.0
7970     */
7971    public static String difference(final String str1, final String str2) {
7972        if (str1 == null) {
7973            return str2;
7974        }
7975        if (str2 == null) {
7976            return str1;
7977        }
7978        final int at = indexOfDifference(str1, str2);
7979        if (at == INDEX_NOT_FOUND) {
7980            return EMPTY;
7981        }
7982        return str2.substring(at);
7983    }
7984
7985    /**
7986     * <p>Compares two CharSequences, and returns the index at which the
7987     * CharSequences begin to differ.</p>
7988     *
7989     * <p>For example,
7990     * {@code indexOfDifference("i am a machine", "i am a robot") -> 7}</p>
7991     *
7992     * <pre>
7993     * StringUtils.indexOfDifference(null, null) = -1
7994     * StringUtils.indexOfDifference("", "") = -1
7995     * StringUtils.indexOfDifference("", "abc") = 0
7996     * StringUtils.indexOfDifference("abc", "") = 0
7997     * StringUtils.indexOfDifference("abc", "abc") = -1
7998     * StringUtils.indexOfDifference("ab", "abxyz") = 2
7999     * StringUtils.indexOfDifference("abcde", "abxyz") = 2
8000     * StringUtils.indexOfDifference("abcde", "xyz") = 0
8001     * </pre>
8002     *
8003     * @param cs1  the first CharSequence, may be null
8004     * @param cs2  the second CharSequence, may be null
8005     * @return the index where cs1 and cs2 begin to differ; -1 if they are equal
8006     * @since 2.0
8007     * @since 3.0 Changed signature from indexOfDifference(String, String) to
8008     * indexOfDifference(CharSequence, CharSequence)
8009     */
8010    public static int indexOfDifference(final CharSequence cs1, final CharSequence cs2) {
8011        if (cs1 == cs2) {
8012            return INDEX_NOT_FOUND;
8013        }
8014        if (cs1 == null || cs2 == null) {
8015            return 0;
8016        }
8017        int i;
8018        for (i = 0; i < cs1.length() && i < cs2.length(); ++i) {
8019            if (cs1.charAt(i) != cs2.charAt(i)) {
8020                break;
8021            }
8022        }
8023        if (i < cs2.length() || i < cs1.length()) {
8024            return i;
8025        }
8026        return INDEX_NOT_FOUND;
8027    }
8028
8029    /**
8030     * <p>Compares all CharSequences in an array and returns the index at which the
8031     * CharSequences begin to differ.</p>
8032     *
8033     * <p>For example,
8034     * {@code indexOfDifference(new String[] {"i am a machine", "i am a robot"}) -> 7}</p>
8035     *
8036     * <pre>
8037     * StringUtils.indexOfDifference(null) = -1
8038     * StringUtils.indexOfDifference(new String[] {}) = -1
8039     * StringUtils.indexOfDifference(new String[] {"abc"}) = -1
8040     * StringUtils.indexOfDifference(new String[] {null, null}) = -1
8041     * StringUtils.indexOfDifference(new String[] {"", ""}) = -1
8042     * StringUtils.indexOfDifference(new String[] {"", null}) = 0
8043     * StringUtils.indexOfDifference(new String[] {"abc", null, null}) = 0
8044     * StringUtils.indexOfDifference(new String[] {null, null, "abc"}) = 0
8045     * StringUtils.indexOfDifference(new String[] {"", "abc"}) = 0
8046     * StringUtils.indexOfDifference(new String[] {"abc", ""}) = 0
8047     * StringUtils.indexOfDifference(new String[] {"abc", "abc"}) = -1
8048     * StringUtils.indexOfDifference(new String[] {"abc", "a"}) = 1
8049     * StringUtils.indexOfDifference(new String[] {"ab", "abxyz"}) = 2
8050     * StringUtils.indexOfDifference(new String[] {"abcde", "abxyz"}) = 2
8051     * StringUtils.indexOfDifference(new String[] {"abcde", "xyz"}) = 0
8052     * StringUtils.indexOfDifference(new String[] {"xyz", "abcde"}) = 0
8053     * StringUtils.indexOfDifference(new String[] {"i am a machine", "i am a robot"}) = 7
8054     * </pre>
8055     *
8056     * @param css  array of CharSequences, entries may be null
8057     * @return the index where the strings begin to differ; -1 if they are all equal
8058     * @since 2.4
8059     * @since 3.0 Changed signature from indexOfDifference(String...) to indexOfDifference(CharSequence...)
8060     */
8061    public static int indexOfDifference(final CharSequence... css) {
8062        if (css == null || css.length <= 1) {
8063            return INDEX_NOT_FOUND;
8064        }
8065        boolean anyStringNull = false;
8066        boolean allStringsNull = true;
8067        final int arrayLen = css.length;
8068        int shortestStrLen = Integer.MAX_VALUE;
8069        int longestStrLen = 0;
8070
8071        // find the min and max string lengths; this avoids checking to make
8072        // sure we are not exceeding the length of the string each time through
8073        // the bottom loop.
8074        for (final CharSequence cs : css) {
8075            if (cs == null) {
8076                anyStringNull = true;
8077                shortestStrLen = 0;
8078            } else {
8079                allStringsNull = false;
8080                shortestStrLen = Math.min(cs.length(), shortestStrLen);
8081                longestStrLen = Math.max(cs.length(), longestStrLen);
8082            }
8083        }
8084
8085        // handle lists containing all nulls or all empty strings
8086        if (allStringsNull || longestStrLen == 0 && !anyStringNull) {
8087            return INDEX_NOT_FOUND;
8088        }
8089
8090        // handle lists containing some nulls or some empty strings
8091        if (shortestStrLen == 0) {
8092            return 0;
8093        }
8094
8095        // find the position with the first difference across all strings
8096        int firstDiff = -1;
8097        for (int stringPos = 0; stringPos < shortestStrLen; stringPos++) {
8098            final char comparisonChar = css[0].charAt(stringPos);
8099            for (int arrayPos = 1; arrayPos < arrayLen; arrayPos++) {
8100                if (css[arrayPos].charAt(stringPos) != comparisonChar) {
8101                    firstDiff = stringPos;
8102                    break;
8103                }
8104            }
8105            if (firstDiff != -1) {
8106                break;
8107            }
8108        }
8109
8110        if (firstDiff == -1 && shortestStrLen != longestStrLen) {
8111            // we compared all of the characters up to the length of the
8112            // shortest string and didn't find a match, but the string lengths
8113            // vary, so return the length of the shortest string.
8114            return shortestStrLen;
8115        }
8116        return firstDiff;
8117    }
8118
8119    /**
8120     * <p>Compares all Strings in an array and returns the initial sequence of
8121     * characters that is common to all of them.</p>
8122     *
8123     * <p>For example,
8124     * <code>getCommonPrefix(new String[] {"i am a machine", "i am a robot"}) -&gt; "i am a "</code></p>
8125     *
8126     * <pre>
8127     * StringUtils.getCommonPrefix(null) = ""
8128     * StringUtils.getCommonPrefix(new String[] {}) = ""
8129     * StringUtils.getCommonPrefix(new String[] {"abc"}) = "abc"
8130     * StringUtils.getCommonPrefix(new String[] {null, null}) = ""
8131     * StringUtils.getCommonPrefix(new String[] {"", ""}) = ""
8132     * StringUtils.getCommonPrefix(new String[] {"", null}) = ""
8133     * StringUtils.getCommonPrefix(new String[] {"abc", null, null}) = ""
8134     * StringUtils.getCommonPrefix(new String[] {null, null, "abc"}) = ""
8135     * StringUtils.getCommonPrefix(new String[] {"", "abc"}) = ""
8136     * StringUtils.getCommonPrefix(new String[] {"abc", ""}) = ""
8137     * StringUtils.getCommonPrefix(new String[] {"abc", "abc"}) = "abc"
8138     * StringUtils.getCommonPrefix(new String[] {"abc", "a"}) = "a"
8139     * StringUtils.getCommonPrefix(new String[] {"ab", "abxyz"}) = "ab"
8140     * StringUtils.getCommonPrefix(new String[] {"abcde", "abxyz"}) = "ab"
8141     * StringUtils.getCommonPrefix(new String[] {"abcde", "xyz"}) = ""
8142     * StringUtils.getCommonPrefix(new String[] {"xyz", "abcde"}) = ""
8143     * StringUtils.getCommonPrefix(new String[] {"i am a machine", "i am a robot"}) = "i am a "
8144     * </pre>
8145     *
8146     * @param strs  array of String objects, entries may be null
8147     * @return the initial sequence of characters that are common to all Strings
8148     * in the array; empty String if the array is null, the elements are all null
8149     * or if there is no common prefix.
8150     * @since 2.4
8151     */
8152    public static String getCommonPrefix(final String... strs) {
8153        if (strs == null || strs.length == 0) {
8154            return EMPTY;
8155        }
8156        final int smallestIndexOfDiff = indexOfDifference(strs);
8157        if (smallestIndexOfDiff == INDEX_NOT_FOUND) {
8158            // all strings were identical
8159            if (strs[0] == null) {
8160                return EMPTY;
8161            }
8162            return strs[0];
8163        } else if (smallestIndexOfDiff == 0) {
8164            // there were no common initial characters
8165            return EMPTY;
8166        } else {
8167            // we found a common initial character sequence
8168            return strs[0].substring(0, smallestIndexOfDiff);
8169        }
8170    }
8171
8172    // Misc
8173    //-----------------------------------------------------------------------
8174    /**
8175     * <p>Find the Levenshtein distance between two Strings.</p>
8176     *
8177     * <p>This is the number of changes needed to change one String into
8178     * another, where each change is a single character modification (deletion,
8179     * insertion or substitution).</p>
8180     *
8181     * <p>The implementation uses a single-dimensional array of length s.length() + 1. See
8182     * <a href="http://blog.softwx.net/2014/12/optimizing-levenshtein-algorithm-in-c.html">
8183     * http://blog.softwx.net/2014/12/optimizing-levenshtein-algorithm-in-c.html</a> for details.</p>
8184     *
8185     * <pre>
8186     * StringUtils.getLevenshteinDistance(null, *)             = IllegalArgumentException
8187     * StringUtils.getLevenshteinDistance(*, null)             = IllegalArgumentException
8188     * StringUtils.getLevenshteinDistance("", "")              = 0
8189     * StringUtils.getLevenshteinDistance("", "a")             = 1
8190     * StringUtils.getLevenshteinDistance("aaapppp", "")       = 7
8191     * StringUtils.getLevenshteinDistance("frog", "fog")       = 1
8192     * StringUtils.getLevenshteinDistance("fly", "ant")        = 3
8193     * StringUtils.getLevenshteinDistance("elephant", "hippo") = 7
8194     * StringUtils.getLevenshteinDistance("hippo", "elephant") = 7
8195     * StringUtils.getLevenshteinDistance("hippo", "zzzzzzzz") = 8
8196     * StringUtils.getLevenshteinDistance("hello", "hallo")    = 1
8197     * </pre>
8198     *
8199     * @param s  the first String, must not be null
8200     * @param t  the second String, must not be null
8201     * @return result distance
8202     * @throws IllegalArgumentException if either String input {@code null}
8203     * @since 3.0 Changed signature from getLevenshteinDistance(String, String) to
8204     * getLevenshteinDistance(CharSequence, CharSequence)
8205     * @deprecated as of 3.6, use commons-text
8206     * <a href="https://commons.apache.org/proper/commons-text/javadocs/api-release/org/apache/commons/text/similarity/LevenshteinDistance.html">
8207     * LevenshteinDistance</a> instead
8208     */
8209    @Deprecated
8210    public static int getLevenshteinDistance(CharSequence s, CharSequence t) {
8211        if (s == null || t == null) {
8212            throw new IllegalArgumentException("Strings must not be null");
8213        }
8214
8215        int n = s.length();
8216        int m = t.length();
8217
8218        if (n == 0) {
8219            return m;
8220        } else if (m == 0) {
8221            return n;
8222        }
8223
8224        if (n > m) {
8225            // swap the input strings to consume less memory
8226            final CharSequence tmp = s;
8227            s = t;
8228            t = tmp;
8229            n = m;
8230            m = t.length();
8231        }
8232
8233        final int p[] = new int[n + 1];
8234        // indexes into strings s and t
8235        int i; // iterates through s
8236        int j; // iterates through t
8237        int upper_left;
8238        int upper;
8239
8240        char t_j; // jth character of t
8241        int cost;
8242
8243        for (i = 0; i <= n; i++) {
8244            p[i] = i;
8245        }
8246
8247        for (j = 1; j <= m; j++) {
8248            upper_left = p[0];
8249            t_j = t.charAt(j - 1);
8250            p[0] = j;
8251
8252            for (i = 1; i <= n; i++) {
8253                upper = p[i];
8254                cost = s.charAt(i - 1) == t_j ? 0 : 1;
8255                // minimum of cell to the left+1, to the top+1, diagonally left and up +cost
8256                p[i] = Math.min(Math.min(p[i - 1] + 1, p[i] + 1), upper_left + cost);
8257                upper_left = upper;
8258            }
8259        }
8260
8261        return p[n];
8262    }
8263
8264    /**
8265     * <p>Find the Levenshtein distance between two Strings if it's less than or equal to a given
8266     * threshold.</p>
8267     *
8268     * <p>This is the number of changes needed to change one String into
8269     * another, where each change is a single character modification (deletion,
8270     * insertion or substitution).</p>
8271     *
8272     * <p>This implementation follows from Algorithms on Strings, Trees and Sequences by Dan Gusfield
8273     * and Chas Emerick's implementation of the Levenshtein distance algorithm from
8274     * <a href="http://www.merriampark.com/ld.htm">http://www.merriampark.com/ld.htm</a></p>
8275     *
8276     * <pre>
8277     * StringUtils.getLevenshteinDistance(null, *, *)             = IllegalArgumentException
8278     * StringUtils.getLevenshteinDistance(*, null, *)             = IllegalArgumentException
8279     * StringUtils.getLevenshteinDistance(*, *, -1)               = IllegalArgumentException
8280     * StringUtils.getLevenshteinDistance("", "", 0)              = 0
8281     * StringUtils.getLevenshteinDistance("aaapppp", "", 8)       = 7
8282     * StringUtils.getLevenshteinDistance("aaapppp", "", 7)       = 7
8283     * StringUtils.getLevenshteinDistance("aaapppp", "", 6))      = -1
8284     * StringUtils.getLevenshteinDistance("elephant", "hippo", 7) = 7
8285     * StringUtils.getLevenshteinDistance("elephant", "hippo", 6) = -1
8286     * StringUtils.getLevenshteinDistance("hippo", "elephant", 7) = 7
8287     * StringUtils.getLevenshteinDistance("hippo", "elephant", 6) = -1
8288     * </pre>
8289     *
8290     * @param s  the first String, must not be null
8291     * @param t  the second String, must not be null
8292     * @param threshold the target threshold, must not be negative
8293     * @return result distance, or {@code -1} if the distance would be greater than the threshold
8294     * @throws IllegalArgumentException if either String input {@code null} or negative threshold
8295     * @deprecated as of 3.6, use commons-text
8296     * <a href="https://commons.apache.org/proper/commons-text/javadocs/api-release/org/apache/commons/text/similarity/LevenshteinDistance.html">
8297     * LevenshteinDistance</a> instead
8298     */
8299    @Deprecated
8300    public static int getLevenshteinDistance(CharSequence s, CharSequence t, final int threshold) {
8301        if (s == null || t == null) {
8302            throw new IllegalArgumentException("Strings must not be null");
8303        }
8304        if (threshold < 0) {
8305            throw new IllegalArgumentException("Threshold must not be negative");
8306        }
8307
8308        /*
8309        This implementation only computes the distance if it's less than or equal to the
8310        threshold value, returning -1 if it's greater.  The advantage is performance: unbounded
8311        distance is O(nm), but a bound of k allows us to reduce it to O(km) time by only
8312        computing a diagonal stripe of width 2k + 1 of the cost table.
8313        It is also possible to use this to compute the unbounded Levenshtein distance by starting
8314        the threshold at 1 and doubling each time until the distance is found; this is O(dm), where
8315        d is the distance.
8316
8317        One subtlety comes from needing to ignore entries on the border of our stripe
8318        eg.
8319        p[] = |#|#|#|*
8320        d[] =  *|#|#|#|
8321        We must ignore the entry to the left of the leftmost member
8322        We must ignore the entry above the rightmost member
8323
8324        Another subtlety comes from our stripe running off the matrix if the strings aren't
8325        of the same size.  Since string s is always swapped to be the shorter of the two,
8326        the stripe will always run off to the upper right instead of the lower left of the matrix.
8327
8328        As a concrete example, suppose s is of length 5, t is of length 7, and our threshold is 1.
8329        In this case we're going to walk a stripe of length 3.  The matrix would look like so:
8330
8331           1 2 3 4 5
8332        1 |#|#| | | |
8333        2 |#|#|#| | |
8334        3 | |#|#|#| |
8335        4 | | |#|#|#|
8336        5 | | | |#|#|
8337        6 | | | | |#|
8338        7 | | | | | |
8339
8340        Note how the stripe leads off the table as there is no possible way to turn a string of length 5
8341        into one of length 7 in edit distance of 1.
8342
8343        Additionally, this implementation decreases memory usage by using two
8344        single-dimensional arrays and swapping them back and forth instead of allocating
8345        an entire n by m matrix.  This requires a few minor changes, such as immediately returning
8346        when it's detected that the stripe has run off the matrix and initially filling the arrays with
8347        large values so that entries we don't compute are ignored.
8348
8349        See Algorithms on Strings, Trees and Sequences by Dan Gusfield for some discussion.
8350         */
8351
8352        int n = s.length(); // length of s
8353        int m = t.length(); // length of t
8354
8355        // if one string is empty, the edit distance is necessarily the length of the other
8356        if (n == 0) {
8357            return m <= threshold ? m : -1;
8358        } else if (m == 0) {
8359            return n <= threshold ? n : -1;
8360        } else if (Math.abs(n - m) > threshold) {
8361            // no need to calculate the distance if the length difference is greater than the threshold
8362            return -1;
8363        }
8364
8365        if (n > m) {
8366            // swap the two strings to consume less memory
8367            final CharSequence tmp = s;
8368            s = t;
8369            t = tmp;
8370            n = m;
8371            m = t.length();
8372        }
8373
8374        int p[] = new int[n + 1]; // 'previous' cost array, horizontally
8375        int d[] = new int[n + 1]; // cost array, horizontally
8376        int _d[]; // placeholder to assist in swapping p and d
8377
8378        // fill in starting table values
8379        final int boundary = Math.min(n, threshold) + 1;
8380        for (int i = 0; i < boundary; i++) {
8381            p[i] = i;
8382        }
8383        // these fills ensure that the value above the rightmost entry of our
8384        // stripe will be ignored in following loop iterations
8385        Arrays.fill(p, boundary, p.length, Integer.MAX_VALUE);
8386        Arrays.fill(d, Integer.MAX_VALUE);
8387
8388        // iterates through t
8389        for (int j = 1; j <= m; j++) {
8390            final char t_j = t.charAt(j - 1); // jth character of t
8391            d[0] = j;
8392
8393            // compute stripe indices, constrain to array size
8394            final int min = Math.max(1, j - threshold);
8395            final int max = j > Integer.MAX_VALUE - threshold ? n : Math.min(n, j + threshold);
8396
8397            // the stripe may lead off of the table if s and t are of different sizes
8398            if (min > max) {
8399                return -1;
8400            }
8401
8402            // ignore entry left of leftmost
8403            if (min > 1) {
8404                d[min - 1] = Integer.MAX_VALUE;
8405            }
8406
8407            // iterates through [min, max] in s
8408            for (int i = min; i <= max; i++) {
8409                if (s.charAt(i - 1) == t_j) {
8410                    // diagonally left and up
8411                    d[i] = p[i - 1];
8412                } else {
8413                    // 1 + minimum of cell to the left, to the top, diagonally left and up
8414                    d[i] = 1 + Math.min(Math.min(d[i - 1], p[i]), p[i - 1]);
8415                }
8416            }
8417
8418            // copy current distance counts to 'previous row' distance counts
8419            _d = p;
8420            p = d;
8421            d = _d;
8422        }
8423
8424        // if p[n] is greater than the threshold, there's no guarantee on it being the correct
8425        // distance
8426        if (p[n] <= threshold) {
8427            return p[n];
8428        }
8429        return -1;
8430    }
8431
8432    /**
8433     * <p>Find the Jaro Winkler Distance which indicates the similarity score between two Strings.</p>
8434     *
8435     * <p>The Jaro measure is the weighted sum of percentage of matched characters from each file and transposed characters.
8436     * Winkler increased this measure for matching initial characters.</p>
8437     *
8438     * <p>This implementation is based on the Jaro Winkler similarity algorithm
8439     * 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>
8440     *
8441     * <pre>
8442     * StringUtils.getJaroWinklerDistance(null, null)          = IllegalArgumentException
8443     * StringUtils.getJaroWinklerDistance("", "")              = 0.0
8444     * StringUtils.getJaroWinklerDistance("", "a")             = 0.0
8445     * StringUtils.getJaroWinklerDistance("aaapppp", "")       = 0.0
8446     * StringUtils.getJaroWinklerDistance("frog", "fog")       = 0.93
8447     * StringUtils.getJaroWinklerDistance("fly", "ant")        = 0.0
8448     * StringUtils.getJaroWinklerDistance("elephant", "hippo") = 0.44
8449     * StringUtils.getJaroWinklerDistance("hippo", "elephant") = 0.44
8450     * StringUtils.getJaroWinklerDistance("hippo", "zzzzzzzz") = 0.0
8451     * StringUtils.getJaroWinklerDistance("hello", "hallo")    = 0.88
8452     * StringUtils.getJaroWinklerDistance("ABC Corporation", "ABC Corp") = 0.93
8453     * StringUtils.getJaroWinklerDistance("D N H Enterprises Inc", "D &amp; H Enterprises, Inc.") = 0.95
8454     * StringUtils.getJaroWinklerDistance("My Gym Children's Fitness Center", "My Gym. Childrens Fitness") = 0.92
8455     * StringUtils.getJaroWinklerDistance("PENNSYLVANIA", "PENNCISYLVNIA") = 0.88
8456     * </pre>
8457     *
8458     * @param first the first String, must not be null
8459     * @param second the second String, must not be null
8460     * @return result distance
8461     * @throws IllegalArgumentException if either String input {@code null}
8462     * @since 3.3
8463     * @deprecated as of 3.6, use commons-text
8464     * <a href="https://commons.apache.org/proper/commons-text/javadocs/api-release/org/apache/commons/text/similarity/JaroWinklerDistance.html">
8465     * JaroWinklerDistance</a> instead
8466     */
8467    @Deprecated
8468    public static double getJaroWinklerDistance(final CharSequence first, final CharSequence second) {
8469        final double DEFAULT_SCALING_FACTOR = 0.1;
8470
8471        if (first == null || second == null) {
8472            throw new IllegalArgumentException("Strings must not be null");
8473        }
8474
8475        final int[] mtp = matches(first, second);
8476        final double m = mtp[0];
8477        if (m == 0) {
8478            return 0D;
8479        }
8480        final double j = ((m / first.length() + m / second.length() + (m - mtp[1]) / m)) / 3;
8481        final double jw = j < 0.7D ? j : j + Math.min(DEFAULT_SCALING_FACTOR, 1D / mtp[3]) * mtp[2] * (1D - j);
8482        return Math.round(jw * 100.0D) / 100.0D;
8483    }
8484
8485    private static int[] matches(final CharSequence first, final CharSequence second) {
8486        CharSequence max, min;
8487        if (first.length() > second.length()) {
8488            max = first;
8489            min = second;
8490        } else {
8491            max = second;
8492            min = first;
8493        }
8494        final int range = Math.max(max.length() / 2 - 1, 0);
8495        final int[] matchIndexes = new int[min.length()];
8496        Arrays.fill(matchIndexes, -1);
8497        final boolean[] matchFlags = new boolean[max.length()];
8498        int matches = 0;
8499        for (int mi = 0; mi < min.length(); mi++) {
8500            final char c1 = min.charAt(mi);
8501            for (int xi = Math.max(mi - range, 0), xn = Math.min(mi + range + 1, max.length()); xi < xn; xi++) {
8502                if (!matchFlags[xi] && c1 == max.charAt(xi)) {
8503                    matchIndexes[mi] = xi;
8504                    matchFlags[xi] = true;
8505                    matches++;
8506                    break;
8507                }
8508            }
8509        }
8510        final char[] ms1 = new char[matches];
8511        final char[] ms2 = new char[matches];
8512        for (int i = 0, si = 0; i < min.length(); i++) {
8513            if (matchIndexes[i] != -1) {
8514                ms1[si] = min.charAt(i);
8515                si++;
8516            }
8517        }
8518        for (int i = 0, si = 0; i < max.length(); i++) {
8519            if (matchFlags[i]) {
8520                ms2[si] = max.charAt(i);
8521                si++;
8522            }
8523        }
8524        int transpositions = 0;
8525        for (int mi = 0; mi < ms1.length; mi++) {
8526            if (ms1[mi] != ms2[mi]) {
8527                transpositions++;
8528            }
8529        }
8530        int prefix = 0;
8531        for (int mi = 0; mi < min.length(); mi++) {
8532            if (first.charAt(mi) == second.charAt(mi)) {
8533                prefix++;
8534            } else {
8535                break;
8536            }
8537        }
8538        return new int[] { matches, transpositions / 2, prefix, max.length() };
8539    }
8540
8541    /**
8542     * <p>Find the Fuzzy Distance which indicates the similarity score between two Strings.</p>
8543     *
8544     * <p>This string matching algorithm is similar to the algorithms of editors such as Sublime Text,
8545     * TextMate, Atom and others. One point is given for every matched character. Subsequent
8546     * matches yield two bonus points. A higher score indicates a higher similarity.</p>
8547     *
8548     * <pre>
8549     * StringUtils.getFuzzyDistance(null, null, null)                                    = IllegalArgumentException
8550     * StringUtils.getFuzzyDistance("", "", Locale.ENGLISH)                              = 0
8551     * StringUtils.getFuzzyDistance("Workshop", "b", Locale.ENGLISH)                     = 0
8552     * StringUtils.getFuzzyDistance("Room", "o", Locale.ENGLISH)                         = 1
8553     * StringUtils.getFuzzyDistance("Workshop", "w", Locale.ENGLISH)                     = 1
8554     * StringUtils.getFuzzyDistance("Workshop", "ws", Locale.ENGLISH)                    = 2
8555     * StringUtils.getFuzzyDistance("Workshop", "wo", Locale.ENGLISH)                    = 4
8556     * StringUtils.getFuzzyDistance("Apache Software Foundation", "asf", Locale.ENGLISH) = 3
8557     * </pre>
8558     *
8559     * @param term a full term that should be matched against, must not be null
8560     * @param query the query that will be matched against a term, must not be null
8561     * @param locale This string matching logic is case insensitive. A locale is necessary to normalize
8562     *  both Strings to lower case.
8563     * @return result score
8564     * @throws IllegalArgumentException if either String input {@code null} or Locale input {@code null}
8565     * @since 3.4
8566     * @deprecated as of 3.6, use commons-text
8567     * <a href="https://commons.apache.org/proper/commons-text/javadocs/api-release/org/apache/commons/text/similarity/FuzzyScore.html">
8568     * FuzzyScore</a> instead
8569     */
8570    @Deprecated
8571    public static int getFuzzyDistance(final CharSequence term, final CharSequence query, final Locale locale) {
8572        if (term == null || query == null) {
8573            throw new IllegalArgumentException("Strings must not be null");
8574        } else if (locale == null) {
8575            throw new IllegalArgumentException("Locale must not be null");
8576        }
8577
8578        // fuzzy logic is case insensitive. We normalize the Strings to lower
8579        // case right from the start. Turning characters to lower case
8580        // via Character.toLowerCase(char) is unfortunately insufficient
8581        // as it does not accept a locale.
8582        final String termLowerCase = term.toString().toLowerCase(locale);
8583        final String queryLowerCase = query.toString().toLowerCase(locale);
8584
8585        // the resulting score
8586        int score = 0;
8587
8588        // the position in the term which will be scanned next for potential
8589        // query character matches
8590        int termIndex = 0;
8591
8592        // index of the previously matched character in the term
8593        int previousMatchingCharacterIndex = Integer.MIN_VALUE;
8594
8595        for (int queryIndex = 0; queryIndex < queryLowerCase.length(); queryIndex++) {
8596            final char queryChar = queryLowerCase.charAt(queryIndex);
8597
8598            boolean termCharacterMatchFound = false;
8599            for (; termIndex < termLowerCase.length() && !termCharacterMatchFound; termIndex++) {
8600                final char termChar = termLowerCase.charAt(termIndex);
8601
8602                if (queryChar == termChar) {
8603                    // simple character matches result in one point
8604                    score++;
8605
8606                    // subsequent character matches further improve
8607                    // the score.
8608                    if (previousMatchingCharacterIndex + 1 == termIndex) {
8609                        score += 2;
8610                    }
8611
8612                    previousMatchingCharacterIndex = termIndex;
8613
8614                    // we can leave the nested loop. Every character in the
8615                    // query can match at most one character in the term.
8616                    termCharacterMatchFound = true;
8617                }
8618            }
8619        }
8620
8621        return score;
8622    }
8623
8624    // startsWith
8625    //-----------------------------------------------------------------------
8626
8627    /**
8628     * <p>Check if a CharSequence starts with a specified prefix.</p>
8629     *
8630     * <p>{@code null}s are handled without exceptions. Two {@code null}
8631     * references are considered to be equal. The comparison is case sensitive.</p>
8632     *
8633     * <pre>
8634     * StringUtils.startsWith(null, null)      = true
8635     * StringUtils.startsWith(null, "abc")     = false
8636     * StringUtils.startsWith("abcdef", null)  = false
8637     * StringUtils.startsWith("abcdef", "abc") = true
8638     * StringUtils.startsWith("ABCDEF", "abc") = false
8639     * </pre>
8640     *
8641     * @see java.lang.String#startsWith(String)
8642     * @param str  the CharSequence to check, may be null
8643     * @param prefix the prefix to find, may be null
8644     * @return {@code true} if the CharSequence starts with the prefix, case sensitive, or
8645     *  both {@code null}
8646     * @since 2.4
8647     * @since 3.0 Changed signature from startsWith(String, String) to startsWith(CharSequence, CharSequence)
8648     */
8649    public static boolean startsWith(final CharSequence str, final CharSequence prefix) {
8650        return startsWith(str, prefix, false);
8651    }
8652
8653    /**
8654     * <p>Case insensitive check if a CharSequence starts with a specified prefix.</p>
8655     *
8656     * <p>{@code null}s are handled without exceptions. Two {@code null}
8657     * references are considered to be equal. The comparison is case insensitive.</p>
8658     *
8659     * <pre>
8660     * StringUtils.startsWithIgnoreCase(null, null)      = true
8661     * StringUtils.startsWithIgnoreCase(null, "abc")     = false
8662     * StringUtils.startsWithIgnoreCase("abcdef", null)  = false
8663     * StringUtils.startsWithIgnoreCase("abcdef", "abc") = true
8664     * StringUtils.startsWithIgnoreCase("ABCDEF", "abc") = true
8665     * </pre>
8666     *
8667     * @see java.lang.String#startsWith(String)
8668     * @param str  the CharSequence to check, may be null
8669     * @param prefix the prefix to find, may be null
8670     * @return {@code true} if the CharSequence starts with the prefix, case insensitive, or
8671     *  both {@code null}
8672     * @since 2.4
8673     * @since 3.0 Changed signature from startsWithIgnoreCase(String, String) to startsWithIgnoreCase(CharSequence, CharSequence)
8674     */
8675    public static boolean startsWithIgnoreCase(final CharSequence str, final CharSequence prefix) {
8676        return startsWith(str, prefix, true);
8677    }
8678
8679    /**
8680     * <p>Check if a CharSequence starts with a specified prefix (optionally case insensitive).</p>
8681     *
8682     * @see java.lang.String#startsWith(String)
8683     * @param str  the CharSequence to check, may be null
8684     * @param prefix the prefix to find, may be null
8685     * @param ignoreCase indicates whether the compare should ignore case
8686     *  (case insensitive) or not.
8687     * @return {@code true} if the CharSequence starts with the prefix or
8688     *  both {@code null}
8689     */
8690    private static boolean startsWith(final CharSequence str, final CharSequence prefix, final boolean ignoreCase) {
8691        if (str == null || prefix == null) {
8692            return str == prefix;
8693        }
8694        if (prefix.length() > str.length()) {
8695            return false;
8696        }
8697        return CharSequenceUtils.regionMatches(str, ignoreCase, 0, prefix, 0, prefix.length());
8698    }
8699
8700    /**
8701     * <p>Check if a CharSequence starts with any of the provided case-sensitive prefixes.</p>
8702     *
8703     * <pre>
8704     * StringUtils.startsWithAny(null, null)      = false
8705     * StringUtils.startsWithAny(null, new String[] {"abc"})  = false
8706     * StringUtils.startsWithAny("abcxyz", null)     = false
8707     * StringUtils.startsWithAny("abcxyz", new String[] {""}) = true
8708     * StringUtils.startsWithAny("abcxyz", new String[] {"abc"}) = true
8709     * StringUtils.startsWithAny("abcxyz", new String[] {null, "xyz", "abc"}) = true
8710     * StringUtils.startsWithAny("abcxyz", null, "xyz", "ABCX") = false
8711     * StringUtils.startsWithAny("ABCXYZ", null, "xyz", "abc") = false
8712     * </pre>
8713     *
8714     * @param sequence the CharSequence to check, may be null
8715     * @param searchStrings the case-sensitive CharSequence prefixes, may be empty or contain {@code null}
8716     * @see StringUtils#startsWith(CharSequence, CharSequence)
8717     * @return {@code true} if the input {@code sequence} is {@code null} AND no {@code searchStrings} are provided, or
8718     *   the input {@code sequence} begins with any of the provided case-sensitive {@code searchStrings}.
8719     * @since 2.5
8720     * @since 3.0 Changed signature from startsWithAny(String, String[]) to startsWithAny(CharSequence, CharSequence...)
8721     */
8722    public static boolean startsWithAny(final CharSequence sequence, final CharSequence... searchStrings) {
8723        if (isEmpty(sequence) || ArrayUtils.isEmpty(searchStrings)) {
8724            return false;
8725        }
8726        for (final CharSequence searchString : searchStrings) {
8727            if (startsWith(sequence, searchString)) {
8728                return true;
8729            }
8730        }
8731        return false;
8732    }
8733
8734    // endsWith
8735    //-----------------------------------------------------------------------
8736
8737    /**
8738     * <p>Check if a CharSequence ends with a specified suffix.</p>
8739     *
8740     * <p>{@code null}s are handled without exceptions. Two {@code null}
8741     * references are considered to be equal. The comparison is case sensitive.</p>
8742     *
8743     * <pre>
8744     * StringUtils.endsWith(null, null)      = true
8745     * StringUtils.endsWith(null, "def")     = false
8746     * StringUtils.endsWith("abcdef", null)  = false
8747     * StringUtils.endsWith("abcdef", "def") = true
8748     * StringUtils.endsWith("ABCDEF", "def") = false
8749     * StringUtils.endsWith("ABCDEF", "cde") = false
8750     * StringUtils.endsWith("ABCDEF", "")    = true
8751     * </pre>
8752     *
8753     * @see java.lang.String#endsWith(String)
8754     * @param str  the CharSequence to check, may be null
8755     * @param suffix the suffix to find, may be null
8756     * @return {@code true} if the CharSequence ends with the suffix, case sensitive, or
8757     *  both {@code null}
8758     * @since 2.4
8759     * @since 3.0 Changed signature from endsWith(String, String) to endsWith(CharSequence, CharSequence)
8760     */
8761    public static boolean endsWith(final CharSequence str, final CharSequence suffix) {
8762        return endsWith(str, suffix, false);
8763    }
8764
8765    /**
8766     * <p>Case insensitive check if a CharSequence ends with a specified suffix.</p>
8767     *
8768     * <p>{@code null}s are handled without exceptions. Two {@code null}
8769     * references are considered to be equal. The comparison is case insensitive.</p>
8770     *
8771     * <pre>
8772     * StringUtils.endsWithIgnoreCase(null, null)      = true
8773     * StringUtils.endsWithIgnoreCase(null, "def")     = false
8774     * StringUtils.endsWithIgnoreCase("abcdef", null)  = false
8775     * StringUtils.endsWithIgnoreCase("abcdef", "def") = true
8776     * StringUtils.endsWithIgnoreCase("ABCDEF", "def") = true
8777     * StringUtils.endsWithIgnoreCase("ABCDEF", "cde") = false
8778     * </pre>
8779     *
8780     * @see java.lang.String#endsWith(String)
8781     * @param str  the CharSequence to check, may be null
8782     * @param suffix the suffix to find, may be null
8783     * @return {@code true} if the CharSequence ends with the suffix, case insensitive, or
8784     *  both {@code null}
8785     * @since 2.4
8786     * @since 3.0 Changed signature from endsWithIgnoreCase(String, String) to endsWithIgnoreCase(CharSequence, CharSequence)
8787     */
8788    public static boolean endsWithIgnoreCase(final CharSequence str, final CharSequence suffix) {
8789        return endsWith(str, suffix, true);
8790    }
8791
8792    /**
8793     * <p>Check if a CharSequence ends with a specified suffix (optionally case insensitive).</p>
8794     *
8795     * @see java.lang.String#endsWith(String)
8796     * @param str  the CharSequence to check, may be null
8797     * @param suffix the suffix to find, may be null
8798     * @param ignoreCase indicates whether the compare should ignore case
8799     *  (case insensitive) or not.
8800     * @return {@code true} if the CharSequence starts with the prefix or
8801     *  both {@code null}
8802     */
8803    private static boolean endsWith(final CharSequence str, final CharSequence suffix, final boolean ignoreCase) {
8804        if (str == null || suffix == null) {
8805            return str == suffix;
8806        }
8807        if (suffix.length() > str.length()) {
8808            return false;
8809        }
8810        final int strOffset = str.length() - suffix.length();
8811        return CharSequenceUtils.regionMatches(str, ignoreCase, strOffset, suffix, 0, suffix.length());
8812    }
8813
8814    /**
8815     * <p>
8816     * Similar to <a
8817     * href="http://www.w3.org/TR/xpath/#function-normalize-space">http://www.w3.org/TR/xpath/#function-normalize
8818     * -space</a>
8819     * </p>
8820     * <p>
8821     * The function returns the argument string with whitespace normalized by using
8822     * <code>{@link #trim(String)}</code> to remove leading and trailing whitespace
8823     * and then replacing sequences of whitespace characters by a single space.
8824     * </p>
8825     * In XML Whitespace characters are the same as those allowed by the <a
8826     * href="http://www.w3.org/TR/REC-xml/#NT-S">S</a> production, which is S ::= (#x20 | #x9 | #xD | #xA)+
8827     * <p>
8828     * Java's regexp pattern \s defines whitespace as [ \t\n\x0B\f\r]
8829     *
8830     * <p>For reference:</p>
8831     * <ul>
8832     * <li>\x0B = vertical tab</li>
8833     * <li>\f = #xC = form feed</li>
8834     * <li>#x20 = space</li>
8835     * <li>#x9 = \t</li>
8836     * <li>#xA = \n</li>
8837     * <li>#xD = \r</li>
8838     * </ul>
8839     *
8840     * <p>
8841     * The difference is that Java's whitespace includes vertical tab and form feed, which this functional will also
8842     * normalize. Additionally <code>{@link #trim(String)}</code> removes control characters (char &lt;= 32) from both
8843     * ends of this String.
8844     * </p>
8845     *
8846     * @see Pattern
8847     * @see #trim(String)
8848     * @see <a
8849     *      href="http://www.w3.org/TR/xpath/#function-normalize-space">http://www.w3.org/TR/xpath/#function-normalize-space</a>
8850     * @param str the source String to normalize whitespaces from, may be null
8851     * @return the modified string with whitespace normalized, {@code null} if null String input
8852     *
8853     * @since 3.0
8854     */
8855    public static String normalizeSpace(final String str) {
8856        // LANG-1020: Improved performance significantly by normalizing manually instead of using regex
8857        // See https://github.com/librucha/commons-lang-normalizespaces-benchmark for performance test
8858        if (isEmpty(str)) {
8859            return str;
8860        }
8861        final int size = str.length();
8862        final char[] newChars = new char[size];
8863        int count = 0;
8864        int whitespacesCount = 0;
8865        boolean startWhitespaces = true;
8866        for (int i = 0; i < size; i++) {
8867            final char actualChar = str.charAt(i);
8868            final boolean isWhitespace = Character.isWhitespace(actualChar);
8869            if (isWhitespace) {
8870                if (whitespacesCount == 0 && !startWhitespaces) {
8871                    newChars[count++] = SPACE.charAt(0);
8872                }
8873                whitespacesCount++;
8874            } else {
8875                startWhitespaces = false;
8876                newChars[count++] = (actualChar == 160 ? 32 : actualChar);
8877                whitespacesCount = 0;
8878            }
8879        }
8880        if (startWhitespaces) {
8881            return EMPTY;
8882        }
8883        return new String(newChars, 0, count - (whitespacesCount > 0 ? 1 : 0)).trim();
8884    }
8885
8886    /**
8887     * <p>Check if a CharSequence ends with any of the provided case-sensitive suffixes.</p>
8888     *
8889     * <pre>
8890     * StringUtils.endsWithAny(null, null)      = false
8891     * StringUtils.endsWithAny(null, new String[] {"abc"})  = false
8892     * StringUtils.endsWithAny("abcxyz", null)     = false
8893     * StringUtils.endsWithAny("abcxyz", new String[] {""}) = true
8894     * StringUtils.endsWithAny("abcxyz", new String[] {"xyz"}) = true
8895     * StringUtils.endsWithAny("abcxyz", new String[] {null, "xyz", "abc"}) = true
8896     * StringUtils.endsWithAny("abcXYZ", "def", "XYZ") = true
8897     * StringUtils.endsWithAny("abcXYZ", "def", "xyz") = false
8898     * </pre>
8899     *
8900     * @param sequence  the CharSequence to check, may be null
8901     * @param searchStrings the case-sensitive CharSequences to find, may be empty or contain {@code null}
8902     * @see StringUtils#endsWith(CharSequence, CharSequence)
8903     * @return {@code true} if the input {@code sequence} is {@code null} AND no {@code searchStrings} are provided, or
8904     *   the input {@code sequence} ends in any of the provided case-sensitive {@code searchStrings}.
8905     * @since 3.0
8906     */
8907    public static boolean endsWithAny(final CharSequence sequence, final CharSequence... searchStrings) {
8908        if (isEmpty(sequence) || ArrayUtils.isEmpty(searchStrings)) {
8909            return false;
8910        }
8911        for (final CharSequence searchString : searchStrings) {
8912            if (endsWith(sequence, searchString)) {
8913                return true;
8914            }
8915        }
8916        return false;
8917    }
8918
8919    /**
8920     * Appends the suffix to the end of the string if the string does not
8921     * already end with the suffix.
8922     *
8923     * @param str The string.
8924     * @param suffix The suffix to append to the end of the string.
8925     * @param ignoreCase Indicates whether the compare should ignore case.
8926     * @param suffixes Additional suffixes that are valid terminators (optional).
8927     *
8928     * @return A new String if suffix was appended, the same string otherwise.
8929     */
8930    private static String appendIfMissing(final String str, final CharSequence suffix, final boolean ignoreCase, final CharSequence... suffixes) {
8931        if (str == null || isEmpty(suffix) || endsWith(str, suffix, ignoreCase)) {
8932            return str;
8933        }
8934        if (suffixes != null && suffixes.length > 0) {
8935            for (final CharSequence s : suffixes) {
8936                if (endsWith(str, s, ignoreCase)) {
8937                    return str;
8938                }
8939            }
8940        }
8941        return str + suffix.toString();
8942    }
8943
8944    /**
8945     * Appends the suffix to the end of the string if the string does not
8946     * already end with any of the suffixes.
8947     *
8948     * <pre>
8949     * StringUtils.appendIfMissing(null, null) = null
8950     * StringUtils.appendIfMissing("abc", null) = "abc"
8951     * StringUtils.appendIfMissing("", "xyz") = "xyz"
8952     * StringUtils.appendIfMissing("abc", "xyz") = "abcxyz"
8953     * StringUtils.appendIfMissing("abcxyz", "xyz") = "abcxyz"
8954     * StringUtils.appendIfMissing("abcXYZ", "xyz") = "abcXYZxyz"
8955     * </pre>
8956     * <p>With additional suffixes,</p>
8957     * <pre>
8958     * StringUtils.appendIfMissing(null, null, null) = null
8959     * StringUtils.appendIfMissing("abc", null, null) = "abc"
8960     * StringUtils.appendIfMissing("", "xyz", null) = "xyz"
8961     * StringUtils.appendIfMissing("abc", "xyz", new CharSequence[]{null}) = "abcxyz"
8962     * StringUtils.appendIfMissing("abc", "xyz", "") = "abc"
8963     * StringUtils.appendIfMissing("abc", "xyz", "mno") = "abcxyz"
8964     * StringUtils.appendIfMissing("abcxyz", "xyz", "mno") = "abcxyz"
8965     * StringUtils.appendIfMissing("abcmno", "xyz", "mno") = "abcmno"
8966     * StringUtils.appendIfMissing("abcXYZ", "xyz", "mno") = "abcXYZxyz"
8967     * StringUtils.appendIfMissing("abcMNO", "xyz", "mno") = "abcMNOxyz"
8968     * </pre>
8969     *
8970     * @param str The string.
8971     * @param suffix The suffix to append to the end of the string.
8972     * @param suffixes Additional suffixes that are valid terminators.
8973     *
8974     * @return A new String if suffix was appended, the same string otherwise.
8975     *
8976     * @since 3.2
8977     */
8978    public static String appendIfMissing(final String str, final CharSequence suffix, final CharSequence... suffixes) {
8979        return appendIfMissing(str, suffix, false, suffixes);
8980    }
8981
8982    /**
8983     * Appends the suffix to the end of the string if the string does not
8984     * already end, case insensitive, with any of the suffixes.
8985     *
8986     * <pre>
8987     * StringUtils.appendIfMissingIgnoreCase(null, null) = null
8988     * StringUtils.appendIfMissingIgnoreCase("abc", null) = "abc"
8989     * StringUtils.appendIfMissingIgnoreCase("", "xyz") = "xyz"
8990     * StringUtils.appendIfMissingIgnoreCase("abc", "xyz") = "abcxyz"
8991     * StringUtils.appendIfMissingIgnoreCase("abcxyz", "xyz") = "abcxyz"
8992     * StringUtils.appendIfMissingIgnoreCase("abcXYZ", "xyz") = "abcXYZ"
8993     * </pre>
8994     * <p>With additional suffixes,</p>
8995     * <pre>
8996     * StringUtils.appendIfMissingIgnoreCase(null, null, null) = null
8997     * StringUtils.appendIfMissingIgnoreCase("abc", null, null) = "abc"
8998     * StringUtils.appendIfMissingIgnoreCase("", "xyz", null) = "xyz"
8999     * StringUtils.appendIfMissingIgnoreCase("abc", "xyz", new CharSequence[]{null}) = "abcxyz"
9000     * StringUtils.appendIfMissingIgnoreCase("abc", "xyz", "") = "abc"
9001     * StringUtils.appendIfMissingIgnoreCase("abc", "xyz", "mno") = "axyz"
9002     * StringUtils.appendIfMissingIgnoreCase("abcxyz", "xyz", "mno") = "abcxyz"
9003     * StringUtils.appendIfMissingIgnoreCase("abcmno", "xyz", "mno") = "abcmno"
9004     * StringUtils.appendIfMissingIgnoreCase("abcXYZ", "xyz", "mno") = "abcXYZ"
9005     * StringUtils.appendIfMissingIgnoreCase("abcMNO", "xyz", "mno") = "abcMNO"
9006     * </pre>
9007     *
9008     * @param str The string.
9009     * @param suffix The suffix to append to the end of the string.
9010     * @param suffixes Additional suffixes that are valid terminators.
9011     *
9012     * @return A new String if suffix was appended, the same string otherwise.
9013     *
9014     * @since 3.2
9015     */
9016    public static String appendIfMissingIgnoreCase(final String str, final CharSequence suffix, final CharSequence... suffixes) {
9017        return appendIfMissing(str, suffix, true, suffixes);
9018    }
9019
9020    /**
9021     * Prepends the prefix to the start of the string if the string does not
9022     * already start with any of the prefixes.
9023     *
9024     * @param str The string.
9025     * @param prefix The prefix to prepend to the start of the string.
9026     * @param ignoreCase Indicates whether the compare should ignore case.
9027     * @param prefixes Additional prefixes that are valid (optional).
9028     *
9029     * @return A new String if prefix was prepended, the same string otherwise.
9030     */
9031    private static String prependIfMissing(final String str, final CharSequence prefix, final boolean ignoreCase, final CharSequence... prefixes) {
9032        if (str == null || isEmpty(prefix) || startsWith(str, prefix, ignoreCase)) {
9033            return str;
9034        }
9035        if (prefixes != null && prefixes.length > 0) {
9036            for (final CharSequence p : prefixes) {
9037                if (startsWith(str, p, ignoreCase)) {
9038                    return str;
9039                }
9040            }
9041        }
9042        return prefix.toString() + str;
9043    }
9044
9045    /**
9046     * Prepends the prefix to the start of the string if the string does not
9047     * already start with any of the prefixes.
9048     *
9049     * <pre>
9050     * StringUtils.prependIfMissing(null, null) = null
9051     * StringUtils.prependIfMissing("abc", null) = "abc"
9052     * StringUtils.prependIfMissing("", "xyz") = "xyz"
9053     * StringUtils.prependIfMissing("abc", "xyz") = "xyzabc"
9054     * StringUtils.prependIfMissing("xyzabc", "xyz") = "xyzabc"
9055     * StringUtils.prependIfMissing("XYZabc", "xyz") = "xyzXYZabc"
9056     * </pre>
9057     * <p>With additional prefixes,</p>
9058     * <pre>
9059     * StringUtils.prependIfMissing(null, null, null) = null
9060     * StringUtils.prependIfMissing("abc", null, null) = "abc"
9061     * StringUtils.prependIfMissing("", "xyz", null) = "xyz"
9062     * StringUtils.prependIfMissing("abc", "xyz", new CharSequence[]{null}) = "xyzabc"
9063     * StringUtils.prependIfMissing("abc", "xyz", "") = "abc"
9064     * StringUtils.prependIfMissing("abc", "xyz", "mno") = "xyzabc"
9065     * StringUtils.prependIfMissing("xyzabc", "xyz", "mno") = "xyzabc"
9066     * StringUtils.prependIfMissing("mnoabc", "xyz", "mno") = "mnoabc"
9067     * StringUtils.prependIfMissing("XYZabc", "xyz", "mno") = "xyzXYZabc"
9068     * StringUtils.prependIfMissing("MNOabc", "xyz", "mno") = "xyzMNOabc"
9069     * </pre>
9070     *
9071     * @param str The string.
9072     * @param prefix The prefix to prepend to the start of the string.
9073     * @param prefixes Additional prefixes that are valid.
9074     *
9075     * @return A new String if prefix was prepended, the same string otherwise.
9076     *
9077     * @since 3.2
9078     */
9079    public static String prependIfMissing(final String str, final CharSequence prefix, final CharSequence... prefixes) {
9080        return prependIfMissing(str, prefix, false, prefixes);
9081    }
9082
9083    /**
9084     * Prepends the prefix to the start of the string if the string does not
9085     * already start, case insensitive, with any of the prefixes.
9086     *
9087     * <pre>
9088     * StringUtils.prependIfMissingIgnoreCase(null, null) = null
9089     * StringUtils.prependIfMissingIgnoreCase("abc", null) = "abc"
9090     * StringUtils.prependIfMissingIgnoreCase("", "xyz") = "xyz"
9091     * StringUtils.prependIfMissingIgnoreCase("abc", "xyz") = "xyzabc"
9092     * StringUtils.prependIfMissingIgnoreCase("xyzabc", "xyz") = "xyzabc"
9093     * StringUtils.prependIfMissingIgnoreCase("XYZabc", "xyz") = "XYZabc"
9094     * </pre>
9095     * <p>With additional prefixes,</p>
9096     * <pre>
9097     * StringUtils.prependIfMissingIgnoreCase(null, null, null) = null
9098     * StringUtils.prependIfMissingIgnoreCase("abc", null, null) = "abc"
9099     * StringUtils.prependIfMissingIgnoreCase("", "xyz", null) = "xyz"
9100     * StringUtils.prependIfMissingIgnoreCase("abc", "xyz", new CharSequence[]{null}) = "xyzabc"
9101     * StringUtils.prependIfMissingIgnoreCase("abc", "xyz", "") = "abc"
9102     * StringUtils.prependIfMissingIgnoreCase("abc", "xyz", "mno") = "xyzabc"
9103     * StringUtils.prependIfMissingIgnoreCase("xyzabc", "xyz", "mno") = "xyzabc"
9104     * StringUtils.prependIfMissingIgnoreCase("mnoabc", "xyz", "mno") = "mnoabc"
9105     * StringUtils.prependIfMissingIgnoreCase("XYZabc", "xyz", "mno") = "XYZabc"
9106     * StringUtils.prependIfMissingIgnoreCase("MNOabc", "xyz", "mno") = "MNOabc"
9107     * </pre>
9108     *
9109     * @param str The string.
9110     * @param prefix The prefix to prepend to the start of the string.
9111     * @param prefixes Additional prefixes that are valid (optional).
9112     *
9113     * @return A new String if prefix was prepended, the same string otherwise.
9114     *
9115     * @since 3.2
9116     */
9117    public static String prependIfMissingIgnoreCase(final String str, final CharSequence prefix, final CharSequence... prefixes) {
9118        return prependIfMissing(str, prefix, true, prefixes);
9119    }
9120
9121    /**
9122     * Converts a <code>byte[]</code> to a String using the specified character encoding.
9123     *
9124     * @param bytes
9125     *            the byte array to read from
9126     * @param charsetName
9127     *            the encoding to use, if null then use the platform default
9128     * @return a new String
9129     * @throws UnsupportedEncodingException
9130     *             If the named charset is not supported
9131     * @throws NullPointerException
9132     *             if the input is null
9133     * @deprecated use {@link StringUtils#toEncodedString(byte[], Charset)} instead of String constants in your code
9134     * @since 3.1
9135     */
9136    @Deprecated
9137    public static String toString(final byte[] bytes, final String charsetName) throws UnsupportedEncodingException {
9138        return charsetName != null ? new String(bytes, charsetName) : new String(bytes, Charset.defaultCharset());
9139    }
9140
9141    /**
9142     * Converts a <code>byte[]</code> to a String using the specified character encoding.
9143     *
9144     * @param bytes
9145     *            the byte array to read from
9146     * @param charset
9147     *            the encoding to use, if null then use the platform default
9148     * @return a new String
9149     * @throws NullPointerException
9150     *             if {@code bytes} is null
9151     * @since 3.2
9152     * @since 3.3 No longer throws {@link UnsupportedEncodingException}.
9153     */
9154    public static String toEncodedString(final byte[] bytes, final Charset charset) {
9155        return new String(bytes, charset != null ? charset : Charset.defaultCharset());
9156    }
9157
9158    /**
9159     * <p>
9160     * Wraps a string with a char.
9161     * </p>
9162     *
9163     * <pre>
9164     * StringUtils.wrap(null, *)        = null
9165     * StringUtils.wrap("", *)          = ""
9166     * StringUtils.wrap("ab", '\0')     = "ab"
9167     * StringUtils.wrap("ab", 'x')      = "xabx"
9168     * StringUtils.wrap("ab", '\'')     = "'ab'"
9169     * StringUtils.wrap("\"ab\"", '\"') = "\"\"ab\"\""
9170     * </pre>
9171     *
9172     * @param str
9173     *            the string to be wrapped, may be {@code null}
9174     * @param wrapWith
9175     *            the char that will wrap {@code str}
9176     * @return the wrapped string, or {@code null} if {@code str==null}
9177     * @since 3.4
9178     */
9179    public static String wrap(final String str, final char wrapWith) {
9180
9181        if (isEmpty(str) || wrapWith == CharUtils.NUL) {
9182            return str;
9183        }
9184
9185        return wrapWith + str + wrapWith;
9186    }
9187
9188    /**
9189     * <p>
9190     * Wraps a String with another String.
9191     * </p>
9192     *
9193     * <p>
9194     * A {@code null} input String returns {@code null}.
9195     * </p>
9196     *
9197     * <pre>
9198     * StringUtils.wrap(null, *)         = null
9199     * StringUtils.wrap("", *)           = ""
9200     * StringUtils.wrap("ab", null)      = "ab"
9201     * StringUtils.wrap("ab", "x")       = "xabx"
9202     * StringUtils.wrap("ab", "\"")      = "\"ab\""
9203     * StringUtils.wrap("\"ab\"", "\"")  = "\"\"ab\"\""
9204     * StringUtils.wrap("ab", "'")       = "'ab'"
9205     * StringUtils.wrap("'abcd'", "'")   = "''abcd''"
9206     * StringUtils.wrap("\"abcd\"", "'") = "'\"abcd\"'"
9207     * StringUtils.wrap("'abcd'", "\"")  = "\"'abcd'\""
9208     * </pre>
9209     *
9210     * @param str
9211     *            the String to be wrapper, may be null
9212     * @param wrapWith
9213     *            the String that will wrap str
9214     * @return wrapped String, {@code null} if null String input
9215     * @since 3.4
9216     */
9217    public static String wrap(final String str, final String wrapWith) {
9218
9219        if (isEmpty(str) || isEmpty(wrapWith)) {
9220            return str;
9221        }
9222
9223        return wrapWith.concat(str).concat(wrapWith);
9224    }
9225
9226    /**
9227     * <p>
9228     * Wraps a string with a char if that char is missing from the start or end of the given string.
9229     * </p>
9230     *
9231     * <pre>
9232     * StringUtils.wrapIfMissing(null, *)        = null
9233     * StringUtils.wrapIfMissing("", *)          = ""
9234     * StringUtils.wrapIfMissing("ab", '\0')     = "ab"
9235     * StringUtils.wrapIfMissing("ab", 'x')      = "xabx"
9236     * StringUtils.wrapIfMissing("ab", '\'')     = "'ab'"
9237     * StringUtils.wrapIfMissing("\"ab\"", '\"') = "\"ab\""
9238     * StringUtils.wrapIfMissing("/", '/')  = "/"
9239     * StringUtils.wrapIfMissing("a/b/c", '/')  = "/a/b/c/"
9240     * StringUtils.wrapIfMissing("/a/b/c", '/')  = "/a/b/c/"
9241     * StringUtils.wrapIfMissing("a/b/c/", '/')  = "/a/b/c/"
9242     * </pre>
9243     *
9244     * @param str
9245     *            the string to be wrapped, may be {@code null}
9246     * @param wrapWith
9247     *            the char that will wrap {@code str}
9248     * @return the wrapped string, or {@code null} if {@code str==null}
9249     * @since 3.5
9250     */
9251    public static String wrapIfMissing(final String str, final char wrapWith) {
9252        if (isEmpty(str) || wrapWith == CharUtils.NUL) {
9253            return str;
9254        }
9255        final StringBuilder builder = new StringBuilder(str.length() + 2);
9256        if (str.charAt(0) != wrapWith) {
9257            builder.append(wrapWith);
9258        }
9259        builder.append(str);
9260        if (str.charAt(str.length() - 1) != wrapWith) {
9261            builder.append(wrapWith);
9262        }
9263        return builder.toString();
9264    }
9265
9266    /**
9267     * <p>
9268     * Wraps a string with a string if that string is missing from the start or end of the given string.
9269     * </p>
9270     *
9271     * <pre>
9272     * StringUtils.wrapIfMissing(null, *)         = null
9273     * StringUtils.wrapIfMissing("", *)           = ""
9274     * StringUtils.wrapIfMissing("ab", null)      = "ab"
9275     * StringUtils.wrapIfMissing("ab", "x")       = "xabx"
9276     * StringUtils.wrapIfMissing("ab", "\"")      = "\"ab\""
9277     * StringUtils.wrapIfMissing("\"ab\"", "\"")  = "\"ab\""
9278     * StringUtils.wrapIfMissing("ab", "'")       = "'ab'"
9279     * StringUtils.wrapIfMissing("'abcd'", "'")   = "'abcd'"
9280     * StringUtils.wrapIfMissing("\"abcd\"", "'") = "'\"abcd\"'"
9281     * StringUtils.wrapIfMissing("'abcd'", "\"")  = "\"'abcd'\""
9282     * StringUtils.wrapIfMissing("/", "/")  = "/"
9283     * StringUtils.wrapIfMissing("a/b/c", "/")  = "/a/b/c/"
9284     * StringUtils.wrapIfMissing("/a/b/c", "/")  = "/a/b/c/"
9285     * StringUtils.wrapIfMissing("a/b/c/", "/")  = "/a/b/c/"
9286     * </pre>
9287     *
9288     * @param str
9289     *            the string to be wrapped, may be {@code null}
9290     * @param wrapWith
9291     *            the char that will wrap {@code str}
9292     * @return the wrapped string, or {@code null} if {@code str==null}
9293     * @since 3.5
9294     */
9295    public static String wrapIfMissing(final String str, final String wrapWith) {
9296        if (isEmpty(str) || isEmpty(wrapWith)) {
9297            return str;
9298        }
9299        final StringBuilder builder = new StringBuilder(str.length() + wrapWith.length() + wrapWith.length());
9300        if (!str.startsWith(wrapWith)) {
9301            builder.append(wrapWith);
9302        }
9303        builder.append(str);
9304        if (!str.endsWith(wrapWith)) {
9305            builder.append(wrapWith);
9306        }
9307        return builder.toString();
9308    }
9309
9310    /**
9311     * <p>
9312     * Unwraps a given string from anther string.
9313     * </p>
9314     *
9315     * <pre>
9316     * StringUtils.unwrap(null, null)         = null
9317     * StringUtils.unwrap(null, "")           = null
9318     * StringUtils.unwrap(null, "1")          = null
9319     * StringUtils.unwrap("\'abc\'", "\'")    = "abc"
9320     * StringUtils.unwrap("\"abc\"", "\"")    = "abc"
9321     * StringUtils.unwrap("AABabcBAA", "AA")  = "BabcB"
9322     * StringUtils.unwrap("A", "#")           = "A"
9323     * StringUtils.unwrap("#A", "#")          = "#A"
9324     * StringUtils.unwrap("A#", "#")          = "A#"
9325     * </pre>
9326     *
9327     * @param str
9328     *          the String to be unwrapped, can be null
9329     * @param wrapToken
9330     *          the String used to unwrap
9331     * @return unwrapped String or the original string
9332     *          if it is not quoted properly with the wrapToken
9333     * @since 3.6
9334     */
9335    public static String unwrap(final String str, final String wrapToken) {
9336        if (isEmpty(str) || isEmpty(wrapToken)) {
9337            return str;
9338        }
9339
9340        if (startsWith(str, wrapToken) && endsWith(str, wrapToken)) {
9341            final int startIndex = str.indexOf(wrapToken);
9342            final int endIndex = str.lastIndexOf(wrapToken);
9343            final int wrapLength = wrapToken.length();
9344            if (startIndex != -1 && endIndex != -1) {
9345                return str.substring(startIndex + wrapLength, endIndex);
9346            }
9347        }
9348
9349        return str;
9350    }
9351
9352    /**
9353     * <p>
9354     * Unwraps a given string from a character.
9355     * </p>
9356     *
9357     * <pre>
9358     * StringUtils.unwrap(null, null)         = null
9359     * StringUtils.unwrap(null, '\0')         = null
9360     * StringUtils.unwrap(null, '1')          = null
9361     * StringUtils.unwrap("\'abc\'", '\'')    = "abc"
9362     * StringUtils.unwrap("AABabcBAA", 'A')  = "ABabcBA"
9363     * StringUtils.unwrap("A", '#')           = "A"
9364     * StringUtils.unwrap("#A", '#')          = "#A"
9365     * StringUtils.unwrap("A#", '#')          = "A#"
9366     * </pre>
9367     *
9368     * @param str
9369     *          the String to be unwrapped, can be null
9370     * @param wrapChar
9371     *          the character used to unwrap
9372     * @return unwrapped String or the original string
9373     *          if it is not quoted properly with the wrapChar
9374     * @since 3.6
9375     */
9376    public static String unwrap(final String str, final char wrapChar) {
9377        if (isEmpty(str) || wrapChar == CharUtils.NUL) {
9378            return str;
9379        }
9380
9381        if (str.charAt(0) == wrapChar && str.charAt(str.length() - 1) == wrapChar) {
9382            final int startIndex = 0;
9383            final int endIndex = str.length() - 1;
9384            if (endIndex != -1) {
9385                return str.substring(startIndex + 1, endIndex);
9386            }
9387        }
9388
9389        return str;
9390    }
9391
9392    /**
9393     * <p>Converts a {@code CharSequence} into an array of code points.</p>
9394     *
9395     * <p>Valid pairs of surrogate code units will be converted into a single supplementary
9396     * code point. Isolated surrogate code units (i.e. a high surrogate not followed by a low surrogate or
9397     * a low surrogate not preceded by a high surrogate) will be returned as-is.</p>
9398     *
9399     * <pre>
9400     * StringUtils.toCodePoints(null)   =  null
9401     * StringUtils.toCodePoints("")     =  []  // empty array
9402     * </pre>
9403     *
9404     * @param str the character sequence to convert
9405     * @return an array of code points
9406     * @since 3.6
9407     */
9408    public static int[] toCodePoints(final CharSequence str) {
9409        if (str == null) {
9410            return null;
9411        }
9412        if (str.length() == 0) {
9413            return ArrayUtils.EMPTY_INT_ARRAY;
9414        }
9415
9416        final String s = str.toString();
9417        final int[] result = new int[s.codePointCount(0, s.length())];
9418        int index = 0;
9419        for (int i = 0; i < result.length; i++) {
9420            result[i] = s.codePointAt(index);
9421            index += Character.charCount(result[i]);
9422        }
9423        return result;
9424    }
9425
9426    /**
9427     * Returns the string representation of the {@code char} array or null.
9428     *
9429     * @param value the character array.
9430     * @return a String or null
9431     * @see String#valueOf(char[])
9432     * @since 3.9
9433     */
9434    public static String valueOf(final char[] value) {
9435        return value == null ? null : String.valueOf(value);
9436    }
9437
9438}