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 case sensitive.</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     * @see Object#equals(Object)
995     * @param cs1  the first CharSequence, may be {@code null}
996     * @param cs2  the second CharSequence, may be {@code null}
997     * @return {@code true} if the CharSequences are equal (case-sensitive), or both {@code null}
998     * @since 3.0 Changed signature from equals(String, String) to equals(CharSequence, CharSequence)
999     */
1000    public static boolean equals(final CharSequence cs1, final CharSequence cs2) {
1001        if (cs1 == cs2) {
1002            return true;
1003        }
1004        if (cs1 == null || cs2 == null) {
1005            return false;
1006        }
1007        if (cs1.length() != cs2.length()) {
1008            return false;
1009        }
1010        if (cs1 instanceof String && cs2 instanceof String) {
1011            return cs1.equals(cs2);
1012        }
1013        return CharSequenceUtils.regionMatches(cs1, false, 0, cs2, 0, cs1.length());
1014    }
1015
1016    /**
1017     * <p>Compares two CharSequences, returning {@code true} if they represent
1018     * equal sequences of characters, ignoring case.</p>
1019     *
1020     * <p>{@code null}s are handled without exceptions. Two {@code null}
1021     * references are considered equal. Comparison is case insensitive.</p>
1022     *
1023     * <pre>
1024     * StringUtils.equalsIgnoreCase(null, null)   = true
1025     * StringUtils.equalsIgnoreCase(null, "abc")  = false
1026     * StringUtils.equalsIgnoreCase("abc", null)  = false
1027     * StringUtils.equalsIgnoreCase("abc", "abc") = true
1028     * StringUtils.equalsIgnoreCase("abc", "ABC") = true
1029     * </pre>
1030     *
1031     * @param str1  the first CharSequence, may be null
1032     * @param str2  the second CharSequence, may be null
1033     * @return {@code true} if the CharSequence are equal, case insensitive, or
1034     *  both {@code null}
1035     * @since 3.0 Changed signature from equalsIgnoreCase(String, String) to equalsIgnoreCase(CharSequence, CharSequence)
1036     */
1037    public static boolean equalsIgnoreCase(final CharSequence str1, final CharSequence str2) {
1038        if (str1 == null || str2 == null) {
1039            return str1 == str2;
1040        } else if (str1 == str2) {
1041            return true;
1042        } else if (str1.length() != str2.length()) {
1043            return false;
1044        } else {
1045            return CharSequenceUtils.regionMatches(str1, true, 0, str2, 0, str1.length());
1046        }
1047    }
1048
1049    // Compare
1050    //-----------------------------------------------------------------------
1051    /**
1052     * <p>Compare two Strings lexicographically, as per {@link String#compareTo(String)}, returning :</p>
1053     * <ul>
1054     *  <li>{@code int = 0}, if {@code str1} is equal to {@code str2} (or both {@code null})</li>
1055     *  <li>{@code int < 0}, if {@code str1} is less than {@code str2}</li>
1056     *  <li>{@code int > 0}, if {@code str1} is greater than {@code str2}</li>
1057     * </ul>
1058     *
1059     * <p>This is a {@code null} safe version of :</p>
1060     * <blockquote><pre>str1.compareTo(str2)</pre></blockquote>
1061     *
1062     * <p>{@code null} value is considered less than non-{@code null} value.
1063     * Two {@code null} references are considered equal.</p>
1064     *
1065     * <pre>
1066     * StringUtils.compare(null, null)   = 0
1067     * StringUtils.compare(null , "a")   &lt; 0
1068     * StringUtils.compare("a", null)    &gt; 0
1069     * StringUtils.compare("abc", "abc") = 0
1070     * StringUtils.compare("a", "b")     &lt; 0
1071     * StringUtils.compare("b", "a")     &gt; 0
1072     * StringUtils.compare("a", "B")     &gt; 0
1073     * StringUtils.compare("ab", "abc")  &lt; 0
1074     * </pre>
1075     *
1076     * @see #compare(String, String, boolean)
1077     * @see String#compareTo(String)
1078     * @param str1  the String to compare from
1079     * @param str2  the String to compare to
1080     * @return &lt; 0, 0, &gt; 0, if {@code str1} is respectively less, equal or greater than {@code str2}
1081     * @since 3.5
1082     */
1083    public static int compare(final String str1, final String str2) {
1084        return compare(str1, str2, true);
1085    }
1086
1087    /**
1088     * <p>Compare two Strings lexicographically, as per {@link String#compareTo(String)}, returning :</p>
1089     * <ul>
1090     *  <li>{@code int = 0}, if {@code str1} is equal to {@code str2} (or both {@code null})</li>
1091     *  <li>{@code int < 0}, if {@code str1} is less than {@code str2}</li>
1092     *  <li>{@code int > 0}, if {@code str1} is greater than {@code str2}</li>
1093     * </ul>
1094     *
1095     * <p>This is a {@code null} safe version of :</p>
1096     * <blockquote><pre>str1.compareTo(str2)</pre></blockquote>
1097     *
1098     * <p>{@code null} inputs are handled according to the {@code nullIsLess} parameter.
1099     * Two {@code null} references are considered equal.</p>
1100     *
1101     * <pre>
1102     * StringUtils.compare(null, null, *)     = 0
1103     * StringUtils.compare(null , "a", true)  &lt; 0
1104     * StringUtils.compare(null , "a", false) &gt; 0
1105     * StringUtils.compare("a", null, true)   &gt; 0
1106     * StringUtils.compare("a", null, false)  &lt; 0
1107     * StringUtils.compare("abc", "abc", *)   = 0
1108     * StringUtils.compare("a", "b", *)       &lt; 0
1109     * StringUtils.compare("b", "a", *)       &gt; 0
1110     * StringUtils.compare("a", "B", *)       &gt; 0
1111     * StringUtils.compare("ab", "abc", *)    &lt; 0
1112     * </pre>
1113     *
1114     * @see String#compareTo(String)
1115     * @param str1  the String to compare from
1116     * @param str2  the String to compare to
1117     * @param nullIsLess  whether consider {@code null} value less than non-{@code null} value
1118     * @return &lt; 0, 0, &gt; 0, if {@code str1} is respectively less, equal ou greater than {@code str2}
1119     * @since 3.5
1120     */
1121    public static int compare(final String str1, final String str2, final boolean nullIsLess) {
1122        if (str1 == str2) {
1123            return 0;
1124        }
1125        if (str1 == null) {
1126            return nullIsLess ? -1 : 1;
1127        }
1128        if (str2 == null) {
1129            return nullIsLess ? 1 : - 1;
1130        }
1131        return str1.compareTo(str2);
1132    }
1133
1134    /**
1135     * <p>Compare two Strings lexicographically, ignoring case differences,
1136     * as per {@link String#compareToIgnoreCase(String)}, returning :</p>
1137     * <ul>
1138     *  <li>{@code int = 0}, if {@code str1} is equal to {@code str2} (or both {@code null})</li>
1139     *  <li>{@code int < 0}, if {@code str1} is less than {@code str2}</li>
1140     *  <li>{@code int > 0}, if {@code str1} is greater than {@code str2}</li>
1141     * </ul>
1142     *
1143     * <p>This is a {@code null} safe version of :</p>
1144     * <blockquote><pre>str1.compareToIgnoreCase(str2)</pre></blockquote>
1145     *
1146     * <p>{@code null} value is considered less than non-{@code null} value.
1147     * Two {@code null} references are considered equal.
1148     * Comparison is case insensitive.</p>
1149     *
1150     * <pre>
1151     * StringUtils.compareIgnoreCase(null, null)   = 0
1152     * StringUtils.compareIgnoreCase(null , "a")   &lt; 0
1153     * StringUtils.compareIgnoreCase("a", null)    &gt; 0
1154     * StringUtils.compareIgnoreCase("abc", "abc") = 0
1155     * StringUtils.compareIgnoreCase("abc", "ABC") = 0
1156     * StringUtils.compareIgnoreCase("a", "b")     &lt; 0
1157     * StringUtils.compareIgnoreCase("b", "a")     &gt; 0
1158     * StringUtils.compareIgnoreCase("a", "B")     &lt; 0
1159     * StringUtils.compareIgnoreCase("A", "b")     &lt; 0
1160     * StringUtils.compareIgnoreCase("ab", "ABC")  &lt; 0
1161     * </pre>
1162     *
1163     * @see #compareIgnoreCase(String, String, boolean)
1164     * @see String#compareToIgnoreCase(String)
1165     * @param str1  the String to compare from
1166     * @param str2  the String to compare to
1167     * @return &lt; 0, 0, &gt; 0, if {@code str1} is respectively less, equal ou greater than {@code str2},
1168     *          ignoring case differences.
1169     * @since 3.5
1170     */
1171    public static int compareIgnoreCase(final String str1, final String str2) {
1172        return compareIgnoreCase(str1, str2, true);
1173    }
1174
1175    /**
1176     * <p>Compare two Strings lexicographically, ignoring case differences,
1177     * as per {@link String#compareToIgnoreCase(String)}, returning :</p>
1178     * <ul>
1179     *  <li>{@code int = 0}, if {@code str1} is equal to {@code str2} (or both {@code null})</li>
1180     *  <li>{@code int < 0}, if {@code str1} is less than {@code str2}</li>
1181     *  <li>{@code int > 0}, if {@code str1} is greater than {@code str2}</li>
1182     * </ul>
1183     *
1184     * <p>This is a {@code null} safe version of :</p>
1185     * <blockquote><pre>str1.compareToIgnoreCase(str2)</pre></blockquote>
1186     *
1187     * <p>{@code null} inputs are handled according to the {@code nullIsLess} parameter.
1188     * Two {@code null} references are considered equal.
1189     * Comparison is case insensitive.</p>
1190     *
1191     * <pre>
1192     * StringUtils.compareIgnoreCase(null, null, *)     = 0
1193     * StringUtils.compareIgnoreCase(null , "a", true)  &lt; 0
1194     * StringUtils.compareIgnoreCase(null , "a", false) &gt; 0
1195     * StringUtils.compareIgnoreCase("a", null, true)   &gt; 0
1196     * StringUtils.compareIgnoreCase("a", null, false)  &lt; 0
1197     * StringUtils.compareIgnoreCase("abc", "abc", *)   = 0
1198     * StringUtils.compareIgnoreCase("abc", "ABC", *)   = 0
1199     * StringUtils.compareIgnoreCase("a", "b", *)       &lt; 0
1200     * StringUtils.compareIgnoreCase("b", "a", *)       &gt; 0
1201     * StringUtils.compareIgnoreCase("a", "B", *)       &lt; 0
1202     * StringUtils.compareIgnoreCase("A", "b", *)       &lt; 0
1203     * StringUtils.compareIgnoreCase("ab", "abc", *)    &lt; 0
1204     * </pre>
1205     *
1206     * @see String#compareToIgnoreCase(String)
1207     * @param str1  the String to compare from
1208     * @param str2  the String to compare to
1209     * @param nullIsLess  whether consider {@code null} value less than non-{@code null} value
1210     * @return &lt; 0, 0, &gt; 0, if {@code str1} is respectively less, equal ou greater than {@code str2},
1211     *          ignoring case differences.
1212     * @since 3.5
1213     */
1214    public static int compareIgnoreCase(final String str1, final String str2, final boolean nullIsLess) {
1215        if (str1 == str2) {
1216            return 0;
1217        }
1218        if (str1 == null) {
1219            return nullIsLess ? -1 : 1;
1220        }
1221        if (str2 == null) {
1222            return nullIsLess ? 1 : - 1;
1223        }
1224        return str1.compareToIgnoreCase(str2);
1225    }
1226
1227    /**
1228     * <p>Compares given <code>string</code> to a CharSequences vararg of <code>searchStrings</code>,
1229     * returning {@code true} if the <code>string</code> is equal to any of the <code>searchStrings</code>.</p>
1230     *
1231     * <pre>
1232     * StringUtils.equalsAny(null, (CharSequence[]) null) = false
1233     * StringUtils.equalsAny(null, null, null)    = true
1234     * StringUtils.equalsAny(null, "abc", "def")  = false
1235     * StringUtils.equalsAny("abc", null, "def")  = false
1236     * StringUtils.equalsAny("abc", "abc", "def") = true
1237     * StringUtils.equalsAny("abc", "ABC", "DEF") = false
1238     * </pre>
1239     *
1240     * @param string to compare, may be {@code null}.
1241     * @param searchStrings a vararg of strings, may be {@code null}.
1242     * @return {@code true} if the string is equal (case-sensitive) to any other element of <code>searchStrings</code>;
1243     * {@code false} if <code>searchStrings</code> is null or contains no matches.
1244     * @since 3.5
1245     */
1246    public static boolean equalsAny(final CharSequence string, final CharSequence... searchStrings) {
1247        if (ArrayUtils.isNotEmpty(searchStrings)) {
1248            for (final CharSequence next : searchStrings) {
1249                if (equals(string, next)) {
1250                    return true;
1251                }
1252            }
1253        }
1254        return false;
1255    }
1256
1257
1258    /**
1259     * <p>Compares given <code>string</code> to a CharSequences vararg of <code>searchStrings</code>,
1260     * returning {@code true} if the <code>string</code> is equal to any of the <code>searchStrings</code>, ignoring case.</p>
1261     *
1262     * <pre>
1263     * StringUtils.equalsAnyIgnoreCase(null, (CharSequence[]) null) = false
1264     * StringUtils.equalsAnyIgnoreCase(null, null, null)    = true
1265     * StringUtils.equalsAnyIgnoreCase(null, "abc", "def")  = false
1266     * StringUtils.equalsAnyIgnoreCase("abc", null, "def")  = false
1267     * StringUtils.equalsAnyIgnoreCase("abc", "abc", "def") = true
1268     * StringUtils.equalsAnyIgnoreCase("abc", "ABC", "DEF") = true
1269     * </pre>
1270     *
1271     * @param string to compare, may be {@code null}.
1272     * @param searchStrings a vararg of strings, may be {@code null}.
1273     * @return {@code true} if the string is equal (case-insensitive) to any other element of <code>searchStrings</code>;
1274     * {@code false} if <code>searchStrings</code> is null or contains no matches.
1275     * @since 3.5
1276     */
1277    public static boolean equalsAnyIgnoreCase(final CharSequence string, final CharSequence...searchStrings) {
1278        if (ArrayUtils.isNotEmpty(searchStrings)) {
1279            for (final CharSequence next : searchStrings) {
1280                if (equalsIgnoreCase(string, next)) {
1281                    return true;
1282                }
1283            }
1284        }
1285        return false;
1286    }
1287
1288    // IndexOf
1289    //-----------------------------------------------------------------------
1290    /**
1291     * Returns the index within <code>seq</code> of the first occurrence of
1292     * the specified character. If a character with value
1293     * <code>searchChar</code> occurs in the character sequence represented by
1294     * <code>seq</code> <code>CharSequence</code> object, then the index (in Unicode
1295     * code units) of the first such occurrence is returned. For
1296     * values of <code>searchChar</code> in the range from 0 to 0xFFFF
1297     * (inclusive), this is the smallest value <i>k</i> such that:
1298     * <blockquote><pre>
1299     * this.charAt(<i>k</i>) == searchChar
1300     * </pre></blockquote>
1301     * is true. For other values of <code>searchChar</code>, it is the
1302     * smallest value <i>k</i> such that:
1303     * <blockquote><pre>
1304     * this.codePointAt(<i>k</i>) == searchChar
1305     * </pre></blockquote>
1306     * is true. In either case, if no such character occurs in <code>seq</code>,
1307     * then {@code INDEX_NOT_FOUND (-1)} is returned.
1308     *
1309     * <p>Furthermore, a {@code null} or empty ("") CharSequence will
1310     * return {@code INDEX_NOT_FOUND (-1)}.</p>
1311     *
1312     * <pre>
1313     * StringUtils.indexOf(null, *)         = -1
1314     * StringUtils.indexOf("", *)           = -1
1315     * StringUtils.indexOf("aabaabaa", 'a') = 0
1316     * StringUtils.indexOf("aabaabaa", 'b') = 2
1317     * </pre>
1318     *
1319     * @param seq  the CharSequence to check, may be null
1320     * @param searchChar  the character to find
1321     * @return the first index of the search character,
1322     *  -1 if no match or {@code null} string input
1323     * @since 2.0
1324     * @since 3.0 Changed signature from indexOf(String, int) to indexOf(CharSequence, int)
1325     * @since 3.6 Updated {@link CharSequenceUtils} call to behave more like <code>String</code>
1326     */
1327    public static int indexOf(final CharSequence seq, final int searchChar) {
1328        if (isEmpty(seq)) {
1329            return INDEX_NOT_FOUND;
1330        }
1331        return CharSequenceUtils.indexOf(seq, searchChar, 0);
1332    }
1333
1334    /**
1335     *
1336     * Returns the index within <code>seq</code> of the first occurrence of the
1337     * specified character, starting the search at the specified index.
1338     * <p>
1339     * If a character with value <code>searchChar</code> occurs in the
1340     * character sequence represented by the <code>seq</code> <code>CharSequence</code>
1341     * object at an index no smaller than <code>startPos</code>, then
1342     * the index of the first such occurrence is returned. For values
1343     * of <code>searchChar</code> in the range from 0 to 0xFFFF (inclusive),
1344     * this is the smallest value <i>k</i> such that:
1345     * <blockquote><pre>
1346     * (this.charAt(<i>k</i>) == searchChar) &amp;&amp; (<i>k</i> &gt;= startPos)
1347     * </pre></blockquote>
1348     * is true. For other values of <code>searchChar</code>, it is the
1349     * smallest value <i>k</i> such that:
1350     * <blockquote><pre>
1351     * (this.codePointAt(<i>k</i>) == searchChar) &amp;&amp; (<i>k</i> &gt;= startPos)
1352     * </pre></blockquote>
1353     * is true. In either case, if no such character occurs in <code>seq</code>
1354     * at or after position <code>startPos</code>, then
1355     * <code>-1</code> is returned.
1356     *
1357     * <p>
1358     * There is no restriction on the value of <code>startPos</code>. If it
1359     * is negative, it has the same effect as if it were zero: this entire
1360     * string may be searched. If it is greater than the length of this
1361     * string, it has the same effect as if it were equal to the length of
1362     * this string: {@code (INDEX_NOT_FOUND) -1} is returned. Furthermore, a
1363     * {@code null} or empty ("") CharSequence will
1364     * return {@code (INDEX_NOT_FOUND) -1}.
1365     *
1366     * <p>All indices are specified in <code>char</code> values
1367     * (Unicode code units).
1368     *
1369     * <pre>
1370     * StringUtils.indexOf(null, *, *)          = -1
1371     * StringUtils.indexOf("", *, *)            = -1
1372     * StringUtils.indexOf("aabaabaa", 'b', 0)  = 2
1373     * StringUtils.indexOf("aabaabaa", 'b', 3)  = 5
1374     * StringUtils.indexOf("aabaabaa", 'b', 9)  = -1
1375     * StringUtils.indexOf("aabaabaa", 'b', -1) = 2
1376     * </pre>
1377     *
1378     * @param seq  the CharSequence to check, may be null
1379     * @param searchChar  the character to find
1380     * @param startPos  the start position, negative treated as zero
1381     * @return the first index of the search character (always &ge; startPos),
1382     *  -1 if no match or {@code null} string input
1383     * @since 2.0
1384     * @since 3.0 Changed signature from indexOf(String, int, int) to indexOf(CharSequence, int, int)
1385     * @since 3.6 Updated {@link CharSequenceUtils} call to behave more like <code>String</code>
1386     */
1387    public static int indexOf(final CharSequence seq, final int searchChar, final int startPos) {
1388        if (isEmpty(seq)) {
1389            return INDEX_NOT_FOUND;
1390        }
1391        return CharSequenceUtils.indexOf(seq, searchChar, startPos);
1392    }
1393
1394    /**
1395     * <p>Finds the first index within a CharSequence, handling {@code null}.
1396     * This method uses {@link String#indexOf(String, int)} if possible.</p>
1397     *
1398     * <p>A {@code null} CharSequence will return {@code -1}.</p>
1399     *
1400     * <pre>
1401     * StringUtils.indexOf(null, *)          = -1
1402     * StringUtils.indexOf(*, null)          = -1
1403     * StringUtils.indexOf("", "")           = 0
1404     * StringUtils.indexOf("", *)            = -1 (except when * = "")
1405     * StringUtils.indexOf("aabaabaa", "a")  = 0
1406     * StringUtils.indexOf("aabaabaa", "b")  = 2
1407     * StringUtils.indexOf("aabaabaa", "ab") = 1
1408     * StringUtils.indexOf("aabaabaa", "")   = 0
1409     * </pre>
1410     *
1411     * @param seq  the CharSequence to check, may be null
1412     * @param searchSeq  the CharSequence to find, may be null
1413     * @return the first index of the search CharSequence,
1414     *  -1 if no match or {@code null} string input
1415     * @since 2.0
1416     * @since 3.0 Changed signature from indexOf(String, String) to indexOf(CharSequence, CharSequence)
1417     */
1418    public static int indexOf(final CharSequence seq, final CharSequence searchSeq) {
1419        if (seq == null || searchSeq == null) {
1420            return INDEX_NOT_FOUND;
1421        }
1422        return CharSequenceUtils.indexOf(seq, searchSeq, 0);
1423    }
1424
1425    /**
1426     * <p>Finds the first index within a CharSequence, handling {@code null}.
1427     * This method uses {@link String#indexOf(String, int)} if possible.</p>
1428     *
1429     * <p>A {@code null} CharSequence will return {@code -1}.
1430     * A negative start position is treated as zero.
1431     * An empty ("") search CharSequence always matches.
1432     * A start position greater than the string length only matches
1433     * an empty search CharSequence.</p>
1434     *
1435     * <pre>
1436     * StringUtils.indexOf(null, *, *)          = -1
1437     * StringUtils.indexOf(*, null, *)          = -1
1438     * StringUtils.indexOf("", "", 0)           = 0
1439     * StringUtils.indexOf("", *, 0)            = -1 (except when * = "")
1440     * StringUtils.indexOf("aabaabaa", "a", 0)  = 0
1441     * StringUtils.indexOf("aabaabaa", "b", 0)  = 2
1442     * StringUtils.indexOf("aabaabaa", "ab", 0) = 1
1443     * StringUtils.indexOf("aabaabaa", "b", 3)  = 5
1444     * StringUtils.indexOf("aabaabaa", "b", 9)  = -1
1445     * StringUtils.indexOf("aabaabaa", "b", -1) = 2
1446     * StringUtils.indexOf("aabaabaa", "", 2)   = 2
1447     * StringUtils.indexOf("abc", "", 9)        = 3
1448     * </pre>
1449     *
1450     * @param seq  the CharSequence to check, may be null
1451     * @param searchSeq  the CharSequence to find, may be null
1452     * @param startPos  the start position, negative treated as zero
1453     * @return the first index of the search CharSequence (always &ge; startPos),
1454     *  -1 if no match or {@code null} string input
1455     * @since 2.0
1456     * @since 3.0 Changed signature from indexOf(String, String, int) to indexOf(CharSequence, CharSequence, int)
1457     */
1458    public static int indexOf(final CharSequence seq, final CharSequence searchSeq, final int startPos) {
1459        if (seq == null || searchSeq == null) {
1460            return INDEX_NOT_FOUND;
1461        }
1462        return CharSequenceUtils.indexOf(seq, searchSeq, startPos);
1463    }
1464
1465    /**
1466     * <p>Finds the n-th index within a CharSequence, handling {@code null}.
1467     * This method uses {@link String#indexOf(String)} if possible.</p>
1468     * <p><b>Note:</b> The code starts looking for a match at the start of the target,
1469     * incrementing the starting index by one after each successful match
1470     * (unless {@code searchStr} is an empty string in which case the position
1471     * is never incremented and {@code 0} is returned immediately).
1472     * This means that matches may overlap.</p>
1473     * <p>A {@code null} CharSequence will return {@code -1}.</p>
1474     *
1475     * <pre>
1476     * StringUtils.ordinalIndexOf(null, *, *)          = -1
1477     * StringUtils.ordinalIndexOf(*, null, *)          = -1
1478     * StringUtils.ordinalIndexOf("", "", *)           = 0
1479     * StringUtils.ordinalIndexOf("aabaabaa", "a", 1)  = 0
1480     * StringUtils.ordinalIndexOf("aabaabaa", "a", 2)  = 1
1481     * StringUtils.ordinalIndexOf("aabaabaa", "b", 1)  = 2
1482     * StringUtils.ordinalIndexOf("aabaabaa", "b", 2)  = 5
1483     * StringUtils.ordinalIndexOf("aabaabaa", "ab", 1) = 1
1484     * StringUtils.ordinalIndexOf("aabaabaa", "ab", 2) = 4
1485     * StringUtils.ordinalIndexOf("aabaabaa", "", 1)   = 0
1486     * StringUtils.ordinalIndexOf("aabaabaa", "", 2)   = 0
1487     * </pre>
1488     *
1489     * <p>Matches may overlap:</p>
1490     * <pre>
1491     * StringUtils.ordinalIndexOf("ababab","aba", 1)   = 0
1492     * StringUtils.ordinalIndexOf("ababab","aba", 2)   = 2
1493     * StringUtils.ordinalIndexOf("ababab","aba", 3)   = -1
1494     *
1495     * StringUtils.ordinalIndexOf("abababab", "abab", 1) = 0
1496     * StringUtils.ordinalIndexOf("abababab", "abab", 2) = 2
1497     * StringUtils.ordinalIndexOf("abababab", "abab", 3) = 4
1498     * StringUtils.ordinalIndexOf("abababab", "abab", 4) = -1
1499     * </pre>
1500     *
1501     * <p>Note that 'head(CharSequence str, int n)' may be implemented as: </p>
1502     *
1503     * <pre>
1504     *   str.substring(0, lastOrdinalIndexOf(str, "\n", n))
1505     * </pre>
1506     *
1507     * @param str  the CharSequence to check, may be null
1508     * @param searchStr  the CharSequence to find, may be null
1509     * @param ordinal  the n-th {@code searchStr} to find
1510     * @return the n-th index of the search CharSequence,
1511     *  {@code -1} ({@code INDEX_NOT_FOUND}) if no match or {@code null} string input
1512     * @since 2.1
1513     * @since 3.0 Changed signature from ordinalIndexOf(String, String, int) to ordinalIndexOf(CharSequence, CharSequence, int)
1514     */
1515    public static int ordinalIndexOf(final CharSequence str, final CharSequence searchStr, final int ordinal) {
1516        return ordinalIndexOf(str, searchStr, ordinal, false);
1517    }
1518
1519    /**
1520     * <p>Finds the n-th index within a String, handling {@code null}.
1521     * This method uses {@link String#indexOf(String)} if possible.</p>
1522     * <p>Note that matches may overlap<p>
1523     *
1524     * <p>A {@code null} CharSequence will return {@code -1}.</p>
1525     *
1526     * @param str  the CharSequence to check, may be null
1527     * @param searchStr  the CharSequence to find, may be null
1528     * @param ordinal  the n-th {@code searchStr} to find, overlapping matches are allowed.
1529     * @param lastIndex true if lastOrdinalIndexOf() otherwise false if ordinalIndexOf()
1530     * @return the n-th index of the search CharSequence,
1531     *  {@code -1} ({@code INDEX_NOT_FOUND}) if no match or {@code null} string input
1532     */
1533    // Shared code between ordinalIndexOf(String,String,int) and lastOrdinalIndexOf(String,String,int)
1534    private static int ordinalIndexOf(final CharSequence str, final CharSequence searchStr, final int ordinal, final boolean lastIndex) {
1535        if (str == null || searchStr == null || ordinal <= 0) {
1536            return INDEX_NOT_FOUND;
1537        }
1538        if (searchStr.length() == 0) {
1539            return lastIndex ? str.length() : 0;
1540        }
1541        int found = 0;
1542        // set the initial index beyond the end of the string
1543        // this is to allow for the initial index decrement/increment
1544        int index = lastIndex ? str.length() : INDEX_NOT_FOUND;
1545        do {
1546            if (lastIndex) {
1547                index = CharSequenceUtils.lastIndexOf(str, searchStr, index - 1); // step backwards thru string
1548            } else {
1549                index = CharSequenceUtils.indexOf(str, searchStr, index + 1); // step forwards through string
1550            }
1551            if (index < 0) {
1552                return index;
1553            }
1554            found++;
1555        } while (found < ordinal);
1556        return index;
1557    }
1558
1559    /**
1560     * <p>Case in-sensitive find of the first index within a CharSequence.</p>
1561     *
1562     * <p>A {@code null} CharSequence will return {@code -1}.
1563     * A negative start position is treated as zero.
1564     * An empty ("") search CharSequence always matches.
1565     * A start position greater than the string length only matches
1566     * an empty search CharSequence.</p>
1567     *
1568     * <pre>
1569     * StringUtils.indexOfIgnoreCase(null, *)          = -1
1570     * StringUtils.indexOfIgnoreCase(*, null)          = -1
1571     * StringUtils.indexOfIgnoreCase("", "")           = 0
1572     * StringUtils.indexOfIgnoreCase("aabaabaa", "a")  = 0
1573     * StringUtils.indexOfIgnoreCase("aabaabaa", "b")  = 2
1574     * StringUtils.indexOfIgnoreCase("aabaabaa", "ab") = 1
1575     * </pre>
1576     *
1577     * @param str  the CharSequence to check, may be null
1578     * @param searchStr  the CharSequence to find, may be null
1579     * @return the first index of the search CharSequence,
1580     *  -1 if no match or {@code null} string input
1581     * @since 2.5
1582     * @since 3.0 Changed signature from indexOfIgnoreCase(String, String) to indexOfIgnoreCase(CharSequence, CharSequence)
1583     */
1584    public static int indexOfIgnoreCase(final CharSequence str, final CharSequence searchStr) {
1585        return indexOfIgnoreCase(str, searchStr, 0);
1586    }
1587
1588    /**
1589     * <p>Case in-sensitive find of the first index within a CharSequence
1590     * from the specified position.</p>
1591     *
1592     * <p>A {@code null} CharSequence will return {@code -1}.
1593     * A negative start position is treated as zero.
1594     * An empty ("") search CharSequence always matches.
1595     * A start position greater than the string length only matches
1596     * an empty search CharSequence.</p>
1597     *
1598     * <pre>
1599     * StringUtils.indexOfIgnoreCase(null, *, *)          = -1
1600     * StringUtils.indexOfIgnoreCase(*, null, *)          = -1
1601     * StringUtils.indexOfIgnoreCase("", "", 0)           = 0
1602     * StringUtils.indexOfIgnoreCase("aabaabaa", "A", 0)  = 0
1603     * StringUtils.indexOfIgnoreCase("aabaabaa", "B", 0)  = 2
1604     * StringUtils.indexOfIgnoreCase("aabaabaa", "AB", 0) = 1
1605     * StringUtils.indexOfIgnoreCase("aabaabaa", "B", 3)  = 5
1606     * StringUtils.indexOfIgnoreCase("aabaabaa", "B", 9)  = -1
1607     * StringUtils.indexOfIgnoreCase("aabaabaa", "B", -1) = 2
1608     * StringUtils.indexOfIgnoreCase("aabaabaa", "", 2)   = 2
1609     * StringUtils.indexOfIgnoreCase("abc", "", 9)        = -1
1610     * </pre>
1611     *
1612     * @param str  the CharSequence to check, may be null
1613     * @param searchStr  the CharSequence to find, may be null
1614     * @param startPos  the start position, negative treated as zero
1615     * @return the first index of the search CharSequence (always &ge; startPos),
1616     *  -1 if no match or {@code null} string input
1617     * @since 2.5
1618     * @since 3.0 Changed signature from indexOfIgnoreCase(String, String, int) to indexOfIgnoreCase(CharSequence, CharSequence, int)
1619     */
1620    public static int indexOfIgnoreCase(final CharSequence str, final CharSequence searchStr, int startPos) {
1621        if (str == null || searchStr == null) {
1622            return INDEX_NOT_FOUND;
1623        }
1624        if (startPos < 0) {
1625            startPos = 0;
1626        }
1627        final int endLimit = str.length() - searchStr.length() + 1;
1628        if (startPos > endLimit) {
1629            return INDEX_NOT_FOUND;
1630        }
1631        if (searchStr.length() == 0) {
1632            return startPos;
1633        }
1634        for (int i = startPos; i < endLimit; i++) {
1635            if (CharSequenceUtils.regionMatches(str, true, i, searchStr, 0, searchStr.length())) {
1636                return i;
1637            }
1638        }
1639        return INDEX_NOT_FOUND;
1640    }
1641
1642    // LastIndexOf
1643    //-----------------------------------------------------------------------
1644    /**
1645     * Returns the index within <code>seq</code> of the last occurrence of
1646     * the specified character. For values of <code>searchChar</code> in the
1647     * range from 0 to 0xFFFF (inclusive), the index (in Unicode code
1648     * units) returned is the largest value <i>k</i> such that:
1649     * <blockquote><pre>
1650     * this.charAt(<i>k</i>) == searchChar
1651     * </pre></blockquote>
1652     * is true. For other values of <code>searchChar</code>, it is the
1653     * largest value <i>k</i> such that:
1654     * <blockquote><pre>
1655     * this.codePointAt(<i>k</i>) == searchChar
1656     * </pre></blockquote>
1657     * is true.  In either case, if no such character occurs in this
1658     * string, then <code>-1</code> is returned. Furthermore, a {@code null} or empty ("")
1659     * <code>CharSequence</code> will return {@code -1}. The
1660     * <code>seq</code> <code>CharSequence</code> object is searched backwards
1661     * starting at the last character.
1662     *
1663     * <pre>
1664     * StringUtils.lastIndexOf(null, *)         = -1
1665     * StringUtils.lastIndexOf("", *)           = -1
1666     * StringUtils.lastIndexOf("aabaabaa", 'a') = 7
1667     * StringUtils.lastIndexOf("aabaabaa", 'b') = 5
1668     * </pre>
1669     *
1670     * @param seq  the <code>CharSequence</code> to check, may be null
1671     * @param searchChar  the character to find
1672     * @return the last index of the search character,
1673     *  -1 if no match or {@code null} string input
1674     * @since 2.0
1675     * @since 3.0 Changed signature from lastIndexOf(String, int) to lastIndexOf(CharSequence, int)
1676     * @since 3.6 Updated {@link CharSequenceUtils} call to behave more like <code>String</code>
1677     */
1678    public static int lastIndexOf(final CharSequence seq, final int searchChar) {
1679        if (isEmpty(seq)) {
1680            return INDEX_NOT_FOUND;
1681        }
1682        return CharSequenceUtils.lastIndexOf(seq, searchChar, seq.length());
1683    }
1684
1685    /**
1686     * Returns the index within <code>seq</code> of the last occurrence of
1687     * the specified character, searching backward starting at the
1688     * specified index. For values of <code>searchChar</code> in the range
1689     * from 0 to 0xFFFF (inclusive), the index returned is the largest
1690     * value <i>k</i> such that:
1691     * <blockquote><pre>
1692     * (this.charAt(<i>k</i>) == searchChar) &amp;&amp; (<i>k</i> &lt;= startPos)
1693     * </pre></blockquote>
1694     * is true. For other values of <code>searchChar</code>, it is the
1695     * largest value <i>k</i> such that:
1696     * <blockquote><pre>
1697     * (this.codePointAt(<i>k</i>) == searchChar) &amp;&amp; (<i>k</i> &lt;= startPos)
1698     * </pre></blockquote>
1699     * is true. In either case, if no such character occurs in <code>seq</code>
1700     * at or before position <code>startPos</code>, then
1701     * <code>-1</code> is returned. Furthermore, a {@code null} or empty ("")
1702     * <code>CharSequence</code> will return {@code -1}. A start position greater
1703     * than the string length searches the whole string.
1704     * The search starts at the <code>startPos</code> and works backwards;
1705     * matches starting after the start position are ignored.
1706     *
1707     * <p>All indices are specified in <code>char</code> values
1708     * (Unicode code units).
1709     *
1710     * <pre>
1711     * StringUtils.lastIndexOf(null, *, *)          = -1
1712     * StringUtils.lastIndexOf("", *,  *)           = -1
1713     * StringUtils.lastIndexOf("aabaabaa", 'b', 8)  = 5
1714     * StringUtils.lastIndexOf("aabaabaa", 'b', 4)  = 2
1715     * StringUtils.lastIndexOf("aabaabaa", 'b', 0)  = -1
1716     * StringUtils.lastIndexOf("aabaabaa", 'b', 9)  = 5
1717     * StringUtils.lastIndexOf("aabaabaa", 'b', -1) = -1
1718     * StringUtils.lastIndexOf("aabaabaa", 'a', 0)  = 0
1719     * </pre>
1720     *
1721     * @param seq  the CharSequence to check, may be null
1722     * @param searchChar  the character to find
1723     * @param startPos  the start position
1724     * @return the last index of the search character (always &le; startPos),
1725     *  -1 if no match or {@code null} string input
1726     * @since 2.0
1727     * @since 3.0 Changed signature from lastIndexOf(String, int, int) to lastIndexOf(CharSequence, int, int)
1728     */
1729    public static int lastIndexOf(final CharSequence seq, final int searchChar, final int startPos) {
1730        if (isEmpty(seq)) {
1731            return INDEX_NOT_FOUND;
1732        }
1733        return CharSequenceUtils.lastIndexOf(seq, searchChar, startPos);
1734    }
1735
1736    /**
1737     * <p>Finds the last index within a CharSequence, handling {@code null}.
1738     * This method uses {@link String#lastIndexOf(String)} if possible.</p>
1739     *
1740     * <p>A {@code null} CharSequence will return {@code -1}.</p>
1741     *
1742     * <pre>
1743     * StringUtils.lastIndexOf(null, *)          = -1
1744     * StringUtils.lastIndexOf(*, null)          = -1
1745     * StringUtils.lastIndexOf("", "")           = 0
1746     * StringUtils.lastIndexOf("aabaabaa", "a")  = 7
1747     * StringUtils.lastIndexOf("aabaabaa", "b")  = 5
1748     * StringUtils.lastIndexOf("aabaabaa", "ab") = 4
1749     * StringUtils.lastIndexOf("aabaabaa", "")   = 8
1750     * </pre>
1751     *
1752     * @param seq  the CharSequence to check, may be null
1753     * @param searchSeq  the CharSequence to find, may be null
1754     * @return the last index of the search String,
1755     *  -1 if no match or {@code null} string input
1756     * @since 2.0
1757     * @since 3.0 Changed signature from lastIndexOf(String, String) to lastIndexOf(CharSequence, CharSequence)
1758     */
1759    public static int lastIndexOf(final CharSequence seq, final CharSequence searchSeq) {
1760        if (seq == null || searchSeq == null) {
1761            return INDEX_NOT_FOUND;
1762        }
1763        return CharSequenceUtils.lastIndexOf(seq, searchSeq, seq.length());
1764    }
1765
1766    /**
1767     * <p>Finds the n-th last index within a String, handling {@code null}.
1768     * This method uses {@link String#lastIndexOf(String)}.</p>
1769     *
1770     * <p>A {@code null} String will return {@code -1}.</p>
1771     *
1772     * <pre>
1773     * StringUtils.lastOrdinalIndexOf(null, *, *)          = -1
1774     * StringUtils.lastOrdinalIndexOf(*, null, *)          = -1
1775     * StringUtils.lastOrdinalIndexOf("", "", *)           = 0
1776     * StringUtils.lastOrdinalIndexOf("aabaabaa", "a", 1)  = 7
1777     * StringUtils.lastOrdinalIndexOf("aabaabaa", "a", 2)  = 6
1778     * StringUtils.lastOrdinalIndexOf("aabaabaa", "b", 1)  = 5
1779     * StringUtils.lastOrdinalIndexOf("aabaabaa", "b", 2)  = 2
1780     * StringUtils.lastOrdinalIndexOf("aabaabaa", "ab", 1) = 4
1781     * StringUtils.lastOrdinalIndexOf("aabaabaa", "ab", 2) = 1
1782     * StringUtils.lastOrdinalIndexOf("aabaabaa", "", 1)   = 8
1783     * StringUtils.lastOrdinalIndexOf("aabaabaa", "", 2)   = 8
1784     * </pre>
1785     *
1786     * <p>Note that 'tail(CharSequence str, int n)' may be implemented as: </p>
1787     *
1788     * <pre>
1789     *   str.substring(lastOrdinalIndexOf(str, "\n", n) + 1)
1790     * </pre>
1791     *
1792     * @param str  the CharSequence to check, may be null
1793     * @param searchStr  the CharSequence to find, may be null
1794     * @param ordinal  the n-th last {@code searchStr} to find
1795     * @return the n-th last index of the search CharSequence,
1796     *  {@code -1} ({@code INDEX_NOT_FOUND}) if no match or {@code null} string input
1797     * @since 2.5
1798     * @since 3.0 Changed signature from lastOrdinalIndexOf(String, String, int) to lastOrdinalIndexOf(CharSequence, CharSequence, int)
1799     */
1800    public static int lastOrdinalIndexOf(final CharSequence str, final CharSequence searchStr, final int ordinal) {
1801        return ordinalIndexOf(str, searchStr, ordinal, true);
1802    }
1803
1804    /**
1805     * <p>Finds the last index within a CharSequence, handling {@code null}.
1806     * This method uses {@link String#lastIndexOf(String, int)} if possible.</p>
1807     *
1808     * <p>A {@code null} CharSequence will return {@code -1}.
1809     * A negative start position returns {@code -1}.
1810     * An empty ("") search CharSequence always matches unless the start position is negative.
1811     * A start position greater than the string length searches the whole string.
1812     * The search starts at the startPos and works backwards; matches starting after the start
1813     * position are ignored.
1814     * </p>
1815     *
1816     * <pre>
1817     * StringUtils.lastIndexOf(null, *, *)          = -1
1818     * StringUtils.lastIndexOf(*, null, *)          = -1
1819     * StringUtils.lastIndexOf("aabaabaa", "a", 8)  = 7
1820     * StringUtils.lastIndexOf("aabaabaa", "b", 8)  = 5
1821     * StringUtils.lastIndexOf("aabaabaa", "ab", 8) = 4
1822     * StringUtils.lastIndexOf("aabaabaa", "b", 9)  = 5
1823     * StringUtils.lastIndexOf("aabaabaa", "b", -1) = -1
1824     * StringUtils.lastIndexOf("aabaabaa", "a", 0)  = 0
1825     * StringUtils.lastIndexOf("aabaabaa", "b", 0)  = -1
1826     * StringUtils.lastIndexOf("aabaabaa", "b", 1)  = -1
1827     * StringUtils.lastIndexOf("aabaabaa", "b", 2)  = 2
1828     * StringUtils.lastIndexOf("aabaabaa", "ba", 2)  = 2
1829     * </pre>
1830     *
1831     * @param seq  the CharSequence to check, may be null
1832     * @param searchSeq  the CharSequence to find, may be null
1833     * @param startPos  the start position, negative treated as zero
1834     * @return the last index of the search CharSequence (always &le; startPos),
1835     *  -1 if no match or {@code null} string input
1836     * @since 2.0
1837     * @since 3.0 Changed signature from lastIndexOf(String, String, int) to lastIndexOf(CharSequence, CharSequence, int)
1838     */
1839    public static int lastIndexOf(final CharSequence seq, final CharSequence searchSeq, final int startPos) {
1840        if (seq == null || searchSeq == null) {
1841            return INDEX_NOT_FOUND;
1842        }
1843        return CharSequenceUtils.lastIndexOf(seq, searchSeq, startPos);
1844    }
1845
1846    /**
1847     * <p>Case in-sensitive find of the last index within a CharSequence.</p>
1848     *
1849     * <p>A {@code null} CharSequence will return {@code -1}.
1850     * A negative start position returns {@code -1}.
1851     * An empty ("") search CharSequence always matches unless the start position is negative.
1852     * A start position greater than the string length searches the whole string.</p>
1853     *
1854     * <pre>
1855     * StringUtils.lastIndexOfIgnoreCase(null, *)          = -1
1856     * StringUtils.lastIndexOfIgnoreCase(*, null)          = -1
1857     * StringUtils.lastIndexOfIgnoreCase("aabaabaa", "A")  = 7
1858     * StringUtils.lastIndexOfIgnoreCase("aabaabaa", "B")  = 5
1859     * StringUtils.lastIndexOfIgnoreCase("aabaabaa", "AB") = 4
1860     * </pre>
1861     *
1862     * @param str  the CharSequence to check, may be null
1863     * @param searchStr  the CharSequence to find, may be null
1864     * @return the first index of the search CharSequence,
1865     *  -1 if no match or {@code null} string input
1866     * @since 2.5
1867     * @since 3.0 Changed signature from lastIndexOfIgnoreCase(String, String) to lastIndexOfIgnoreCase(CharSequence, CharSequence)
1868     */
1869    public static int lastIndexOfIgnoreCase(final CharSequence str, final CharSequence searchStr) {
1870        if (str == null || searchStr == null) {
1871            return INDEX_NOT_FOUND;
1872        }
1873        return lastIndexOfIgnoreCase(str, searchStr, str.length());
1874    }
1875
1876    /**
1877     * <p>Case in-sensitive find of the last index within a CharSequence
1878     * from the specified position.</p>
1879     *
1880     * <p>A {@code null} CharSequence will return {@code -1}.
1881     * A negative start position returns {@code -1}.
1882     * An empty ("") search CharSequence always matches unless the start position is negative.
1883     * A start position greater than the string length searches the whole string.
1884     * The search starts at the startPos and works backwards; matches starting after the start
1885     * position are ignored.
1886     * </p>
1887     *
1888     * <pre>
1889     * StringUtils.lastIndexOfIgnoreCase(null, *, *)          = -1
1890     * StringUtils.lastIndexOfIgnoreCase(*, null, *)          = -1
1891     * StringUtils.lastIndexOfIgnoreCase("aabaabaa", "A", 8)  = 7
1892     * StringUtils.lastIndexOfIgnoreCase("aabaabaa", "B", 8)  = 5
1893     * StringUtils.lastIndexOfIgnoreCase("aabaabaa", "AB", 8) = 4
1894     * StringUtils.lastIndexOfIgnoreCase("aabaabaa", "B", 9)  = 5
1895     * StringUtils.lastIndexOfIgnoreCase("aabaabaa", "B", -1) = -1
1896     * StringUtils.lastIndexOfIgnoreCase("aabaabaa", "A", 0)  = 0
1897     * StringUtils.lastIndexOfIgnoreCase("aabaabaa", "B", 0)  = -1
1898     * </pre>
1899     *
1900     * @param str  the CharSequence to check, may be null
1901     * @param searchStr  the CharSequence to find, may be null
1902     * @param startPos  the start position
1903     * @return the last index of the search CharSequence (always &le; startPos),
1904     *  -1 if no match or {@code null} input
1905     * @since 2.5
1906     * @since 3.0 Changed signature from lastIndexOfIgnoreCase(String, String, int) to lastIndexOfIgnoreCase(CharSequence, CharSequence, int)
1907     */
1908    public static int lastIndexOfIgnoreCase(final CharSequence str, final CharSequence searchStr, int startPos) {
1909        if (str == null || searchStr == null) {
1910            return INDEX_NOT_FOUND;
1911        }
1912        if (startPos > str.length() - searchStr.length()) {
1913            startPos = str.length() - searchStr.length();
1914        }
1915        if (startPos < 0) {
1916            return INDEX_NOT_FOUND;
1917        }
1918        if (searchStr.length() == 0) {
1919            return startPos;
1920        }
1921
1922        for (int i = startPos; i >= 0; i--) {
1923            if (CharSequenceUtils.regionMatches(str, true, i, searchStr, 0, searchStr.length())) {
1924                return i;
1925            }
1926        }
1927        return INDEX_NOT_FOUND;
1928    }
1929
1930    // Contains
1931    //-----------------------------------------------------------------------
1932    /**
1933     * <p>Checks if CharSequence contains a search character, handling {@code null}.
1934     * This method uses {@link String#indexOf(int)} if possible.</p>
1935     *
1936     * <p>A {@code null} or empty ("") CharSequence will return {@code false}.</p>
1937     *
1938     * <pre>
1939     * StringUtils.contains(null, *)    = false
1940     * StringUtils.contains("", *)      = false
1941     * StringUtils.contains("abc", 'a') = true
1942     * StringUtils.contains("abc", 'z') = false
1943     * </pre>
1944     *
1945     * @param seq  the CharSequence to check, may be null
1946     * @param searchChar  the character to find
1947     * @return true if the CharSequence contains the search character,
1948     *  false if not or {@code null} string input
1949     * @since 2.0
1950     * @since 3.0 Changed signature from contains(String, int) to contains(CharSequence, int)
1951     */
1952    public static boolean contains(final CharSequence seq, final int searchChar) {
1953        if (isEmpty(seq)) {
1954            return false;
1955        }
1956        return CharSequenceUtils.indexOf(seq, searchChar, 0) >= 0;
1957    }
1958
1959    /**
1960     * <p>Checks if CharSequence contains a search CharSequence, handling {@code null}.
1961     * This method uses {@link String#indexOf(String)} if possible.</p>
1962     *
1963     * <p>A {@code null} CharSequence will return {@code false}.</p>
1964     *
1965     * <pre>
1966     * StringUtils.contains(null, *)     = false
1967     * StringUtils.contains(*, null)     = false
1968     * StringUtils.contains("", "")      = true
1969     * StringUtils.contains("abc", "")   = true
1970     * StringUtils.contains("abc", "a")  = true
1971     * StringUtils.contains("abc", "z")  = false
1972     * </pre>
1973     *
1974     * @param seq  the CharSequence to check, may be null
1975     * @param searchSeq  the CharSequence to find, may be null
1976     * @return true if the CharSequence contains the search CharSequence,
1977     *  false if not or {@code null} string input
1978     * @since 2.0
1979     * @since 3.0 Changed signature from contains(String, String) to contains(CharSequence, CharSequence)
1980     */
1981    public static boolean contains(final CharSequence seq, final CharSequence searchSeq) {
1982        if (seq == null || searchSeq == null) {
1983            return false;
1984        }
1985        return CharSequenceUtils.indexOf(seq, searchSeq, 0) >= 0;
1986    }
1987
1988    /**
1989     * <p>Checks if CharSequence contains a search CharSequence irrespective of case,
1990     * handling {@code null}. Case-insensitivity is defined as by
1991     * {@link String#equalsIgnoreCase(String)}.
1992     *
1993     * <p>A {@code null} CharSequence will return {@code false}.</p>
1994     *
1995     * <pre>
1996     * StringUtils.containsIgnoreCase(null, *) = false
1997     * StringUtils.containsIgnoreCase(*, null) = false
1998     * StringUtils.containsIgnoreCase("", "") = true
1999     * StringUtils.containsIgnoreCase("abc", "") = true
2000     * StringUtils.containsIgnoreCase("abc", "a") = true
2001     * StringUtils.containsIgnoreCase("abc", "z") = false
2002     * StringUtils.containsIgnoreCase("abc", "A") = true
2003     * StringUtils.containsIgnoreCase("abc", "Z") = false
2004     * </pre>
2005     *
2006     * @param str  the CharSequence to check, may be null
2007     * @param searchStr  the CharSequence to find, may be null
2008     * @return true if the CharSequence contains the search CharSequence irrespective of
2009     * case or false if not or {@code null} string input
2010     * @since 3.0 Changed signature from containsIgnoreCase(String, String) to containsIgnoreCase(CharSequence, CharSequence)
2011     */
2012    public static boolean containsIgnoreCase(final CharSequence str, final CharSequence searchStr) {
2013        if (str == null || searchStr == null) {
2014            return false;
2015        }
2016        final int len = searchStr.length();
2017        final int max = str.length() - len;
2018        for (int i = 0; i <= max; i++) {
2019            if (CharSequenceUtils.regionMatches(str, true, i, searchStr, 0, len)) {
2020                return true;
2021            }
2022        }
2023        return false;
2024    }
2025
2026    /**
2027     * <p>Check whether the given CharSequence contains any whitespace characters.</p>
2028     *
2029     * <p>Whitespace is defined by {@link Character#isWhitespace(char)}.</p>
2030     *
2031     * @param seq the CharSequence to check (may be {@code null})
2032     * @return {@code true} if the CharSequence is not empty and
2033     * contains at least 1 (breaking) whitespace character
2034     * @since 3.0
2035     */
2036    // From org.springframework.util.StringUtils, under Apache License 2.0
2037    public static boolean containsWhitespace(final CharSequence seq) {
2038        if (isEmpty(seq)) {
2039            return false;
2040        }
2041        final int strLen = seq.length();
2042        for (int i = 0; i < strLen; i++) {
2043            if (Character.isWhitespace(seq.charAt(i))) {
2044                return true;
2045            }
2046        }
2047        return false;
2048    }
2049
2050    // IndexOfAny chars
2051    //-----------------------------------------------------------------------
2052    /**
2053     * <p>Search a CharSequence to find the first index of any
2054     * character in the given set of characters.</p>
2055     *
2056     * <p>A {@code null} String will return {@code -1}.
2057     * A {@code null} or zero length search array will return {@code -1}.</p>
2058     *
2059     * <pre>
2060     * StringUtils.indexOfAny(null, *)                = -1
2061     * StringUtils.indexOfAny("", *)                  = -1
2062     * StringUtils.indexOfAny(*, null)                = -1
2063     * StringUtils.indexOfAny(*, [])                  = -1
2064     * StringUtils.indexOfAny("zzabyycdxx",['z','a']) = 0
2065     * StringUtils.indexOfAny("zzabyycdxx",['b','y']) = 3
2066     * StringUtils.indexOfAny("aba", ['z'])           = -1
2067     * </pre>
2068     *
2069     * @param cs  the CharSequence to check, may be null
2070     * @param searchChars  the chars to search for, may be null
2071     * @return the index of any of the chars, -1 if no match or null input
2072     * @since 2.0
2073     * @since 3.0 Changed signature from indexOfAny(String, char[]) to indexOfAny(CharSequence, char...)
2074     */
2075    public static int indexOfAny(final CharSequence cs, final char... searchChars) {
2076        if (isEmpty(cs) || ArrayUtils.isEmpty(searchChars)) {
2077            return INDEX_NOT_FOUND;
2078        }
2079        final int csLen = cs.length();
2080        final int csLast = csLen - 1;
2081        final int searchLen = searchChars.length;
2082        final int searchLast = searchLen - 1;
2083        for (int i = 0; i < csLen; i++) {
2084            final char ch = cs.charAt(i);
2085            for (int j = 0; j < searchLen; j++) {
2086                if (searchChars[j] == ch) {
2087                    if (i < csLast && j < searchLast && Character.isHighSurrogate(ch)) {
2088                        // ch is a supplementary character
2089                        if (searchChars[j + 1] == cs.charAt(i + 1)) {
2090                            return i;
2091                        }
2092                    } else {
2093                        return i;
2094                    }
2095                }
2096            }
2097        }
2098        return INDEX_NOT_FOUND;
2099    }
2100
2101    /**
2102     * <p>Search a CharSequence to find the first index of any
2103     * character in the given set of characters.</p>
2104     *
2105     * <p>A {@code null} String will return {@code -1}.
2106     * A {@code null} search string will return {@code -1}.</p>
2107     *
2108     * <pre>
2109     * StringUtils.indexOfAny(null, *)            = -1
2110     * StringUtils.indexOfAny("", *)              = -1
2111     * StringUtils.indexOfAny(*, null)            = -1
2112     * StringUtils.indexOfAny(*, "")              = -1
2113     * StringUtils.indexOfAny("zzabyycdxx", "za") = 0
2114     * StringUtils.indexOfAny("zzabyycdxx", "by") = 3
2115     * StringUtils.indexOfAny("aba","z")          = -1
2116     * </pre>
2117     *
2118     * @param cs  the CharSequence to check, may be null
2119     * @param searchChars  the chars to search for, may be null
2120     * @return the index of any of the chars, -1 if no match or null input
2121     * @since 2.0
2122     * @since 3.0 Changed signature from indexOfAny(String, String) to indexOfAny(CharSequence, String)
2123     */
2124    public static int indexOfAny(final CharSequence cs, final String searchChars) {
2125        if (isEmpty(cs) || isEmpty(searchChars)) {
2126            return INDEX_NOT_FOUND;
2127        }
2128        return indexOfAny(cs, searchChars.toCharArray());
2129    }
2130
2131    // ContainsAny
2132    //-----------------------------------------------------------------------
2133    /**
2134     * <p>Checks if the CharSequence contains any character in the given
2135     * set of characters.</p>
2136     *
2137     * <p>A {@code null} CharSequence will return {@code false}.
2138     * A {@code null} or zero length search array will return {@code false}.</p>
2139     *
2140     * <pre>
2141     * StringUtils.containsAny(null, *)                = false
2142     * StringUtils.containsAny("", *)                  = false
2143     * StringUtils.containsAny(*, null)                = false
2144     * StringUtils.containsAny(*, [])                  = false
2145     * StringUtils.containsAny("zzabyycdxx",['z','a']) = true
2146     * StringUtils.containsAny("zzabyycdxx",['b','y']) = true
2147     * StringUtils.containsAny("zzabyycdxx",['z','y']) = true
2148     * StringUtils.containsAny("aba", ['z'])           = false
2149     * </pre>
2150     *
2151     * @param cs  the CharSequence to check, may be null
2152     * @param searchChars  the chars to search for, may be null
2153     * @return the {@code true} if any of the chars are found,
2154     * {@code false} if no match or null input
2155     * @since 2.4
2156     * @since 3.0 Changed signature from containsAny(String, char[]) to containsAny(CharSequence, char...)
2157     */
2158    public static boolean containsAny(final CharSequence cs, final char... searchChars) {
2159        if (isEmpty(cs) || ArrayUtils.isEmpty(searchChars)) {
2160            return false;
2161        }
2162        final int csLength = cs.length();
2163        final int searchLength = searchChars.length;
2164        final int csLast = csLength - 1;
2165        final int searchLast = searchLength - 1;
2166        for (int i = 0; i < csLength; i++) {
2167            final char ch = cs.charAt(i);
2168            for (int j = 0; j < searchLength; j++) {
2169                if (searchChars[j] == ch) {
2170                    if (Character.isHighSurrogate(ch)) {
2171                        if (j == searchLast) {
2172                            // missing low surrogate, fine, like String.indexOf(String)
2173                            return true;
2174                        }
2175                        if (i < csLast && searchChars[j + 1] == cs.charAt(i + 1)) {
2176                            return true;
2177                        }
2178                    } else {
2179                        // ch is in the Basic Multilingual Plane
2180                        return true;
2181                    }
2182                }
2183            }
2184        }
2185        return false;
2186    }
2187
2188    /**
2189     * <p>
2190     * Checks if the CharSequence contains any character in the given set of characters.
2191     * </p>
2192     *
2193     * <p>
2194     * A {@code null} CharSequence will return {@code false}. A {@code null} search CharSequence will return
2195     * {@code false}.
2196     * </p>
2197     *
2198     * <pre>
2199     * StringUtils.containsAny(null, *)               = false
2200     * StringUtils.containsAny("", *)                 = false
2201     * StringUtils.containsAny(*, null)               = false
2202     * StringUtils.containsAny(*, "")                 = false
2203     * StringUtils.containsAny("zzabyycdxx", "za")    = true
2204     * StringUtils.containsAny("zzabyycdxx", "by")    = true
2205     * StringUtils.containsAny("zzabyycdxx", "zy")    = true
2206     * StringUtils.containsAny("zzabyycdxx", "\tx")   = true
2207     * StringUtils.containsAny("zzabyycdxx", "$.#yF") = true
2208     * StringUtils.containsAny("aba","z")             = false
2209     * </pre>
2210     *
2211     * @param cs
2212     *            the CharSequence to check, may be null
2213     * @param searchChars
2214     *            the chars to search for, may be null
2215     * @return the {@code true} if any of the chars are found, {@code false} if no match or null input
2216     * @since 2.4
2217     * @since 3.0 Changed signature from containsAny(String, String) to containsAny(CharSequence, CharSequence)
2218     */
2219    public static boolean containsAny(final CharSequence cs, final CharSequence searchChars) {
2220        if (searchChars == null) {
2221            return false;
2222        }
2223        return containsAny(cs, CharSequenceUtils.toCharArray(searchChars));
2224    }
2225
2226    /**
2227     * <p>Checks if the CharSequence contains any of the CharSequences in the given array.</p>
2228     *
2229     * <p>
2230     * A {@code null} {@code cs} CharSequence will return {@code false}. A {@code null} or zero
2231     * length search array will return {@code false}.
2232     * </p>
2233     *
2234     * <pre>
2235     * StringUtils.containsAny(null, *)            = false
2236     * StringUtils.containsAny("", *)              = false
2237     * StringUtils.containsAny(*, null)            = false
2238     * StringUtils.containsAny(*, [])              = false
2239     * StringUtils.containsAny("abcd", "ab", null) = true
2240     * StringUtils.containsAny("abcd", "ab", "cd") = true
2241     * StringUtils.containsAny("abc", "d", "abc")  = true
2242     * </pre>
2243     *
2244     *
2245     * @param cs The CharSequence to check, may be null
2246     * @param searchCharSequences The array of CharSequences to search for, may be null.
2247     * Individual CharSequences may be null as well.
2248     * @return {@code true} if any of the search CharSequences are found, {@code false} otherwise
2249     * @since 3.4
2250     */
2251    public static boolean containsAny(final CharSequence cs, final CharSequence... searchCharSequences) {
2252        if (isEmpty(cs) || ArrayUtils.isEmpty(searchCharSequences)) {
2253            return false;
2254        }
2255        for (final CharSequence searchCharSequence : searchCharSequences) {
2256            if (contains(cs, searchCharSequence)) {
2257                return true;
2258            }
2259        }
2260        return false;
2261    }
2262
2263    // IndexOfAnyBut chars
2264    //-----------------------------------------------------------------------
2265    /**
2266     * <p>Searches a CharSequence to find the first index of any
2267     * character not in the given set of characters.</p>
2268     *
2269     * <p>A {@code null} CharSequence will return {@code -1}.
2270     * A {@code null} or zero length search array will return {@code -1}.</p>
2271     *
2272     * <pre>
2273     * StringUtils.indexOfAnyBut(null, *)                              = -1
2274     * StringUtils.indexOfAnyBut("", *)                                = -1
2275     * StringUtils.indexOfAnyBut(*, null)                              = -1
2276     * StringUtils.indexOfAnyBut(*, [])                                = -1
2277     * StringUtils.indexOfAnyBut("zzabyycdxx", new char[] {'z', 'a'} ) = 3
2278     * StringUtils.indexOfAnyBut("aba", new char[] {'z'} )             = 0
2279     * StringUtils.indexOfAnyBut("aba", new char[] {'a', 'b'} )        = -1
2280
2281     * </pre>
2282     *
2283     * @param cs  the CharSequence to check, may be null
2284     * @param searchChars  the chars to search for, may be null
2285     * @return the index of any of the chars, -1 if no match or null input
2286     * @since 2.0
2287     * @since 3.0 Changed signature from indexOfAnyBut(String, char[]) to indexOfAnyBut(CharSequence, char...)
2288     */
2289    public static int indexOfAnyBut(final CharSequence cs, final char... searchChars) {
2290        if (isEmpty(cs) || ArrayUtils.isEmpty(searchChars)) {
2291            return INDEX_NOT_FOUND;
2292        }
2293        final int csLen = cs.length();
2294        final int csLast = csLen - 1;
2295        final int searchLen = searchChars.length;
2296        final int searchLast = searchLen - 1;
2297        outer:
2298        for (int i = 0; i < csLen; i++) {
2299            final char ch = cs.charAt(i);
2300            for (int j = 0; j < searchLen; j++) {
2301                if (searchChars[j] == ch) {
2302                    if (i < csLast && j < searchLast && Character.isHighSurrogate(ch)) {
2303                        if (searchChars[j + 1] == cs.charAt(i + 1)) {
2304                            continue outer;
2305                        }
2306                    } else {
2307                        continue outer;
2308                    }
2309                }
2310            }
2311            return i;
2312        }
2313        return INDEX_NOT_FOUND;
2314    }
2315
2316    /**
2317     * <p>Search a CharSequence to find the first index of any
2318     * character not in the given set of characters.</p>
2319     *
2320     * <p>A {@code null} CharSequence will return {@code -1}.
2321     * A {@code null} or empty search string will return {@code -1}.</p>
2322     *
2323     * <pre>
2324     * StringUtils.indexOfAnyBut(null, *)            = -1
2325     * StringUtils.indexOfAnyBut("", *)              = -1
2326     * StringUtils.indexOfAnyBut(*, null)            = -1
2327     * StringUtils.indexOfAnyBut(*, "")              = -1
2328     * StringUtils.indexOfAnyBut("zzabyycdxx", "za") = 3
2329     * StringUtils.indexOfAnyBut("zzabyycdxx", "")   = -1
2330     * StringUtils.indexOfAnyBut("aba","ab")         = -1
2331     * </pre>
2332     *
2333     * @param seq  the CharSequence to check, may be null
2334     * @param searchChars  the chars to search for, may be null
2335     * @return the index of any of the chars, -1 if no match or null input
2336     * @since 2.0
2337     * @since 3.0 Changed signature from indexOfAnyBut(String, String) to indexOfAnyBut(CharSequence, CharSequence)
2338     */
2339    public static int indexOfAnyBut(final CharSequence seq, final CharSequence searchChars) {
2340        if (isEmpty(seq) || isEmpty(searchChars)) {
2341            return INDEX_NOT_FOUND;
2342        }
2343        final int strLen = seq.length();
2344        for (int i = 0; i < strLen; i++) {
2345            final char ch = seq.charAt(i);
2346            final boolean chFound = CharSequenceUtils.indexOf(searchChars, ch, 0) >= 0;
2347            if (i + 1 < strLen && Character.isHighSurrogate(ch)) {
2348                final char ch2 = seq.charAt(i + 1);
2349                if (chFound && CharSequenceUtils.indexOf(searchChars, ch2, 0) < 0) {
2350                    return i;
2351                }
2352            } else {
2353                if (!chFound) {
2354                    return i;
2355                }
2356            }
2357        }
2358        return INDEX_NOT_FOUND;
2359    }
2360
2361    // ContainsOnly
2362    //-----------------------------------------------------------------------
2363    /**
2364     * <p>Checks if the CharSequence contains only certain characters.</p>
2365     *
2366     * <p>A {@code null} CharSequence will return {@code false}.
2367     * A {@code null} valid character array will return {@code false}.
2368     * An empty CharSequence (length()=0) always returns {@code true}.</p>
2369     *
2370     * <pre>
2371     * StringUtils.containsOnly(null, *)       = false
2372     * StringUtils.containsOnly(*, null)       = false
2373     * StringUtils.containsOnly("", *)         = true
2374     * StringUtils.containsOnly("ab", '')      = false
2375     * StringUtils.containsOnly("abab", 'abc') = true
2376     * StringUtils.containsOnly("ab1", 'abc')  = false
2377     * StringUtils.containsOnly("abz", 'abc')  = false
2378     * </pre>
2379     *
2380     * @param cs  the String to check, may be null
2381     * @param valid  an array of valid chars, may be null
2382     * @return true if it only contains valid chars and is non-null
2383     * @since 3.0 Changed signature from containsOnly(String, char[]) to containsOnly(CharSequence, char...)
2384     */
2385    public static boolean containsOnly(final CharSequence cs, final char... valid) {
2386        // All these pre-checks are to maintain API with an older version
2387        if (valid == null || cs == null) {
2388            return false;
2389        }
2390        if (cs.length() == 0) {
2391            return true;
2392        }
2393        if (valid.length == 0) {
2394            return false;
2395        }
2396        return indexOfAnyBut(cs, valid) == INDEX_NOT_FOUND;
2397    }
2398
2399    /**
2400     * <p>Checks if the CharSequence contains only certain characters.</p>
2401     *
2402     * <p>A {@code null} CharSequence will return {@code false}.
2403     * A {@code null} valid character String will return {@code false}.
2404     * An empty String (length()=0) always returns {@code true}.</p>
2405     *
2406     * <pre>
2407     * StringUtils.containsOnly(null, *)       = false
2408     * StringUtils.containsOnly(*, null)       = false
2409     * StringUtils.containsOnly("", *)         = true
2410     * StringUtils.containsOnly("ab", "")      = false
2411     * StringUtils.containsOnly("abab", "abc") = true
2412     * StringUtils.containsOnly("ab1", "abc")  = false
2413     * StringUtils.containsOnly("abz", "abc")  = false
2414     * </pre>
2415     *
2416     * @param cs  the CharSequence to check, may be null
2417     * @param validChars  a String of valid chars, may be null
2418     * @return true if it only contains valid chars and is non-null
2419     * @since 2.0
2420     * @since 3.0 Changed signature from containsOnly(String, String) to containsOnly(CharSequence, String)
2421     */
2422    public static boolean containsOnly(final CharSequence cs, final String validChars) {
2423        if (cs == null || validChars == null) {
2424            return false;
2425        }
2426        return containsOnly(cs, validChars.toCharArray());
2427    }
2428
2429    // ContainsNone
2430    //-----------------------------------------------------------------------
2431    /**
2432     * <p>Checks that the CharSequence does not contain certain characters.</p>
2433     *
2434     * <p>A {@code null} CharSequence will return {@code true}.
2435     * A {@code null} invalid character array will return {@code true}.
2436     * An empty CharSequence (length()=0) always returns true.</p>
2437     *
2438     * <pre>
2439     * StringUtils.containsNone(null, *)       = true
2440     * StringUtils.containsNone(*, null)       = true
2441     * StringUtils.containsNone("", *)         = true
2442     * StringUtils.containsNone("ab", '')      = true
2443     * StringUtils.containsNone("abab", 'xyz') = true
2444     * StringUtils.containsNone("ab1", 'xyz')  = true
2445     * StringUtils.containsNone("abz", 'xyz')  = false
2446     * </pre>
2447     *
2448     * @param cs  the CharSequence to check, may be null
2449     * @param searchChars  an array of invalid chars, may be null
2450     * @return true if it contains none of the invalid chars, or is null
2451     * @since 2.0
2452     * @since 3.0 Changed signature from containsNone(String, char[]) to containsNone(CharSequence, char...)
2453     */
2454    public static boolean containsNone(final CharSequence cs, final char... searchChars) {
2455        if (cs == null || searchChars == null) {
2456            return true;
2457        }
2458        final int csLen = cs.length();
2459        final int csLast = csLen - 1;
2460        final int searchLen = searchChars.length;
2461        final int searchLast = searchLen - 1;
2462        for (int i = 0; i < csLen; i++) {
2463            final char ch = cs.charAt(i);
2464            for (int j = 0; j < searchLen; j++) {
2465                if (searchChars[j] == ch) {
2466                    if (Character.isHighSurrogate(ch)) {
2467                        if (j == searchLast) {
2468                            // missing low surrogate, fine, like String.indexOf(String)
2469                            return false;
2470                        }
2471                        if (i < csLast && searchChars[j + 1] == cs.charAt(i + 1)) {
2472                            return false;
2473                        }
2474                    } else {
2475                        // ch is in the Basic Multilingual Plane
2476                        return false;
2477                    }
2478                }
2479            }
2480        }
2481        return true;
2482    }
2483
2484    /**
2485     * <p>Checks that the CharSequence does not contain certain characters.</p>
2486     *
2487     * <p>A {@code null} CharSequence will return {@code true}.
2488     * A {@code null} invalid character array will return {@code true}.
2489     * An empty String ("") always returns true.</p>
2490     *
2491     * <pre>
2492     * StringUtils.containsNone(null, *)       = true
2493     * StringUtils.containsNone(*, null)       = true
2494     * StringUtils.containsNone("", *)         = true
2495     * StringUtils.containsNone("ab", "")      = true
2496     * StringUtils.containsNone("abab", "xyz") = true
2497     * StringUtils.containsNone("ab1", "xyz")  = true
2498     * StringUtils.containsNone("abz", "xyz")  = false
2499     * </pre>
2500     *
2501     * @param cs  the CharSequence to check, may be null
2502     * @param invalidChars  a String of invalid chars, may be null
2503     * @return true if it contains none of the invalid chars, or is null
2504     * @since 2.0
2505     * @since 3.0 Changed signature from containsNone(String, String) to containsNone(CharSequence, String)
2506     */
2507    public static boolean containsNone(final CharSequence cs, final String invalidChars) {
2508        if (cs == null || invalidChars == null) {
2509            return true;
2510        }
2511        return containsNone(cs, invalidChars.toCharArray());
2512    }
2513
2514    // IndexOfAny strings
2515    //-----------------------------------------------------------------------
2516    /**
2517     * <p>Find the first index of any of a set of potential substrings.</p>
2518     *
2519     * <p>A {@code null} CharSequence will return {@code -1}.
2520     * A {@code null} or zero length search array will return {@code -1}.
2521     * A {@code null} search array entry will be ignored, but a search
2522     * array containing "" will return {@code 0} if {@code str} is not
2523     * null. This method uses {@link String#indexOf(String)} if possible.</p>
2524     *
2525     * <pre>
2526     * StringUtils.indexOfAny(null, *)                     = -1
2527     * StringUtils.indexOfAny(*, null)                     = -1
2528     * StringUtils.indexOfAny(*, [])                       = -1
2529     * StringUtils.indexOfAny("zzabyycdxx", ["ab","cd"])   = 2
2530     * StringUtils.indexOfAny("zzabyycdxx", ["cd","ab"])   = 2
2531     * StringUtils.indexOfAny("zzabyycdxx", ["mn","op"])   = -1
2532     * StringUtils.indexOfAny("zzabyycdxx", ["zab","aby"]) = 1
2533     * StringUtils.indexOfAny("zzabyycdxx", [""])          = 0
2534     * StringUtils.indexOfAny("", [""])                    = 0
2535     * StringUtils.indexOfAny("", ["a"])                   = -1
2536     * </pre>
2537     *
2538     * @param str  the CharSequence to check, may be null
2539     * @param searchStrs  the CharSequences to search for, may be null
2540     * @return the first index of any of the searchStrs in str, -1 if no match
2541     * @since 3.0 Changed signature from indexOfAny(String, String[]) to indexOfAny(CharSequence, CharSequence...)
2542     */
2543    public static int indexOfAny(final CharSequence str, final CharSequence... searchStrs) {
2544        if (str == null || searchStrs == null) {
2545            return INDEX_NOT_FOUND;
2546        }
2547
2548        // String's can't have a MAX_VALUEth index.
2549        int ret = Integer.MAX_VALUE;
2550
2551        int tmp = 0;
2552        for (final CharSequence search : searchStrs) {
2553            if (search == null) {
2554                continue;
2555            }
2556            tmp = CharSequenceUtils.indexOf(str, search, 0);
2557            if (tmp == INDEX_NOT_FOUND) {
2558                continue;
2559            }
2560
2561            if (tmp < ret) {
2562                ret = tmp;
2563            }
2564        }
2565
2566        return ret == Integer.MAX_VALUE ? INDEX_NOT_FOUND : ret;
2567    }
2568
2569    /**
2570     * <p>Find the latest index of any of a set of potential substrings.</p>
2571     *
2572     * <p>A {@code null} CharSequence will return {@code -1}.
2573     * A {@code null} search array will return {@code -1}.
2574     * A {@code null} or zero length search array entry will be ignored,
2575     * but a search array containing "" will return the length of {@code str}
2576     * if {@code str} is not null. This method uses {@link String#indexOf(String)} if possible</p>
2577     *
2578     * <pre>
2579     * StringUtils.lastIndexOfAny(null, *)                   = -1
2580     * StringUtils.lastIndexOfAny(*, null)                   = -1
2581     * StringUtils.lastIndexOfAny(*, [])                     = -1
2582     * StringUtils.lastIndexOfAny(*, [null])                 = -1
2583     * StringUtils.lastIndexOfAny("zzabyycdxx", ["ab","cd"]) = 6
2584     * StringUtils.lastIndexOfAny("zzabyycdxx", ["cd","ab"]) = 6
2585     * StringUtils.lastIndexOfAny("zzabyycdxx", ["mn","op"]) = -1
2586     * StringUtils.lastIndexOfAny("zzabyycdxx", ["mn","op"]) = -1
2587     * StringUtils.lastIndexOfAny("zzabyycdxx", ["mn",""])   = 10
2588     * </pre>
2589     *
2590     * @param str  the CharSequence to check, may be null
2591     * @param searchStrs  the CharSequences to search for, may be null
2592     * @return the last index of any of the CharSequences, -1 if no match
2593     * @since 3.0 Changed signature from lastIndexOfAny(String, String[]) to lastIndexOfAny(CharSequence, CharSequence)
2594     */
2595    public static int lastIndexOfAny(final CharSequence str, final CharSequence... searchStrs) {
2596        if (str == null || searchStrs == null) {
2597            return INDEX_NOT_FOUND;
2598        }
2599        int ret = INDEX_NOT_FOUND;
2600        int tmp = 0;
2601        for (final CharSequence search : searchStrs) {
2602            if (search == null) {
2603                continue;
2604            }
2605            tmp = CharSequenceUtils.lastIndexOf(str, search, str.length());
2606            if (tmp > ret) {
2607                ret = tmp;
2608            }
2609        }
2610        return ret;
2611    }
2612
2613    // Substring
2614    //-----------------------------------------------------------------------
2615    /**
2616     * <p>Gets a substring from the specified String avoiding exceptions.</p>
2617     *
2618     * <p>A negative start position can be used to start {@code n}
2619     * characters from the end of the String.</p>
2620     *
2621     * <p>A {@code null} String will return {@code null}.
2622     * An empty ("") String will return "".</p>
2623     *
2624     * <pre>
2625     * StringUtils.substring(null, *)   = null
2626     * StringUtils.substring("", *)     = ""
2627     * StringUtils.substring("abc", 0)  = "abc"
2628     * StringUtils.substring("abc", 2)  = "c"
2629     * StringUtils.substring("abc", 4)  = ""
2630     * StringUtils.substring("abc", -2) = "bc"
2631     * StringUtils.substring("abc", -4) = "abc"
2632     * </pre>
2633     *
2634     * @param str  the String to get the substring from, may be null
2635     * @param start  the position to start from, negative means
2636     *  count back from the end of the String by this many characters
2637     * @return substring from start position, {@code null} if null String input
2638     */
2639    public static String substring(final String str, int start) {
2640        if (str == null) {
2641            return null;
2642        }
2643
2644        // handle negatives, which means last n characters
2645        if (start < 0) {
2646            start = str.length() + start; // remember start is negative
2647        }
2648
2649        if (start < 0) {
2650            start = 0;
2651        }
2652        if (start > str.length()) {
2653            return EMPTY;
2654        }
2655
2656        return str.substring(start);
2657    }
2658
2659    /**
2660     * <p>Gets a substring from the specified String avoiding exceptions.</p>
2661     *
2662     * <p>A negative start position can be used to start/end {@code n}
2663     * characters from the end of the String.</p>
2664     *
2665     * <p>The returned substring starts with the character in the {@code start}
2666     * position and ends before the {@code end} position. All position counting is
2667     * zero-based -- i.e., to start at the beginning of the string use
2668     * {@code start = 0}. Negative start and end positions can be used to
2669     * specify offsets relative to the end of the String.</p>
2670     *
2671     * <p>If {@code start} is not strictly to the left of {@code end}, ""
2672     * is returned.</p>
2673     *
2674     * <pre>
2675     * StringUtils.substring(null, *, *)    = null
2676     * StringUtils.substring("", * ,  *)    = "";
2677     * StringUtils.substring("abc", 0, 2)   = "ab"
2678     * StringUtils.substring("abc", 2, 0)   = ""
2679     * StringUtils.substring("abc", 2, 4)   = "c"
2680     * StringUtils.substring("abc", 4, 6)   = ""
2681     * StringUtils.substring("abc", 2, 2)   = ""
2682     * StringUtils.substring("abc", -2, -1) = "b"
2683     * StringUtils.substring("abc", -4, 2)  = "ab"
2684     * </pre>
2685     *
2686     * @param str  the String to get the substring from, may be null
2687     * @param start  the position to start from, negative means
2688     *  count back from the end of the String by this many characters
2689     * @param end  the position to end at (exclusive), negative means
2690     *  count back from the end of the String by this many characters
2691     * @return substring from start position to end position,
2692     *  {@code null} if null String input
2693     */
2694    public static String substring(final String str, int start, int end) {
2695        if (str == null) {
2696            return null;
2697        }
2698
2699        // handle negatives
2700        if (end < 0) {
2701            end = str.length() + end; // remember end is negative
2702        }
2703        if (start < 0) {
2704            start = str.length() + start; // remember start is negative
2705        }
2706
2707        // check length next
2708        if (end > str.length()) {
2709            end = str.length();
2710        }
2711
2712        // if start is greater than end, return ""
2713        if (start > end) {
2714            return EMPTY;
2715        }
2716
2717        if (start < 0) {
2718            start = 0;
2719        }
2720        if (end < 0) {
2721            end = 0;
2722        }
2723
2724        return str.substring(start, end);
2725    }
2726
2727    // Left/Right/Mid
2728    //-----------------------------------------------------------------------
2729    /**
2730     * <p>Gets the leftmost {@code len} characters of a String.</p>
2731     *
2732     * <p>If {@code len} characters are not available, or the
2733     * String is {@code null}, the String will be returned without
2734     * an exception. An empty String is returned if len is negative.</p>
2735     *
2736     * <pre>
2737     * StringUtils.left(null, *)    = null
2738     * StringUtils.left(*, -ve)     = ""
2739     * StringUtils.left("", *)      = ""
2740     * StringUtils.left("abc", 0)   = ""
2741     * StringUtils.left("abc", 2)   = "ab"
2742     * StringUtils.left("abc", 4)   = "abc"
2743     * </pre>
2744     *
2745     * @param str  the String to get the leftmost characters from, may be null
2746     * @param len  the length of the required String
2747     * @return the leftmost characters, {@code null} if null String input
2748     */
2749    public static String left(final String str, final int len) {
2750        if (str == null) {
2751            return null;
2752        }
2753        if (len < 0) {
2754            return EMPTY;
2755        }
2756        if (str.length() <= len) {
2757            return str;
2758        }
2759        return str.substring(0, len);
2760    }
2761
2762    /**
2763     * <p>Gets the rightmost {@code len} characters of a String.</p>
2764     *
2765     * <p>If {@code len} characters are not available, or the String
2766     * is {@code null}, the String will be returned without an
2767     * an exception. An empty String is returned if len is negative.</p>
2768     *
2769     * <pre>
2770     * StringUtils.right(null, *)    = null
2771     * StringUtils.right(*, -ve)     = ""
2772     * StringUtils.right("", *)      = ""
2773     * StringUtils.right("abc", 0)   = ""
2774     * StringUtils.right("abc", 2)   = "bc"
2775     * StringUtils.right("abc", 4)   = "abc"
2776     * </pre>
2777     *
2778     * @param str  the String to get the rightmost characters from, may be null
2779     * @param len  the length of the required String
2780     * @return the rightmost characters, {@code null} if null String input
2781     */
2782    public static String right(final String str, final int len) {
2783        if (str == null) {
2784            return null;
2785        }
2786        if (len < 0) {
2787            return EMPTY;
2788        }
2789        if (str.length() <= len) {
2790            return str;
2791        }
2792        return str.substring(str.length() - len);
2793    }
2794
2795    /**
2796     * <p>Gets {@code len} characters from the middle of a String.</p>
2797     *
2798     * <p>If {@code len} characters are not available, the remainder
2799     * of the String will be returned without an exception. If the
2800     * String is {@code null}, {@code null} will be returned.
2801     * An empty String is returned if len is negative or exceeds the
2802     * length of {@code str}.</p>
2803     *
2804     * <pre>
2805     * StringUtils.mid(null, *, *)    = null
2806     * StringUtils.mid(*, *, -ve)     = ""
2807     * StringUtils.mid("", 0, *)      = ""
2808     * StringUtils.mid("abc", 0, 2)   = "ab"
2809     * StringUtils.mid("abc", 0, 4)   = "abc"
2810     * StringUtils.mid("abc", 2, 4)   = "c"
2811     * StringUtils.mid("abc", 4, 2)   = ""
2812     * StringUtils.mid("abc", -2, 2)  = "ab"
2813     * </pre>
2814     *
2815     * @param str  the String to get the characters from, may be null
2816     * @param pos  the position to start from, negative treated as zero
2817     * @param len  the length of the required String
2818     * @return the middle characters, {@code null} if null String input
2819     */
2820    public static String mid(final String str, int pos, final int len) {
2821        if (str == null) {
2822            return null;
2823        }
2824        if (len < 0 || pos > str.length()) {
2825            return EMPTY;
2826        }
2827        if (pos < 0) {
2828            pos = 0;
2829        }
2830        if (str.length() <= pos + len) {
2831            return str.substring(pos);
2832        }
2833        return str.substring(pos, pos + len);
2834    }
2835
2836    private static StringBuilder newStringBuilder(final int noOfItems) {
2837        return new StringBuilder(noOfItems * 16);
2838    }
2839
2840    // SubStringAfter/SubStringBefore
2841    //-----------------------------------------------------------------------
2842    /**
2843     * <p>Gets the substring before the first occurrence of a separator.
2844     * The separator is not returned.</p>
2845     *
2846     * <p>A {@code null} string input will return {@code null}.
2847     * An empty ("") string input will return the empty string.
2848     * A {@code null} separator will return the input string.</p>
2849     *
2850     * <p>If nothing is found, the string input is returned.</p>
2851     *
2852     * <pre>
2853     * StringUtils.substringBefore(null, *)      = null
2854     * StringUtils.substringBefore("", *)        = ""
2855     * StringUtils.substringBefore("abc", "a")   = ""
2856     * StringUtils.substringBefore("abcba", "b") = "a"
2857     * StringUtils.substringBefore("abc", "c")   = "ab"
2858     * StringUtils.substringBefore("abc", "d")   = "abc"
2859     * StringUtils.substringBefore("abc", "")    = ""
2860     * StringUtils.substringBefore("abc", null)  = "abc"
2861     * </pre>
2862     *
2863     * @param str  the String to get a substring from, may be null
2864     * @param separator  the String to search for, may be null
2865     * @return the substring before the first occurrence of the separator,
2866     *  {@code null} if null String input
2867     * @since 2.0
2868     */
2869    public static String substringBefore(final String str, final String separator) {
2870        if (isEmpty(str) || separator == null) {
2871            return str;
2872        }
2873        if (separator.isEmpty()) {
2874            return EMPTY;
2875        }
2876        final int pos = str.indexOf(separator);
2877        if (pos == INDEX_NOT_FOUND) {
2878            return str;
2879        }
2880        return str.substring(0, pos);
2881    }
2882
2883    /**
2884     * <p>Gets the substring after the first occurrence of a separator.
2885     * The separator is not returned.</p>
2886     *
2887     * <p>A {@code null} string input will return {@code null}.
2888     * An empty ("") string input will return the empty string.
2889     * A {@code null} separator will return the empty string if the
2890     * input string is not {@code null}.</p>
2891     *
2892     * <p>If nothing is found, the empty string is returned.</p>
2893     *
2894     * <pre>
2895     * StringUtils.substringAfter(null, *)      = null
2896     * StringUtils.substringAfter("", *)        = ""
2897     * StringUtils.substringAfter(*, null)      = ""
2898     * StringUtils.substringAfter("abc", "a")   = "bc"
2899     * StringUtils.substringAfter("abcba", "b") = "cba"
2900     * StringUtils.substringAfter("abc", "c")   = ""
2901     * StringUtils.substringAfter("abc", "d")   = ""
2902     * StringUtils.substringAfter("abc", "")    = "abc"
2903     * </pre>
2904     *
2905     * @param str  the String to get a substring from, may be null
2906     * @param separator  the String to search for, may be null
2907     * @return the substring after the first occurrence of the separator,
2908     *  {@code null} if null String input
2909     * @since 2.0
2910     */
2911    public static String substringAfter(final String str, final String separator) {
2912        if (isEmpty(str)) {
2913            return str;
2914        }
2915        if (separator == null) {
2916            return EMPTY;
2917        }
2918        final int pos = str.indexOf(separator);
2919        if (pos == INDEX_NOT_FOUND) {
2920            return EMPTY;
2921        }
2922        return str.substring(pos + separator.length());
2923    }
2924
2925    /**
2926     * <p>Gets the substring before the last occurrence of a separator.
2927     * The separator is not returned.</p>
2928     *
2929     * <p>A {@code null} string input will return {@code null}.
2930     * An empty ("") string input will return the empty string.
2931     * An empty or {@code null} separator will return the input string.</p>
2932     *
2933     * <p>If nothing is found, the string input is returned.</p>
2934     *
2935     * <pre>
2936     * StringUtils.substringBeforeLast(null, *)      = null
2937     * StringUtils.substringBeforeLast("", *)        = ""
2938     * StringUtils.substringBeforeLast("abcba", "b") = "abc"
2939     * StringUtils.substringBeforeLast("abc", "c")   = "ab"
2940     * StringUtils.substringBeforeLast("a", "a")     = ""
2941     * StringUtils.substringBeforeLast("a", "z")     = "a"
2942     * StringUtils.substringBeforeLast("a", null)    = "a"
2943     * StringUtils.substringBeforeLast("a", "")      = "a"
2944     * </pre>
2945     *
2946     * @param str  the String to get a substring from, may be null
2947     * @param separator  the String to search for, may be null
2948     * @return the substring before the last occurrence of the separator,
2949     *  {@code null} if null String input
2950     * @since 2.0
2951     */
2952    public static String substringBeforeLast(final String str, final String separator) {
2953        if (isEmpty(str) || isEmpty(separator)) {
2954            return str;
2955        }
2956        final int pos = str.lastIndexOf(separator);
2957        if (pos == INDEX_NOT_FOUND) {
2958            return str;
2959        }
2960        return str.substring(0, pos);
2961    }
2962
2963    /**
2964     * <p>Gets the substring after the last occurrence of a separator.
2965     * The separator is not returned.</p>
2966     *
2967     * <p>A {@code null} string input will return {@code null}.
2968     * An empty ("") string input will return the empty string.
2969     * An empty or {@code null} separator will return the empty string if
2970     * the input string is not {@code null}.</p>
2971     *
2972     * <p>If nothing is found, the empty string is returned.</p>
2973     *
2974     * <pre>
2975     * StringUtils.substringAfterLast(null, *)      = null
2976     * StringUtils.substringAfterLast("", *)        = ""
2977     * StringUtils.substringAfterLast(*, "")        = ""
2978     * StringUtils.substringAfterLast(*, null)      = ""
2979     * StringUtils.substringAfterLast("abc", "a")   = "bc"
2980     * StringUtils.substringAfterLast("abcba", "b") = "a"
2981     * StringUtils.substringAfterLast("abc", "c")   = ""
2982     * StringUtils.substringAfterLast("a", "a")     = ""
2983     * StringUtils.substringAfterLast("a", "z")     = ""
2984     * </pre>
2985     *
2986     * @param str  the String to get a substring from, may be null
2987     * @param separator  the String to search for, may be null
2988     * @return the substring after the last occurrence of the separator,
2989     *  {@code null} if null String input
2990     * @since 2.0
2991     */
2992    public static String substringAfterLast(final String str, final String separator) {
2993        if (isEmpty(str)) {
2994            return str;
2995        }
2996        if (isEmpty(separator)) {
2997            return EMPTY;
2998        }
2999        final int pos = str.lastIndexOf(separator);
3000        if (pos == INDEX_NOT_FOUND || pos == str.length() - separator.length()) {
3001            return EMPTY;
3002        }
3003        return str.substring(pos + separator.length());
3004    }
3005
3006    // Substring between
3007    //-----------------------------------------------------------------------
3008    /**
3009     * <p>Gets the String that is nested in between two instances of the
3010     * same String.</p>
3011     *
3012     * <p>A {@code null} input String returns {@code null}.
3013     * A {@code null} tag returns {@code null}.</p>
3014     *
3015     * <pre>
3016     * StringUtils.substringBetween(null, *)            = null
3017     * StringUtils.substringBetween("", "")             = ""
3018     * StringUtils.substringBetween("", "tag")          = null
3019     * StringUtils.substringBetween("tagabctag", null)  = null
3020     * StringUtils.substringBetween("tagabctag", "")    = ""
3021     * StringUtils.substringBetween("tagabctag", "tag") = "abc"
3022     * </pre>
3023     *
3024     * @param str  the String containing the substring, may be null
3025     * @param tag  the String before and after the substring, may be null
3026     * @return the substring, {@code null} if no match
3027     * @since 2.0
3028     */
3029    public static String substringBetween(final String str, final String tag) {
3030        return substringBetween(str, tag, tag);
3031    }
3032
3033    /**
3034     * <p>Gets the String that is nested in between two Strings.
3035     * Only the first match is returned.</p>
3036     *
3037     * <p>A {@code null} input String returns {@code null}.
3038     * A {@code null} open/close returns {@code null} (no match).
3039     * An empty ("") open and close returns an empty string.</p>
3040     *
3041     * <pre>
3042     * StringUtils.substringBetween("wx[b]yz", "[", "]") = "b"
3043     * StringUtils.substringBetween(null, *, *)          = null
3044     * StringUtils.substringBetween(*, null, *)          = null
3045     * StringUtils.substringBetween(*, *, null)          = null
3046     * StringUtils.substringBetween("", "", "")          = ""
3047     * StringUtils.substringBetween("", "", "]")         = null
3048     * StringUtils.substringBetween("", "[", "]")        = null
3049     * StringUtils.substringBetween("yabcz", "", "")     = ""
3050     * StringUtils.substringBetween("yabcz", "y", "z")   = "abc"
3051     * StringUtils.substringBetween("yabczyabcz", "y", "z")   = "abc"
3052     * </pre>
3053     *
3054     * @param str  the String containing the substring, may be null
3055     * @param open  the String before the substring, may be null
3056     * @param close  the String after the substring, may be null
3057     * @return the substring, {@code null} if no match
3058     * @since 2.0
3059     */
3060    public static String substringBetween(final String str, final String open, final String close) {
3061        if (str == null || open == null || close == null) {
3062            return null;
3063        }
3064        final int start = str.indexOf(open);
3065        if (start != INDEX_NOT_FOUND) {
3066            final int end = str.indexOf(close, start + open.length());
3067            if (end != INDEX_NOT_FOUND) {
3068                return str.substring(start + open.length(), end);
3069            }
3070        }
3071        return null;
3072    }
3073
3074    /**
3075     * <p>Searches a String for substrings delimited by a start and end tag,
3076     * returning all matching substrings in an array.</p>
3077     *
3078     * <p>A {@code null} input String returns {@code null}.
3079     * A {@code null} open/close returns {@code null} (no match).
3080     * An empty ("") open/close returns {@code null} (no match).</p>
3081     *
3082     * <pre>
3083     * StringUtils.substringsBetween("[a][b][c]", "[", "]") = ["a","b","c"]
3084     * StringUtils.substringsBetween(null, *, *)            = null
3085     * StringUtils.substringsBetween(*, null, *)            = null
3086     * StringUtils.substringsBetween(*, *, null)            = null
3087     * StringUtils.substringsBetween("", "[", "]")          = []
3088     * </pre>
3089     *
3090     * @param str  the String containing the substrings, null returns null, empty returns empty
3091     * @param open  the String identifying the start of the substring, empty returns null
3092     * @param close  the String identifying the end of the substring, empty returns null
3093     * @return a String Array of substrings, or {@code null} if no match
3094     * @since 2.3
3095     */
3096    public static String[] substringsBetween(final String str, final String open, final String close) {
3097        if (str == null || isEmpty(open) || isEmpty(close)) {
3098            return null;
3099        }
3100        final int strLen = str.length();
3101        if (strLen == 0) {
3102            return ArrayUtils.EMPTY_STRING_ARRAY;
3103        }
3104        final int closeLen = close.length();
3105        final int openLen = open.length();
3106        final List<String> list = new ArrayList<>();
3107        int pos = 0;
3108        while (pos < strLen - closeLen) {
3109            int start = str.indexOf(open, pos);
3110            if (start < 0) {
3111                break;
3112            }
3113            start += openLen;
3114            final int end = str.indexOf(close, start);
3115            if (end < 0) {
3116                break;
3117            }
3118            list.add(str.substring(start, end));
3119            pos = end + closeLen;
3120        }
3121        if (list.isEmpty()) {
3122            return null;
3123        }
3124        return list.toArray(new String [list.size()]);
3125    }
3126
3127    // Nested extraction
3128    //-----------------------------------------------------------------------
3129
3130    // Splitting
3131    //-----------------------------------------------------------------------
3132    /**
3133     * <p>Splits the provided text into an array, using whitespace as the
3134     * separator.
3135     * Whitespace is defined by {@link Character#isWhitespace(char)}.</p>
3136     *
3137     * <p>The separator is not included in the returned String array.
3138     * Adjacent separators are treated as one separator.
3139     * For more control over the split use the StrTokenizer class.</p>
3140     *
3141     * <p>A {@code null} input String returns {@code null}.</p>
3142     *
3143     * <pre>
3144     * StringUtils.split(null)       = null
3145     * StringUtils.split("")         = []
3146     * StringUtils.split("abc def")  = ["abc", "def"]
3147     * StringUtils.split("abc  def") = ["abc", "def"]
3148     * StringUtils.split(" abc ")    = ["abc"]
3149     * </pre>
3150     *
3151     * @param str  the String to parse, may be null
3152     * @return an array of parsed Strings, {@code null} if null String input
3153     */
3154    public static String[] split(final String str) {
3155        return split(str, null, -1);
3156    }
3157
3158    /**
3159     * <p>Splits the provided text into an array, separator specified.
3160     * This is an alternative to using StringTokenizer.</p>
3161     *
3162     * <p>The separator is not included in the returned String array.
3163     * Adjacent separators are treated as one separator.
3164     * For more control over the split use the StrTokenizer class.</p>
3165     *
3166     * <p>A {@code null} input String returns {@code null}.</p>
3167     *
3168     * <pre>
3169     * StringUtils.split(null, *)         = null
3170     * StringUtils.split("", *)           = []
3171     * StringUtils.split("a.b.c", '.')    = ["a", "b", "c"]
3172     * StringUtils.split("a..b.c", '.')   = ["a", "b", "c"]
3173     * StringUtils.split("a:b:c", '.')    = ["a:b:c"]
3174     * StringUtils.split("a b c", ' ')    = ["a", "b", "c"]
3175     * </pre>
3176     *
3177     * @param str  the String to parse, may be null
3178     * @param separatorChar  the character used as the delimiter
3179     * @return an array of parsed Strings, {@code null} if null String input
3180     * @since 2.0
3181     */
3182    public static String[] split(final String str, final char separatorChar) {
3183        return splitWorker(str, separatorChar, false);
3184    }
3185
3186    /**
3187     * <p>Splits the provided text into an array, separators specified.
3188     * This is an alternative to using StringTokenizer.</p>
3189     *
3190     * <p>The separator is not included in the returned String array.
3191     * Adjacent separators are treated as one separator.
3192     * For more control over the split use the StrTokenizer class.</p>
3193     *
3194     * <p>A {@code null} input String returns {@code null}.
3195     * A {@code null} separatorChars splits on whitespace.</p>
3196     *
3197     * <pre>
3198     * StringUtils.split(null, *)         = null
3199     * StringUtils.split("", *)           = []
3200     * StringUtils.split("abc def", null) = ["abc", "def"]
3201     * StringUtils.split("abc def", " ")  = ["abc", "def"]
3202     * StringUtils.split("abc  def", " ") = ["abc", "def"]
3203     * StringUtils.split("ab:cd:ef", ":") = ["ab", "cd", "ef"]
3204     * </pre>
3205     *
3206     * @param str  the String to parse, may be null
3207     * @param separatorChars  the characters used as the delimiters,
3208     *  {@code null} splits on whitespace
3209     * @return an array of parsed Strings, {@code null} if null String input
3210     */
3211    public static String[] split(final String str, final String separatorChars) {
3212        return splitWorker(str, separatorChars, -1, false);
3213    }
3214
3215    /**
3216     * <p>Splits the provided text into an array with a maximum length,
3217     * separators specified.</p>
3218     *
3219     * <p>The separator is not included in the returned String array.
3220     * Adjacent separators are treated as one separator.</p>
3221     *
3222     * <p>A {@code null} input String returns {@code null}.
3223     * A {@code null} separatorChars splits on whitespace.</p>
3224     *
3225     * <p>If more than {@code max} delimited substrings are found, the last
3226     * returned string includes all characters after the first {@code max - 1}
3227     * returned strings (including separator characters).</p>
3228     *
3229     * <pre>
3230     * StringUtils.split(null, *, *)            = null
3231     * StringUtils.split("", *, *)              = []
3232     * StringUtils.split("ab cd ef", null, 0)   = ["ab", "cd", "ef"]
3233     * StringUtils.split("ab   cd ef", null, 0) = ["ab", "cd", "ef"]
3234     * StringUtils.split("ab:cd:ef", ":", 0)    = ["ab", "cd", "ef"]
3235     * StringUtils.split("ab:cd:ef", ":", 2)    = ["ab", "cd:ef"]
3236     * </pre>
3237     *
3238     * @param str  the String to parse, may be null
3239     * @param separatorChars  the characters used as the delimiters,
3240     *  {@code null} splits on whitespace
3241     * @param max  the maximum number of elements to include in the
3242     *  array. A zero or negative value implies no limit
3243     * @return an array of parsed Strings, {@code null} if null String input
3244     */
3245    public static String[] split(final String str, final String separatorChars, final int max) {
3246        return splitWorker(str, separatorChars, max, false);
3247    }
3248
3249    /**
3250     * <p>Splits the provided text into an array, separator string specified.</p>
3251     *
3252     * <p>The separator(s) will not be included in the returned String array.
3253     * Adjacent separators are treated as one separator.</p>
3254     *
3255     * <p>A {@code null} input String returns {@code null}.
3256     * A {@code null} separator splits on whitespace.</p>
3257     *
3258     * <pre>
3259     * StringUtils.splitByWholeSeparator(null, *)               = null
3260     * StringUtils.splitByWholeSeparator("", *)                 = []
3261     * StringUtils.splitByWholeSeparator("ab de fg", null)      = ["ab", "de", "fg"]
3262     * StringUtils.splitByWholeSeparator("ab   de fg", null)    = ["ab", "de", "fg"]
3263     * StringUtils.splitByWholeSeparator("ab:cd:ef", ":")       = ["ab", "cd", "ef"]
3264     * StringUtils.splitByWholeSeparator("ab-!-cd-!-ef", "-!-") = ["ab", "cd", "ef"]
3265     * </pre>
3266     *
3267     * @param str  the String to parse, may be null
3268     * @param separator  String containing the String to be used as a delimiter,
3269     *  {@code null} splits on whitespace
3270     * @return an array of parsed Strings, {@code null} if null String was input
3271     */
3272    public static String[] splitByWholeSeparator(final String str, final String separator) {
3273        return splitByWholeSeparatorWorker(str, separator, -1, false ) ;
3274    }
3275
3276    /**
3277     * <p>Splits the provided text into an array, separator string specified.
3278     * Returns a maximum of {@code max} substrings.</p>
3279     *
3280     * <p>The separator(s) will not be included in the returned String array.
3281     * Adjacent separators are treated as one separator.</p>
3282     *
3283     * <p>A {@code null} input String returns {@code null}.
3284     * A {@code null} separator splits on whitespace.</p>
3285     *
3286     * <pre>
3287     * StringUtils.splitByWholeSeparator(null, *, *)               = null
3288     * StringUtils.splitByWholeSeparator("", *, *)                 = []
3289     * StringUtils.splitByWholeSeparator("ab de fg", null, 0)      = ["ab", "de", "fg"]
3290     * StringUtils.splitByWholeSeparator("ab   de fg", null, 0)    = ["ab", "de", "fg"]
3291     * StringUtils.splitByWholeSeparator("ab:cd:ef", ":", 2)       = ["ab", "cd:ef"]
3292     * StringUtils.splitByWholeSeparator("ab-!-cd-!-ef", "-!-", 5) = ["ab", "cd", "ef"]
3293     * StringUtils.splitByWholeSeparator("ab-!-cd-!-ef", "-!-", 2) = ["ab", "cd-!-ef"]
3294     * </pre>
3295     *
3296     * @param str  the String to parse, may be null
3297     * @param separator  String containing the String to be used as a delimiter,
3298     *  {@code null} splits on whitespace
3299     * @param max  the maximum number of elements to include in the returned
3300     *  array. A zero or negative value implies no limit.
3301     * @return an array of parsed Strings, {@code null} if null String was input
3302     */
3303    public static String[] splitByWholeSeparator( final String str, final String separator, final int max) {
3304        return splitByWholeSeparatorWorker(str, separator, max, false);
3305    }
3306
3307    /**
3308     * <p>Splits the provided text into an array, separator string specified. </p>
3309     *
3310     * <p>The separator is not included in the returned String array.
3311     * Adjacent separators are treated as separators for empty tokens.
3312     * For more control over the split use the StrTokenizer class.</p>
3313     *
3314     * <p>A {@code null} input String returns {@code null}.
3315     * A {@code null} separator splits on whitespace.</p>
3316     *
3317     * <pre>
3318     * StringUtils.splitByWholeSeparatorPreserveAllTokens(null, *)               = null
3319     * StringUtils.splitByWholeSeparatorPreserveAllTokens("", *)                 = []
3320     * StringUtils.splitByWholeSeparatorPreserveAllTokens("ab de fg", null)      = ["ab", "de", "fg"]
3321     * StringUtils.splitByWholeSeparatorPreserveAllTokens("ab   de fg", null)    = ["ab", "", "", "de", "fg"]
3322     * StringUtils.splitByWholeSeparatorPreserveAllTokens("ab:cd:ef", ":")       = ["ab", "cd", "ef"]
3323     * StringUtils.splitByWholeSeparatorPreserveAllTokens("ab-!-cd-!-ef", "-!-") = ["ab", "cd", "ef"]
3324     * </pre>
3325     *
3326     * @param str  the String to parse, may be null
3327     * @param separator  String containing the String to be used as a delimiter,
3328     *  {@code null} splits on whitespace
3329     * @return an array of parsed Strings, {@code null} if null String was input
3330     * @since 2.4
3331     */
3332    public static String[] splitByWholeSeparatorPreserveAllTokens(final String str, final String separator) {
3333        return splitByWholeSeparatorWorker(str, separator, -1, true);
3334    }
3335
3336    /**
3337     * <p>Splits the provided text into an array, separator string specified.
3338     * Returns a maximum of {@code max} substrings.</p>
3339     *
3340     * <p>The separator is not included in the returned String array.
3341     * Adjacent separators are treated as separators for empty tokens.
3342     * For more control over the split use the StrTokenizer class.</p>
3343     *
3344     * <p>A {@code null} input String returns {@code null}.
3345     * A {@code null} separator splits on whitespace.</p>
3346     *
3347     * <pre>
3348     * StringUtils.splitByWholeSeparatorPreserveAllTokens(null, *, *)               = null
3349     * StringUtils.splitByWholeSeparatorPreserveAllTokens("", *, *)                 = []
3350     * StringUtils.splitByWholeSeparatorPreserveAllTokens("ab de fg", null, 0)      = ["ab", "de", "fg"]
3351     * StringUtils.splitByWholeSeparatorPreserveAllTokens("ab   de fg", null, 0)    = ["ab", "", "", "de", "fg"]
3352     * StringUtils.splitByWholeSeparatorPreserveAllTokens("ab:cd:ef", ":", 2)       = ["ab", "cd:ef"]
3353     * StringUtils.splitByWholeSeparatorPreserveAllTokens("ab-!-cd-!-ef", "-!-", 5) = ["ab", "cd", "ef"]
3354     * StringUtils.splitByWholeSeparatorPreserveAllTokens("ab-!-cd-!-ef", "-!-", 2) = ["ab", "cd-!-ef"]
3355     * </pre>
3356     *
3357     * @param str  the String to parse, may be null
3358     * @param separator  String containing the String to be used as a delimiter,
3359     *  {@code null} splits on whitespace
3360     * @param max  the maximum number of elements to include in the returned
3361     *  array. A zero or negative value implies no limit.
3362     * @return an array of parsed Strings, {@code null} if null String was input
3363     * @since 2.4
3364     */
3365    public static String[] splitByWholeSeparatorPreserveAllTokens(final String str, final String separator, final int max) {
3366        return splitByWholeSeparatorWorker(str, separator, max, true);
3367    }
3368
3369    /**
3370     * Performs the logic for the {@code splitByWholeSeparatorPreserveAllTokens} methods.
3371     *
3372     * @param str  the String to parse, may be {@code null}
3373     * @param separator  String containing the String to be used as a delimiter,
3374     *  {@code null} splits on whitespace
3375     * @param max  the maximum number of elements to include in the returned
3376     *  array. A zero or negative value implies no limit.
3377     * @param preserveAllTokens if {@code true}, adjacent separators are
3378     * treated as empty token separators; if {@code false}, adjacent
3379     * separators are treated as one separator.
3380     * @return an array of parsed Strings, {@code null} if null String input
3381     * @since 2.4
3382     */
3383    private static String[] splitByWholeSeparatorWorker(
3384            final String str, final String separator, final int max, final boolean preserveAllTokens) {
3385        if (str == null) {
3386            return null;
3387        }
3388
3389        final int len = str.length();
3390
3391        if (len == 0) {
3392            return ArrayUtils.EMPTY_STRING_ARRAY;
3393        }
3394
3395        if (separator == null || EMPTY.equals(separator)) {
3396            // Split on whitespace.
3397            return splitWorker(str, null, max, preserveAllTokens);
3398        }
3399
3400        final int separatorLength = separator.length();
3401
3402        final ArrayList<String> substrings = new ArrayList<>();
3403        int numberOfSubstrings = 0;
3404        int beg = 0;
3405        int end = 0;
3406        while (end < len) {
3407            end = str.indexOf(separator, beg);
3408
3409            if (end > -1) {
3410                if (end > beg) {
3411                    numberOfSubstrings += 1;
3412
3413                    if (numberOfSubstrings == max) {
3414                        end = len;
3415                        substrings.add(str.substring(beg));
3416                    } else {
3417                        // The following is OK, because String.substring( beg, end ) excludes
3418                        // the character at the position 'end'.
3419                        substrings.add(str.substring(beg, end));
3420
3421                        // Set the starting point for the next search.
3422                        // The following is equivalent to beg = end + (separatorLength - 1) + 1,
3423                        // which is the right calculation:
3424                        beg = end + separatorLength;
3425                    }
3426                } else {
3427                    // We found a consecutive occurrence of the separator, so skip it.
3428                    if (preserveAllTokens) {
3429                        numberOfSubstrings += 1;
3430                        if (numberOfSubstrings == max) {
3431                            end = len;
3432                            substrings.add(str.substring(beg));
3433                        } else {
3434                            substrings.add(EMPTY);
3435                        }
3436                    }
3437                    beg = end + separatorLength;
3438                }
3439            } else {
3440                // String.substring( beg ) goes from 'beg' to the end of the String.
3441                substrings.add(str.substring(beg));
3442                end = len;
3443            }
3444        }
3445
3446        return substrings.toArray(new String[substrings.size()]);
3447    }
3448
3449    // -----------------------------------------------------------------------
3450    /**
3451     * <p>Splits the provided text into an array, using whitespace as the
3452     * separator, preserving all tokens, including empty tokens created by
3453     * adjacent separators. This is an alternative to using StringTokenizer.
3454     * Whitespace is defined by {@link Character#isWhitespace(char)}.</p>
3455     *
3456     * <p>The separator is not included in the returned String array.
3457     * Adjacent separators are treated as separators for empty tokens.
3458     * For more control over the split use the StrTokenizer class.</p>
3459     *
3460     * <p>A {@code null} input String returns {@code null}.</p>
3461     *
3462     * <pre>
3463     * StringUtils.splitPreserveAllTokens(null)       = null
3464     * StringUtils.splitPreserveAllTokens("")         = []
3465     * StringUtils.splitPreserveAllTokens("abc def")  = ["abc", "def"]
3466     * StringUtils.splitPreserveAllTokens("abc  def") = ["abc", "", "def"]
3467     * StringUtils.splitPreserveAllTokens(" abc ")    = ["", "abc", ""]
3468     * </pre>
3469     *
3470     * @param str  the String to parse, may be {@code null}
3471     * @return an array of parsed Strings, {@code null} if null String input
3472     * @since 2.1
3473     */
3474    public static String[] splitPreserveAllTokens(final String str) {
3475        return splitWorker(str, null, -1, true);
3476    }
3477
3478    /**
3479     * <p>Splits the provided text into an array, separator specified,
3480     * preserving all tokens, including empty tokens created by adjacent
3481     * separators. This is an alternative to using StringTokenizer.</p>
3482     *
3483     * <p>The separator is not included in the returned String array.
3484     * Adjacent separators are treated as separators for empty tokens.
3485     * For more control over the split use the StrTokenizer class.</p>
3486     *
3487     * <p>A {@code null} input String returns {@code null}.</p>
3488     *
3489     * <pre>
3490     * StringUtils.splitPreserveAllTokens(null, *)         = null
3491     * StringUtils.splitPreserveAllTokens("", *)           = []
3492     * StringUtils.splitPreserveAllTokens("a.b.c", '.')    = ["a", "b", "c"]
3493     * StringUtils.splitPreserveAllTokens("a..b.c", '.')   = ["a", "", "b", "c"]
3494     * StringUtils.splitPreserveAllTokens("a:b:c", '.')    = ["a:b:c"]
3495     * StringUtils.splitPreserveAllTokens("a\tb\nc", null) = ["a", "b", "c"]
3496     * StringUtils.splitPreserveAllTokens("a b c", ' ')    = ["a", "b", "c"]
3497     * StringUtils.splitPreserveAllTokens("a b c ", ' ')   = ["a", "b", "c", ""]
3498     * StringUtils.splitPreserveAllTokens("a b c  ", ' ')   = ["a", "b", "c", "", ""]
3499     * StringUtils.splitPreserveAllTokens(" a b c", ' ')   = ["", a", "b", "c"]
3500     * StringUtils.splitPreserveAllTokens("  a b c", ' ')  = ["", "", a", "b", "c"]
3501     * StringUtils.splitPreserveAllTokens(" a b c ", ' ')  = ["", a", "b", "c", ""]
3502     * </pre>
3503     *
3504     * @param str  the String to parse, may be {@code null}
3505     * @param separatorChar  the character used as the delimiter,
3506     *  {@code null} splits on whitespace
3507     * @return an array of parsed Strings, {@code null} if null String input
3508     * @since 2.1
3509     */
3510    public static String[] splitPreserveAllTokens(final String str, final char separatorChar) {
3511        return splitWorker(str, separatorChar, true);
3512    }
3513
3514    /**
3515     * Performs the logic for the {@code split} and
3516     * {@code splitPreserveAllTokens} methods that do not return a
3517     * maximum array length.
3518     *
3519     * @param str  the String to parse, may be {@code null}
3520     * @param separatorChar the separate character
3521     * @param preserveAllTokens if {@code true}, adjacent separators are
3522     * treated as empty token separators; if {@code false}, adjacent
3523     * separators are treated as one separator.
3524     * @return an array of parsed Strings, {@code null} if null String input
3525     */
3526    private static String[] splitWorker(final String str, final char separatorChar, final boolean preserveAllTokens) {
3527        // Performance tuned for 2.0 (JDK1.4)
3528
3529        if (str == null) {
3530            return null;
3531        }
3532        final int len = str.length();
3533        if (len == 0) {
3534            return ArrayUtils.EMPTY_STRING_ARRAY;
3535        }
3536        final List<String> list = new ArrayList<>();
3537        int i = 0, start = 0;
3538        boolean match = false;
3539        boolean lastMatch = false;
3540        while (i < len) {
3541            if (str.charAt(i) == separatorChar) {
3542                if (match || preserveAllTokens) {
3543                    list.add(str.substring(start, i));
3544                    match = false;
3545                    lastMatch = true;
3546                }
3547                start = ++i;
3548                continue;
3549            }
3550            lastMatch = false;
3551            match = true;
3552            i++;
3553        }
3554        if (match || preserveAllTokens && lastMatch) {
3555            list.add(str.substring(start, i));
3556        }
3557        return list.toArray(new String[list.size()]);
3558    }
3559
3560    /**
3561     * <p>Splits the provided text into an array, separators specified,
3562     * preserving all tokens, including empty tokens created by adjacent
3563     * separators. This is an alternative to using StringTokenizer.</p>
3564     *
3565     * <p>The separator is not included in the returned String array.
3566     * Adjacent separators are treated as separators for empty tokens.
3567     * For more control over the split use the StrTokenizer class.</p>
3568     *
3569     * <p>A {@code null} input String returns {@code null}.
3570     * A {@code null} separatorChars splits on whitespace.</p>
3571     *
3572     * <pre>
3573     * StringUtils.splitPreserveAllTokens(null, *)           = null
3574     * StringUtils.splitPreserveAllTokens("", *)             = []
3575     * StringUtils.splitPreserveAllTokens("abc def", null)   = ["abc", "def"]
3576     * StringUtils.splitPreserveAllTokens("abc def", " ")    = ["abc", "def"]
3577     * StringUtils.splitPreserveAllTokens("abc  def", " ")   = ["abc", "", def"]
3578     * StringUtils.splitPreserveAllTokens("ab:cd:ef", ":")   = ["ab", "cd", "ef"]
3579     * StringUtils.splitPreserveAllTokens("ab:cd:ef:", ":")  = ["ab", "cd", "ef", ""]
3580     * StringUtils.splitPreserveAllTokens("ab:cd:ef::", ":") = ["ab", "cd", "ef", "", ""]
3581     * StringUtils.splitPreserveAllTokens("ab::cd:ef", ":")  = ["ab", "", cd", "ef"]
3582     * StringUtils.splitPreserveAllTokens(":cd:ef", ":")     = ["", cd", "ef"]
3583     * StringUtils.splitPreserveAllTokens("::cd:ef", ":")    = ["", "", cd", "ef"]
3584     * StringUtils.splitPreserveAllTokens(":cd:ef:", ":")    = ["", cd", "ef", ""]
3585     * </pre>
3586     *
3587     * @param str  the String to parse, may be {@code null}
3588     * @param separatorChars  the characters used as the delimiters,
3589     *  {@code null} splits on whitespace
3590     * @return an array of parsed Strings, {@code null} if null String input
3591     * @since 2.1
3592     */
3593    public static String[] splitPreserveAllTokens(final String str, final String separatorChars) {
3594        return splitWorker(str, separatorChars, -1, true);
3595    }
3596
3597    /**
3598     * <p>Splits the provided text into an array with a maximum length,
3599     * separators specified, preserving all tokens, including empty tokens
3600     * created by adjacent separators.</p>
3601     *
3602     * <p>The separator is not included in the returned String array.
3603     * Adjacent separators are treated as separators for empty tokens.
3604     * Adjacent separators are treated as one separator.</p>
3605     *
3606     * <p>A {@code null} input String returns {@code null}.
3607     * A {@code null} separatorChars splits on whitespace.</p>
3608     *
3609     * <p>If more than {@code max} delimited substrings are found, the last
3610     * returned string includes all characters after the first {@code max - 1}
3611     * returned strings (including separator characters).</p>
3612     *
3613     * <pre>
3614     * StringUtils.splitPreserveAllTokens(null, *, *)            = null
3615     * StringUtils.splitPreserveAllTokens("", *, *)              = []
3616     * StringUtils.splitPreserveAllTokens("ab de fg", null, 0)   = ["ab", "cd", "ef"]
3617     * StringUtils.splitPreserveAllTokens("ab   de fg", null, 0) = ["ab", "cd", "ef"]
3618     * StringUtils.splitPreserveAllTokens("ab:cd:ef", ":", 0)    = ["ab", "cd", "ef"]
3619     * StringUtils.splitPreserveAllTokens("ab:cd:ef", ":", 2)    = ["ab", "cd:ef"]
3620     * StringUtils.splitPreserveAllTokens("ab   de fg", null, 2) = ["ab", "  de fg"]
3621     * StringUtils.splitPreserveAllTokens("ab   de fg", null, 3) = ["ab", "", " de fg"]
3622     * StringUtils.splitPreserveAllTokens("ab   de fg", null, 4) = ["ab", "", "", "de fg"]
3623     * </pre>
3624     *
3625     * @param str  the String to parse, may be {@code null}
3626     * @param separatorChars  the characters used as the delimiters,
3627     *  {@code null} splits on whitespace
3628     * @param max  the maximum number of elements to include in the
3629     *  array. A zero or negative value implies no limit
3630     * @return an array of parsed Strings, {@code null} if null String input
3631     * @since 2.1
3632     */
3633    public static String[] splitPreserveAllTokens(final String str, final String separatorChars, final int max) {
3634        return splitWorker(str, separatorChars, max, true);
3635    }
3636
3637    /**
3638     * Performs the logic for the {@code split} and
3639     * {@code splitPreserveAllTokens} methods that return a maximum array
3640     * length.
3641     *
3642     * @param str  the String to parse, may be {@code null}
3643     * @param separatorChars the separate character
3644     * @param max  the maximum number of elements to include in the
3645     *  array. A zero or negative value implies no limit.
3646     * @param preserveAllTokens if {@code true}, adjacent separators are
3647     * treated as empty token separators; if {@code false}, adjacent
3648     * separators are treated as one separator.
3649     * @return an array of parsed Strings, {@code null} if null String input
3650     */
3651    private static String[] splitWorker(final String str, final String separatorChars, final int max, final boolean preserveAllTokens) {
3652        // Performance tuned for 2.0 (JDK1.4)
3653        // Direct code is quicker than StringTokenizer.
3654        // Also, StringTokenizer uses isSpace() not isWhitespace()
3655
3656        if (str == null) {
3657            return null;
3658        }
3659        final int len = str.length();
3660        if (len == 0) {
3661            return ArrayUtils.EMPTY_STRING_ARRAY;
3662        }
3663        final List<String> list = new ArrayList<>();
3664        int sizePlus1 = 1;
3665        int i = 0, start = 0;
3666        boolean match = false;
3667        boolean lastMatch = false;
3668        if (separatorChars == null) {
3669            // Null separator means use whitespace
3670            while (i < len) {
3671                if (Character.isWhitespace(str.charAt(i))) {
3672                    if (match || preserveAllTokens) {
3673                        lastMatch = true;
3674                        if (sizePlus1++ == max) {
3675                            i = len;
3676                            lastMatch = false;
3677                        }
3678                        list.add(str.substring(start, i));
3679                        match = false;
3680                    }
3681                    start = ++i;
3682                    continue;
3683                }
3684                lastMatch = false;
3685                match = true;
3686                i++;
3687            }
3688        } else if (separatorChars.length() == 1) {
3689            // Optimise 1 character case
3690            final char sep = separatorChars.charAt(0);
3691            while (i < len) {
3692                if (str.charAt(i) == sep) {
3693                    if (match || preserveAllTokens) {
3694                        lastMatch = true;
3695                        if (sizePlus1++ == max) {
3696                            i = len;
3697                            lastMatch = false;
3698                        }
3699                        list.add(str.substring(start, i));
3700                        match = false;
3701                    }
3702                    start = ++i;
3703                    continue;
3704                }
3705                lastMatch = false;
3706                match = true;
3707                i++;
3708            }
3709        } else {
3710            // standard case
3711            while (i < len) {
3712                if (separatorChars.indexOf(str.charAt(i)) >= 0) {
3713                    if (match || preserveAllTokens) {
3714                        lastMatch = true;
3715                        if (sizePlus1++ == max) {
3716                            i = len;
3717                            lastMatch = false;
3718                        }
3719                        list.add(str.substring(start, i));
3720                        match = false;
3721                    }
3722                    start = ++i;
3723                    continue;
3724                }
3725                lastMatch = false;
3726                match = true;
3727                i++;
3728            }
3729        }
3730        if (match || preserveAllTokens && lastMatch) {
3731            list.add(str.substring(start, i));
3732        }
3733        return list.toArray(new String[list.size()]);
3734    }
3735
3736    /**
3737     * <p>Splits a String by Character type as returned by
3738     * {@code java.lang.Character.getType(char)}. Groups of contiguous
3739     * characters of the same type are returned as complete tokens.
3740     * <pre>
3741     * StringUtils.splitByCharacterType(null)         = null
3742     * StringUtils.splitByCharacterType("")           = []
3743     * StringUtils.splitByCharacterType("ab de fg")   = ["ab", " ", "de", " ", "fg"]
3744     * StringUtils.splitByCharacterType("ab   de fg") = ["ab", "   ", "de", " ", "fg"]
3745     * StringUtils.splitByCharacterType("ab:cd:ef")   = ["ab", ":", "cd", ":", "ef"]
3746     * StringUtils.splitByCharacterType("number5")    = ["number", "5"]
3747     * StringUtils.splitByCharacterType("fooBar")     = ["foo", "B", "ar"]
3748     * StringUtils.splitByCharacterType("foo200Bar")  = ["foo", "200", "B", "ar"]
3749     * StringUtils.splitByCharacterType("ASFRules")   = ["ASFR", "ules"]
3750     * </pre>
3751     * @param str the String to split, may be {@code null}
3752     * @return an array of parsed Strings, {@code null} if null String input
3753     * @since 2.4
3754     */
3755    public static String[] splitByCharacterType(final String str) {
3756        return splitByCharacterType(str, false);
3757    }
3758
3759    /**
3760     * <p>Splits a String by Character type as returned by
3761     * {@code java.lang.Character.getType(char)}. Groups of contiguous
3762     * characters of the same type are returned as complete tokens, with the
3763     * following exception: the character of type
3764     * {@code Character.UPPERCASE_LETTER}, if any, immediately
3765     * preceding a token of type {@code Character.LOWERCASE_LETTER}
3766     * will belong to the following token rather than to the preceding, if any,
3767     * {@code Character.UPPERCASE_LETTER} token.
3768     * <pre>
3769     * StringUtils.splitByCharacterTypeCamelCase(null)         = null
3770     * StringUtils.splitByCharacterTypeCamelCase("")           = []
3771     * StringUtils.splitByCharacterTypeCamelCase("ab de fg")   = ["ab", " ", "de", " ", "fg"]
3772     * StringUtils.splitByCharacterTypeCamelCase("ab   de fg") = ["ab", "   ", "de", " ", "fg"]
3773     * StringUtils.splitByCharacterTypeCamelCase("ab:cd:ef")   = ["ab", ":", "cd", ":", "ef"]
3774     * StringUtils.splitByCharacterTypeCamelCase("number5")    = ["number", "5"]
3775     * StringUtils.splitByCharacterTypeCamelCase("fooBar")     = ["foo", "Bar"]
3776     * StringUtils.splitByCharacterTypeCamelCase("foo200Bar")  = ["foo", "200", "Bar"]
3777     * StringUtils.splitByCharacterTypeCamelCase("ASFRules")   = ["ASF", "Rules"]
3778     * </pre>
3779     * @param str the String to split, may be {@code null}
3780     * @return an array of parsed Strings, {@code null} if null String input
3781     * @since 2.4
3782     */
3783    public static String[] splitByCharacterTypeCamelCase(final String str) {
3784        return splitByCharacterType(str, true);
3785    }
3786
3787    /**
3788     * <p>Splits a String by Character type as returned by
3789     * {@code java.lang.Character.getType(char)}. Groups of contiguous
3790     * characters of the same type are returned as complete tokens, with the
3791     * following exception: if {@code camelCase} is {@code true},
3792     * the character of type {@code Character.UPPERCASE_LETTER}, if any,
3793     * immediately preceding a token of type {@code Character.LOWERCASE_LETTER}
3794     * will belong to the following token rather than to the preceding, if any,
3795     * {@code Character.UPPERCASE_LETTER} token.
3796     * @param str the String to split, may be {@code null}
3797     * @param camelCase whether to use so-called "camel-case" for letter types
3798     * @return an array of parsed Strings, {@code null} if null String input
3799     * @since 2.4
3800     */
3801    private static String[] splitByCharacterType(final String str, final boolean camelCase) {
3802        if (str == null) {
3803            return null;
3804        }
3805        if (str.isEmpty()) {
3806            return ArrayUtils.EMPTY_STRING_ARRAY;
3807        }
3808        final char[] c = str.toCharArray();
3809        final List<String> list = new ArrayList<>();
3810        int tokenStart = 0;
3811        int currentType = Character.getType(c[tokenStart]);
3812        for (int pos = tokenStart + 1; pos < c.length; pos++) {
3813            final int type = Character.getType(c[pos]);
3814            if (type == currentType) {
3815                continue;
3816            }
3817            if (camelCase && type == Character.LOWERCASE_LETTER && currentType == Character.UPPERCASE_LETTER) {
3818                final int newTokenStart = pos - 1;
3819                if (newTokenStart != tokenStart) {
3820                    list.add(new String(c, tokenStart, newTokenStart - tokenStart));
3821                    tokenStart = newTokenStart;
3822                }
3823            } else {
3824                list.add(new String(c, tokenStart, pos - tokenStart));
3825                tokenStart = pos;
3826            }
3827            currentType = type;
3828        }
3829        list.add(new String(c, tokenStart, c.length - tokenStart));
3830        return list.toArray(new String[list.size()]);
3831    }
3832
3833    // Joining
3834    //-----------------------------------------------------------------------
3835    /**
3836     * <p>Joins the elements of the provided array into a single String
3837     * containing the provided list of elements.</p>
3838     *
3839     * <p>No separator is added to the joined String.
3840     * Null objects or empty strings within the array are represented by
3841     * empty strings.</p>
3842     *
3843     * <pre>
3844     * StringUtils.join(null)            = null
3845     * StringUtils.join([])              = ""
3846     * StringUtils.join([null])          = ""
3847     * StringUtils.join(["a", "b", "c"]) = "abc"
3848     * StringUtils.join([null, "", "a"]) = "a"
3849     * </pre>
3850     *
3851     * @param <T> the specific type of values to join together
3852     * @param elements  the values to join together, may be null
3853     * @return the joined String, {@code null} if null array input
3854     * @since 2.0
3855     * @since 3.0 Changed signature to use varargs
3856     */
3857    @SafeVarargs
3858    public static <T> String join(final T... elements) {
3859        return join(elements, null);
3860    }
3861
3862    /**
3863     * <p>Joins the elements of the provided array into a single String
3864     * containing the provided list of elements.</p>
3865     *
3866     * <p>No delimiter is added before or after the list.
3867     * Null objects or empty strings within the array are represented by
3868     * empty strings.</p>
3869     *
3870     * <pre>
3871     * StringUtils.join(null, *)               = null
3872     * StringUtils.join([], *)                 = ""
3873     * StringUtils.join([null], *)             = ""
3874     * StringUtils.join(["a", "b", "c"], ';')  = "a;b;c"
3875     * StringUtils.join(["a", "b", "c"], null) = "abc"
3876     * StringUtils.join([null, "", "a"], ';')  = ";;a"
3877     * </pre>
3878     *
3879     * @param array  the array of values to join together, may be null
3880     * @param separator  the separator character to use
3881     * @return the joined String, {@code null} if null array input
3882     * @since 2.0
3883     */
3884    public static String join(final Object[] array, final char separator) {
3885        if (array == null) {
3886            return null;
3887        }
3888        return join(array, separator, 0, array.length);
3889    }
3890
3891    /**
3892     * <p>
3893     * Joins the elements of the provided array into a single String containing the provided list of elements.
3894     * </p>
3895     *
3896     * <p>
3897     * No delimiter is added before or after the list. Null objects or empty strings within the array are represented
3898     * by empty strings.
3899     * </p>
3900     *
3901     * <pre>
3902     * StringUtils.join(null, *)               = null
3903     * StringUtils.join([], *)                 = ""
3904     * StringUtils.join([null], *)             = ""
3905     * StringUtils.join([1, 2, 3], ';')  = "1;2;3"
3906     * StringUtils.join([1, 2, 3], null) = "123"
3907     * </pre>
3908     *
3909     * @param array
3910     *            the array of values to join together, may be null
3911     * @param separator
3912     *            the separator character to use
3913     * @return the joined String, {@code null} if null array input
3914     * @since 3.2
3915     */
3916    public static String join(final long[] array, final char separator) {
3917        if (array == null) {
3918            return null;
3919        }
3920        return join(array, separator, 0, array.length);
3921    }
3922
3923    /**
3924     * <p>
3925     * Joins the elements of the provided array into a single String containing the provided list of elements.
3926     * </p>
3927     *
3928     * <p>
3929     * No delimiter is added before or after the list. Null objects or empty strings within the array are represented
3930     * by empty strings.
3931     * </p>
3932     *
3933     * <pre>
3934     * StringUtils.join(null, *)               = null
3935     * StringUtils.join([], *)                 = ""
3936     * StringUtils.join([null], *)             = ""
3937     * StringUtils.join([1, 2, 3], ';')  = "1;2;3"
3938     * StringUtils.join([1, 2, 3], null) = "123"
3939     * </pre>
3940     *
3941     * @param array
3942     *            the array of values to join together, may be null
3943     * @param separator
3944     *            the separator character to use
3945     * @return the joined String, {@code null} if null array input
3946     * @since 3.2
3947     */
3948    public static String join(final int[] array, final char separator) {
3949        if (array == null) {
3950            return null;
3951        }
3952        return join(array, separator, 0, array.length);
3953    }
3954
3955    /**
3956     * <p>
3957     * Joins the elements of the provided array into a single String containing the provided list of elements.
3958     * </p>
3959     *
3960     * <p>
3961     * No delimiter is added before or after the list. Null objects or empty strings within the array are represented
3962     * by empty strings.
3963     * </p>
3964     *
3965     * <pre>
3966     * StringUtils.join(null, *)               = null
3967     * StringUtils.join([], *)                 = ""
3968     * StringUtils.join([null], *)             = ""
3969     * StringUtils.join([1, 2, 3], ';')  = "1;2;3"
3970     * StringUtils.join([1, 2, 3], null) = "123"
3971     * </pre>
3972     *
3973     * @param array
3974     *            the array of values to join together, may be null
3975     * @param separator
3976     *            the separator character to use
3977     * @return the joined String, {@code null} if null array input
3978     * @since 3.2
3979     */
3980    public static String join(final short[] array, final char separator) {
3981        if (array == null) {
3982            return null;
3983        }
3984        return join(array, separator, 0, array.length);
3985    }
3986
3987    /**
3988     * <p>
3989     * Joins the elements of the provided array into a single String containing the provided list of elements.
3990     * </p>
3991     *
3992     * <p>
3993     * No delimiter is added before or after the list. Null objects or empty strings within the array are represented
3994     * by empty strings.
3995     * </p>
3996     *
3997     * <pre>
3998     * StringUtils.join(null, *)               = null
3999     * StringUtils.join([], *)                 = ""
4000     * StringUtils.join([null], *)             = ""
4001     * StringUtils.join([1, 2, 3], ';')  = "1;2;3"
4002     * StringUtils.join([1, 2, 3], null) = "123"
4003     * </pre>
4004     *
4005     * @param array
4006     *            the array of values to join together, may be null
4007     * @param separator
4008     *            the separator character to use
4009     * @return the joined String, {@code null} if null array input
4010     * @since 3.2
4011     */
4012    public static String join(final byte[] array, final char separator) {
4013        if (array == null) {
4014            return null;
4015        }
4016        return join(array, separator, 0, array.length);
4017    }
4018
4019    /**
4020     * <p>
4021     * Joins the elements of the provided array into a single String containing the provided list of elements.
4022     * </p>
4023     *
4024     * <p>
4025     * No delimiter is added before or after the list. Null objects or empty strings within the array are represented
4026     * by empty strings.
4027     * </p>
4028     *
4029     * <pre>
4030     * StringUtils.join(null, *)               = null
4031     * StringUtils.join([], *)                 = ""
4032     * StringUtils.join([null], *)             = ""
4033     * StringUtils.join([1, 2, 3], ';')  = "1;2;3"
4034     * StringUtils.join([1, 2, 3], null) = "123"
4035     * </pre>
4036     *
4037     * @param array
4038     *            the array of values to join together, may be null
4039     * @param separator
4040     *            the separator character to use
4041     * @return the joined String, {@code null} if null array input
4042     * @since 3.2
4043     */
4044    public static String join(final char[] array, final char separator) {
4045        if (array == null) {
4046            return null;
4047        }
4048        return join(array, separator, 0, array.length);
4049    }
4050
4051    /**
4052     * <p>
4053     * Joins the elements of the provided array into a single String containing the provided list of elements.
4054     * </p>
4055     *
4056     * <p>
4057     * No delimiter is added before or after the list. Null objects or empty strings within the array are represented
4058     * by empty strings.
4059     * </p>
4060     *
4061     * <pre>
4062     * StringUtils.join(null, *)               = null
4063     * StringUtils.join([], *)                 = ""
4064     * StringUtils.join([null], *)             = ""
4065     * StringUtils.join([1, 2, 3], ';')  = "1;2;3"
4066     * StringUtils.join([1, 2, 3], null) = "123"
4067     * </pre>
4068     *
4069     * @param array
4070     *            the array of values to join together, may be null
4071     * @param separator
4072     *            the separator character to use
4073     * @return the joined String, {@code null} if null array input
4074     * @since 3.2
4075     */
4076    public static String join(final float[] array, final char separator) {
4077        if (array == null) {
4078            return null;
4079        }
4080        return join(array, separator, 0, array.length);
4081    }
4082
4083    /**
4084     * <p>
4085     * Joins the elements of the provided array into a single String containing the provided list of elements.
4086     * </p>
4087     *
4088     * <p>
4089     * No delimiter is added before or after the list. Null objects or empty strings within the array are represented
4090     * by empty strings.
4091     * </p>
4092     *
4093     * <pre>
4094     * StringUtils.join(null, *)               = null
4095     * StringUtils.join([], *)                 = ""
4096     * StringUtils.join([null], *)             = ""
4097     * StringUtils.join([1, 2, 3], ';')  = "1;2;3"
4098     * StringUtils.join([1, 2, 3], null) = "123"
4099     * </pre>
4100     *
4101     * @param array
4102     *            the array of values to join together, may be null
4103     * @param separator
4104     *            the separator character to use
4105     * @return the joined String, {@code null} if null array input
4106     * @since 3.2
4107     */
4108    public static String join(final double[] array, final char separator) {
4109        if (array == null) {
4110            return null;
4111        }
4112        return join(array, separator, 0, array.length);
4113    }
4114
4115
4116    /**
4117     * <p>Joins the elements of the provided array into a single String
4118     * containing the provided list of elements.</p>
4119     *
4120     * <p>No delimiter is added before or after the list.
4121     * Null objects or empty strings within the array are represented by
4122     * empty strings.</p>
4123     *
4124     * <pre>
4125     * StringUtils.join(null, *)               = null
4126     * StringUtils.join([], *)                 = ""
4127     * StringUtils.join([null], *)             = ""
4128     * StringUtils.join(["a", "b", "c"], ';')  = "a;b;c"
4129     * StringUtils.join(["a", "b", "c"], null) = "abc"
4130     * StringUtils.join([null, "", "a"], ';')  = ";;a"
4131     * </pre>
4132     *
4133     * @param array  the array of values to join together, may be null
4134     * @param separator  the separator character to use
4135     * @param startIndex the first index to start joining from.  It is
4136     * an error to pass in an end index past the end of the array
4137     * @param endIndex the index to stop joining from (exclusive). It is
4138     * an error to pass in an end index past the end of the array
4139     * @return the joined String, {@code null} if null array input
4140     * @since 2.0
4141     */
4142    public static String join(final Object[] array, final char separator, final int startIndex, final int endIndex) {
4143        if (array == null) {
4144            return null;
4145        }
4146        final int noOfItems = endIndex - startIndex;
4147        if (noOfItems <= 0) {
4148            return EMPTY;
4149        }
4150        final StringBuilder buf = newStringBuilder(noOfItems);
4151        for (int i = startIndex; i < endIndex; i++) {
4152            if (i > startIndex) {
4153                buf.append(separator);
4154            }
4155            if (array[i] != null) {
4156                buf.append(array[i]);
4157            }
4158        }
4159        return buf.toString();
4160    }
4161
4162    /**
4163     * <p>
4164     * Joins the elements of the provided array into a single String containing the provided list of elements.
4165     * </p>
4166     *
4167     * <p>
4168     * No delimiter is added before or after the list. Null objects or empty strings within the array are represented
4169     * by empty strings.
4170     * </p>
4171     *
4172     * <pre>
4173     * StringUtils.join(null, *)               = null
4174     * StringUtils.join([], *)                 = ""
4175     * StringUtils.join([null], *)             = ""
4176     * StringUtils.join([1, 2, 3], ';')  = "1;2;3"
4177     * StringUtils.join([1, 2, 3], null) = "123"
4178     * </pre>
4179     *
4180     * @param array
4181     *            the array of values to join together, may be null
4182     * @param separator
4183     *            the separator character to use
4184     * @param startIndex
4185     *            the first index to start joining from. It is an error to pass in an end index past the end of the
4186     *            array
4187     * @param endIndex
4188     *            the index to stop joining from (exclusive). It is an error to pass in an end index past the end of
4189     *            the array
4190     * @return the joined String, {@code null} if null array input
4191     * @since 3.2
4192     */
4193    public static String join(final long[] array, final char separator, final int startIndex, final int endIndex) {
4194        if (array == null) {
4195            return null;
4196        }
4197        final int noOfItems = endIndex - startIndex;
4198        if (noOfItems <= 0) {
4199            return EMPTY;
4200        }
4201        final StringBuilder buf = newStringBuilder(noOfItems);
4202        for (int i = startIndex; i < endIndex; i++) {
4203            if (i > startIndex) {
4204                buf.append(separator);
4205            }
4206            buf.append(array[i]);
4207        }
4208        return buf.toString();
4209    }
4210
4211    /**
4212     * <p>
4213     * Joins the elements of the provided array into a single String containing the provided list of elements.
4214     * </p>
4215     *
4216     * <p>
4217     * No delimiter is added before or after the list. Null objects or empty strings within the array are represented
4218     * by empty strings.
4219     * </p>
4220     *
4221     * <pre>
4222     * StringUtils.join(null, *)               = null
4223     * StringUtils.join([], *)                 = ""
4224     * StringUtils.join([null], *)             = ""
4225     * StringUtils.join([1, 2, 3], ';')  = "1;2;3"
4226     * StringUtils.join([1, 2, 3], null) = "123"
4227     * </pre>
4228     *
4229     * @param array
4230     *            the array of values to join together, may be null
4231     * @param separator
4232     *            the separator character to use
4233     * @param startIndex
4234     *            the first index to start joining from. It is an error to pass in an end index past the end of the
4235     *            array
4236     * @param endIndex
4237     *            the index to stop joining from (exclusive). It is an error to pass in an end index past the end of
4238     *            the array
4239     * @return the joined String, {@code null} if null array input
4240     * @since 3.2
4241     */
4242    public static String join(final int[] array, final char separator, final int startIndex, final int endIndex) {
4243        if (array == null) {
4244            return null;
4245        }
4246        final int noOfItems = endIndex - startIndex;
4247        if (noOfItems <= 0) {
4248            return EMPTY;
4249        }
4250        final StringBuilder buf = newStringBuilder(noOfItems);
4251        for (int i = startIndex; i < endIndex; i++) {
4252            if (i > startIndex) {
4253                buf.append(separator);
4254            }
4255            buf.append(array[i]);
4256        }
4257        return buf.toString();
4258    }
4259
4260    /**
4261     * <p>
4262     * Joins the elements of the provided array into a single String containing the provided list of elements.
4263     * </p>
4264     *
4265     * <p>
4266     * No delimiter is added before or after the list. Null objects or empty strings within the array are represented
4267     * by empty strings.
4268     * </p>
4269     *
4270     * <pre>
4271     * StringUtils.join(null, *)               = null
4272     * StringUtils.join([], *)                 = ""
4273     * StringUtils.join([null], *)             = ""
4274     * StringUtils.join([1, 2, 3], ';')  = "1;2;3"
4275     * StringUtils.join([1, 2, 3], null) = "123"
4276     * </pre>
4277     *
4278     * @param array
4279     *            the array of values to join together, may be null
4280     * @param separator
4281     *            the separator character to use
4282     * @param startIndex
4283     *            the first index to start joining from. It is an error to pass in an end index past the end of the
4284     *            array
4285     * @param endIndex
4286     *            the index to stop joining from (exclusive). It is an error to pass in an end index past the end of
4287     *            the array
4288     * @return the joined String, {@code null} if null array input
4289     * @since 3.2
4290     */
4291    public static String join(final byte[] array, final char separator, final int startIndex, final int endIndex) {
4292        if (array == null) {
4293            return null;
4294        }
4295        final int noOfItems = endIndex - startIndex;
4296        if (noOfItems <= 0) {
4297            return EMPTY;
4298        }
4299        final StringBuilder buf = newStringBuilder(noOfItems);
4300        for (int i = startIndex; i < endIndex; i++) {
4301            if (i > startIndex) {
4302                buf.append(separator);
4303            }
4304            buf.append(array[i]);
4305        }
4306        return buf.toString();
4307    }
4308
4309    /**
4310     * <p>
4311     * Joins the elements of the provided array into a single String containing the provided list of elements.
4312     * </p>
4313     *
4314     * <p>
4315     * No delimiter is added before or after the list. Null objects or empty strings within the array are represented
4316     * by empty strings.
4317     * </p>
4318     *
4319     * <pre>
4320     * StringUtils.join(null, *)               = null
4321     * StringUtils.join([], *)                 = ""
4322     * StringUtils.join([null], *)             = ""
4323     * StringUtils.join([1, 2, 3], ';')  = "1;2;3"
4324     * StringUtils.join([1, 2, 3], null) = "123"
4325     * </pre>
4326     *
4327     * @param array
4328     *            the array of values to join together, may be null
4329     * @param separator
4330     *            the separator character to use
4331     * @param startIndex
4332     *            the first index to start joining from. It is an error to pass in an end index past the end of the
4333     *            array
4334     * @param endIndex
4335     *            the index to stop joining from (exclusive). It is an error to pass in an end index past the end of
4336     *            the array
4337     * @return the joined String, {@code null} if null array input
4338     * @since 3.2
4339     */
4340    public static String join(final short[] array, final char separator, final int startIndex, final int endIndex) {
4341        if (array == null) {
4342            return null;
4343        }
4344        final int noOfItems = endIndex - startIndex;
4345        if (noOfItems <= 0) {
4346            return EMPTY;
4347        }
4348        final StringBuilder buf = newStringBuilder(noOfItems);
4349        for (int i = startIndex; i < endIndex; i++) {
4350            if (i > startIndex) {
4351                buf.append(separator);
4352            }
4353            buf.append(array[i]);
4354        }
4355        return buf.toString();
4356    }
4357
4358    /**
4359     * <p>
4360     * Joins the elements of the provided array into a single String containing the provided list of elements.
4361     * </p>
4362     *
4363     * <p>
4364     * No delimiter is added before or after the list. Null objects or empty strings within the array are represented
4365     * by empty strings.
4366     * </p>
4367     *
4368     * <pre>
4369     * StringUtils.join(null, *)               = null
4370     * StringUtils.join([], *)                 = ""
4371     * StringUtils.join([null], *)             = ""
4372     * StringUtils.join([1, 2, 3], ';')  = "1;2;3"
4373     * StringUtils.join([1, 2, 3], null) = "123"
4374     * </pre>
4375     *
4376     * @param array
4377     *            the array of values to join together, may be null
4378     * @param separator
4379     *            the separator character to use
4380     * @param startIndex
4381     *            the first index to start joining from. It is an error to pass in an end index past the end of the
4382     *            array
4383     * @param endIndex
4384     *            the index to stop joining from (exclusive). It is an error to pass in an end index past the end of
4385     *            the array
4386     * @return the joined String, {@code null} if null array input
4387     * @since 3.2
4388     */
4389    public static String join(final char[] array, final char separator, final int startIndex, final int endIndex) {
4390        if (array == null) {
4391            return null;
4392        }
4393        final int noOfItems = endIndex - startIndex;
4394        if (noOfItems <= 0) {
4395            return EMPTY;
4396        }
4397        final StringBuilder buf = newStringBuilder(noOfItems);
4398        for (int i = startIndex; i < endIndex; i++) {
4399            if (i > startIndex) {
4400                buf.append(separator);
4401            }
4402            buf.append(array[i]);
4403        }
4404        return buf.toString();
4405    }
4406
4407    /**
4408     * <p>
4409     * Joins the elements of the provided array into a single String containing the provided list of elements.
4410     * </p>
4411     *
4412     * <p>
4413     * No delimiter is added before or after the list. Null objects or empty strings within the array are represented
4414     * by empty strings.
4415     * </p>
4416     *
4417     * <pre>
4418     * StringUtils.join(null, *)               = null
4419     * StringUtils.join([], *)                 = ""
4420     * StringUtils.join([null], *)             = ""
4421     * StringUtils.join([1, 2, 3], ';')  = "1;2;3"
4422     * StringUtils.join([1, 2, 3], null) = "123"
4423     * </pre>
4424     *
4425     * @param array
4426     *            the array of values to join together, may be null
4427     * @param separator
4428     *            the separator character to use
4429     * @param startIndex
4430     *            the first index to start joining from. It is an error to pass in an end index past the end of the
4431     *            array
4432     * @param endIndex
4433     *            the index to stop joining from (exclusive). It is an error to pass in an end index past the end of
4434     *            the array
4435     * @return the joined String, {@code null} if null array input
4436     * @since 3.2
4437     */
4438    public static String join(final double[] array, final char separator, final int startIndex, final int endIndex) {
4439        if (array == null) {
4440            return null;
4441        }
4442        final int noOfItems = endIndex - startIndex;
4443        if (noOfItems <= 0) {
4444            return EMPTY;
4445        }
4446        final StringBuilder buf = newStringBuilder(noOfItems);
4447        for (int i = startIndex; i < endIndex; i++) {
4448            if (i > startIndex) {
4449                buf.append(separator);
4450            }
4451            buf.append(array[i]);
4452        }
4453        return buf.toString();
4454    }
4455
4456    /**
4457     * <p>
4458     * Joins the elements of the provided array into a single String containing the provided list of elements.
4459     * </p>
4460     *
4461     * <p>
4462     * No delimiter is added before or after the list. Null objects or empty strings within the array are represented
4463     * by empty strings.
4464     * </p>
4465     *
4466     * <pre>
4467     * StringUtils.join(null, *)               = null
4468     * StringUtils.join([], *)                 = ""
4469     * StringUtils.join([null], *)             = ""
4470     * StringUtils.join([1, 2, 3], ';')  = "1;2;3"
4471     * StringUtils.join([1, 2, 3], null) = "123"
4472     * </pre>
4473     *
4474     * @param array
4475     *            the array of values to join together, may be null
4476     * @param separator
4477     *            the separator character to use
4478     * @param startIndex
4479     *            the first index to start joining from. It is an error to pass in an end index past the end of the
4480     *            array
4481     * @param endIndex
4482     *            the index to stop joining from (exclusive). It is an error to pass in an end index past the end of
4483     *            the array
4484     * @return the joined String, {@code null} if null array input
4485     * @since 3.2
4486     */
4487    public static String join(final float[] array, final char separator, final int startIndex, final int endIndex) {
4488        if (array == null) {
4489            return null;
4490        }
4491        final int noOfItems = endIndex - startIndex;
4492        if (noOfItems <= 0) {
4493            return EMPTY;
4494        }
4495        final StringBuilder buf = newStringBuilder(noOfItems);
4496        for (int i = startIndex; i < endIndex; i++) {
4497            if (i > startIndex) {
4498                buf.append(separator);
4499            }
4500            buf.append(array[i]);
4501        }
4502        return buf.toString();
4503    }
4504
4505
4506    /**
4507     * <p>Joins the elements of the provided array into a single String
4508     * containing the provided list of elements.</p>
4509     *
4510     * <p>No delimiter is added before or after the list.
4511     * A {@code null} separator is the same as an empty String ("").
4512     * Null objects or empty strings within the array are represented by
4513     * empty strings.</p>
4514     *
4515     * <pre>
4516     * StringUtils.join(null, *)                = null
4517     * StringUtils.join([], *)                  = ""
4518     * StringUtils.join([null], *)              = ""
4519     * StringUtils.join(["a", "b", "c"], "--")  = "a--b--c"
4520     * StringUtils.join(["a", "b", "c"], null)  = "abc"
4521     * StringUtils.join(["a", "b", "c"], "")    = "abc"
4522     * StringUtils.join([null, "", "a"], ',')   = ",,a"
4523     * </pre>
4524     *
4525     * @param array  the array of values to join together, may be null
4526     * @param separator  the separator character to use, null treated as ""
4527     * @return the joined String, {@code null} if null array input
4528     */
4529    public static String join(final Object[] array, final String separator) {
4530        if (array == null) {
4531            return null;
4532        }
4533        return join(array, separator, 0, array.length);
4534    }
4535
4536    /**
4537     * <p>Joins the elements of the provided array into a single String
4538     * containing the provided list of elements.</p>
4539     *
4540     * <p>No delimiter is added before or after the list.
4541     * A {@code null} separator is the same as an empty String ("").
4542     * Null objects or empty strings within the array are represented by
4543     * empty strings.</p>
4544     *
4545     * <pre>
4546     * StringUtils.join(null, *, *, *)                = null
4547     * StringUtils.join([], *, *, *)                  = ""
4548     * StringUtils.join([null], *, *, *)              = ""
4549     * StringUtils.join(["a", "b", "c"], "--", 0, 3)  = "a--b--c"
4550     * StringUtils.join(["a", "b", "c"], "--", 1, 3)  = "b--c"
4551     * StringUtils.join(["a", "b", "c"], "--", 2, 3)  = "c"
4552     * StringUtils.join(["a", "b", "c"], "--", 2, 2)  = ""
4553     * StringUtils.join(["a", "b", "c"], null, 0, 3)  = "abc"
4554     * StringUtils.join(["a", "b", "c"], "", 0, 3)    = "abc"
4555     * StringUtils.join([null, "", "a"], ',', 0, 3)   = ",,a"
4556     * </pre>
4557     *
4558     * @param array  the array of values to join together, may be null
4559     * @param separator  the separator character to use, null treated as ""
4560     * @param startIndex the first index to start joining from.
4561     * @param endIndex the index to stop joining from (exclusive).
4562     * @return the joined String, {@code null} if null array input; or the empty string
4563     * if {@code endIndex - startIndex <= 0}. The number of joined entries is given by
4564     * {@code endIndex - startIndex}
4565     * @throws ArrayIndexOutOfBoundsException ife<br>
4566     * {@code startIndex < 0} or <br>
4567     * {@code startIndex >= array.length()} or <br>
4568     * {@code endIndex < 0} or <br>
4569     * {@code endIndex > array.length()}
4570     */
4571    public static String join(final Object[] array, String separator, final int startIndex, final int endIndex) {
4572        if (array == null) {
4573            return null;
4574        }
4575        if (separator == null) {
4576            separator = EMPTY;
4577        }
4578
4579        // endIndex - startIndex > 0:   Len = NofStrings *(len(firstString) + len(separator))
4580        //           (Assuming that all Strings are roughly equally long)
4581        final int noOfItems = endIndex - startIndex;
4582        if (noOfItems <= 0) {
4583            return EMPTY;
4584        }
4585
4586        final StringBuilder buf = newStringBuilder(noOfItems);
4587
4588        for (int i = startIndex; i < endIndex; i++) {
4589            if (i > startIndex) {
4590                buf.append(separator);
4591            }
4592            if (array[i] != null) {
4593                buf.append(array[i]);
4594            }
4595        }
4596        return buf.toString();
4597    }
4598
4599    /**
4600     * <p>Joins the elements of the provided {@code Iterator} into
4601     * a single String containing the provided elements.</p>
4602     *
4603     * <p>No delimiter is added before or after the list. Null objects or empty
4604     * strings within the iteration are represented by empty strings.</p>
4605     *
4606     * <p>See the examples here: {@link #join(Object[],char)}. </p>
4607     *
4608     * @param iterator  the {@code Iterator} of values to join together, may be null
4609     * @param separator  the separator character to use
4610     * @return the joined String, {@code null} if null iterator input
4611     * @since 2.0
4612     */
4613    public static String join(final Iterator<?> iterator, final char separator) {
4614
4615        // handle null, zero and one elements before building a buffer
4616        if (iterator == null) {
4617            return null;
4618        }
4619        if (!iterator.hasNext()) {
4620            return EMPTY;
4621        }
4622        final Object first = iterator.next();
4623        if (!iterator.hasNext()) {
4624            return Objects.toString(first, EMPTY);
4625        }
4626
4627        // two or more elements
4628        final StringBuilder buf = new StringBuilder(STRING_BUILDER_SIZE); // Java default is 16, probably too small
4629        if (first != null) {
4630            buf.append(first);
4631        }
4632
4633        while (iterator.hasNext()) {
4634            buf.append(separator);
4635            final Object obj = iterator.next();
4636            if (obj != null) {
4637                buf.append(obj);
4638            }
4639        }
4640
4641        return buf.toString();
4642    }
4643
4644    /**
4645     * <p>Joins the elements of the provided {@code Iterator} into
4646     * a single String containing the provided elements.</p>
4647     *
4648     * <p>No delimiter is added before or after the list.
4649     * A {@code null} separator is the same as an empty String ("").</p>
4650     *
4651     * <p>See the examples here: {@link #join(Object[],String)}. </p>
4652     *
4653     * @param iterator  the {@code Iterator} of values to join together, may be null
4654     * @param separator  the separator character to use, null treated as ""
4655     * @return the joined String, {@code null} if null iterator input
4656     */
4657    public static String join(final Iterator<?> iterator, final String separator) {
4658
4659        // handle null, zero and one elements before building a buffer
4660        if (iterator == null) {
4661            return null;
4662        }
4663        if (!iterator.hasNext()) {
4664            return EMPTY;
4665        }
4666        final Object first = iterator.next();
4667        if (!iterator.hasNext()) {
4668            return Objects.toString(first, "");
4669        }
4670
4671        // two or more elements
4672        final StringBuilder buf = new StringBuilder(STRING_BUILDER_SIZE); // Java default is 16, probably too small
4673        if (first != null) {
4674            buf.append(first);
4675        }
4676
4677        while (iterator.hasNext()) {
4678            if (separator != null) {
4679                buf.append(separator);
4680            }
4681            final Object obj = iterator.next();
4682            if (obj != null) {
4683                buf.append(obj);
4684            }
4685        }
4686        return buf.toString();
4687    }
4688
4689    /**
4690     * <p>Joins the elements of the provided {@code Iterable} into
4691     * a single String containing the provided elements.</p>
4692     *
4693     * <p>No delimiter is added before or after the list. Null objects or empty
4694     * strings within the iteration are represented by empty strings.</p>
4695     *
4696     * <p>See the examples here: {@link #join(Object[],char)}. </p>
4697     *
4698     * @param iterable  the {@code Iterable} providing the values to join together, may be null
4699     * @param separator  the separator character to use
4700     * @return the joined String, {@code null} if null iterator input
4701     * @since 2.3
4702     */
4703    public static String join(final Iterable<?> iterable, final char separator) {
4704        if (iterable == null) {
4705            return null;
4706        }
4707        return join(iterable.iterator(), separator);
4708    }
4709
4710    /**
4711     * <p>Joins the elements of the provided {@code Iterable} into
4712     * a single String containing the provided elements.</p>
4713     *
4714     * <p>No delimiter is added before or after the list.
4715     * A {@code null} separator is the same as an empty String ("").</p>
4716     *
4717     * <p>See the examples here: {@link #join(Object[],String)}. </p>
4718     *
4719     * @param iterable  the {@code Iterable} providing the values to join together, may be null
4720     * @param separator  the separator character to use, null treated as ""
4721     * @return the joined String, {@code null} if null iterator input
4722     * @since 2.3
4723     */
4724    public static String join(final Iterable<?> iterable, final String separator) {
4725        if (iterable == null) {
4726            return null;
4727        }
4728        return join(iterable.iterator(), separator);
4729    }
4730
4731    /**
4732     * <p>Joins the elements of the provided {@code List} into a single String
4733     * containing the provided list of elements.</p>
4734     *
4735     * <p>No delimiter is added before or after the list.
4736     * Null objects or empty strings within the array are represented by
4737     * empty strings.</p>
4738     *
4739     * <pre>
4740     * StringUtils.join(null, *)               = null
4741     * StringUtils.join([], *)                 = ""
4742     * StringUtils.join([null], *)             = ""
4743     * StringUtils.join(["a", "b", "c"], ';')  = "a;b;c"
4744     * StringUtils.join(["a", "b", "c"], null) = "abc"
4745     * StringUtils.join([null, "", "a"], ';')  = ";;a"
4746     * </pre>
4747     *
4748     * @param list  the {@code List} of values to join together, may be null
4749     * @param separator  the separator character to use
4750     * @param startIndex the first index to start joining from.  It is
4751     * an error to pass in an end index past the end of the list
4752     * @param endIndex the index to stop joining from (exclusive). It is
4753     * an error to pass in an end index past the end of the list
4754     * @return the joined String, {@code null} if null list input
4755     * @since 3.8
4756     */
4757    public static String join(final List<?> list, final char separator, final int startIndex, final int endIndex) {
4758        if (list == null) {
4759            return null;
4760        }
4761        final int noOfItems = endIndex - startIndex;
4762        if (noOfItems <= 0) {
4763            return EMPTY;
4764        }
4765        final List<?> subList = list.subList(startIndex, endIndex);
4766        return join(subList.iterator(), separator);
4767    }
4768
4769    /**
4770     * <p>Joins the elements of the provided {@code List} into a single String
4771     * containing the provided list of elements.</p>
4772     *
4773     * <p>No delimiter is added before or after the list.
4774     * Null objects or empty strings within the array are represented by
4775     * empty strings.</p>
4776     *
4777     * <pre>
4778     * StringUtils.join(null, *)               = null
4779     * StringUtils.join([], *)                 = ""
4780     * StringUtils.join([null], *)             = ""
4781     * StringUtils.join(["a", "b", "c"], ';')  = "a;b;c"
4782     * StringUtils.join(["a", "b", "c"], null) = "abc"
4783     * StringUtils.join([null, "", "a"], ';')  = ";;a"
4784     * </pre>
4785     *
4786     * @param list  the {@code List} of values to join together, may be null
4787     * @param separator  the separator character to use
4788     * @param startIndex the first index to start joining from.  It is
4789     * an error to pass in an end index past the end of the list
4790     * @param endIndex the index to stop joining from (exclusive). It is
4791     * an error to pass in an end index past the end of the list
4792     * @return the joined String, {@code null} if null list input
4793     * @since 3.8
4794     */
4795    public static String join(final List<?> list, final String separator, final int startIndex, final int endIndex) {
4796        if (list == null) {
4797            return null;
4798        }
4799        final int noOfItems = endIndex - startIndex;
4800        if (noOfItems <= 0) {
4801            return EMPTY;
4802        }
4803        final List<?> subList = list.subList(startIndex, endIndex);
4804        return join(subList.iterator(), separator);
4805    }
4806
4807    /**
4808     * <p>Joins the elements of the provided varargs into a
4809     * single String containing the provided elements.</p>
4810     *
4811     * <p>No delimiter is added before or after the list.
4812     * {@code null} elements and separator are treated as empty Strings ("").</p>
4813     *
4814     * <pre>
4815     * StringUtils.joinWith(",", {"a", "b"})        = "a,b"
4816     * StringUtils.joinWith(",", {"a", "b",""})     = "a,b,"
4817     * StringUtils.joinWith(",", {"a", null, "b"})  = "a,,b"
4818     * StringUtils.joinWith(null, {"a", "b"})       = "ab"
4819     * </pre>
4820     *
4821     * @param separator the separator character to use, null treated as ""
4822     * @param objects the varargs providing the values to join together. {@code null} elements are treated as ""
4823     * @return the joined String.
4824     * @throws java.lang.IllegalArgumentException if a null varargs is provided
4825     * @since 3.5
4826     */
4827    public static String joinWith(final String separator, final Object... objects) {
4828        if (objects == null) {
4829            throw new IllegalArgumentException("Object varargs must not be null");
4830        }
4831
4832        final String sanitizedSeparator = defaultString(separator);
4833
4834        final StringBuilder result = new StringBuilder();
4835
4836        final Iterator<Object> iterator = Arrays.asList(objects).iterator();
4837        while (iterator.hasNext()) {
4838            final String value = Objects.toString(iterator.next(), "");
4839            result.append(value);
4840
4841            if (iterator.hasNext()) {
4842                result.append(sanitizedSeparator);
4843            }
4844        }
4845
4846        return result.toString();
4847    }
4848
4849    // Delete
4850    //-----------------------------------------------------------------------
4851    /**
4852     * <p>Deletes all whitespaces from a String as defined by
4853     * {@link Character#isWhitespace(char)}.</p>
4854     *
4855     * <pre>
4856     * StringUtils.deleteWhitespace(null)         = null
4857     * StringUtils.deleteWhitespace("")           = ""
4858     * StringUtils.deleteWhitespace("abc")        = "abc"
4859     * StringUtils.deleteWhitespace("   ab  c  ") = "abc"
4860     * </pre>
4861     *
4862     * @param str  the String to delete whitespace from, may be null
4863     * @return the String without whitespaces, {@code null} if null String input
4864     */
4865    public static String deleteWhitespace(final String str) {
4866        if (isEmpty(str)) {
4867            return str;
4868        }
4869        final int sz = str.length();
4870        final char[] chs = new char[sz];
4871        int count = 0;
4872        for (int i = 0; i < sz; i++) {
4873            if (!Character.isWhitespace(str.charAt(i))) {
4874                chs[count++] = str.charAt(i);
4875            }
4876        }
4877        if (count == sz) {
4878            return str;
4879        }
4880        return new String(chs, 0, count);
4881    }
4882
4883    // Remove
4884    //-----------------------------------------------------------------------
4885    /**
4886     * <p>Removes a substring only if it is at the beginning of a source string,
4887     * otherwise returns the source string.</p>
4888     *
4889     * <p>A {@code null} source string will return {@code null}.
4890     * An empty ("") source string will return the empty string.
4891     * A {@code null} search string will return the source string.</p>
4892     *
4893     * <pre>
4894     * StringUtils.removeStart(null, *)      = null
4895     * StringUtils.removeStart("", *)        = ""
4896     * StringUtils.removeStart(*, null)      = *
4897     * StringUtils.removeStart("www.domain.com", "www.")   = "domain.com"
4898     * StringUtils.removeStart("domain.com", "www.")       = "domain.com"
4899     * StringUtils.removeStart("www.domain.com", "domain") = "www.domain.com"
4900     * StringUtils.removeStart("abc", "")    = "abc"
4901     * </pre>
4902     *
4903     * @param str  the source String to search, may be null
4904     * @param remove  the String to search for and remove, may be null
4905     * @return the substring with the string removed if found,
4906     *  {@code null} if null String input
4907     * @since 2.1
4908     */
4909    public static String removeStart(final String str, final String remove) {
4910        if (isEmpty(str) || isEmpty(remove)) {
4911            return str;
4912        }
4913        if (str.startsWith(remove)){
4914            return str.substring(remove.length());
4915        }
4916        return str;
4917    }
4918
4919    /**
4920     * <p>Case insensitive removal of a substring if it is at the beginning of a source string,
4921     * otherwise returns the source string.</p>
4922     *
4923     * <p>A {@code null} source string will return {@code null}.
4924     * An empty ("") source string will return the empty string.
4925     * A {@code null} search string will return the source string.</p>
4926     *
4927     * <pre>
4928     * StringUtils.removeStartIgnoreCase(null, *)      = null
4929     * StringUtils.removeStartIgnoreCase("", *)        = ""
4930     * StringUtils.removeStartIgnoreCase(*, null)      = *
4931     * StringUtils.removeStartIgnoreCase("www.domain.com", "www.")   = "domain.com"
4932     * StringUtils.removeStartIgnoreCase("www.domain.com", "WWW.")   = "domain.com"
4933     * StringUtils.removeStartIgnoreCase("domain.com", "www.")       = "domain.com"
4934     * StringUtils.removeStartIgnoreCase("www.domain.com", "domain") = "www.domain.com"
4935     * StringUtils.removeStartIgnoreCase("abc", "")    = "abc"
4936     * </pre>
4937     *
4938     * @param str  the source String to search, may be null
4939     * @param remove  the String to search for (case insensitive) and remove, may be null
4940     * @return the substring with the string removed if found,
4941     *  {@code null} if null String input
4942     * @since 2.4
4943     */
4944    public static String removeStartIgnoreCase(final String str, final String remove) {
4945        if (isEmpty(str) || isEmpty(remove)) {
4946            return str;
4947        }
4948        if (startsWithIgnoreCase(str, remove)) {
4949            return str.substring(remove.length());
4950        }
4951        return str;
4952    }
4953
4954    /**
4955     * <p>Removes a substring only if it is at the end of a source string,
4956     * otherwise returns the source string.</p>
4957     *
4958     * <p>A {@code null} source string will return {@code null}.
4959     * An empty ("") source string will return the empty string.
4960     * A {@code null} search string will return the source string.</p>
4961     *
4962     * <pre>
4963     * StringUtils.removeEnd(null, *)      = null
4964     * StringUtils.removeEnd("", *)        = ""
4965     * StringUtils.removeEnd(*, null)      = *
4966     * StringUtils.removeEnd("www.domain.com", ".com.")  = "www.domain.com"
4967     * StringUtils.removeEnd("www.domain.com", ".com")   = "www.domain"
4968     * StringUtils.removeEnd("www.domain.com", "domain") = "www.domain.com"
4969     * StringUtils.removeEnd("abc", "")    = "abc"
4970     * </pre>
4971     *
4972     * @param str  the source String to search, may be null
4973     * @param remove  the String to search for and remove, may be null
4974     * @return the substring with the string removed if found,
4975     *  {@code null} if null String input
4976     * @since 2.1
4977     */
4978    public static String removeEnd(final String str, final String remove) {
4979        if (isEmpty(str) || isEmpty(remove)) {
4980            return str;
4981        }
4982        if (str.endsWith(remove)) {
4983            return str.substring(0, str.length() - remove.length());
4984        }
4985        return str;
4986    }
4987
4988    /**
4989     * <p>Case insensitive removal of a substring if it is at the end of a source string,
4990     * otherwise returns the source string.</p>
4991     *
4992     * <p>A {@code null} source string will return {@code null}.
4993     * An empty ("") source string will return the empty string.
4994     * A {@code null} search string will return the source string.</p>
4995     *
4996     * <pre>
4997     * StringUtils.removeEndIgnoreCase(null, *)      = null
4998     * StringUtils.removeEndIgnoreCase("", *)        = ""
4999     * StringUtils.removeEndIgnoreCase(*, null)      = *
5000     * StringUtils.removeEndIgnoreCase("www.domain.com", ".com.")  = "www.domain.com"
5001     * StringUtils.removeEndIgnoreCase("www.domain.com", ".com")   = "www.domain"
5002     * StringUtils.removeEndIgnoreCase("www.domain.com", "domain") = "www.domain.com"
5003     * StringUtils.removeEndIgnoreCase("abc", "")    = "abc"
5004     * StringUtils.removeEndIgnoreCase("www.domain.com", ".COM") = "www.domain")
5005     * StringUtils.removeEndIgnoreCase("www.domain.COM", ".com") = "www.domain")
5006     * </pre>
5007     *
5008     * @param str  the source String to search, may be null
5009     * @param remove  the String to search for (case insensitive) and remove, may be null
5010     * @return the substring with the string removed if found,
5011     *  {@code null} if null String input
5012     * @since 2.4
5013     */
5014    public static String removeEndIgnoreCase(final String str, final String remove) {
5015        if (isEmpty(str) || isEmpty(remove)) {
5016            return str;
5017        }
5018        if (endsWithIgnoreCase(str, remove)) {
5019            return str.substring(0, str.length() - remove.length());
5020        }
5021        return str;
5022    }
5023
5024    /**
5025     * <p>Removes all occurrences of a substring from within the source string.</p>
5026     *
5027     * <p>A {@code null} source string will return {@code null}.
5028     * An empty ("") source string will return the empty string.
5029     * A {@code null} remove string will return the source string.
5030     * An empty ("") remove string will return the source string.</p>
5031     *
5032     * <pre>
5033     * StringUtils.remove(null, *)        = null
5034     * StringUtils.remove("", *)          = ""
5035     * StringUtils.remove(*, null)        = *
5036     * StringUtils.remove(*, "")          = *
5037     * StringUtils.remove("queued", "ue") = "qd"
5038     * StringUtils.remove("queued", "zz") = "queued"
5039     * </pre>
5040     *
5041     * @param str  the source String to search, may be null
5042     * @param remove  the String to search for and remove, may be null
5043     * @return the substring with the string removed if found,
5044     *  {@code null} if null String input
5045     * @since 2.1
5046     */
5047    public static String remove(final String str, final String remove) {
5048        if (isEmpty(str) || isEmpty(remove)) {
5049            return str;
5050        }
5051        return replace(str, remove, EMPTY, -1);
5052    }
5053
5054    /**
5055     * <p>
5056     * Case insensitive removal of all occurrences of a substring from within
5057     * the source string.
5058     * </p>
5059     *
5060     * <p>
5061     * A {@code null} source string will return {@code null}. An empty ("")
5062     * source string will return the empty string. A {@code null} remove string
5063     * will return the source string. An empty ("") remove string will return
5064     * the source string.
5065     * </p>
5066     *
5067     * <pre>
5068     * StringUtils.removeIgnoreCase(null, *)        = null
5069     * StringUtils.removeIgnoreCase("", *)          = ""
5070     * StringUtils.removeIgnoreCase(*, null)        = *
5071     * StringUtils.removeIgnoreCase(*, "")          = *
5072     * StringUtils.removeIgnoreCase("queued", "ue") = "qd"
5073     * StringUtils.removeIgnoreCase("queued", "zz") = "queued"
5074     * StringUtils.removeIgnoreCase("quEUed", "UE") = "qd"
5075     * StringUtils.removeIgnoreCase("queued", "zZ") = "queued"
5076     * </pre>
5077     *
5078     * @param str
5079     *            the source String to search, may be null
5080     * @param remove
5081     *            the String to search for (case insensitive) and remove, may be
5082     *            null
5083     * @return the substring with the string removed if found, {@code null} if
5084     *         null String input
5085     * @since 3.5
5086     */
5087    public static String removeIgnoreCase(final String str, final String remove) {
5088        if (isEmpty(str) || isEmpty(remove)) {
5089            return str;
5090        }
5091        return replaceIgnoreCase(str, remove, EMPTY, -1);
5092    }
5093
5094    /**
5095     * <p>Removes all occurrences of a character from within the source string.</p>
5096     *
5097     * <p>A {@code null} source string will return {@code null}.
5098     * An empty ("") source string will return the empty string.</p>
5099     *
5100     * <pre>
5101     * StringUtils.remove(null, *)       = null
5102     * StringUtils.remove("", *)         = ""
5103     * StringUtils.remove("queued", 'u') = "qeed"
5104     * StringUtils.remove("queued", 'z') = "queued"
5105     * </pre>
5106     *
5107     * @param str  the source String to search, may be null
5108     * @param remove  the char to search for and remove, may be null
5109     * @return the substring with the char removed if found,
5110     *  {@code null} if null String input
5111     * @since 2.1
5112     */
5113    public static String remove(final String str, final char remove) {
5114        if (isEmpty(str) || str.indexOf(remove) == INDEX_NOT_FOUND) {
5115            return str;
5116        }
5117        final char[] chars = str.toCharArray();
5118        int pos = 0;
5119        for (int i = 0; i < chars.length; i++) {
5120            if (chars[i] != remove) {
5121                chars[pos++] = chars[i];
5122            }
5123        }
5124        return new String(chars, 0, pos);
5125    }
5126
5127    /**
5128     * <p>Removes each substring of the text String that matches the given regular expression.</p>
5129     *
5130     * This method is a {@code null} safe equivalent to:
5131     * <ul>
5132     *  <li>{@code text.replaceAll(regex, StringUtils.EMPTY)}</li>
5133     *  <li>{@code Pattern.compile(regex).matcher(text).replaceAll(StringUtils.EMPTY)}</li>
5134     * </ul>
5135     *
5136     * <p>A {@code null} reference passed to this method is a no-op.</p>
5137     *
5138     * <p>Unlike in the {@link #removePattern(String, String)} method, the {@link Pattern#DOTALL} option
5139     * is NOT automatically added.
5140     * To use the DOTALL option prepend <code>"(?s)"</code> to the regex.
5141     * DOTALL is also known as single-line mode in Perl.</p>
5142     *
5143     * <pre>
5144     * StringUtils.removeAll(null, *)      = null
5145     * StringUtils.removeAll("any", (String) null)  = "any"
5146     * StringUtils.removeAll("any", "")    = "any"
5147     * StringUtils.removeAll("any", ".*")  = ""
5148     * StringUtils.removeAll("any", ".+")  = ""
5149     * StringUtils.removeAll("abc", ".?")  = ""
5150     * StringUtils.removeAll("A&lt;__&gt;\n&lt;__&gt;B", "&lt;.*&gt;")      = "A\nB"
5151     * StringUtils.removeAll("A&lt;__&gt;\n&lt;__&gt;B", "(?s)&lt;.*&gt;")  = "AB"
5152     * StringUtils.removeAll("ABCabc123abc", "[a-z]")     = "ABC123"
5153     * </pre>
5154     *
5155     * @param text  text to remove from, may be null
5156     * @param regex  the regular expression to which this string is to be matched
5157     * @return  the text with any removes processed,
5158     *              {@code null} if null String input
5159     *
5160     * @throws  java.util.regex.PatternSyntaxException
5161     *              if the regular expression's syntax is invalid
5162     *
5163     * @see #replaceAll(String, String, String)
5164     * @see #removePattern(String, String)
5165     * @see String#replaceAll(String, String)
5166     * @see java.util.regex.Pattern
5167     * @see java.util.regex.Pattern#DOTALL
5168     * @since 3.5
5169     *
5170     * @deprecated Moved to RegExUtils.
5171     */
5172    @Deprecated
5173    public static String removeAll(final String text, final String regex) {
5174        return RegExUtils.removeAll(text, regex);
5175    }
5176
5177    /**
5178     * <p>Removes the first substring of the text string that matches the given regular expression.</p>
5179     *
5180     * This method is a {@code null} safe equivalent to:
5181     * <ul>
5182     *  <li>{@code text.replaceFirst(regex, StringUtils.EMPTY)}</li>
5183     *  <li>{@code Pattern.compile(regex).matcher(text).replaceFirst(StringUtils.EMPTY)}</li>
5184     * </ul>
5185     *
5186     * <p>A {@code null} reference passed to this method is a no-op.</p>
5187     *
5188     * <p>The {@link Pattern#DOTALL} option is NOT automatically added.
5189     * To use the DOTALL option prepend <code>"(?s)"</code> to the regex.
5190     * DOTALL is also known as single-line mode in Perl.</p>
5191     *
5192     * <pre>
5193     * StringUtils.removeFirst(null, *)      = null
5194     * StringUtils.removeFirst("any", (String) null)  = "any"
5195     * StringUtils.removeFirst("any", "")    = "any"
5196     * StringUtils.removeFirst("any", ".*")  = ""
5197     * StringUtils.removeFirst("any", ".+")  = ""
5198     * StringUtils.removeFirst("abc", ".?")  = "bc"
5199     * StringUtils.removeFirst("A&lt;__&gt;\n&lt;__&gt;B", "&lt;.*&gt;")      = "A\n&lt;__&gt;B"
5200     * StringUtils.removeFirst("A&lt;__&gt;\n&lt;__&gt;B", "(?s)&lt;.*&gt;")  = "AB"
5201     * StringUtils.removeFirst("ABCabc123", "[a-z]")          = "ABCbc123"
5202     * StringUtils.removeFirst("ABCabc123abc", "[a-z]+")      = "ABC123abc"
5203     * </pre>
5204     *
5205     * @param text  text to remove from, may be null
5206     * @param regex  the regular expression to which this string is to be matched
5207     * @return  the text with the first replacement processed,
5208     *              {@code null} if null String input
5209     *
5210     * @throws  java.util.regex.PatternSyntaxException
5211     *              if the regular expression's syntax is invalid
5212     *
5213     * @see #replaceFirst(String, String, String)
5214     * @see String#replaceFirst(String, String)
5215     * @see java.util.regex.Pattern
5216     * @see java.util.regex.Pattern#DOTALL
5217     * @since 3.5
5218     *
5219     * @deprecated Moved to RegExUtils.
5220     */
5221    @Deprecated
5222    public static String removeFirst(final String text, final String regex) {
5223        return replaceFirst(text, regex, EMPTY);
5224    }
5225
5226    // Replacing
5227    //-----------------------------------------------------------------------
5228    /**
5229     * <p>Replaces a String with another String inside a larger String, once.</p>
5230     *
5231     * <p>A {@code null} reference passed to this method is a no-op.</p>
5232     *
5233     * <pre>
5234     * StringUtils.replaceOnce(null, *, *)        = null
5235     * StringUtils.replaceOnce("", *, *)          = ""
5236     * StringUtils.replaceOnce("any", null, *)    = "any"
5237     * StringUtils.replaceOnce("any", *, null)    = "any"
5238     * StringUtils.replaceOnce("any", "", *)      = "any"
5239     * StringUtils.replaceOnce("aba", "a", null)  = "aba"
5240     * StringUtils.replaceOnce("aba", "a", "")    = "ba"
5241     * StringUtils.replaceOnce("aba", "a", "z")   = "zba"
5242     * </pre>
5243     *
5244     * @see #replace(String text, String searchString, String replacement, int max)
5245     * @param text  text to search and replace in, may be null
5246     * @param searchString  the String to search for, may be null
5247     * @param replacement  the String to replace with, may be null
5248     * @return the text with any replacements processed,
5249     *  {@code null} if null String input
5250     */
5251    public static String replaceOnce(final String text, final String searchString, final String replacement) {
5252        return replace(text, searchString, replacement, 1);
5253    }
5254
5255    /**
5256     * <p>Case insensitively replaces a String with another String inside a larger String, once.</p>
5257     *
5258     * <p>A {@code null} reference passed to this method is a no-op.</p>
5259     *
5260     * <pre>
5261     * StringUtils.replaceOnceIgnoreCase(null, *, *)        = null
5262     * StringUtils.replaceOnceIgnoreCase("", *, *)          = ""
5263     * StringUtils.replaceOnceIgnoreCase("any", null, *)    = "any"
5264     * StringUtils.replaceOnceIgnoreCase("any", *, null)    = "any"
5265     * StringUtils.replaceOnceIgnoreCase("any", "", *)      = "any"
5266     * StringUtils.replaceOnceIgnoreCase("aba", "a", null)  = "aba"
5267     * StringUtils.replaceOnceIgnoreCase("aba", "a", "")    = "ba"
5268     * StringUtils.replaceOnceIgnoreCase("aba", "a", "z")   = "zba"
5269     * StringUtils.replaceOnceIgnoreCase("FoOFoofoo", "foo", "") = "Foofoo"
5270     * </pre>
5271     *
5272     * @see #replaceIgnoreCase(String text, String searchString, String replacement, int max)
5273     * @param text  text to search and replace in, may be null
5274     * @param searchString  the String to search for (case insensitive), may be null
5275     * @param replacement  the String to replace with, may be null
5276     * @return the text with any replacements processed,
5277     *  {@code null} if null String input
5278     * @since 3.5
5279     */
5280    public static String replaceOnceIgnoreCase(final String text, final String searchString, final String replacement) {
5281        return replaceIgnoreCase(text, searchString, replacement, 1);
5282    }
5283
5284    /**
5285     * <p>Replaces each substring of the source String that matches the given regular expression with the given
5286     * replacement using the {@link Pattern#DOTALL} option. DOTALL is also known as single-line mode in Perl.</p>
5287     *
5288     * This call is a {@code null} safe equivalent to:
5289     * <ul>
5290     * <li>{@code source.replaceAll(&quot;(?s)&quot; + regex, replacement)}</li>
5291     * <li>{@code Pattern.compile(regex, Pattern.DOTALL).matcher(source).replaceAll(replacement)}</li>
5292     * </ul>
5293     *
5294     * <p>A {@code null} reference passed to this method is a no-op.</p>
5295     *
5296     * <pre>
5297     * StringUtils.replacePattern(null, *, *)       = null
5298     * StringUtils.replacePattern("any", (String) null, *)   = "any"
5299     * StringUtils.replacePattern("any", *, null)   = "any"
5300     * StringUtils.replacePattern("", "", "zzz")    = "zzz"
5301     * StringUtils.replacePattern("", ".*", "zzz")  = "zzz"
5302     * StringUtils.replacePattern("", ".+", "zzz")  = ""
5303     * StringUtils.replacePattern("&lt;__&gt;\n&lt;__&gt;", "&lt;.*&gt;", "z")       = "z"
5304     * StringUtils.replacePattern("ABCabc123", "[a-z]", "_")       = "ABC___123"
5305     * StringUtils.replacePattern("ABCabc123", "[^A-Z0-9]+", "_")  = "ABC_123"
5306     * StringUtils.replacePattern("ABCabc123", "[^A-Z0-9]+", "")   = "ABC123"
5307     * StringUtils.replacePattern("Lorem ipsum  dolor   sit", "( +)([a-z]+)", "_$2")  = "Lorem_ipsum_dolor_sit"
5308     * </pre>
5309     *
5310     * @param source
5311     *            the source string
5312     * @param regex
5313     *            the regular expression to which this string is to be matched
5314     * @param replacement
5315     *            the string to be substituted for each match
5316     * @return The resulting {@code String}
5317     * @see #replaceAll(String, String, String)
5318     * @see String#replaceAll(String, String)
5319     * @see Pattern#DOTALL
5320     * @since 3.2
5321     * @since 3.5 Changed {@code null} reference passed to this method is a no-op.
5322     *
5323     * @deprecated Moved to RegExUtils.
5324     */
5325    @Deprecated
5326    public static String replacePattern(final String source, final String regex, final String replacement) {
5327        return RegExUtils.replacePattern(source, regex, replacement);
5328    }
5329
5330    /**
5331     * <p>Removes each substring of the source String that matches the given regular expression using the DOTALL option.
5332     * </p>
5333     *
5334     * This call is a {@code null} safe equivalent to:
5335     * <ul>
5336     * <li>{@code source.replaceAll(&quot;(?s)&quot; + regex, StringUtils.EMPTY)}</li>
5337     * <li>{@code Pattern.compile(regex, Pattern.DOTALL).matcher(source).replaceAll(StringUtils.EMPTY)}</li>
5338     * </ul>
5339     *
5340     * <p>A {@code null} reference passed to this method is a no-op.</p>
5341     *
5342     * <pre>
5343     * StringUtils.removePattern(null, *)       = null
5344     * StringUtils.removePattern("any", (String) null)   = "any"
5345     * StringUtils.removePattern("A&lt;__&gt;\n&lt;__&gt;B", "&lt;.*&gt;")  = "AB"
5346     * StringUtils.removePattern("ABCabc123", "[a-z]")    = "ABC123"
5347     * </pre>
5348     *
5349     * @param source
5350     *            the source string
5351     * @param regex
5352     *            the regular expression to which this string is to be matched
5353     * @return The resulting {@code String}
5354     * @see #replacePattern(String, String, String)
5355     * @see String#replaceAll(String, String)
5356     * @see Pattern#DOTALL
5357     * @since 3.2
5358     * @since 3.5 Changed {@code null} reference passed to this method is a no-op.
5359     *
5360     * @deprecated Moved to RegExUtils.
5361     */
5362    @Deprecated
5363    public static String removePattern(final String source, final String regex) {
5364        return RegExUtils.removePattern(source, regex);
5365    }
5366
5367    /**
5368     * <p>Replaces each substring of the text String that matches the given regular expression
5369     * with the given replacement.</p>
5370     *
5371     * This method is a {@code null} safe equivalent to:
5372     * <ul>
5373     *  <li>{@code text.replaceAll(regex, replacement)}</li>
5374     *  <li>{@code Pattern.compile(regex).matcher(text).replaceAll(replacement)}</li>
5375     * </ul>
5376     *
5377     * <p>A {@code null} reference passed to this method is a no-op.</p>
5378     *
5379     * <p>Unlike in the {@link #replacePattern(String, String, String)} method, the {@link Pattern#DOTALL} option
5380     * is NOT automatically added.
5381     * To use the DOTALL option prepend <code>"(?s)"</code> to the regex.
5382     * DOTALL is also known as single-line mode in Perl.</p>
5383     *
5384     * <pre>
5385     * StringUtils.replaceAll(null, *, *)       = null
5386     * StringUtils.replaceAll("any", (String) null, *)   = "any"
5387     * StringUtils.replaceAll("any", *, null)   = "any"
5388     * StringUtils.replaceAll("", "", "zzz")    = "zzz"
5389     * StringUtils.replaceAll("", ".*", "zzz")  = "zzz"
5390     * StringUtils.replaceAll("", ".+", "zzz")  = ""
5391     * StringUtils.replaceAll("abc", "", "ZZ")  = "ZZaZZbZZcZZ"
5392     * StringUtils.replaceAll("&lt;__&gt;\n&lt;__&gt;", "&lt;.*&gt;", "z")      = "z\nz"
5393     * StringUtils.replaceAll("&lt;__&gt;\n&lt;__&gt;", "(?s)&lt;.*&gt;", "z")  = "z"
5394     * StringUtils.replaceAll("ABCabc123", "[a-z]", "_")       = "ABC___123"
5395     * StringUtils.replaceAll("ABCabc123", "[^A-Z0-9]+", "_")  = "ABC_123"
5396     * StringUtils.replaceAll("ABCabc123", "[^A-Z0-9]+", "")   = "ABC123"
5397     * StringUtils.replaceAll("Lorem ipsum  dolor   sit", "( +)([a-z]+)", "_$2")  = "Lorem_ipsum_dolor_sit"
5398     * </pre>
5399     *
5400     * @param text  text to search and replace in, may be null
5401     * @param regex  the regular expression to which this string is to be matched
5402     * @param replacement  the string to be substituted for each match
5403     * @return  the text with any replacements processed,
5404     *              {@code null} if null String input
5405     *
5406     * @throws  java.util.regex.PatternSyntaxException
5407     *              if the regular expression's syntax is invalid
5408     *
5409     * @see #replacePattern(String, String, String)
5410     * @see String#replaceAll(String, String)
5411     * @see java.util.regex.Pattern
5412     * @see java.util.regex.Pattern#DOTALL
5413     * @since 3.5
5414     *
5415     * @deprecated Moved to RegExUtils.
5416     */
5417    @Deprecated
5418    public static String replaceAll(final String text, final String regex, final String replacement) {
5419        return RegExUtils.replaceAll(text, regex, replacement);
5420    }
5421
5422    /**
5423     * <p>Replaces the first substring of the text string that matches the given regular expression
5424     * with the given replacement.</p>
5425     *
5426     * This method is a {@code null} safe equivalent to:
5427     * <ul>
5428     *  <li>{@code text.replaceFirst(regex, replacement)}</li>
5429     *  <li>{@code Pattern.compile(regex).matcher(text).replaceFirst(replacement)}</li>
5430     * </ul>
5431     *
5432     * <p>A {@code null} reference passed to this method is a no-op.</p>
5433     *
5434     * <p>The {@link Pattern#DOTALL} option is NOT automatically added.
5435     * To use the DOTALL option prepend <code>"(?s)"</code> to the regex.
5436     * DOTALL is also known as single-line mode in Perl.</p>
5437     *
5438     * <pre>
5439     * StringUtils.replaceFirst(null, *, *)       = null
5440     * StringUtils.replaceFirst("any", (String) null, *)   = "any"
5441     * StringUtils.replaceFirst("any", *, null)   = "any"
5442     * StringUtils.replaceFirst("", "", "zzz")    = "zzz"
5443     * StringUtils.replaceFirst("", ".*", "zzz")  = "zzz"
5444     * StringUtils.replaceFirst("", ".+", "zzz")  = ""
5445     * StringUtils.replaceFirst("abc", "", "ZZ")  = "ZZabc"
5446     * StringUtils.replaceFirst("&lt;__&gt;\n&lt;__&gt;", "&lt;.*&gt;", "z")      = "z\n&lt;__&gt;"
5447     * StringUtils.replaceFirst("&lt;__&gt;\n&lt;__&gt;", "(?s)&lt;.*&gt;", "z")  = "z"
5448     * StringUtils.replaceFirst("ABCabc123", "[a-z]", "_")          = "ABC_bc123"
5449     * StringUtils.replaceFirst("ABCabc123abc", "[^A-Z0-9]+", "_")  = "ABC_123abc"
5450     * StringUtils.replaceFirst("ABCabc123abc", "[^A-Z0-9]+", "")   = "ABC123abc"
5451     * StringUtils.replaceFirst("Lorem ipsum  dolor   sit", "( +)([a-z]+)", "_$2")  = "Lorem_ipsum  dolor   sit"
5452     * </pre>
5453     *
5454     * @param text  text to search and replace in, may be null
5455     * @param regex  the regular expression to which this string is to be matched
5456     * @param replacement  the string to be substituted for the first match
5457     * @return  the text with the first replacement processed,
5458     *              {@code null} if null String input
5459     *
5460     * @throws  java.util.regex.PatternSyntaxException
5461     *              if the regular expression's syntax is invalid
5462     *
5463     * @see String#replaceFirst(String, String)
5464     * @see java.util.regex.Pattern
5465     * @see java.util.regex.Pattern#DOTALL
5466     * @since 3.5
5467     *
5468     * @deprecated Moved to RegExUtils.
5469     */
5470    @Deprecated
5471    public static String replaceFirst(final String text, final String regex, final String replacement) {
5472        return RegExUtils.replaceFirst(text, regex, replacement);
5473    }
5474
5475    /**
5476     * <p>Replaces all occurrences of a String within another String.</p>
5477     *
5478     * <p>A {@code null} reference passed to this method is a no-op.</p>
5479     *
5480     * <pre>
5481     * StringUtils.replace(null, *, *)        = null
5482     * StringUtils.replace("", *, *)          = ""
5483     * StringUtils.replace("any", null, *)    = "any"
5484     * StringUtils.replace("any", *, null)    = "any"
5485     * StringUtils.replace("any", "", *)      = "any"
5486     * StringUtils.replace("aba", "a", null)  = "aba"
5487     * StringUtils.replace("aba", "a", "")    = "b"
5488     * StringUtils.replace("aba", "a", "z")   = "zbz"
5489     * </pre>
5490     *
5491     * @see #replace(String text, String searchString, String replacement, int max)
5492     * @param text  text to search and replace in, may be null
5493     * @param searchString  the String to search for, may be null
5494     * @param replacement  the String to replace it with, may be null
5495     * @return the text with any replacements processed,
5496     *  {@code null} if null String input
5497     */
5498    public static String replace(final String text, final String searchString, final String replacement) {
5499        return replace(text, searchString, replacement, -1);
5500    }
5501
5502    /**
5503    * <p>Case insensitively replaces all occurrences of a String within another String.</p>
5504    *
5505    * <p>A {@code null} reference passed to this method is a no-op.</p>
5506    *
5507    * <pre>
5508    * StringUtils.replaceIgnoreCase(null, *, *)        = null
5509    * StringUtils.replaceIgnoreCase("", *, *)          = ""
5510    * StringUtils.replaceIgnoreCase("any", null, *)    = "any"
5511    * StringUtils.replaceIgnoreCase("any", *, null)    = "any"
5512    * StringUtils.replaceIgnoreCase("any", "", *)      = "any"
5513    * StringUtils.replaceIgnoreCase("aba", "a", null)  = "aba"
5514    * StringUtils.replaceIgnoreCase("abA", "A", "")    = "b"
5515    * StringUtils.replaceIgnoreCase("aba", "A", "z")   = "zbz"
5516    * </pre>
5517    *
5518    * @see #replaceIgnoreCase(String text, String searchString, String replacement, int max)
5519    * @param text  text to search and replace in, may be null
5520    * @param searchString  the String to search for (case insensitive), may be null
5521    * @param replacement  the String to replace it with, may be null
5522    * @return the text with any replacements processed,
5523    *  {@code null} if null String input
5524    * @since 3.5
5525    */
5526   public static String replaceIgnoreCase(final String text, final String searchString, final String replacement) {
5527       return replaceIgnoreCase(text, searchString, replacement, -1);
5528   }
5529
5530    /**
5531     * <p>Replaces a String with another String inside a larger String,
5532     * for the first {@code max} values of the search String.</p>
5533     *
5534     * <p>A {@code null} reference passed to this method is a no-op.</p>
5535     *
5536     * <pre>
5537     * StringUtils.replace(null, *, *, *)         = null
5538     * StringUtils.replace("", *, *, *)           = ""
5539     * StringUtils.replace("any", null, *, *)     = "any"
5540     * StringUtils.replace("any", *, null, *)     = "any"
5541     * StringUtils.replace("any", "", *, *)       = "any"
5542     * StringUtils.replace("any", *, *, 0)        = "any"
5543     * StringUtils.replace("abaa", "a", null, -1) = "abaa"
5544     * StringUtils.replace("abaa", "a", "", -1)   = "b"
5545     * StringUtils.replace("abaa", "a", "z", 0)   = "abaa"
5546     * StringUtils.replace("abaa", "a", "z", 1)   = "zbaa"
5547     * StringUtils.replace("abaa", "a", "z", 2)   = "zbza"
5548     * StringUtils.replace("abaa", "a", "z", -1)  = "zbzz"
5549     * </pre>
5550     *
5551     * @param text  text to search and replace in, may be null
5552     * @param searchString  the String to search for, may be null
5553     * @param replacement  the String to replace it with, may be null
5554     * @param max  maximum number of values to replace, or {@code -1} if no maximum
5555     * @return the text with any replacements processed,
5556     *  {@code null} if null String input
5557     */
5558    public static String replace(final String text, final String searchString, final String replacement, final int max) {
5559        return replace(text, searchString, replacement, max, false);
5560    }
5561
5562    /**
5563     * <p>Replaces a String with another String inside a larger String,
5564     * for the first {@code max} values of the search String,
5565     * case sensitively/insensisitively based on {@code ignoreCase} value.</p>
5566     *
5567     * <p>A {@code null} reference passed to this method is a no-op.</p>
5568     *
5569     * <pre>
5570     * StringUtils.replace(null, *, *, *, false)         = null
5571     * StringUtils.replace("", *, *, *, false)           = ""
5572     * StringUtils.replace("any", null, *, *, false)     = "any"
5573     * StringUtils.replace("any", *, null, *, false)     = "any"
5574     * StringUtils.replace("any", "", *, *, false)       = "any"
5575     * StringUtils.replace("any", *, *, 0, false)        = "any"
5576     * StringUtils.replace("abaa", "a", null, -1, false) = "abaa"
5577     * StringUtils.replace("abaa", "a", "", -1, false)   = "b"
5578     * StringUtils.replace("abaa", "a", "z", 0, false)   = "abaa"
5579     * StringUtils.replace("abaa", "A", "z", 1, false)   = "abaa"
5580     * StringUtils.replace("abaa", "A", "z", 1, true)   = "zbaa"
5581     * StringUtils.replace("abAa", "a", "z", 2, true)   = "zbza"
5582     * StringUtils.replace("abAa", "a", "z", -1, true)  = "zbzz"
5583     * </pre>
5584     *
5585     * @param text  text to search and replace in, may be null
5586     * @param searchString  the String to search for (case insensitive), may be null
5587     * @param replacement  the String to replace it with, may be null
5588     * @param max  maximum number of values to replace, or {@code -1} if no maximum
5589     * @param ignoreCase if true replace is case insensitive, otherwise case sensitive
5590     * @return the text with any replacements processed,
5591     *  {@code null} if null String input
5592     */
5593     private static String replace(final String text, String searchString, final String replacement, int max, final boolean ignoreCase) {
5594         if (isEmpty(text) || isEmpty(searchString) || replacement == null || max == 0) {
5595             return text;
5596         }
5597         String searchText = text;
5598         if (ignoreCase) {
5599             searchText = text.toLowerCase();
5600             searchString = searchString.toLowerCase();
5601         }
5602         int start = 0;
5603         int end = searchText.indexOf(searchString, start);
5604         if (end == INDEX_NOT_FOUND) {
5605             return text;
5606         }
5607         final int replLength = searchString.length();
5608         int increase = replacement.length() - replLength;
5609         increase = increase < 0 ? 0 : increase;
5610         increase *= max < 0 ? 16 : max > 64 ? 64 : max;
5611         final StringBuilder buf = new StringBuilder(text.length() + increase);
5612         while (end != INDEX_NOT_FOUND) {
5613             buf.append(text, start, end).append(replacement);
5614             start = end + replLength;
5615             if (--max == 0) {
5616                 break;
5617             }
5618             end = searchText.indexOf(searchString, start);
5619         }
5620         buf.append(text, start, text.length());
5621         return buf.toString();
5622     }
5623
5624    /**
5625     * <p>Case insensitively replaces a String with another String inside a larger String,
5626     * for the first {@code max} values of the search String.</p>
5627     *
5628     * <p>A {@code null} reference passed to this method is a no-op.</p>
5629     *
5630     * <pre>
5631     * StringUtils.replaceIgnoreCase(null, *, *, *)         = null
5632     * StringUtils.replaceIgnoreCase("", *, *, *)           = ""
5633     * StringUtils.replaceIgnoreCase("any", null, *, *)     = "any"
5634     * StringUtils.replaceIgnoreCase("any", *, null, *)     = "any"
5635     * StringUtils.replaceIgnoreCase("any", "", *, *)       = "any"
5636     * StringUtils.replaceIgnoreCase("any", *, *, 0)        = "any"
5637     * StringUtils.replaceIgnoreCase("abaa", "a", null, -1) = "abaa"
5638     * StringUtils.replaceIgnoreCase("abaa", "a", "", -1)   = "b"
5639     * StringUtils.replaceIgnoreCase("abaa", "a", "z", 0)   = "abaa"
5640     * StringUtils.replaceIgnoreCase("abaa", "A", "z", 1)   = "zbaa"
5641     * StringUtils.replaceIgnoreCase("abAa", "a", "z", 2)   = "zbza"
5642     * StringUtils.replaceIgnoreCase("abAa", "a", "z", -1)  = "zbzz"
5643     * </pre>
5644     *
5645     * @param text  text to search and replace in, may be null
5646     * @param searchString  the String to search for (case insensitive), may be null
5647     * @param replacement  the String to replace it with, may be null
5648     * @param max  maximum number of values to replace, or {@code -1} if no maximum
5649     * @return the text with any replacements processed,
5650     *  {@code null} if null String input
5651     * @since 3.5
5652     */
5653    public static String replaceIgnoreCase(final String text, final String searchString, final String replacement, final int max) {
5654        return replace(text, searchString, replacement, max, true);
5655    }
5656
5657    /**
5658     * <p>
5659     * Replaces all occurrences of Strings within another String.
5660     * </p>
5661     *
5662     * <p>
5663     * A {@code null} reference passed to this method is a no-op, or if
5664     * any "search string" or "string to replace" is null, that replace will be
5665     * ignored. This will not repeat. For repeating replaces, call the
5666     * overloaded method.
5667     * </p>
5668     *
5669     * <pre>
5670     *  StringUtils.replaceEach(null, *, *)        = null
5671     *  StringUtils.replaceEach("", *, *)          = ""
5672     *  StringUtils.replaceEach("aba", null, null) = "aba"
5673     *  StringUtils.replaceEach("aba", new String[0], null) = "aba"
5674     *  StringUtils.replaceEach("aba", null, new String[0]) = "aba"
5675     *  StringUtils.replaceEach("aba", new String[]{"a"}, null)  = "aba"
5676     *  StringUtils.replaceEach("aba", new String[]{"a"}, new String[]{""})  = "b"
5677     *  StringUtils.replaceEach("aba", new String[]{null}, new String[]{"a"})  = "aba"
5678     *  StringUtils.replaceEach("abcde", new String[]{"ab", "d"}, new String[]{"w", "t"})  = "wcte"
5679     *  (example of how it does not repeat)
5680     *  StringUtils.replaceEach("abcde", new String[]{"ab", "d"}, new String[]{"d", "t"})  = "dcte"
5681     * </pre>
5682     *
5683     * @param text
5684     *            text to search and replace in, no-op if null
5685     * @param searchList
5686     *            the Strings to search for, no-op if null
5687     * @param replacementList
5688     *            the Strings to replace them with, no-op if null
5689     * @return the text with any replacements processed, {@code null} if
5690     *         null String input
5691     * @throws IllegalArgumentException
5692     *             if the lengths of the arrays are not the same (null is ok,
5693     *             and/or size 0)
5694     * @since 2.4
5695     */
5696    public static String replaceEach(final String text, final String[] searchList, final String[] replacementList) {
5697        return replaceEach(text, searchList, replacementList, false, 0);
5698    }
5699
5700    /**
5701     * <p>
5702     * Replaces all occurrences of Strings within another String.
5703     * </p>
5704     *
5705     * <p>
5706     * A {@code null} reference passed to this method is a no-op, or if
5707     * any "search string" or "string to replace" is null, that replace will be
5708     * ignored.
5709     * </p>
5710     *
5711     * <pre>
5712     *  StringUtils.replaceEachRepeatedly(null, *, *) = null
5713     *  StringUtils.replaceEachRepeatedly("", *, *) = ""
5714     *  StringUtils.replaceEachRepeatedly("aba", null, null) = "aba"
5715     *  StringUtils.replaceEachRepeatedly("aba", new String[0], null) = "aba"
5716     *  StringUtils.replaceEachRepeatedly("aba", null, new String[0]) = "aba"
5717     *  StringUtils.replaceEachRepeatedly("aba", new String[]{"a"}, null) = "aba"
5718     *  StringUtils.replaceEachRepeatedly("aba", new String[]{"a"}, new String[]{""}) = "b"
5719     *  StringUtils.replaceEachRepeatedly("aba", new String[]{null}, new String[]{"a"}) = "aba"
5720     *  StringUtils.replaceEachRepeatedly("abcde", new String[]{"ab", "d"}, new String[]{"w", "t"}) = "wcte"
5721     *  (example of how it repeats)
5722     *  StringUtils.replaceEachRepeatedly("abcde", new String[]{"ab", "d"}, new String[]{"d", "t"}) = "tcte"
5723     *  StringUtils.replaceEachRepeatedly("abcde", new String[]{"ab", "d"}, new String[]{"d", "ab"}) = IllegalStateException
5724     * </pre>
5725     *
5726     * @param text
5727     *            text to search and replace in, no-op if null
5728     * @param searchList
5729     *            the Strings to search for, no-op if null
5730     * @param replacementList
5731     *            the Strings to replace them with, no-op if null
5732     * @return the text with any replacements processed, {@code null} if
5733     *         null String input
5734     * @throws IllegalStateException
5735     *             if the search is repeating and there is an endless loop due
5736     *             to outputs of one being inputs to another
5737     * @throws IllegalArgumentException
5738     *             if the lengths of the arrays are not the same (null is ok,
5739     *             and/or size 0)
5740     * @since 2.4
5741     */
5742    public static String replaceEachRepeatedly(final String text, final String[] searchList, final String[] replacementList) {
5743        // timeToLive should be 0 if not used or nothing to replace, else it's
5744        // the length of the replace array
5745        final int timeToLive = searchList == null ? 0 : searchList.length;
5746        return replaceEach(text, searchList, replacementList, true, timeToLive);
5747    }
5748
5749    /**
5750     * <p>
5751     * Replace all occurrences of Strings within another String.
5752     * This is a private recursive helper method for {@link #replaceEachRepeatedly(String, String[], String[])} and
5753     * {@link #replaceEach(String, String[], String[])}
5754     * </p>
5755     *
5756     * <p>
5757     * A {@code null} reference passed to this method is a no-op, or if
5758     * any "search string" or "string to replace" is null, that replace will be
5759     * ignored.
5760     * </p>
5761     *
5762     * <pre>
5763     *  StringUtils.replaceEach(null, *, *, *, *) = null
5764     *  StringUtils.replaceEach("", *, *, *, *) = ""
5765     *  StringUtils.replaceEach("aba", null, null, *, *) = "aba"
5766     *  StringUtils.replaceEach("aba", new String[0], null, *, *) = "aba"
5767     *  StringUtils.replaceEach("aba", null, new String[0], *, *) = "aba"
5768     *  StringUtils.replaceEach("aba", new String[]{"a"}, null, *, *) = "aba"
5769     *  StringUtils.replaceEach("aba", new String[]{"a"}, new String[]{""}, *, >=0) = "b"
5770     *  StringUtils.replaceEach("aba", new String[]{null}, new String[]{"a"}, *, >=0) = "aba"
5771     *  StringUtils.replaceEach("abcde", new String[]{"ab", "d"}, new String[]{"w", "t"}, *, >=0) = "wcte"
5772     *  (example of how it repeats)
5773     *  StringUtils.replaceEach("abcde", new String[]{"ab", "d"}, new String[]{"d", "t"}, false, >=0) = "dcte"
5774     *  StringUtils.replaceEach("abcde", new String[]{"ab", "d"}, new String[]{"d", "t"}, true, >=2) = "tcte"
5775     *  StringUtils.replaceEach("abcde", new String[]{"ab", "d"}, new String[]{"d", "ab"}, *, *) = IllegalStateException
5776     * </pre>
5777     *
5778     * @param text
5779     *            text to search and replace in, no-op if null
5780     * @param searchList
5781     *            the Strings to search for, no-op if null
5782     * @param replacementList
5783     *            the Strings to replace them with, no-op if null
5784     * @param repeat if true, then replace repeatedly
5785     *       until there are no more possible replacements or timeToLive < 0
5786     * @param timeToLive
5787     *            if less than 0 then there is a circular reference and endless
5788     *            loop
5789     * @return the text with any replacements processed, {@code null} if
5790     *         null String input
5791     * @throws IllegalStateException
5792     *             if the search is repeating and there is an endless loop due
5793     *             to outputs of one being inputs to another
5794     * @throws IllegalArgumentException
5795     *             if the lengths of the arrays are not the same (null is ok,
5796     *             and/or size 0)
5797     * @since 2.4
5798     */
5799    private static String replaceEach(
5800            final String text, final String[] searchList, final String[] replacementList, final boolean repeat, final int timeToLive) {
5801
5802        // mchyzer Performance note: This creates very few new objects (one major goal)
5803        // let me know if there are performance requests, we can create a harness to measure
5804
5805        if (text == null || text.isEmpty() || searchList == null ||
5806                searchList.length == 0 || replacementList == null || replacementList.length == 0) {
5807            return text;
5808        }
5809
5810        // if recursing, this shouldn't be less than 0
5811        if (timeToLive < 0) {
5812            throw new IllegalStateException("Aborting to protect against StackOverflowError - " +
5813                                            "output of one loop is the input of another");
5814        }
5815
5816        final int searchLength = searchList.length;
5817        final int replacementLength = replacementList.length;
5818
5819        // make sure lengths are ok, these need to be equal
5820        if (searchLength != replacementLength) {
5821            throw new IllegalArgumentException("Search and Replace array lengths don't match: "
5822                + searchLength
5823                + " vs "
5824                + replacementLength);
5825        }
5826
5827        // keep track of which still have matches
5828        final boolean[] noMoreMatchesForReplIndex = new boolean[searchLength];
5829
5830        // index on index that the match was found
5831        int textIndex = -1;
5832        int replaceIndex = -1;
5833        int tempIndex = -1;
5834
5835        // index of replace array that will replace the search string found
5836        // NOTE: logic duplicated below START
5837        for (int i = 0; i < searchLength; i++) {
5838            if (noMoreMatchesForReplIndex[i] || searchList[i] == null ||
5839                    searchList[i].isEmpty() || replacementList[i] == null) {
5840                continue;
5841            }
5842            tempIndex = text.indexOf(searchList[i]);
5843
5844            // see if we need to keep searching for this
5845            if (tempIndex == -1) {
5846                noMoreMatchesForReplIndex[i] = true;
5847            } else {
5848                if (textIndex == -1 || tempIndex < textIndex) {
5849                    textIndex = tempIndex;
5850                    replaceIndex = i;
5851                }
5852            }
5853        }
5854        // NOTE: logic mostly below END
5855
5856        // no search strings found, we are done
5857        if (textIndex == -1) {
5858            return text;
5859        }
5860
5861        int start = 0;
5862
5863        // get a good guess on the size of the result buffer so it doesn't have to double if it goes over a bit
5864        int increase = 0;
5865
5866        // count the replacement text elements that are larger than their corresponding text being replaced
5867        for (int i = 0; i < searchList.length; i++) {
5868            if (searchList[i] == null || replacementList[i] == null) {
5869                continue;
5870            }
5871            final int greater = replacementList[i].length() - searchList[i].length();
5872            if (greater > 0) {
5873                increase += 3 * greater; // assume 3 matches
5874            }
5875        }
5876        // have upper-bound at 20% increase, then let Java take over
5877        increase = Math.min(increase, text.length() / 5);
5878
5879        final StringBuilder buf = new StringBuilder(text.length() + increase);
5880
5881        while (textIndex != -1) {
5882
5883            for (int i = start; i < textIndex; i++) {
5884                buf.append(text.charAt(i));
5885            }
5886            buf.append(replacementList[replaceIndex]);
5887
5888            start = textIndex + searchList[replaceIndex].length();
5889
5890            textIndex = -1;
5891            replaceIndex = -1;
5892            tempIndex = -1;
5893            // find the next earliest match
5894            // NOTE: logic mostly duplicated above START
5895            for (int i = 0; i < searchLength; i++) {
5896                if (noMoreMatchesForReplIndex[i] || searchList[i] == null ||
5897                        searchList[i].isEmpty() || replacementList[i] == null) {
5898                    continue;
5899                }
5900                tempIndex = text.indexOf(searchList[i], start);
5901
5902                // see if we need to keep searching for this
5903                if (tempIndex == -1) {
5904                    noMoreMatchesForReplIndex[i] = true;
5905                } else {
5906                    if (textIndex == -1 || tempIndex < textIndex) {
5907                        textIndex = tempIndex;
5908                        replaceIndex = i;
5909                    }
5910                }
5911            }
5912            // NOTE: logic duplicated above END
5913
5914        }
5915        final int textLength = text.length();
5916        for (int i = start; i < textLength; i++) {
5917            buf.append(text.charAt(i));
5918        }
5919        final String result = buf.toString();
5920        if (!repeat) {
5921            return result;
5922        }
5923
5924        return replaceEach(result, searchList, replacementList, repeat, timeToLive - 1);
5925    }
5926
5927    // Replace, character based
5928    //-----------------------------------------------------------------------
5929    /**
5930     * <p>Replaces all occurrences of a character in a String with another.
5931     * This is a null-safe version of {@link String#replace(char, char)}.</p>
5932     *
5933     * <p>A {@code null} string input returns {@code null}.
5934     * An empty ("") string input returns an empty string.</p>
5935     *
5936     * <pre>
5937     * StringUtils.replaceChars(null, *, *)        = null
5938     * StringUtils.replaceChars("", *, *)          = ""
5939     * StringUtils.replaceChars("abcba", 'b', 'y') = "aycya"
5940     * StringUtils.replaceChars("abcba", 'z', 'y') = "abcba"
5941     * </pre>
5942     *
5943     * @param str  String to replace characters in, may be null
5944     * @param searchChar  the character to search for, may be null
5945     * @param replaceChar  the character to replace, may be null
5946     * @return modified String, {@code null} if null string input
5947     * @since 2.0
5948     */
5949    public static String replaceChars(final String str, final char searchChar, final char replaceChar) {
5950        if (str == null) {
5951            return null;
5952        }
5953        return str.replace(searchChar, replaceChar);
5954    }
5955
5956    /**
5957     * <p>Replaces multiple characters in a String in one go.
5958     * This method can also be used to delete characters.</p>
5959     *
5960     * <p>For example:<br>
5961     * <code>replaceChars(&quot;hello&quot;, &quot;ho&quot;, &quot;jy&quot;) = jelly</code>.</p>
5962     *
5963     * <p>A {@code null} string input returns {@code null}.
5964     * An empty ("") string input returns an empty string.
5965     * A null or empty set of search characters returns the input string.</p>
5966     *
5967     * <p>The length of the search characters should normally equal the length
5968     * of the replace characters.
5969     * If the search characters is longer, then the extra search characters
5970     * are deleted.
5971     * If the search characters is shorter, then the extra replace characters
5972     * are ignored.</p>
5973     *
5974     * <pre>
5975     * StringUtils.replaceChars(null, *, *)           = null
5976     * StringUtils.replaceChars("", *, *)             = ""
5977     * StringUtils.replaceChars("abc", null, *)       = "abc"
5978     * StringUtils.replaceChars("abc", "", *)         = "abc"
5979     * StringUtils.replaceChars("abc", "b", null)     = "ac"
5980     * StringUtils.replaceChars("abc", "b", "")       = "ac"
5981     * StringUtils.replaceChars("abcba", "bc", "yz")  = "ayzya"
5982     * StringUtils.replaceChars("abcba", "bc", "y")   = "ayya"
5983     * StringUtils.replaceChars("abcba", "bc", "yzx") = "ayzya"
5984     * </pre>
5985     *
5986     * @param str  String to replace characters in, may be null
5987     * @param searchChars  a set of characters to search for, may be null
5988     * @param replaceChars  a set of characters to replace, may be null
5989     * @return modified String, {@code null} if null string input
5990     * @since 2.0
5991     */
5992    public static String replaceChars(final String str, final String searchChars, String replaceChars) {
5993        if (isEmpty(str) || isEmpty(searchChars)) {
5994            return str;
5995        }
5996        if (replaceChars == null) {
5997            replaceChars = EMPTY;
5998        }
5999        boolean modified = false;
6000        final int replaceCharsLength = replaceChars.length();
6001        final int strLength = str.length();
6002        final StringBuilder buf = new StringBuilder(strLength);
6003        for (int i = 0; i < strLength; i++) {
6004            final char ch = str.charAt(i);
6005            final int index = searchChars.indexOf(ch);
6006            if (index >= 0) {
6007                modified = true;
6008                if (index < replaceCharsLength) {
6009                    buf.append(replaceChars.charAt(index));
6010                }
6011            } else {
6012                buf.append(ch);
6013            }
6014        }
6015        if (modified) {
6016            return buf.toString();
6017        }
6018        return str;
6019    }
6020
6021    // Overlay
6022    //-----------------------------------------------------------------------
6023    /**
6024     * <p>Overlays part of a String with another String.</p>
6025     *
6026     * <p>A {@code null} string input returns {@code null}.
6027     * A negative index is treated as zero.
6028     * An index greater than the string length is treated as the string length.
6029     * The start index is always the smaller of the two indices.</p>
6030     *
6031     * <pre>
6032     * StringUtils.overlay(null, *, *, *)            = null
6033     * StringUtils.overlay("", "abc", 0, 0)          = "abc"
6034     * StringUtils.overlay("abcdef", null, 2, 4)     = "abef"
6035     * StringUtils.overlay("abcdef", "", 2, 4)       = "abef"
6036     * StringUtils.overlay("abcdef", "", 4, 2)       = "abef"
6037     * StringUtils.overlay("abcdef", "zzzz", 2, 4)   = "abzzzzef"
6038     * StringUtils.overlay("abcdef", "zzzz", 4, 2)   = "abzzzzef"
6039     * StringUtils.overlay("abcdef", "zzzz", -1, 4)  = "zzzzef"
6040     * StringUtils.overlay("abcdef", "zzzz", 2, 8)   = "abzzzz"
6041     * StringUtils.overlay("abcdef", "zzzz", -2, -3) = "zzzzabcdef"
6042     * StringUtils.overlay("abcdef", "zzzz", 8, 10)  = "abcdefzzzz"
6043     * </pre>
6044     *
6045     * @param str  the String to do overlaying in, may be null
6046     * @param overlay  the String to overlay, may be null
6047     * @param start  the position to start overlaying at
6048     * @param end  the position to stop overlaying before
6049     * @return overlayed String, {@code null} if null String input
6050     * @since 2.0
6051     */
6052    public static String overlay(final String str, String overlay, int start, int end) {
6053        if (str == null) {
6054            return null;
6055        }
6056        if (overlay == null) {
6057            overlay = EMPTY;
6058        }
6059        final int len = str.length();
6060        if (start < 0) {
6061            start = 0;
6062        }
6063        if (start > len) {
6064            start = len;
6065        }
6066        if (end < 0) {
6067            end = 0;
6068        }
6069        if (end > len) {
6070            end = len;
6071        }
6072        if (start > end) {
6073            final int temp = start;
6074            start = end;
6075            end = temp;
6076        }
6077        return str.substring(0, start) +
6078            overlay +
6079            str.substring(end);
6080    }
6081
6082    // Chomping
6083    //-----------------------------------------------------------------------
6084    /**
6085     * <p>Removes one newline from end of a String if it's there,
6086     * otherwise leave it alone.  A newline is &quot;{@code \n}&quot;,
6087     * &quot;{@code \r}&quot;, or &quot;{@code \r\n}&quot;.</p>
6088     *
6089     * <p>NOTE: This method changed in 2.0.
6090     * It now more closely matches Perl chomp.</p>
6091     *
6092     * <pre>
6093     * StringUtils.chomp(null)          = null
6094     * StringUtils.chomp("")            = ""
6095     * StringUtils.chomp("abc \r")      = "abc "
6096     * StringUtils.chomp("abc\n")       = "abc"
6097     * StringUtils.chomp("abc\r\n")     = "abc"
6098     * StringUtils.chomp("abc\r\n\r\n") = "abc\r\n"
6099     * StringUtils.chomp("abc\n\r")     = "abc\n"
6100     * StringUtils.chomp("abc\n\rabc")  = "abc\n\rabc"
6101     * StringUtils.chomp("\r")          = ""
6102     * StringUtils.chomp("\n")          = ""
6103     * StringUtils.chomp("\r\n")        = ""
6104     * </pre>
6105     *
6106     * @param str  the String to chomp a newline from, may be null
6107     * @return String without newline, {@code null} if null String input
6108     */
6109    public static String chomp(final String str) {
6110        if (isEmpty(str)) {
6111            return str;
6112        }
6113
6114        if (str.length() == 1) {
6115            final char ch = str.charAt(0);
6116            if (ch == CharUtils.CR || ch == CharUtils.LF) {
6117                return EMPTY;
6118            }
6119            return str;
6120        }
6121
6122        int lastIdx = str.length() - 1;
6123        final char last = str.charAt(lastIdx);
6124
6125        if (last == CharUtils.LF) {
6126            if (str.charAt(lastIdx - 1) == CharUtils.CR) {
6127                lastIdx--;
6128            }
6129        } else if (last != CharUtils.CR) {
6130            lastIdx++;
6131        }
6132        return str.substring(0, lastIdx);
6133    }
6134
6135    /**
6136     * <p>Removes {@code separator} from the end of
6137     * {@code str} if it's there, otherwise leave it alone.</p>
6138     *
6139     * <p>NOTE: This method changed in version 2.0.
6140     * It now more closely matches Perl chomp.
6141     * For the previous behavior, use {@link #substringBeforeLast(String, String)}.
6142     * This method uses {@link String#endsWith(String)}.</p>
6143     *
6144     * <pre>
6145     * StringUtils.chomp(null, *)         = null
6146     * StringUtils.chomp("", *)           = ""
6147     * StringUtils.chomp("foobar", "bar") = "foo"
6148     * StringUtils.chomp("foobar", "baz") = "foobar"
6149     * StringUtils.chomp("foo", "foo")    = ""
6150     * StringUtils.chomp("foo ", "foo")   = "foo "
6151     * StringUtils.chomp(" foo", "foo")   = " "
6152     * StringUtils.chomp("foo", "foooo")  = "foo"
6153     * StringUtils.chomp("foo", "")       = "foo"
6154     * StringUtils.chomp("foo", null)     = "foo"
6155     * </pre>
6156     *
6157     * @param str  the String to chomp from, may be null
6158     * @param separator  separator String, may be null
6159     * @return String without trailing separator, {@code null} if null String input
6160     * @deprecated This feature will be removed in Lang 4.0, use {@link StringUtils#removeEnd(String, String)} instead
6161     */
6162    @Deprecated
6163    public static String chomp(final String str, final String separator) {
6164        return removeEnd(str,separator);
6165    }
6166
6167    // Chopping
6168    //-----------------------------------------------------------------------
6169    /**
6170     * <p>Remove the last character from a String.</p>
6171     *
6172     * <p>If the String ends in {@code \r\n}, then remove both
6173     * of them.</p>
6174     *
6175     * <pre>
6176     * StringUtils.chop(null)          = null
6177     * StringUtils.chop("")            = ""
6178     * StringUtils.chop("abc \r")      = "abc "
6179     * StringUtils.chop("abc\n")       = "abc"
6180     * StringUtils.chop("abc\r\n")     = "abc"
6181     * StringUtils.chop("abc")         = "ab"
6182     * StringUtils.chop("abc\nabc")    = "abc\nab"
6183     * StringUtils.chop("a")           = ""
6184     * StringUtils.chop("\r")          = ""
6185     * StringUtils.chop("\n")          = ""
6186     * StringUtils.chop("\r\n")        = ""
6187     * </pre>
6188     *
6189     * @param str  the String to chop last character from, may be null
6190     * @return String without last character, {@code null} if null String input
6191     */
6192    public static String chop(final String str) {
6193        if (str == null) {
6194            return null;
6195        }
6196        final int strLen = str.length();
6197        if (strLen < 2) {
6198            return EMPTY;
6199        }
6200        final int lastIdx = strLen - 1;
6201        final String ret = str.substring(0, lastIdx);
6202        final char last = str.charAt(lastIdx);
6203        if (last == CharUtils.LF && ret.charAt(lastIdx - 1) == CharUtils.CR) {
6204            return ret.substring(0, lastIdx - 1);
6205        }
6206        return ret;
6207    }
6208
6209    // Conversion
6210    //-----------------------------------------------------------------------
6211
6212    // Padding
6213    //-----------------------------------------------------------------------
6214    /**
6215     * <p>Repeat a String {@code repeat} times to form a
6216     * new String.</p>
6217     *
6218     * <pre>
6219     * StringUtils.repeat(null, 2) = null
6220     * StringUtils.repeat("", 0)   = ""
6221     * StringUtils.repeat("", 2)   = ""
6222     * StringUtils.repeat("a", 3)  = "aaa"
6223     * StringUtils.repeat("ab", 2) = "abab"
6224     * StringUtils.repeat("a", -2) = ""
6225     * </pre>
6226     *
6227     * @param str  the String to repeat, may be null
6228     * @param repeat  number of times to repeat str, negative treated as zero
6229     * @return a new String consisting of the original String repeated,
6230     *  {@code null} if null String input
6231     */
6232    public static String repeat(final String str, final int repeat) {
6233        // Performance tuned for 2.0 (JDK1.4)
6234
6235        if (str == null) {
6236            return null;
6237        }
6238        if (repeat <= 0) {
6239            return EMPTY;
6240        }
6241        final int inputLength = str.length();
6242        if (repeat == 1 || inputLength == 0) {
6243            return str;
6244        }
6245        if (inputLength == 1 && repeat <= PAD_LIMIT) {
6246            return repeat(str.charAt(0), repeat);
6247        }
6248
6249        final int outputLength = inputLength * repeat;
6250        switch (inputLength) {
6251            case 1 :
6252                return repeat(str.charAt(0), repeat);
6253            case 2 :
6254                final char ch0 = str.charAt(0);
6255                final char ch1 = str.charAt(1);
6256                final char[] output2 = new char[outputLength];
6257                for (int i = repeat * 2 - 2; i >= 0; i--, i--) {
6258                    output2[i] = ch0;
6259                    output2[i + 1] = ch1;
6260                }
6261                return new String(output2);
6262            default :
6263                final StringBuilder buf = new StringBuilder(outputLength);
6264                for (int i = 0; i < repeat; i++) {
6265                    buf.append(str);
6266                }
6267                return buf.toString();
6268        }
6269    }
6270
6271    /**
6272     * <p>Repeat a String {@code repeat} times to form a
6273     * new String, with a String separator injected each time. </p>
6274     *
6275     * <pre>
6276     * StringUtils.repeat(null, null, 2) = null
6277     * StringUtils.repeat(null, "x", 2)  = null
6278     * StringUtils.repeat("", null, 0)   = ""
6279     * StringUtils.repeat("", "", 2)     = ""
6280     * StringUtils.repeat("", "x", 3)    = "xxx"
6281     * StringUtils.repeat("?", ", ", 3)  = "?, ?, ?"
6282     * </pre>
6283     *
6284     * @param str        the String to repeat, may be null
6285     * @param separator  the String to inject, may be null
6286     * @param repeat     number of times to repeat str, negative treated as zero
6287     * @return a new String consisting of the original String repeated,
6288     *  {@code null} if null String input
6289     * @since 2.5
6290     */
6291    public static String repeat(final String str, final String separator, final int repeat) {
6292        if(str == null || separator == null) {
6293            return repeat(str, repeat);
6294        }
6295        // given that repeat(String, int) is quite optimized, better to rely on it than try and splice this into it
6296        final String result = repeat(str + separator, repeat);
6297        return removeEnd(result, separator);
6298    }
6299
6300    /**
6301     * <p>Returns padding using the specified delimiter repeated
6302     * to a given length.</p>
6303     *
6304     * <pre>
6305     * StringUtils.repeat('e', 0)  = ""
6306     * StringUtils.repeat('e', 3)  = "eee"
6307     * StringUtils.repeat('e', -2) = ""
6308     * </pre>
6309     *
6310     * <p>Note: this method does not support padding with
6311     * <a href="http://www.unicode.org/glossary/#supplementary_character">Unicode Supplementary Characters</a>
6312     * as they require a pair of {@code char}s to be represented.
6313     * If you are needing to support full I18N of your applications
6314     * consider using {@link #repeat(String, int)} instead.
6315     * </p>
6316     *
6317     * @param ch  character to repeat
6318     * @param repeat  number of times to repeat char, negative treated as zero
6319     * @return String with repeated character
6320     * @see #repeat(String, int)
6321     */
6322    public static String repeat(final char ch, final int repeat) {
6323        if (repeat <= 0) {
6324            return EMPTY;
6325        }
6326        final char[] buf = new char[repeat];
6327        for (int i = repeat - 1; i >= 0; i--) {
6328            buf[i] = ch;
6329        }
6330        return new String(buf);
6331    }
6332
6333    /**
6334     * <p>Right pad a String with spaces (' ').</p>
6335     *
6336     * <p>The String is padded to the size of {@code size}.</p>
6337     *
6338     * <pre>
6339     * StringUtils.rightPad(null, *)   = null
6340     * StringUtils.rightPad("", 3)     = "   "
6341     * StringUtils.rightPad("bat", 3)  = "bat"
6342     * StringUtils.rightPad("bat", 5)  = "bat  "
6343     * StringUtils.rightPad("bat", 1)  = "bat"
6344     * StringUtils.rightPad("bat", -1) = "bat"
6345     * </pre>
6346     *
6347     * @param str  the String to pad out, may be null
6348     * @param size  the size to pad to
6349     * @return right padded String or original String if no padding is necessary,
6350     *  {@code null} if null String input
6351     */
6352    public static String rightPad(final String str, final int size) {
6353        return rightPad(str, size, ' ');
6354    }
6355
6356    /**
6357     * <p>Right pad a String with a specified character.</p>
6358     *
6359     * <p>The String is padded to the size of {@code size}.</p>
6360     *
6361     * <pre>
6362     * StringUtils.rightPad(null, *, *)     = null
6363     * StringUtils.rightPad("", 3, 'z')     = "zzz"
6364     * StringUtils.rightPad("bat", 3, 'z')  = "bat"
6365     * StringUtils.rightPad("bat", 5, 'z')  = "batzz"
6366     * StringUtils.rightPad("bat", 1, 'z')  = "bat"
6367     * StringUtils.rightPad("bat", -1, 'z') = "bat"
6368     * </pre>
6369     *
6370     * @param str  the String to pad out, may be null
6371     * @param size  the size to pad to
6372     * @param padChar  the character to pad with
6373     * @return right padded String or original String if no padding is necessary,
6374     *  {@code null} if null String input
6375     * @since 2.0
6376     */
6377    public static String rightPad(final String str, final int size, final char padChar) {
6378        if (str == null) {
6379            return null;
6380        }
6381        final int pads = size - str.length();
6382        if (pads <= 0) {
6383            return str; // returns original String when possible
6384        }
6385        if (pads > PAD_LIMIT) {
6386            return rightPad(str, size, String.valueOf(padChar));
6387        }
6388        return str.concat(repeat(padChar, pads));
6389    }
6390
6391    /**
6392     * <p>Right pad a String with a specified String.</p>
6393     *
6394     * <p>The String is padded to the size of {@code size}.</p>
6395     *
6396     * <pre>
6397     * StringUtils.rightPad(null, *, *)      = null
6398     * StringUtils.rightPad("", 3, "z")      = "zzz"
6399     * StringUtils.rightPad("bat", 3, "yz")  = "bat"
6400     * StringUtils.rightPad("bat", 5, "yz")  = "batyz"
6401     * StringUtils.rightPad("bat", 8, "yz")  = "batyzyzy"
6402     * StringUtils.rightPad("bat", 1, "yz")  = "bat"
6403     * StringUtils.rightPad("bat", -1, "yz") = "bat"
6404     * StringUtils.rightPad("bat", 5, null)  = "bat  "
6405     * StringUtils.rightPad("bat", 5, "")    = "bat  "
6406     * </pre>
6407     *
6408     * @param str  the String to pad out, may be null
6409     * @param size  the size to pad to
6410     * @param padStr  the String to pad with, null or empty treated as single space
6411     * @return right padded String or original String if no padding is necessary,
6412     *  {@code null} if null String input
6413     */
6414    public static String rightPad(final String str, final int size, String padStr) {
6415        if (str == null) {
6416            return null;
6417        }
6418        if (isEmpty(padStr)) {
6419            padStr = SPACE;
6420        }
6421        final int padLen = padStr.length();
6422        final int strLen = str.length();
6423        final int pads = size - strLen;
6424        if (pads <= 0) {
6425            return str; // returns original String when possible
6426        }
6427        if (padLen == 1 && pads <= PAD_LIMIT) {
6428            return rightPad(str, size, padStr.charAt(0));
6429        }
6430
6431        if (pads == padLen) {
6432            return str.concat(padStr);
6433        } else if (pads < padLen) {
6434            return str.concat(padStr.substring(0, pads));
6435        } else {
6436            final char[] padding = new char[pads];
6437            final char[] padChars = padStr.toCharArray();
6438            for (int i = 0; i < pads; i++) {
6439                padding[i] = padChars[i % padLen];
6440            }
6441            return str.concat(new String(padding));
6442        }
6443    }
6444
6445    /**
6446     * <p>Left pad a String with spaces (' ').</p>
6447     *
6448     * <p>The String is padded to the size of {@code size}.</p>
6449     *
6450     * <pre>
6451     * StringUtils.leftPad(null, *)   = null
6452     * StringUtils.leftPad("", 3)     = "   "
6453     * StringUtils.leftPad("bat", 3)  = "bat"
6454     * StringUtils.leftPad("bat", 5)  = "  bat"
6455     * StringUtils.leftPad("bat", 1)  = "bat"
6456     * StringUtils.leftPad("bat", -1) = "bat"
6457     * </pre>
6458     *
6459     * @param str  the String to pad out, may be null
6460     * @param size  the size to pad to
6461     * @return left padded String or original String if no padding is necessary,
6462     *  {@code null} if null String input
6463     */
6464    public static String leftPad(final String str, final int size) {
6465        return leftPad(str, size, ' ');
6466    }
6467
6468    /**
6469     * <p>Left pad a String with a specified character.</p>
6470     *
6471     * <p>Pad to a size of {@code size}.</p>
6472     *
6473     * <pre>
6474     * StringUtils.leftPad(null, *, *)     = null
6475     * StringUtils.leftPad("", 3, 'z')     = "zzz"
6476     * StringUtils.leftPad("bat", 3, 'z')  = "bat"
6477     * StringUtils.leftPad("bat", 5, 'z')  = "zzbat"
6478     * StringUtils.leftPad("bat", 1, 'z')  = "bat"
6479     * StringUtils.leftPad("bat", -1, 'z') = "bat"
6480     * </pre>
6481     *
6482     * @param str  the String to pad out, may be null
6483     * @param size  the size to pad to
6484     * @param padChar  the character to pad with
6485     * @return left padded String or original String if no padding is necessary,
6486     *  {@code null} if null String input
6487     * @since 2.0
6488     */
6489    public static String leftPad(final String str, final int size, final char padChar) {
6490        if (str == null) {
6491            return null;
6492        }
6493        final int pads = size - str.length();
6494        if (pads <= 0) {
6495            return str; // returns original String when possible
6496        }
6497        if (pads > PAD_LIMIT) {
6498            return leftPad(str, size, String.valueOf(padChar));
6499        }
6500        return repeat(padChar, pads).concat(str);
6501    }
6502
6503    /**
6504     * <p>Left pad a String with a specified String.</p>
6505     *
6506     * <p>Pad to a size of {@code size}.</p>
6507     *
6508     * <pre>
6509     * StringUtils.leftPad(null, *, *)      = null
6510     * StringUtils.leftPad("", 3, "z")      = "zzz"
6511     * StringUtils.leftPad("bat", 3, "yz")  = "bat"
6512     * StringUtils.leftPad("bat", 5, "yz")  = "yzbat"
6513     * StringUtils.leftPad("bat", 8, "yz")  = "yzyzybat"
6514     * StringUtils.leftPad("bat", 1, "yz")  = "bat"
6515     * StringUtils.leftPad("bat", -1, "yz") = "bat"
6516     * StringUtils.leftPad("bat", 5, null)  = "  bat"
6517     * StringUtils.leftPad("bat", 5, "")    = "  bat"
6518     * </pre>
6519     *
6520     * @param str  the String to pad out, may be null
6521     * @param size  the size to pad to
6522     * @param padStr  the String to pad with, null or empty treated as single space
6523     * @return left padded String or original String if no padding is necessary,
6524     *  {@code null} if null String input
6525     */
6526    public static String leftPad(final String str, final int size, String padStr) {
6527        if (str == null) {
6528            return null;
6529        }
6530        if (isEmpty(padStr)) {
6531            padStr = SPACE;
6532        }
6533        final int padLen = padStr.length();
6534        final int strLen = str.length();
6535        final int pads = size - strLen;
6536        if (pads <= 0) {
6537            return str; // returns original String when possible
6538        }
6539        if (padLen == 1 && pads <= PAD_LIMIT) {
6540            return leftPad(str, size, padStr.charAt(0));
6541        }
6542
6543        if (pads == padLen) {
6544            return padStr.concat(str);
6545        } else if (pads < padLen) {
6546            return padStr.substring(0, pads).concat(str);
6547        } else {
6548            final char[] padding = new char[pads];
6549            final char[] padChars = padStr.toCharArray();
6550            for (int i = 0; i < pads; i++) {
6551                padding[i] = padChars[i % padLen];
6552            }
6553            return new String(padding).concat(str);
6554        }
6555    }
6556
6557    /**
6558     * Gets a CharSequence length or {@code 0} if the CharSequence is
6559     * {@code null}.
6560     *
6561     * @param cs
6562     *            a CharSequence or {@code null}
6563     * @return CharSequence length or {@code 0} if the CharSequence is
6564     *         {@code null}.
6565     * @since 2.4
6566     * @since 3.0 Changed signature from length(String) to length(CharSequence)
6567     */
6568    public static int length(final CharSequence cs) {
6569        return cs == null ? 0 : cs.length();
6570    }
6571
6572    // Centering
6573    //-----------------------------------------------------------------------
6574    /**
6575     * <p>Centers a String in a larger String of size {@code size}
6576     * using the space character (' ').</p>
6577     *
6578     * <p>If the size is less than the String length, the String is returned.
6579     * A {@code null} String returns {@code null}.
6580     * A negative size is treated as zero.</p>
6581     *
6582     * <p>Equivalent to {@code center(str, size, " ")}.</p>
6583     *
6584     * <pre>
6585     * StringUtils.center(null, *)   = null
6586     * StringUtils.center("", 4)     = "    "
6587     * StringUtils.center("ab", -1)  = "ab"
6588     * StringUtils.center("ab", 4)   = " ab "
6589     * StringUtils.center("abcd", 2) = "abcd"
6590     * StringUtils.center("a", 4)    = " a  "
6591     * </pre>
6592     *
6593     * @param str  the String to center, may be null
6594     * @param size  the int size of new String, negative treated as zero
6595     * @return centered String, {@code null} if null String input
6596     */
6597    public static String center(final String str, final int size) {
6598        return center(str, size, ' ');
6599    }
6600
6601    /**
6602     * <p>Centers a String in a larger String of size {@code size}.
6603     * Uses a supplied character as the value to pad the String with.</p>
6604     *
6605     * <p>If the size is less than the String length, the String is returned.
6606     * A {@code null} String returns {@code null}.
6607     * A negative size is treated as zero.</p>
6608     *
6609     * <pre>
6610     * StringUtils.center(null, *, *)     = null
6611     * StringUtils.center("", 4, ' ')     = "    "
6612     * StringUtils.center("ab", -1, ' ')  = "ab"
6613     * StringUtils.center("ab", 4, ' ')   = " ab "
6614     * StringUtils.center("abcd", 2, ' ') = "abcd"
6615     * StringUtils.center("a", 4, ' ')    = " a  "
6616     * StringUtils.center("a", 4, 'y')    = "yayy"
6617     * </pre>
6618     *
6619     * @param str  the String to center, may be null
6620     * @param size  the int size of new String, negative treated as zero
6621     * @param padChar  the character to pad the new String with
6622     * @return centered String, {@code null} if null String input
6623     * @since 2.0
6624     */
6625    public static String center(String str, final int size, final char padChar) {
6626        if (str == null || size <= 0) {
6627            return str;
6628        }
6629        final int strLen = str.length();
6630        final int pads = size - strLen;
6631        if (pads <= 0) {
6632            return str;
6633        }
6634        str = leftPad(str, strLen + pads / 2, padChar);
6635        str = rightPad(str, size, padChar);
6636        return str;
6637    }
6638
6639    /**
6640     * <p>Centers a String in a larger String of size {@code size}.
6641     * Uses a supplied String as the value to pad the String with.</p>
6642     *
6643     * <p>If the size is less than the String length, the String is returned.
6644     * A {@code null} String returns {@code null}.
6645     * A negative size is treated as zero.</p>
6646     *
6647     * <pre>
6648     * StringUtils.center(null, *, *)     = null
6649     * StringUtils.center("", 4, " ")     = "    "
6650     * StringUtils.center("ab", -1, " ")  = "ab"
6651     * StringUtils.center("ab", 4, " ")   = " ab "
6652     * StringUtils.center("abcd", 2, " ") = "abcd"
6653     * StringUtils.center("a", 4, " ")    = " a  "
6654     * StringUtils.center("a", 4, "yz")   = "yayz"
6655     * StringUtils.center("abc", 7, null) = "  abc  "
6656     * StringUtils.center("abc", 7, "")   = "  abc  "
6657     * </pre>
6658     *
6659     * @param str  the String to center, may be null
6660     * @param size  the int size of new String, negative treated as zero
6661     * @param padStr  the String to pad the new String with, must not be null or empty
6662     * @return centered String, {@code null} if null String input
6663     * @throws IllegalArgumentException if padStr is {@code null} or empty
6664     */
6665    public static String center(String str, final int size, String padStr) {
6666        if (str == null || size <= 0) {
6667            return str;
6668        }
6669        if (isEmpty(padStr)) {
6670            padStr = SPACE;
6671        }
6672        final int strLen = str.length();
6673        final int pads = size - strLen;
6674        if (pads <= 0) {
6675            return str;
6676        }
6677        str = leftPad(str, strLen + pads / 2, padStr);
6678        str = rightPad(str, size, padStr);
6679        return str;
6680    }
6681
6682    // Case conversion
6683    //-----------------------------------------------------------------------
6684    /**
6685     * <p>Converts a String to upper case as per {@link String#toUpperCase()}.</p>
6686     *
6687     * <p>A {@code null} input String returns {@code null}.</p>
6688     *
6689     * <pre>
6690     * StringUtils.upperCase(null)  = null
6691     * StringUtils.upperCase("")    = ""
6692     * StringUtils.upperCase("aBc") = "ABC"
6693     * </pre>
6694     *
6695     * <p><strong>Note:</strong> As described in the documentation for {@link String#toUpperCase()},
6696     * the result of this method is affected by the current locale.
6697     * For platform-independent case transformations, the method {@link #lowerCase(String, Locale)}
6698     * should be used with a specific locale (e.g. {@link Locale#ENGLISH}).</p>
6699     *
6700     * @param str  the String to upper case, may be null
6701     * @return the upper cased String, {@code null} if null String input
6702     */
6703    public static String upperCase(final String str) {
6704        if (str == null) {
6705            return null;
6706        }
6707        return str.toUpperCase();
6708    }
6709
6710    /**
6711     * <p>Converts a String to upper case as per {@link String#toUpperCase(Locale)}.</p>
6712     *
6713     * <p>A {@code null} input String returns {@code null}.</p>
6714     *
6715     * <pre>
6716     * StringUtils.upperCase(null, Locale.ENGLISH)  = null
6717     * StringUtils.upperCase("", Locale.ENGLISH)    = ""
6718     * StringUtils.upperCase("aBc", Locale.ENGLISH) = "ABC"
6719     * </pre>
6720     *
6721     * @param str  the String to upper case, may be null
6722     * @param locale  the locale that defines the case transformation rules, must not be null
6723     * @return the upper cased String, {@code null} if null String input
6724     * @since 2.5
6725     */
6726    public static String upperCase(final String str, final Locale locale) {
6727        if (str == null) {
6728            return null;
6729        }
6730        return str.toUpperCase(locale);
6731    }
6732
6733    /**
6734     * <p>Converts a String to lower case as per {@link String#toLowerCase()}.</p>
6735     *
6736     * <p>A {@code null} input String returns {@code null}.</p>
6737     *
6738     * <pre>
6739     * StringUtils.lowerCase(null)  = null
6740     * StringUtils.lowerCase("")    = ""
6741     * StringUtils.lowerCase("aBc") = "abc"
6742     * </pre>
6743     *
6744     * <p><strong>Note:</strong> As described in the documentation for {@link String#toLowerCase()},
6745     * the result of this method is affected by the current locale.
6746     * For platform-independent case transformations, the method {@link #lowerCase(String, Locale)}
6747     * should be used with a specific locale (e.g. {@link Locale#ENGLISH}).</p>
6748     *
6749     * @param str  the String to lower case, may be null
6750     * @return the lower cased String, {@code null} if null String input
6751     */
6752    public static String lowerCase(final String str) {
6753        if (str == null) {
6754            return null;
6755        }
6756        return str.toLowerCase();
6757    }
6758
6759    /**
6760     * <p>Converts a String to lower case as per {@link String#toLowerCase(Locale)}.</p>
6761     *
6762     * <p>A {@code null} input String returns {@code null}.</p>
6763     *
6764     * <pre>
6765     * StringUtils.lowerCase(null, Locale.ENGLISH)  = null
6766     * StringUtils.lowerCase("", Locale.ENGLISH)    = ""
6767     * StringUtils.lowerCase("aBc", Locale.ENGLISH) = "abc"
6768     * </pre>
6769     *
6770     * @param str  the String to lower case, may be null
6771     * @param locale  the locale that defines the case transformation rules, must not be null
6772     * @return the lower cased String, {@code null} if null String input
6773     * @since 2.5
6774     */
6775    public static String lowerCase(final String str, final Locale locale) {
6776        if (str == null) {
6777            return null;
6778        }
6779        return str.toLowerCase(locale);
6780    }
6781
6782    /**
6783     * <p>Capitalizes a String changing the first character to title case as
6784     * per {@link Character#toTitleCase(int)}. No other characters are changed.</p>
6785     *
6786     * <p>For a word based algorithm, see {@link org.apache.commons.lang3.text.WordUtils#capitalize(String)}.
6787     * A {@code null} input String returns {@code null}.</p>
6788     *
6789     * <pre>
6790     * StringUtils.capitalize(null)  = null
6791     * StringUtils.capitalize("")    = ""
6792     * StringUtils.capitalize("cat") = "Cat"
6793     * StringUtils.capitalize("cAt") = "CAt"
6794     * StringUtils.capitalize("'cat'") = "'cat'"
6795     * </pre>
6796     *
6797     * @param str the String to capitalize, may be null
6798     * @return the capitalized String, {@code null} if null String input
6799     * @see org.apache.commons.lang3.text.WordUtils#capitalize(String)
6800     * @see #uncapitalize(String)
6801     * @since 2.0
6802     */
6803    public static String capitalize(final String str) {
6804        int strLen;
6805        if (str == null || (strLen = str.length()) == 0) {
6806            return str;
6807        }
6808
6809        final int firstCodepoint = str.codePointAt(0);
6810        final int newCodePoint = Character.toTitleCase(firstCodepoint);
6811        if (firstCodepoint == newCodePoint) {
6812            // already capitalized
6813            return str;
6814        }
6815
6816        final int newCodePoints[] = new int[strLen]; // cannot be longer than the char array
6817        int outOffset = 0;
6818        newCodePoints[outOffset++] = newCodePoint; // copy the first codepoint
6819        for (int inOffset = Character.charCount(firstCodepoint); inOffset < strLen; ) {
6820            final int codepoint = str.codePointAt(inOffset);
6821            newCodePoints[outOffset++] = codepoint; // copy the remaining ones
6822            inOffset += Character.charCount(codepoint);
6823         }
6824        return new String(newCodePoints, 0, outOffset);
6825    }
6826
6827    /**
6828     * <p>Uncapitalizes a String, changing the first character to lower case as
6829     * per {@link Character#toLowerCase(int)}. No other characters are changed.</p>
6830     *
6831     * <p>For a word based algorithm, see {@link org.apache.commons.lang3.text.WordUtils#uncapitalize(String)}.
6832     * A {@code null} input String returns {@code null}.</p>
6833     *
6834     * <pre>
6835     * StringUtils.uncapitalize(null)  = null
6836     * StringUtils.uncapitalize("")    = ""
6837     * StringUtils.uncapitalize("cat") = "cat"
6838     * StringUtils.uncapitalize("Cat") = "cat"
6839     * StringUtils.uncapitalize("CAT") = "cAT"
6840     * </pre>
6841     *
6842     * @param str the String to uncapitalize, may be null
6843     * @return the uncapitalized String, {@code null} if null String input
6844     * @see org.apache.commons.lang3.text.WordUtils#uncapitalize(String)
6845     * @see #capitalize(String)
6846     * @since 2.0
6847     */
6848    public static String uncapitalize(final String str) {
6849        int strLen;
6850        if (str == null || (strLen = str.length()) == 0) {
6851            return str;
6852        }
6853
6854        final int firstCodepoint = str.codePointAt(0);
6855        final int newCodePoint = Character.toLowerCase(firstCodepoint);
6856        if (firstCodepoint == newCodePoint) {
6857            // already capitalized
6858            return str;
6859        }
6860
6861        final int newCodePoints[] = new int[strLen]; // cannot be longer than the char array
6862        int outOffset = 0;
6863        newCodePoints[outOffset++] = newCodePoint; // copy the first codepoint
6864        for (int inOffset = Character.charCount(firstCodepoint); inOffset < strLen; ) {
6865            final int codepoint = str.codePointAt(inOffset);
6866            newCodePoints[outOffset++] = codepoint; // copy the remaining ones
6867            inOffset += Character.charCount(codepoint);
6868         }
6869        return new String(newCodePoints, 0, outOffset);
6870    }
6871
6872    /**
6873     * <p>Swaps the case of a String changing upper and title case to
6874     * lower case, and lower case to upper case.</p>
6875     *
6876     * <ul>
6877     *  <li>Upper case character converts to Lower case</li>
6878     *  <li>Title case character converts to Lower case</li>
6879     *  <li>Lower case character converts to Upper case</li>
6880     * </ul>
6881     *
6882     * <p>For a word based algorithm, see {@link org.apache.commons.lang3.text.WordUtils#swapCase(String)}.
6883     * A {@code null} input String returns {@code null}.</p>
6884     *
6885     * <pre>
6886     * StringUtils.swapCase(null)                 = null
6887     * StringUtils.swapCase("")                   = ""
6888     * StringUtils.swapCase("The dog has a BONE") = "tHE DOG HAS A bone"
6889     * </pre>
6890     *
6891     * <p>NOTE: This method changed in Lang version 2.0.
6892     * It no longer performs a word based algorithm.
6893     * If you only use ASCII, you will notice no change.
6894     * That functionality is available in org.apache.commons.lang3.text.WordUtils.</p>
6895     *
6896     * @param str  the String to swap case, may be null
6897     * @return the changed String, {@code null} if null String input
6898     */
6899    public static String swapCase(final String str) {
6900        if (isEmpty(str)) {
6901            return str;
6902        }
6903
6904        final int strLen = str.length();
6905        final int newCodePoints[] = new int[strLen]; // cannot be longer than the char array
6906        int outOffset = 0;
6907        for (int i = 0; i < strLen; ) {
6908            final int oldCodepoint = str.codePointAt(i);
6909            final int newCodePoint;
6910            if (Character.isUpperCase(oldCodepoint)) {
6911                newCodePoint = Character.toLowerCase(oldCodepoint);
6912            } else if (Character.isTitleCase(oldCodepoint)) {
6913                newCodePoint = Character.toLowerCase(oldCodepoint);
6914            } else if (Character.isLowerCase(oldCodepoint)) {
6915                newCodePoint = Character.toUpperCase(oldCodepoint);
6916            } else {
6917                newCodePoint = oldCodepoint;
6918            }
6919            newCodePoints[outOffset++] = newCodePoint;
6920            i += Character.charCount(newCodePoint);
6921         }
6922        return new String(newCodePoints, 0, outOffset);
6923    }
6924
6925    // Count matches
6926    //-----------------------------------------------------------------------
6927    /**
6928     * <p>Counts how many times the substring appears in the larger string.</p>
6929     *
6930     * <p>A {@code null} or empty ("") String input returns {@code 0}.</p>
6931     *
6932     * <pre>
6933     * StringUtils.countMatches(null, *)       = 0
6934     * StringUtils.countMatches("", *)         = 0
6935     * StringUtils.countMatches("abba", null)  = 0
6936     * StringUtils.countMatches("abba", "")    = 0
6937     * StringUtils.countMatches("abba", "a")   = 2
6938     * StringUtils.countMatches("abba", "ab")  = 1
6939     * StringUtils.countMatches("abba", "xxx") = 0
6940     * </pre>
6941     *
6942     * @param str  the CharSequence to check, may be null
6943     * @param sub  the substring to count, may be null
6944     * @return the number of occurrences, 0 if either CharSequence is {@code null}
6945     * @since 3.0 Changed signature from countMatches(String, String) to countMatches(CharSequence, CharSequence)
6946     */
6947    public static int countMatches(final CharSequence str, final CharSequence sub) {
6948        if (isEmpty(str) || isEmpty(sub)) {
6949            return 0;
6950        }
6951        int count = 0;
6952        int idx = 0;
6953        while ((idx = CharSequenceUtils.indexOf(str, sub, idx)) != INDEX_NOT_FOUND) {
6954            count++;
6955            idx += sub.length();
6956        }
6957        return count;
6958    }
6959
6960    /**
6961     * <p>Counts how many times the char appears in the given string.</p>
6962     *
6963     * <p>A {@code null} or empty ("") String input returns {@code 0}.</p>
6964     *
6965     * <pre>
6966     * StringUtils.countMatches(null, *)       = 0
6967     * StringUtils.countMatches("", *)         = 0
6968     * StringUtils.countMatches("abba", 0)  = 0
6969     * StringUtils.countMatches("abba", 'a')   = 2
6970     * StringUtils.countMatches("abba", 'b')  = 2
6971     * StringUtils.countMatches("abba", 'x') = 0
6972     * </pre>
6973     *
6974     * @param str  the CharSequence to check, may be null
6975     * @param ch  the char to count
6976     * @return the number of occurrences, 0 if the CharSequence is {@code null}
6977     * @since 3.4
6978     */
6979    public static int countMatches(final CharSequence str, final char ch) {
6980        if (isEmpty(str)) {
6981            return 0;
6982        }
6983        int count = 0;
6984        // We could also call str.toCharArray() for faster look ups but that would generate more garbage.
6985        for (int i = 0; i < str.length(); i++) {
6986            if (ch == str.charAt(i)) {
6987                count++;
6988            }
6989        }
6990        return count;
6991    }
6992
6993    // Character Tests
6994    //-----------------------------------------------------------------------
6995    /**
6996     * <p>Checks if the CharSequence contains only Unicode letters.</p>
6997     *
6998     * <p>{@code null} will return {@code false}.
6999     * An empty CharSequence (length()=0) will return {@code false}.</p>
7000     *
7001     * <pre>
7002     * StringUtils.isAlpha(null)   = false
7003     * StringUtils.isAlpha("")     = false
7004     * StringUtils.isAlpha("  ")   = false
7005     * StringUtils.isAlpha("abc")  = true
7006     * StringUtils.isAlpha("ab2c") = false
7007     * StringUtils.isAlpha("ab-c") = false
7008     * </pre>
7009     *
7010     * @param cs  the CharSequence to check, may be null
7011     * @return {@code true} if only contains letters, and is non-null
7012     * @since 3.0 Changed signature from isAlpha(String) to isAlpha(CharSequence)
7013     * @since 3.0 Changed "" to return false and not true
7014     */
7015    public static boolean isAlpha(final CharSequence cs) {
7016        if (isEmpty(cs)) {
7017            return false;
7018        }
7019        final int sz = cs.length();
7020        for (int i = 0; i < sz; i++) {
7021            if (!Character.isLetter(cs.charAt(i))) {
7022                return false;
7023            }
7024        }
7025        return true;
7026    }
7027
7028    /**
7029     * <p>Checks if the CharSequence contains only Unicode letters and
7030     * space (' ').</p>
7031     *
7032     * <p>{@code null} will return {@code false}
7033     * An empty CharSequence (length()=0) will return {@code true}.</p>
7034     *
7035     * <pre>
7036     * StringUtils.isAlphaSpace(null)   = false
7037     * StringUtils.isAlphaSpace("")     = true
7038     * StringUtils.isAlphaSpace("  ")   = true
7039     * StringUtils.isAlphaSpace("abc")  = true
7040     * StringUtils.isAlphaSpace("ab c") = true
7041     * StringUtils.isAlphaSpace("ab2c") = false
7042     * StringUtils.isAlphaSpace("ab-c") = false
7043     * </pre>
7044     *
7045     * @param cs  the CharSequence to check, may be null
7046     * @return {@code true} if only contains letters and space,
7047     *  and is non-null
7048     * @since 3.0 Changed signature from isAlphaSpace(String) to isAlphaSpace(CharSequence)
7049     */
7050    public static boolean isAlphaSpace(final CharSequence cs) {
7051        if (cs == null) {
7052            return false;
7053        }
7054        final int sz = cs.length();
7055        for (int i = 0; i < sz; i++) {
7056            if (!Character.isLetter(cs.charAt(i)) && cs.charAt(i) != ' ') {
7057                return false;
7058            }
7059        }
7060        return true;
7061    }
7062
7063    /**
7064     * <p>Checks if the CharSequence contains only Unicode letters or digits.</p>
7065     *
7066     * <p>{@code null} will return {@code false}.
7067     * An empty CharSequence (length()=0) will return {@code false}.</p>
7068     *
7069     * <pre>
7070     * StringUtils.isAlphanumeric(null)   = false
7071     * StringUtils.isAlphanumeric("")     = false
7072     * StringUtils.isAlphanumeric("  ")   = false
7073     * StringUtils.isAlphanumeric("abc")  = true
7074     * StringUtils.isAlphanumeric("ab c") = false
7075     * StringUtils.isAlphanumeric("ab2c") = true
7076     * StringUtils.isAlphanumeric("ab-c") = false
7077     * </pre>
7078     *
7079     * @param cs  the CharSequence to check, may be null
7080     * @return {@code true} if only contains letters or digits,
7081     *  and is non-null
7082     * @since 3.0 Changed signature from isAlphanumeric(String) to isAlphanumeric(CharSequence)
7083     * @since 3.0 Changed "" to return false and not true
7084     */
7085    public static boolean isAlphanumeric(final CharSequence cs) {
7086        if (isEmpty(cs)) {
7087            return false;
7088        }
7089        final int sz = cs.length();
7090        for (int i = 0; i < sz; i++) {
7091            if (!Character.isLetterOrDigit(cs.charAt(i))) {
7092                return false;
7093            }
7094        }
7095        return true;
7096    }
7097
7098    /**
7099     * <p>Checks if the CharSequence contains only Unicode letters, digits
7100     * or space ({@code ' '}).</p>
7101     *
7102     * <p>{@code null} will return {@code false}.
7103     * An empty CharSequence (length()=0) will return {@code true}.</p>
7104     *
7105     * <pre>
7106     * StringUtils.isAlphanumericSpace(null)   = false
7107     * StringUtils.isAlphanumericSpace("")     = true
7108     * StringUtils.isAlphanumericSpace("  ")   = true
7109     * StringUtils.isAlphanumericSpace("abc")  = true
7110     * StringUtils.isAlphanumericSpace("ab c") = true
7111     * StringUtils.isAlphanumericSpace("ab2c") = true
7112     * StringUtils.isAlphanumericSpace("ab-c") = false
7113     * </pre>
7114     *
7115     * @param cs  the CharSequence to check, may be null
7116     * @return {@code true} if only contains letters, digits or space,
7117     *  and is non-null
7118     * @since 3.0 Changed signature from isAlphanumericSpace(String) to isAlphanumericSpace(CharSequence)
7119     */
7120    public static boolean isAlphanumericSpace(final CharSequence cs) {
7121        if (cs == null) {
7122            return false;
7123        }
7124        final int sz = cs.length();
7125        for (int i = 0; i < sz; i++) {
7126            if (!Character.isLetterOrDigit(cs.charAt(i)) && cs.charAt(i) != ' ') {
7127                return false;
7128            }
7129        }
7130        return true;
7131    }
7132
7133    /**
7134     * <p>Checks if the CharSequence contains only ASCII printable characters.</p>
7135     *
7136     * <p>{@code null} will return {@code false}.
7137     * An empty CharSequence (length()=0) will return {@code true}.</p>
7138     *
7139     * <pre>
7140     * StringUtils.isAsciiPrintable(null)     = false
7141     * StringUtils.isAsciiPrintable("")       = true
7142     * StringUtils.isAsciiPrintable(" ")      = true
7143     * StringUtils.isAsciiPrintable("Ceki")   = true
7144     * StringUtils.isAsciiPrintable("ab2c")   = true
7145     * StringUtils.isAsciiPrintable("!ab-c~") = true
7146     * StringUtils.isAsciiPrintable("\u0020") = true
7147     * StringUtils.isAsciiPrintable("\u0021") = true
7148     * StringUtils.isAsciiPrintable("\u007e") = true
7149     * StringUtils.isAsciiPrintable("\u007f") = false
7150     * StringUtils.isAsciiPrintable("Ceki G\u00fclc\u00fc") = false
7151     * </pre>
7152     *
7153     * @param cs the CharSequence to check, may be null
7154     * @return {@code true} if every character is in the range
7155     *  32 thru 126
7156     * @since 2.1
7157     * @since 3.0 Changed signature from isAsciiPrintable(String) to isAsciiPrintable(CharSequence)
7158     */
7159    public static boolean isAsciiPrintable(final CharSequence cs) {
7160        if (cs == null) {
7161            return false;
7162        }
7163        final int sz = cs.length();
7164        for (int i = 0; i < sz; i++) {
7165            if (!CharUtils.isAsciiPrintable(cs.charAt(i))) {
7166                return false;
7167            }
7168        }
7169        return true;
7170    }
7171
7172    /**
7173     * <p>Checks if the CharSequence contains only Unicode digits.
7174     * A decimal point is not a Unicode digit and returns false.</p>
7175     *
7176     * <p>{@code null} will return {@code false}.
7177     * An empty CharSequence (length()=0) will return {@code false}.</p>
7178     *
7179     * <p>Note that the method does not allow for a leading sign, either positive or negative.
7180     * Also, if a String passes the numeric test, it may still generate a NumberFormatException
7181     * when parsed by Integer.parseInt or Long.parseLong, e.g. if the value is outside the range
7182     * for int or long respectively.</p>
7183     *
7184     * <pre>
7185     * StringUtils.isNumeric(null)   = false
7186     * StringUtils.isNumeric("")     = false
7187     * StringUtils.isNumeric("  ")   = false
7188     * StringUtils.isNumeric("123")  = true
7189     * StringUtils.isNumeric("\u0967\u0968\u0969")  = true
7190     * StringUtils.isNumeric("12 3") = false
7191     * StringUtils.isNumeric("ab2c") = false
7192     * StringUtils.isNumeric("12-3") = false
7193     * StringUtils.isNumeric("12.3") = false
7194     * StringUtils.isNumeric("-123") = false
7195     * StringUtils.isNumeric("+123") = false
7196     * </pre>
7197     *
7198     * @param cs  the CharSequence to check, may be null
7199     * @return {@code true} if only contains digits, and is non-null
7200     * @since 3.0 Changed signature from isNumeric(String) to isNumeric(CharSequence)
7201     * @since 3.0 Changed "" to return false and not true
7202     */
7203    public static boolean isNumeric(final CharSequence cs) {
7204        if (isEmpty(cs)) {
7205            return false;
7206        }
7207        final int sz = cs.length();
7208        for (int i = 0; i < sz; i++) {
7209            if (!Character.isDigit(cs.charAt(i))) {
7210                return false;
7211            }
7212        }
7213        return true;
7214    }
7215
7216    /**
7217     * <p>Checks if the CharSequence contains only Unicode digits or space
7218     * ({@code ' '}).
7219     * A decimal point is not a Unicode digit and returns false.</p>
7220     *
7221     * <p>{@code null} will return {@code false}.
7222     * An empty CharSequence (length()=0) will return {@code true}.</p>
7223     *
7224     * <pre>
7225     * StringUtils.isNumericSpace(null)   = false
7226     * StringUtils.isNumericSpace("")     = true
7227     * StringUtils.isNumericSpace("  ")   = true
7228     * StringUtils.isNumericSpace("123")  = true
7229     * StringUtils.isNumericSpace("12 3") = true
7230     * StringUtils.isNumeric("\u0967\u0968\u0969")  = true
7231     * StringUtils.isNumeric("\u0967\u0968 \u0969")  = true
7232     * StringUtils.isNumericSpace("ab2c") = false
7233     * StringUtils.isNumericSpace("12-3") = false
7234     * StringUtils.isNumericSpace("12.3") = false
7235     * </pre>
7236     *
7237     * @param cs  the CharSequence to check, may be null
7238     * @return {@code true} if only contains digits or space,
7239     *  and is non-null
7240     * @since 3.0 Changed signature from isNumericSpace(String) to isNumericSpace(CharSequence)
7241     */
7242    public static boolean isNumericSpace(final CharSequence cs) {
7243        if (cs == null) {
7244            return false;
7245        }
7246        final int sz = cs.length();
7247        for (int i = 0; i < sz; i++) {
7248            if (!Character.isDigit(cs.charAt(i)) && cs.charAt(i) != ' ') {
7249                return false;
7250            }
7251        }
7252        return true;
7253    }
7254
7255    /**
7256     * <p>Checks if a String {@code str} contains Unicode digits,
7257     * if yes then concatenate all the digits in {@code str} and return it as a String.</p>
7258     *
7259     * <p>An empty ("") String will be returned if no digits found in {@code str}.</p>
7260     *
7261     * <pre>
7262     * StringUtils.getDigits(null)  = null
7263     * StringUtils.getDigits("")    = ""
7264     * StringUtils.getDigits("abc") = ""
7265     * StringUtils.getDigits("1000$") = "1000"
7266     * StringUtils.getDigits("1123~45") = "112345"
7267     * StringUtils.getDigits("(541) 754-3010") = "5417543010"
7268     * StringUtils.getDigits("\u0967\u0968\u0969") = "\u0967\u0968\u0969"
7269     * </pre>
7270     *
7271     * @param str the String to extract digits from, may be null
7272     * @return String with only digits,
7273     *           or an empty ("") String if no digits found,
7274     *           or {@code null} String if {@code str} is null
7275     * @since 3.6
7276     */
7277    public static String getDigits(final String str) {
7278        if (isEmpty(str)) {
7279            return str;
7280        }
7281        final int sz = str.length();
7282        final StringBuilder strDigits = new StringBuilder(sz);
7283        for (int i = 0; i < sz; i++) {
7284            final char tempChar = str.charAt(i);
7285            if (Character.isDigit(tempChar)) {
7286                strDigits.append(tempChar);
7287            }
7288        }
7289        return strDigits.toString();
7290    }
7291
7292    /**
7293     * <p>Checks if the CharSequence contains only whitespace.</p>
7294     *
7295     * <p>Whitespace is defined by {@link Character#isWhitespace(char)}.</p>
7296     *
7297     * <p>{@code null} will return {@code false}.
7298     * An empty CharSequence (length()=0) will return {@code true}.</p>
7299     *
7300     * <pre>
7301     * StringUtils.isWhitespace(null)   = false
7302     * StringUtils.isWhitespace("")     = true
7303     * StringUtils.isWhitespace("  ")   = true
7304     * StringUtils.isWhitespace("abc")  = false
7305     * StringUtils.isWhitespace("ab2c") = false
7306     * StringUtils.isWhitespace("ab-c") = false
7307     * </pre>
7308     *
7309     * @param cs  the CharSequence to check, may be null
7310     * @return {@code true} if only contains whitespace, and is non-null
7311     * @since 2.0
7312     * @since 3.0 Changed signature from isWhitespace(String) to isWhitespace(CharSequence)
7313     */
7314    public static boolean isWhitespace(final CharSequence cs) {
7315        if (cs == null) {
7316            return false;
7317        }
7318        final int sz = cs.length();
7319        for (int i = 0; i < sz; i++) {
7320            if (!Character.isWhitespace(cs.charAt(i))) {
7321                return false;
7322            }
7323        }
7324        return true;
7325    }
7326
7327    /**
7328     * <p>Checks if the CharSequence contains only lowercase characters.</p>
7329     *
7330     * <p>{@code null} will return {@code false}.
7331     * An empty CharSequence (length()=0) will return {@code false}.</p>
7332     *
7333     * <pre>
7334     * StringUtils.isAllLowerCase(null)   = false
7335     * StringUtils.isAllLowerCase("")     = false
7336     * StringUtils.isAllLowerCase("  ")   = false
7337     * StringUtils.isAllLowerCase("abc")  = true
7338     * StringUtils.isAllLowerCase("abC")  = false
7339     * StringUtils.isAllLowerCase("ab c") = false
7340     * StringUtils.isAllLowerCase("ab1c") = false
7341     * StringUtils.isAllLowerCase("ab/c") = false
7342     * </pre>
7343     *
7344     * @param cs  the CharSequence to check, may be null
7345     * @return {@code true} if only contains lowercase characters, and is non-null
7346     * @since 2.5
7347     * @since 3.0 Changed signature from isAllLowerCase(String) to isAllLowerCase(CharSequence)
7348     */
7349    public static boolean isAllLowerCase(final CharSequence cs) {
7350        if (cs == null || isEmpty(cs)) {
7351            return false;
7352        }
7353        final int sz = cs.length();
7354        for (int i = 0; i < sz; i++) {
7355            if (!Character.isLowerCase(cs.charAt(i))) {
7356                return false;
7357            }
7358        }
7359        return true;
7360    }
7361
7362    /**
7363     * <p>Checks if the CharSequence contains only uppercase characters.</p>
7364     *
7365     * <p>{@code null} will return {@code false}.
7366     * An empty String (length()=0) will return {@code false}.</p>
7367     *
7368     * <pre>
7369     * StringUtils.isAllUpperCase(null)   = false
7370     * StringUtils.isAllUpperCase("")     = false
7371     * StringUtils.isAllUpperCase("  ")   = false
7372     * StringUtils.isAllUpperCase("ABC")  = true
7373     * StringUtils.isAllUpperCase("aBC")  = false
7374     * StringUtils.isAllUpperCase("A C")  = false
7375     * StringUtils.isAllUpperCase("A1C")  = false
7376     * StringUtils.isAllUpperCase("A/C")  = false
7377     * </pre>
7378     *
7379     * @param cs the CharSequence to check, may be null
7380     * @return {@code true} if only contains uppercase characters, and is non-null
7381     * @since 2.5
7382     * @since 3.0 Changed signature from isAllUpperCase(String) to isAllUpperCase(CharSequence)
7383     */
7384    public static boolean isAllUpperCase(final CharSequence cs) {
7385        if (cs == null || isEmpty(cs)) {
7386            return false;
7387        }
7388        final int sz = cs.length();
7389        for (int i = 0; i < sz; i++) {
7390            if (!Character.isUpperCase(cs.charAt(i))) {
7391                return false;
7392            }
7393        }
7394        return true;
7395    }
7396
7397    /**
7398     * <p>Checks if the CharSequence contains mixed casing of both uppercase and lowercase characters.</p>
7399     *
7400     * <p>{@code null} will return {@code false}. An empty CharSequence ({@code length()=0}) will return
7401     * {@code false}.</p>
7402     *
7403     * <pre>
7404     * StringUtils.isMixedCase(null)    = false
7405     * StringUtils.isMixedCase("")      = false
7406     * StringUtils.isMixedCase("ABC")   = false
7407     * StringUtils.isMixedCase("abc")   = false
7408     * StringUtils.isMixedCase("aBc")   = true
7409     * StringUtils.isMixedCase("A c")   = true
7410     * StringUtils.isMixedCase("A1c")   = true
7411     * StringUtils.isMixedCase("a/C")   = true
7412     * StringUtils.isMixedCase("aC\t")  = true
7413     * </pre>
7414     *
7415     * @param cs the CharSequence to check, may be null
7416     * @return {@code true} if the CharSequence contains both uppercase and lowercase characters
7417     * @since 3.5
7418     */
7419    public static boolean isMixedCase(final CharSequence cs) {
7420        if (isEmpty(cs) || cs.length() == 1) {
7421            return false;
7422        }
7423        boolean containsUppercase = false;
7424        boolean containsLowercase = false;
7425        final int sz = cs.length();
7426        for (int i = 0; i < sz; i++) {
7427            if (containsUppercase && containsLowercase) {
7428                return true;
7429            } else if (Character.isUpperCase(cs.charAt(i))) {
7430                containsUppercase = true;
7431            } else if (Character.isLowerCase(cs.charAt(i))) {
7432                containsLowercase = true;
7433            }
7434        }
7435        return containsUppercase && containsLowercase;
7436    }
7437
7438    // Defaults
7439    //-----------------------------------------------------------------------
7440    /**
7441     * <p>Returns either the passed in String,
7442     * or if the String is {@code null}, an empty String ("").</p>
7443     *
7444     * <pre>
7445     * StringUtils.defaultString(null)  = ""
7446     * StringUtils.defaultString("")    = ""
7447     * StringUtils.defaultString("bat") = "bat"
7448     * </pre>
7449     *
7450     * @see ObjectUtils#toString(Object)
7451     * @see String#valueOf(Object)
7452     * @param str  the String to check, may be null
7453     * @return the passed in String, or the empty String if it
7454     *  was {@code null}
7455     */
7456    public static String defaultString(final String str) {
7457        return defaultString(str, EMPTY);
7458    }
7459
7460    /**
7461     * <p>Returns either the passed in String, or if the String is
7462     * {@code null}, the value of {@code defaultStr}.</p>
7463     *
7464     * <pre>
7465     * StringUtils.defaultString(null, "NULL")  = "NULL"
7466     * StringUtils.defaultString("", "NULL")    = ""
7467     * StringUtils.defaultString("bat", "NULL") = "bat"
7468     * </pre>
7469     *
7470     * @see ObjectUtils#toString(Object,String)
7471     * @see String#valueOf(Object)
7472     * @param str  the String to check, may be null
7473     * @param defaultStr  the default String to return
7474     *  if the input is {@code null}, may be null
7475     * @return the passed in String, or the default if it was {@code null}
7476     */
7477    public static String defaultString(final String str, final String defaultStr) {
7478        return str == null ? defaultStr : str;
7479    }
7480
7481    /**
7482     * <p>Returns the first value in the array which is not empty (""),
7483     * {@code null} or whitespace only.</p>
7484     *
7485     * <p>Whitespace is defined by {@link Character#isWhitespace(char)}.</p>
7486     *
7487     * <p>If all values are blank or the array is {@code null}
7488     * or empty then {@code null} is returned.</p>
7489     *
7490     * <pre>
7491     * StringUtils.firstNonBlank(null, null, null)     = null
7492     * StringUtils.firstNonBlank(null, "", " ")        = null
7493     * StringUtils.firstNonBlank("abc")                = "abc"
7494     * StringUtils.firstNonBlank(null, "xyz")          = "xyz"
7495     * StringUtils.firstNonBlank(null, "", " ", "xyz") = "xyz"
7496     * StringUtils.firstNonBlank(null, "xyz", "abc")   = "xyz"
7497     * StringUtils.firstNonBlank()                     = null
7498     * </pre>
7499     *
7500     * @param <T> the specific kind of CharSequence
7501     * @param values  the values to test, may be {@code null} or empty
7502     * @return the first value from {@code values} which is not blank,
7503     *  or {@code null} if there are no non-blank values
7504     * @since 3.8
7505     */
7506    @SafeVarargs
7507    public static <T extends CharSequence> T firstNonBlank(final T... values) {
7508        if (values != null) {
7509            for (final T val : values) {
7510                if (isNotBlank(val)) {
7511                    return val;
7512                }
7513            }
7514        }
7515        return null;
7516    }
7517
7518    /**
7519     * <p>Returns the first value in the array which is not empty.</p>
7520     *
7521     * <p>If all values are empty or the array is {@code null}
7522     * or empty then {@code null} is returned.</p>
7523     *
7524     * <pre>
7525     * StringUtils.firstNonEmpty(null, null, null)   = null
7526     * StringUtils.firstNonEmpty(null, null, "")     = null
7527     * StringUtils.firstNonEmpty(null, "", " ")      = " "
7528     * StringUtils.firstNonEmpty("abc")              = "abc"
7529     * StringUtils.firstNonEmpty(null, "xyz")        = "xyz"
7530     * StringUtils.firstNonEmpty("", "xyz")          = "xyz"
7531     * StringUtils.firstNonEmpty(null, "xyz", "abc") = "xyz"
7532     * StringUtils.firstNonEmpty()                   = null
7533     * </pre>
7534     *
7535     * @param <T> the specific kind of CharSequence
7536     * @param values  the values to test, may be {@code null} or empty
7537     * @return the first value from {@code values} which is not empty,
7538     *  or {@code null} if there are no non-empty values
7539     * @since 3.8
7540     */
7541    @SafeVarargs
7542    public static <T extends CharSequence> T firstNonEmpty(final T... values) {
7543        if (values != null) {
7544            for (final T val : values) {
7545                if (isNotEmpty(val)) {
7546                    return val;
7547                }
7548            }
7549        }
7550        return null;
7551    }
7552
7553    /**
7554     * <p>Returns either the passed in CharSequence, or if the CharSequence is
7555     * whitespace, empty ("") or {@code null}, the value of {@code defaultStr}.</p>
7556     *
7557     * <p>Whitespace is defined by {@link Character#isWhitespace(char)}.</p>
7558     *
7559     * <pre>
7560     * StringUtils.defaultIfBlank(null, "NULL")  = "NULL"
7561     * StringUtils.defaultIfBlank("", "NULL")    = "NULL"
7562     * StringUtils.defaultIfBlank(" ", "NULL")   = "NULL"
7563     * StringUtils.defaultIfBlank("bat", "NULL") = "bat"
7564     * StringUtils.defaultIfBlank("", null)      = null
7565     * </pre>
7566     * @param <T> the specific kind of CharSequence
7567     * @param str the CharSequence to check, may be null
7568     * @param defaultStr  the default CharSequence to return
7569     *  if the input is whitespace, empty ("") or {@code null}, may be null
7570     * @return the passed in CharSequence, or the default
7571     * @see StringUtils#defaultString(String, String)
7572     */
7573    public static <T extends CharSequence> T defaultIfBlank(final T str, final T defaultStr) {
7574        return isBlank(str) ? defaultStr : str;
7575    }
7576
7577    /**
7578     * <p>Returns either the passed in CharSequence, or if the CharSequence is
7579     * empty or {@code null}, the value of {@code defaultStr}.</p>
7580     *
7581     * <pre>
7582     * StringUtils.defaultIfEmpty(null, "NULL")  = "NULL"
7583     * StringUtils.defaultIfEmpty("", "NULL")    = "NULL"
7584     * StringUtils.defaultIfEmpty(" ", "NULL")   = " "
7585     * StringUtils.defaultIfEmpty("bat", "NULL") = "bat"
7586     * StringUtils.defaultIfEmpty("", null)      = null
7587     * </pre>
7588     * @param <T> the specific kind of CharSequence
7589     * @param str  the CharSequence to check, may be null
7590     * @param defaultStr  the default CharSequence to return
7591     *  if the input is empty ("") or {@code null}, may be null
7592     * @return the passed in CharSequence, or the default
7593     * @see StringUtils#defaultString(String, String)
7594     */
7595    public static <T extends CharSequence> T defaultIfEmpty(final T str, final T defaultStr) {
7596        return isEmpty(str) ? defaultStr : str;
7597    }
7598
7599    // Rotating (circular shift)
7600    //-----------------------------------------------------------------------
7601    /**
7602     * <p>Rotate (circular shift) a String of {@code shift} characters.</p>
7603     * <ul>
7604     *  <li>If {@code shift > 0}, right circular shift (ex : ABCDEF =&gt; FABCDE)</li>
7605     *  <li>If {@code shift < 0}, left circular shift (ex : ABCDEF =&gt; BCDEFA)</li>
7606     * </ul>
7607     *
7608     * <pre>
7609     * StringUtils.rotate(null, *)        = null
7610     * StringUtils.rotate("", *)          = ""
7611     * StringUtils.rotate("abcdefg", 0)   = "abcdefg"
7612     * StringUtils.rotate("abcdefg", 2)   = "fgabcde"
7613     * StringUtils.rotate("abcdefg", -2)  = "cdefgab"
7614     * StringUtils.rotate("abcdefg", 7)   = "abcdefg"
7615     * StringUtils.rotate("abcdefg", -7)  = "abcdefg"
7616     * StringUtils.rotate("abcdefg", 9)   = "fgabcde"
7617     * StringUtils.rotate("abcdefg", -9)  = "cdefgab"
7618     * </pre>
7619     *
7620     * @param str  the String to rotate, may be null
7621     * @param shift  number of time to shift (positive : right shift, negative : left shift)
7622     * @return the rotated String,
7623     *          or the original String if {@code shift == 0},
7624     *          or {@code null} if null String input
7625     * @since 3.5
7626     */
7627    public static String rotate(final String str, final int shift) {
7628        if (str == null) {
7629            return null;
7630        }
7631
7632        final int strLen = str.length();
7633        if (shift == 0 || strLen == 0 || shift % strLen == 0) {
7634            return str;
7635        }
7636
7637        final StringBuilder builder = new StringBuilder(strLen);
7638        final int offset = - (shift % strLen);
7639        builder.append(substring(str, offset));
7640        builder.append(substring(str, 0, offset));
7641        return builder.toString();
7642    }
7643
7644    // Reversing
7645    //-----------------------------------------------------------------------
7646    /**
7647     * <p>Reverses a String as per {@link StringBuilder#reverse()}.</p>
7648     *
7649     * <p>A {@code null} String returns {@code null}.</p>
7650     *
7651     * <pre>
7652     * StringUtils.reverse(null)  = null
7653     * StringUtils.reverse("")    = ""
7654     * StringUtils.reverse("bat") = "tab"
7655     * </pre>
7656     *
7657     * @param str  the String to reverse, may be null
7658     * @return the reversed String, {@code null} if null String input
7659     */
7660    public static String reverse(final String str) {
7661        if (str == null) {
7662            return null;
7663        }
7664        return new StringBuilder(str).reverse().toString();
7665    }
7666
7667    /**
7668     * <p>Reverses a String that is delimited by a specific character.</p>
7669     *
7670     * <p>The Strings between the delimiters are not reversed.
7671     * Thus java.lang.String becomes String.lang.java (if the delimiter
7672     * is {@code '.'}).</p>
7673     *
7674     * <pre>
7675     * StringUtils.reverseDelimited(null, *)      = null
7676     * StringUtils.reverseDelimited("", *)        = ""
7677     * StringUtils.reverseDelimited("a.b.c", 'x') = "a.b.c"
7678     * StringUtils.reverseDelimited("a.b.c", ".") = "c.b.a"
7679     * </pre>
7680     *
7681     * @param str  the String to reverse, may be null
7682     * @param separatorChar  the separator character to use
7683     * @return the reversed String, {@code null} if null String input
7684     * @since 2.0
7685     */
7686    public static String reverseDelimited(final String str, final char separatorChar) {
7687        if (str == null) {
7688            return null;
7689        }
7690        // could implement manually, but simple way is to reuse other,
7691        // probably slower, methods.
7692        final String[] strs = split(str, separatorChar);
7693        ArrayUtils.reverse(strs);
7694        return join(strs, separatorChar);
7695    }
7696
7697    // Abbreviating
7698    //-----------------------------------------------------------------------
7699    /**
7700     * <p>Abbreviates a String using ellipses. This will turn
7701     * "Now is the time for all good men" into "Now is the time for..."</p>
7702     *
7703     * <p>Specifically:</p>
7704     * <ul>
7705     *   <li>If the number of characters in {@code str} is less than or equal to
7706     *       {@code maxWidth}, return {@code str}.</li>
7707     *   <li>Else abbreviate it to {@code (substring(str, 0, max-3) + "...")}.</li>
7708     *   <li>If {@code maxWidth} is less than {@code 4}, throw an
7709     *       {@code IllegalArgumentException}.</li>
7710     *   <li>In no case will it return a String of length greater than
7711     *       {@code maxWidth}.</li>
7712     * </ul>
7713     *
7714     * <pre>
7715     * StringUtils.abbreviate(null, *)      = null
7716     * StringUtils.abbreviate("", 4)        = ""
7717     * StringUtils.abbreviate("abcdefg", 6) = "abc..."
7718     * StringUtils.abbreviate("abcdefg", 7) = "abcdefg"
7719     * StringUtils.abbreviate("abcdefg", 8) = "abcdefg"
7720     * StringUtils.abbreviate("abcdefg", 4) = "a..."
7721     * StringUtils.abbreviate("abcdefg", 3) = IllegalArgumentException
7722     * </pre>
7723     *
7724     * @param str  the String to check, may be null
7725     * @param maxWidth  maximum length of result String, must be at least 4
7726     * @return abbreviated String, {@code null} if null String input
7727     * @throws IllegalArgumentException if the width is too small
7728     * @since 2.0
7729     */
7730    public static String abbreviate(final String str, final int maxWidth) {
7731        final String defaultAbbrevMarker = "...";
7732        return abbreviate(str, defaultAbbrevMarker, 0, maxWidth);
7733    }
7734
7735    /**
7736     * <p>Abbreviates a String using ellipses. This will turn
7737     * "Now is the time for all good men" into "...is the time for..."</p>
7738     *
7739     * <p>Works like {@code abbreviate(String, int)}, but allows you to specify
7740     * a "left edge" offset.  Note that this left edge is not necessarily going to
7741     * be the leftmost character in the result, or the first character following the
7742     * ellipses, but it will appear somewhere in the result.
7743     *
7744     * <p>In no case will it return a String of length greater than
7745     * {@code maxWidth}.</p>
7746     *
7747     * <pre>
7748     * StringUtils.abbreviate(null, *, *)                = null
7749     * StringUtils.abbreviate("", 0, 4)                  = ""
7750     * StringUtils.abbreviate("abcdefghijklmno", -1, 10) = "abcdefg..."
7751     * StringUtils.abbreviate("abcdefghijklmno", 0, 10)  = "abcdefg..."
7752     * StringUtils.abbreviate("abcdefghijklmno", 1, 10)  = "abcdefg..."
7753     * StringUtils.abbreviate("abcdefghijklmno", 4, 10)  = "abcdefg..."
7754     * StringUtils.abbreviate("abcdefghijklmno", 5, 10)  = "...fghi..."
7755     * StringUtils.abbreviate("abcdefghijklmno", 6, 10)  = "...ghij..."
7756     * StringUtils.abbreviate("abcdefghijklmno", 8, 10)  = "...ijklmno"
7757     * StringUtils.abbreviate("abcdefghijklmno", 10, 10) = "...ijklmno"
7758     * StringUtils.abbreviate("abcdefghijklmno", 12, 10) = "...ijklmno"
7759     * StringUtils.abbreviate("abcdefghij", 0, 3)        = IllegalArgumentException
7760     * StringUtils.abbreviate("abcdefghij", 5, 6)        = IllegalArgumentException
7761     * </pre>
7762     *
7763     * @param str  the String to check, may be null
7764     * @param offset  left edge of source String
7765     * @param maxWidth  maximum length of result String, must be at least 4
7766     * @return abbreviated String, {@code null} if null String input
7767     * @throws IllegalArgumentException if the width is too small
7768     * @since 2.0
7769     */
7770    public static String abbreviate(final String str, final int offset, final int maxWidth) {
7771        final String defaultAbbrevMarker = "...";
7772        return abbreviate(str, defaultAbbrevMarker, offset, maxWidth);
7773    }
7774
7775    /**
7776     * <p>Abbreviates a String using another given String as replacement marker. This will turn
7777     * "Now is the time for all good men" into "Now is the time for..." if "..." was defined
7778     * as the replacement marker.</p>
7779     *
7780     * <p>Specifically:</p>
7781     * <ul>
7782     *   <li>If the number of characters in {@code str} is less than or equal to
7783     *       {@code maxWidth}, return {@code str}.</li>
7784     *   <li>Else abbreviate it to {@code (substring(str, 0, max-abbrevMarker.length) + abbrevMarker)}.</li>
7785     *   <li>If {@code maxWidth} is less than {@code abbrevMarker.length + 1}, throw an
7786     *       {@code IllegalArgumentException}.</li>
7787     *   <li>In no case will it return a String of length greater than
7788     *       {@code maxWidth}.</li>
7789     * </ul>
7790     *
7791     * <pre>
7792     * StringUtils.abbreviate(null, "...", *)      = null
7793     * StringUtils.abbreviate("abcdefg", null, *)  = "abcdefg"
7794     * StringUtils.abbreviate("", "...", 4)        = ""
7795     * StringUtils.abbreviate("abcdefg", ".", 5)   = "abcd."
7796     * StringUtils.abbreviate("abcdefg", ".", 7)   = "abcdefg"
7797     * StringUtils.abbreviate("abcdefg", ".", 8)   = "abcdefg"
7798     * StringUtils.abbreviate("abcdefg", "..", 4)  = "ab.."
7799     * StringUtils.abbreviate("abcdefg", "..", 3)  = "a.."
7800     * StringUtils.abbreviate("abcdefg", "..", 2)  = IllegalArgumentException
7801     * StringUtils.abbreviate("abcdefg", "...", 3) = IllegalArgumentException
7802     * </pre>
7803     *
7804     * @param str  the String to check, may be null
7805     * @param abbrevMarker  the String used as replacement marker
7806     * @param maxWidth  maximum length of result String, must be at least {@code abbrevMarker.length + 1}
7807     * @return abbreviated String, {@code null} if null String input
7808     * @throws IllegalArgumentException if the width is too small
7809     * @since 3.6
7810     */
7811    public static String abbreviate(final String str, final String abbrevMarker, final int maxWidth) {
7812        return abbreviate(str, abbrevMarker, 0, maxWidth);
7813    }
7814
7815    /**
7816     * <p>Abbreviates a String using a given replacement marker. This will turn
7817     * "Now is the time for all good men" into "...is the time for..." if "..." was defined
7818     * as the replacement marker.</p>
7819     *
7820     * <p>Works like {@code abbreviate(String, String, int)}, but allows you to specify
7821     * a "left edge" offset.  Note that this left edge is not necessarily going to
7822     * be the leftmost character in the result, or the first character following the
7823     * replacement marker, but it will appear somewhere in the result.
7824     *
7825     * <p>In no case will it return a String of length greater than {@code maxWidth}.</p>
7826     *
7827     * <pre>
7828     * StringUtils.abbreviate(null, null, *, *)                 = null
7829     * StringUtils.abbreviate("abcdefghijklmno", null, *, *)    = "abcdefghijklmno"
7830     * StringUtils.abbreviate("", "...", 0, 4)                  = ""
7831     * StringUtils.abbreviate("abcdefghijklmno", "---", -1, 10) = "abcdefg---"
7832     * StringUtils.abbreviate("abcdefghijklmno", ",", 0, 10)    = "abcdefghi,"
7833     * StringUtils.abbreviate("abcdefghijklmno", ",", 1, 10)    = "abcdefghi,"
7834     * StringUtils.abbreviate("abcdefghijklmno", ",", 2, 10)    = "abcdefghi,"
7835     * StringUtils.abbreviate("abcdefghijklmno", "::", 4, 10)   = "::efghij::"
7836     * StringUtils.abbreviate("abcdefghijklmno", "...", 6, 10)  = "...ghij..."
7837     * StringUtils.abbreviate("abcdefghijklmno", "*", 9, 10)    = "*ghijklmno"
7838     * StringUtils.abbreviate("abcdefghijklmno", "'", 10, 10)   = "'ghijklmno"
7839     * StringUtils.abbreviate("abcdefghijklmno", "!", 12, 10)   = "!ghijklmno"
7840     * StringUtils.abbreviate("abcdefghij", "abra", 0, 4)       = IllegalArgumentException
7841     * StringUtils.abbreviate("abcdefghij", "...", 5, 6)        = IllegalArgumentException
7842     * </pre>
7843     *
7844     * @param str  the String to check, may be null
7845     * @param abbrevMarker  the String used as replacement marker
7846     * @param offset  left edge of source String
7847     * @param maxWidth  maximum length of result String, must be at least 4
7848     * @return abbreviated String, {@code null} if null String input
7849     * @throws IllegalArgumentException if the width is too small
7850     * @since 3.6
7851     */
7852    public static String abbreviate(final String str, final String abbrevMarker, int offset, final int maxWidth) {
7853        if (isEmpty(str) || isEmpty(abbrevMarker)) {
7854            return str;
7855        }
7856
7857        final int abbrevMarkerLength = abbrevMarker.length();
7858        final int minAbbrevWidth = abbrevMarkerLength + 1;
7859        final int minAbbrevWidthOffset = abbrevMarkerLength + abbrevMarkerLength + 1;
7860
7861        if (maxWidth < minAbbrevWidth) {
7862            throw new IllegalArgumentException(String.format("Minimum abbreviation width is %d", minAbbrevWidth));
7863        }
7864        if (str.length() <= maxWidth) {
7865            return str;
7866        }
7867        if (offset > str.length()) {
7868            offset = str.length();
7869        }
7870        if (str.length() - offset < maxWidth - abbrevMarkerLength) {
7871            offset = str.length() - (maxWidth - abbrevMarkerLength);
7872        }
7873        if (offset <= abbrevMarkerLength+1) {
7874            return str.substring(0, maxWidth - abbrevMarkerLength) + abbrevMarker;
7875        }
7876        if (maxWidth < minAbbrevWidthOffset) {
7877            throw new IllegalArgumentException(String.format("Minimum abbreviation width with offset is %d", minAbbrevWidthOffset));
7878        }
7879        if (offset + maxWidth - abbrevMarkerLength < str.length()) {
7880            return abbrevMarker + abbreviate(str.substring(offset), abbrevMarker, maxWidth - abbrevMarkerLength);
7881        }
7882        return abbrevMarker + str.substring(str.length() - (maxWidth - abbrevMarkerLength));
7883    }
7884
7885    /**
7886     * <p>Abbreviates a String to the length passed, replacing the middle characters with the supplied
7887     * replacement String.</p>
7888     *
7889     * <p>This abbreviation only occurs if the following criteria is met:</p>
7890     * <ul>
7891     * <li>Neither the String for abbreviation nor the replacement String are null or empty </li>
7892     * <li>The length to truncate to is less than the length of the supplied String</li>
7893     * <li>The length to truncate to is greater than 0</li>
7894     * <li>The abbreviated String will have enough room for the length supplied replacement String
7895     * and the first and last characters of the supplied String for abbreviation</li>
7896     * </ul>
7897     * <p>Otherwise, the returned String will be the same as the supplied String for abbreviation.
7898     * </p>
7899     *
7900     * <pre>
7901     * StringUtils.abbreviateMiddle(null, null, 0)      = null
7902     * StringUtils.abbreviateMiddle("abc", null, 0)      = "abc"
7903     * StringUtils.abbreviateMiddle("abc", ".", 0)      = "abc"
7904     * StringUtils.abbreviateMiddle("abc", ".", 3)      = "abc"
7905     * StringUtils.abbreviateMiddle("abcdef", ".", 4)     = "ab.f"
7906     * </pre>
7907     *
7908     * @param str  the String to abbreviate, may be null
7909     * @param middle the String to replace the middle characters with, may be null
7910     * @param length the length to abbreviate {@code str} to.
7911     * @return the abbreviated String if the above criteria is met, or the original String supplied for abbreviation.
7912     * @since 2.5
7913     */
7914    public static String abbreviateMiddle(final String str, final String middle, final int length) {
7915        if (isEmpty(str) || isEmpty(middle)) {
7916            return str;
7917        }
7918
7919        if (length >= str.length() || length < middle.length()+2) {
7920            return str;
7921        }
7922
7923        final int targetSting = length-middle.length();
7924        final int startOffset = targetSting/2+targetSting%2;
7925        final int endOffset = str.length()-targetSting/2;
7926
7927        return str.substring(0, startOffset) +
7928            middle +
7929            str.substring(endOffset);
7930    }
7931
7932    // Difference
7933    //-----------------------------------------------------------------------
7934    /**
7935     * <p>Compares two Strings, and returns the portion where they differ.
7936     * More precisely, return the remainder of the second String,
7937     * starting from where it's different from the first. This means that
7938     * the difference between "abc" and "ab" is the empty String and not "c". </p>
7939     *
7940     * <p>For example,
7941     * {@code difference("i am a machine", "i am a robot") -> "robot"}.</p>
7942     *
7943     * <pre>
7944     * StringUtils.difference(null, null) = null
7945     * StringUtils.difference("", "") = ""
7946     * StringUtils.difference("", "abc") = "abc"
7947     * StringUtils.difference("abc", "") = ""
7948     * StringUtils.difference("abc", "abc") = ""
7949     * StringUtils.difference("abc", "ab") = ""
7950     * StringUtils.difference("ab", "abxyz") = "xyz"
7951     * StringUtils.difference("abcde", "abxyz") = "xyz"
7952     * StringUtils.difference("abcde", "xyz") = "xyz"
7953     * </pre>
7954     *
7955     * @param str1  the first String, may be null
7956     * @param str2  the second String, may be null
7957     * @return the portion of str2 where it differs from str1; returns the
7958     * empty String if they are equal
7959     * @see #indexOfDifference(CharSequence,CharSequence)
7960     * @since 2.0
7961     */
7962    public static String difference(final String str1, final String str2) {
7963        if (str1 == null) {
7964            return str2;
7965        }
7966        if (str2 == null) {
7967            return str1;
7968        }
7969        final int at = indexOfDifference(str1, str2);
7970        if (at == INDEX_NOT_FOUND) {
7971            return EMPTY;
7972        }
7973        return str2.substring(at);
7974    }
7975
7976    /**
7977     * <p>Compares two CharSequences, and returns the index at which the
7978     * CharSequences begin to differ.</p>
7979     *
7980     * <p>For example,
7981     * {@code indexOfDifference("i am a machine", "i am a robot") -> 7}</p>
7982     *
7983     * <pre>
7984     * StringUtils.indexOfDifference(null, null) = -1
7985     * StringUtils.indexOfDifference("", "") = -1
7986     * StringUtils.indexOfDifference("", "abc") = 0
7987     * StringUtils.indexOfDifference("abc", "") = 0
7988     * StringUtils.indexOfDifference("abc", "abc") = -1
7989     * StringUtils.indexOfDifference("ab", "abxyz") = 2
7990     * StringUtils.indexOfDifference("abcde", "abxyz") = 2
7991     * StringUtils.indexOfDifference("abcde", "xyz") = 0
7992     * </pre>
7993     *
7994     * @param cs1  the first CharSequence, may be null
7995     * @param cs2  the second CharSequence, may be null
7996     * @return the index where cs1 and cs2 begin to differ; -1 if they are equal
7997     * @since 2.0
7998     * @since 3.0 Changed signature from indexOfDifference(String, String) to
7999     * indexOfDifference(CharSequence, CharSequence)
8000     */
8001    public static int indexOfDifference(final CharSequence cs1, final CharSequence cs2) {
8002        if (cs1 == cs2) {
8003            return INDEX_NOT_FOUND;
8004        }
8005        if (cs1 == null || cs2 == null) {
8006            return 0;
8007        }
8008        int i;
8009        for (i = 0; i < cs1.length() && i < cs2.length(); ++i) {
8010            if (cs1.charAt(i) != cs2.charAt(i)) {
8011                break;
8012            }
8013        }
8014        if (i < cs2.length() || i < cs1.length()) {
8015            return i;
8016        }
8017        return INDEX_NOT_FOUND;
8018    }
8019
8020    /**
8021     * <p>Compares all CharSequences in an array and returns the index at which the
8022     * CharSequences begin to differ.</p>
8023     *
8024     * <p>For example,
8025     * <code>indexOfDifference(new String[] {"i am a machine", "i am a robot"}) -&gt; 7</code></p>
8026     *
8027     * <pre>
8028     * StringUtils.indexOfDifference(null) = -1
8029     * StringUtils.indexOfDifference(new String[] {}) = -1
8030     * StringUtils.indexOfDifference(new String[] {"abc"}) = -1
8031     * StringUtils.indexOfDifference(new String[] {null, null}) = -1
8032     * StringUtils.indexOfDifference(new String[] {"", ""}) = -1
8033     * StringUtils.indexOfDifference(new String[] {"", null}) = 0
8034     * StringUtils.indexOfDifference(new String[] {"abc", null, null}) = 0
8035     * StringUtils.indexOfDifference(new String[] {null, null, "abc"}) = 0
8036     * StringUtils.indexOfDifference(new String[] {"", "abc"}) = 0
8037     * StringUtils.indexOfDifference(new String[] {"abc", ""}) = 0
8038     * StringUtils.indexOfDifference(new String[] {"abc", "abc"}) = -1
8039     * StringUtils.indexOfDifference(new String[] {"abc", "a"}) = 1
8040     * StringUtils.indexOfDifference(new String[] {"ab", "abxyz"}) = 2
8041     * StringUtils.indexOfDifference(new String[] {"abcde", "abxyz"}) = 2
8042     * StringUtils.indexOfDifference(new String[] {"abcde", "xyz"}) = 0
8043     * StringUtils.indexOfDifference(new String[] {"xyz", "abcde"}) = 0
8044     * StringUtils.indexOfDifference(new String[] {"i am a machine", "i am a robot"}) = 7
8045     * </pre>
8046     *
8047     * @param css  array of CharSequences, entries may be null
8048     * @return the index where the strings begin to differ; -1 if they are all equal
8049     * @since 2.4
8050     * @since 3.0 Changed signature from indexOfDifference(String...) to indexOfDifference(CharSequence...)
8051     */
8052    public static int indexOfDifference(final CharSequence... css) {
8053        if (css == null || css.length <= 1) {
8054            return INDEX_NOT_FOUND;
8055        }
8056        boolean anyStringNull = false;
8057        boolean allStringsNull = true;
8058        final int arrayLen = css.length;
8059        int shortestStrLen = Integer.MAX_VALUE;
8060        int longestStrLen = 0;
8061
8062        // find the min and max string lengths; this avoids checking to make
8063        // sure we are not exceeding the length of the string each time through
8064        // the bottom loop.
8065        for (final CharSequence cs : css) {
8066            if (cs == null) {
8067                anyStringNull = true;
8068                shortestStrLen = 0;
8069            } else {
8070                allStringsNull = false;
8071                shortestStrLen = Math.min(cs.length(), shortestStrLen);
8072                longestStrLen = Math.max(cs.length(), longestStrLen);
8073            }
8074        }
8075
8076        // handle lists containing all nulls or all empty strings
8077        if (allStringsNull || longestStrLen == 0 && !anyStringNull) {
8078            return INDEX_NOT_FOUND;
8079        }
8080
8081        // handle lists containing some nulls or some empty strings
8082        if (shortestStrLen == 0) {
8083            return 0;
8084        }
8085
8086        // find the position with the first difference across all strings
8087        int firstDiff = -1;
8088        for (int stringPos = 0; stringPos < shortestStrLen; stringPos++) {
8089            final char comparisonChar = css[0].charAt(stringPos);
8090            for (int arrayPos = 1; arrayPos < arrayLen; arrayPos++) {
8091                if (css[arrayPos].charAt(stringPos) != comparisonChar) {
8092                    firstDiff = stringPos;
8093                    break;
8094                }
8095            }
8096            if (firstDiff != -1) {
8097                break;
8098            }
8099        }
8100
8101        if (firstDiff == -1 && shortestStrLen != longestStrLen) {
8102            // we compared all of the characters up to the length of the
8103            // shortest string and didn't find a match, but the string lengths
8104            // vary, so return the length of the shortest string.
8105            return shortestStrLen;
8106        }
8107        return firstDiff;
8108    }
8109
8110    /**
8111     * <p>Compares all Strings in an array and returns the initial sequence of
8112     * characters that is common to all of them.</p>
8113     *
8114     * <p>For example,
8115     * <code>getCommonPrefix(new String[] {"i am a machine", "i am a robot"}) -&gt; "i am a "</code></p>
8116     *
8117     * <pre>
8118     * StringUtils.getCommonPrefix(null) = ""
8119     * StringUtils.getCommonPrefix(new String[] {}) = ""
8120     * StringUtils.getCommonPrefix(new String[] {"abc"}) = "abc"
8121     * StringUtils.getCommonPrefix(new String[] {null, null}) = ""
8122     * StringUtils.getCommonPrefix(new String[] {"", ""}) = ""
8123     * StringUtils.getCommonPrefix(new String[] {"", null}) = ""
8124     * StringUtils.getCommonPrefix(new String[] {"abc", null, null}) = ""
8125     * StringUtils.getCommonPrefix(new String[] {null, null, "abc"}) = ""
8126     * StringUtils.getCommonPrefix(new String[] {"", "abc"}) = ""
8127     * StringUtils.getCommonPrefix(new String[] {"abc", ""}) = ""
8128     * StringUtils.getCommonPrefix(new String[] {"abc", "abc"}) = "abc"
8129     * StringUtils.getCommonPrefix(new String[] {"abc", "a"}) = "a"
8130     * StringUtils.getCommonPrefix(new String[] {"ab", "abxyz"}) = "ab"
8131     * StringUtils.getCommonPrefix(new String[] {"abcde", "abxyz"}) = "ab"
8132     * StringUtils.getCommonPrefix(new String[] {"abcde", "xyz"}) = ""
8133     * StringUtils.getCommonPrefix(new String[] {"xyz", "abcde"}) = ""
8134     * StringUtils.getCommonPrefix(new String[] {"i am a machine", "i am a robot"}) = "i am a "
8135     * </pre>
8136     *
8137     * @param strs  array of String objects, entries may be null
8138     * @return the initial sequence of characters that are common to all Strings
8139     * in the array; empty String if the array is null, the elements are all null
8140     * or if there is no common prefix.
8141     * @since 2.4
8142     */
8143    public static String getCommonPrefix(final String... strs) {
8144        if (strs == null || strs.length == 0) {
8145            return EMPTY;
8146        }
8147        final int smallestIndexOfDiff = indexOfDifference(strs);
8148        if (smallestIndexOfDiff == INDEX_NOT_FOUND) {
8149            // all strings were identical
8150            if (strs[0] == null) {
8151                return EMPTY;
8152            }
8153            return strs[0];
8154        } else if (smallestIndexOfDiff == 0) {
8155            // there were no common initial characters
8156            return EMPTY;
8157        } else {
8158            // we found a common initial character sequence
8159            return strs[0].substring(0, smallestIndexOfDiff);
8160        }
8161    }
8162
8163    // Misc
8164    //-----------------------------------------------------------------------
8165    /**
8166     * <p>Find the Levenshtein distance between two Strings.</p>
8167     *
8168     * <p>This is the number of changes needed to change one String into
8169     * another, where each change is a single character modification (deletion,
8170     * insertion or substitution).</p>
8171     *
8172     * <p>The implementation uses a single-dimensional array of length s.length() + 1. See
8173     * <a href="http://blog.softwx.net/2014/12/optimizing-levenshtein-algorithm-in-c.html">
8174     * http://blog.softwx.net/2014/12/optimizing-levenshtein-algorithm-in-c.html</a> for details.</p>
8175     *
8176     * <pre>
8177     * StringUtils.getLevenshteinDistance(null, *)             = IllegalArgumentException
8178     * StringUtils.getLevenshteinDistance(*, null)             = IllegalArgumentException
8179     * StringUtils.getLevenshteinDistance("","")               = 0
8180     * StringUtils.getLevenshteinDistance("","a")              = 1
8181     * StringUtils.getLevenshteinDistance("aaapppp", "")       = 7
8182     * StringUtils.getLevenshteinDistance("frog", "fog")       = 1
8183     * StringUtils.getLevenshteinDistance("fly", "ant")        = 3
8184     * StringUtils.getLevenshteinDistance("elephant", "hippo") = 7
8185     * StringUtils.getLevenshteinDistance("hippo", "elephant") = 7
8186     * StringUtils.getLevenshteinDistance("hippo", "zzzzzzzz") = 8
8187     * StringUtils.getLevenshteinDistance("hello", "hallo")    = 1
8188     * </pre>
8189     *
8190     * @param s  the first String, must not be null
8191     * @param t  the second String, must not be null
8192     * @return result distance
8193     * @throws IllegalArgumentException if either String input {@code null}
8194     * @since 3.0 Changed signature from getLevenshteinDistance(String, String) to
8195     * getLevenshteinDistance(CharSequence, CharSequence)
8196     * @deprecated as of 3.6, use commons-text
8197     * <a href="https://commons.apache.org/proper/commons-text/javadocs/api-release/org/apache/commons/text/similarity/LevenshteinDistance.html">
8198     * LevenshteinDistance</a> instead
8199     */
8200    @Deprecated
8201    public static int getLevenshteinDistance(CharSequence s, CharSequence t) {
8202        if (s == null || t == null) {
8203            throw new IllegalArgumentException("Strings must not be null");
8204        }
8205
8206        int n = s.length();
8207        int m = t.length();
8208
8209        if (n == 0) {
8210            return m;
8211        } else if (m == 0) {
8212            return n;
8213        }
8214
8215        if (n > m) {
8216            // swap the input strings to consume less memory
8217            final CharSequence tmp = s;
8218            s = t;
8219            t = tmp;
8220            n = m;
8221            m = t.length();
8222        }
8223
8224        final int p[] = new int[n + 1];
8225        // indexes into strings s and t
8226        int i; // iterates through s
8227        int j; // iterates through t
8228        int upper_left;
8229        int upper;
8230
8231        char t_j; // jth character of t
8232        int cost;
8233
8234        for (i = 0; i <= n; i++) {
8235            p[i] = i;
8236        }
8237
8238        for (j = 1; j <= m; j++) {
8239            upper_left = p[0];
8240            t_j = t.charAt(j - 1);
8241            p[0] = j;
8242
8243            for (i = 1; i <= n; i++) {
8244                upper = p[i];
8245                cost = s.charAt(i - 1) == t_j ? 0 : 1;
8246                // minimum of cell to the left+1, to the top+1, diagonally left and up +cost
8247                p[i] = Math.min(Math.min(p[i - 1] + 1, p[i] + 1), upper_left + cost);
8248                upper_left = upper;
8249            }
8250        }
8251
8252        return p[n];
8253    }
8254
8255    /**
8256     * <p>Find the Levenshtein distance between two Strings if it's less than or equal to a given
8257     * threshold.</p>
8258     *
8259     * <p>This is the number of changes needed to change one String into
8260     * another, where each change is a single character modification (deletion,
8261     * insertion or substitution).</p>
8262     *
8263     * <p>This implementation follows from Algorithms on Strings, Trees and Sequences by Dan Gusfield
8264     * and Chas Emerick's implementation of the Levenshtein distance algorithm from
8265     * <a href="http://www.merriampark.com/ld.htm">http://www.merriampark.com/ld.htm</a></p>
8266     *
8267     * <pre>
8268     * StringUtils.getLevenshteinDistance(null, *, *)             = IllegalArgumentException
8269     * StringUtils.getLevenshteinDistance(*, null, *)             = IllegalArgumentException
8270     * StringUtils.getLevenshteinDistance(*, *, -1)               = IllegalArgumentException
8271     * StringUtils.getLevenshteinDistance("","", 0)               = 0
8272     * StringUtils.getLevenshteinDistance("aaapppp", "", 8)       = 7
8273     * StringUtils.getLevenshteinDistance("aaapppp", "", 7)       = 7
8274     * StringUtils.getLevenshteinDistance("aaapppp", "", 6))      = -1
8275     * StringUtils.getLevenshteinDistance("elephant", "hippo", 7) = 7
8276     * StringUtils.getLevenshteinDistance("elephant", "hippo", 6) = -1
8277     * StringUtils.getLevenshteinDistance("hippo", "elephant", 7) = 7
8278     * StringUtils.getLevenshteinDistance("hippo", "elephant", 6) = -1
8279     * </pre>
8280     *
8281     * @param s  the first String, must not be null
8282     * @param t  the second String, must not be null
8283     * @param threshold the target threshold, must not be negative
8284     * @return result distance, or {@code -1} if the distance would be greater than the threshold
8285     * @throws IllegalArgumentException if either String input {@code null} or negative threshold
8286     * @deprecated as of 3.6, use commons-text
8287     * <a href="https://commons.apache.org/proper/commons-text/javadocs/api-release/org/apache/commons/text/similarity/LevenshteinDistance.html">
8288     * LevenshteinDistance</a> instead
8289     */
8290    @Deprecated
8291    public static int getLevenshteinDistance(CharSequence s, CharSequence t, final int threshold) {
8292        if (s == null || t == null) {
8293            throw new IllegalArgumentException("Strings must not be null");
8294        }
8295        if (threshold < 0) {
8296            throw new IllegalArgumentException("Threshold must not be negative");
8297        }
8298
8299        /*
8300        This implementation only computes the distance if it's less than or equal to the
8301        threshold value, returning -1 if it's greater.  The advantage is performance: unbounded
8302        distance is O(nm), but a bound of k allows us to reduce it to O(km) time by only
8303        computing a diagonal stripe of width 2k + 1 of the cost table.
8304        It is also possible to use this to compute the unbounded Levenshtein distance by starting
8305        the threshold at 1 and doubling each time until the distance is found; this is O(dm), where
8306        d is the distance.
8307
8308        One subtlety comes from needing to ignore entries on the border of our stripe
8309        eg.
8310        p[] = |#|#|#|*
8311        d[] =  *|#|#|#|
8312        We must ignore the entry to the left of the leftmost member
8313        We must ignore the entry above the rightmost member
8314
8315        Another subtlety comes from our stripe running off the matrix if the strings aren't
8316        of the same size.  Since string s is always swapped to be the shorter of the two,
8317        the stripe will always run off to the upper right instead of the lower left of the matrix.
8318
8319        As a concrete example, suppose s is of length 5, t is of length 7, and our threshold is 1.
8320        In this case we're going to walk a stripe of length 3.  The matrix would look like so:
8321
8322           1 2 3 4 5
8323        1 |#|#| | | |
8324        2 |#|#|#| | |
8325        3 | |#|#|#| |
8326        4 | | |#|#|#|
8327        5 | | | |#|#|
8328        6 | | | | |#|
8329        7 | | | | | |
8330
8331        Note how the stripe leads off the table as there is no possible way to turn a string of length 5
8332        into one of length 7 in edit distance of 1.
8333
8334        Additionally, this implementation decreases memory usage by using two
8335        single-dimensional arrays and swapping them back and forth instead of allocating
8336        an entire n by m matrix.  This requires a few minor changes, such as immediately returning
8337        when it's detected that the stripe has run off the matrix and initially filling the arrays with
8338        large values so that entries we don't compute are ignored.
8339
8340        See Algorithms on Strings, Trees and Sequences by Dan Gusfield for some discussion.
8341         */
8342
8343        int n = s.length(); // length of s
8344        int m = t.length(); // length of t
8345
8346        // if one string is empty, the edit distance is necessarily the length of the other
8347        if (n == 0) {
8348            return m <= threshold ? m : -1;
8349        } else if (m == 0) {
8350            return n <= threshold ? n : -1;
8351        } else if (Math.abs(n - m) > threshold) {
8352            // no need to calculate the distance if the length difference is greater than the threshold
8353            return -1;
8354        }
8355
8356        if (n > m) {
8357            // swap the two strings to consume less memory
8358            final CharSequence tmp = s;
8359            s = t;
8360            t = tmp;
8361            n = m;
8362            m = t.length();
8363        }
8364
8365        int p[] = new int[n + 1]; // 'previous' cost array, horizontally
8366        int d[] = new int[n + 1]; // cost array, horizontally
8367        int _d[]; // placeholder to assist in swapping p and d
8368
8369        // fill in starting table values
8370        final int boundary = Math.min(n, threshold) + 1;
8371        for (int i = 0; i < boundary; i++) {
8372            p[i] = i;
8373        }
8374        // these fills ensure that the value above the rightmost entry of our
8375        // stripe will be ignored in following loop iterations
8376        Arrays.fill(p, boundary, p.length, Integer.MAX_VALUE);
8377        Arrays.fill(d, Integer.MAX_VALUE);
8378
8379        // iterates through t
8380        for (int j = 1; j <= m; j++) {
8381            final char t_j = t.charAt(j - 1); // jth character of t
8382            d[0] = j;
8383
8384            // compute stripe indices, constrain to array size
8385            final int min = Math.max(1, j - threshold);
8386            final int max = j > Integer.MAX_VALUE - threshold ? n : Math.min(n, j + threshold);
8387
8388            // the stripe may lead off of the table if s and t are of different sizes
8389            if (min > max) {
8390                return -1;
8391            }
8392
8393            // ignore entry left of leftmost
8394            if (min > 1) {
8395                d[min - 1] = Integer.MAX_VALUE;
8396            }
8397
8398            // iterates through [min, max] in s
8399            for (int i = min; i <= max; i++) {
8400                if (s.charAt(i - 1) == t_j) {
8401                    // diagonally left and up
8402                    d[i] = p[i - 1];
8403                } else {
8404                    // 1 + minimum of cell to the left, to the top, diagonally left and up
8405                    d[i] = 1 + Math.min(Math.min(d[i - 1], p[i]), p[i - 1]);
8406                }
8407            }
8408
8409            // copy current distance counts to 'previous row' distance counts
8410            _d = p;
8411            p = d;
8412            d = _d;
8413        }
8414
8415        // if p[n] is greater than the threshold, there's no guarantee on it being the correct
8416        // distance
8417        if (p[n] <= threshold) {
8418            return p[n];
8419        }
8420        return -1;
8421    }
8422
8423    /**
8424     * <p>Find the Jaro Winkler Distance which indicates the similarity score between two Strings.</p>
8425     *
8426     * <p>The Jaro measure is the weighted sum of percentage of matched characters from each file and transposed characters.
8427     * Winkler increased this measure for matching initial characters.</p>
8428     *
8429     * <p>This implementation is based on the Jaro Winkler similarity algorithm
8430     * 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>
8431     *
8432     * <pre>
8433     * StringUtils.getJaroWinklerDistance(null, null)          = IllegalArgumentException
8434     * StringUtils.getJaroWinklerDistance("","")               = 0.0
8435     * StringUtils.getJaroWinklerDistance("","a")              = 0.0
8436     * StringUtils.getJaroWinklerDistance("aaapppp", "")       = 0.0
8437     * StringUtils.getJaroWinklerDistance("frog", "fog")       = 0.93
8438     * StringUtils.getJaroWinklerDistance("fly", "ant")        = 0.0
8439     * StringUtils.getJaroWinklerDistance("elephant", "hippo") = 0.44
8440     * StringUtils.getJaroWinklerDistance("hippo", "elephant") = 0.44
8441     * StringUtils.getJaroWinklerDistance("hippo", "zzzzzzzz") = 0.0
8442     * StringUtils.getJaroWinklerDistance("hello", "hallo")    = 0.88
8443     * StringUtils.getJaroWinklerDistance("ABC Corporation", "ABC Corp") = 0.93
8444     * StringUtils.getJaroWinklerDistance("D N H Enterprises Inc", "D &amp; H Enterprises, Inc.") = 0.95
8445     * StringUtils.getJaroWinklerDistance("My Gym Children's Fitness Center", "My Gym. Childrens Fitness") = 0.92
8446     * StringUtils.getJaroWinklerDistance("PENNSYLVANIA", "PENNCISYLVNIA") = 0.88
8447     * </pre>
8448     *
8449     * @param first the first String, must not be null
8450     * @param second the second String, must not be null
8451     * @return result distance
8452     * @throws IllegalArgumentException if either String input {@code null}
8453     * @since 3.3
8454     * @deprecated as of 3.6, use commons-text
8455     * <a href="https://commons.apache.org/proper/commons-text/javadocs/api-release/org/apache/commons/text/similarity/JaroWinklerDistance.html">
8456     * JaroWinklerDistance</a> instead
8457     */
8458    @Deprecated
8459    public static double getJaroWinklerDistance(final CharSequence first, final CharSequence second) {
8460        final double DEFAULT_SCALING_FACTOR = 0.1;
8461
8462        if (first == null || second == null) {
8463            throw new IllegalArgumentException("Strings must not be null");
8464        }
8465
8466        final int[] mtp = matches(first, second);
8467        final double m = mtp[0];
8468        if (m == 0) {
8469            return 0D;
8470        }
8471        final double j = ((m / first.length() + m / second.length() + (m - mtp[1]) / m)) / 3;
8472        final double jw = j < 0.7D ? j : j + Math.min(DEFAULT_SCALING_FACTOR, 1D / mtp[3]) * mtp[2] * (1D - j);
8473        return Math.round(jw * 100.0D) / 100.0D;
8474    }
8475
8476    private static int[] matches(final CharSequence first, final CharSequence second) {
8477        CharSequence max, min;
8478        if (first.length() > second.length()) {
8479            max = first;
8480            min = second;
8481        } else {
8482            max = second;
8483            min = first;
8484        }
8485        final int range = Math.max(max.length() / 2 - 1, 0);
8486        final int[] matchIndexes = new int[min.length()];
8487        Arrays.fill(matchIndexes, -1);
8488        final boolean[] matchFlags = new boolean[max.length()];
8489        int matches = 0;
8490        for (int mi = 0; mi < min.length(); mi++) {
8491            final char c1 = min.charAt(mi);
8492            for (int xi = Math.max(mi - range, 0), xn = Math.min(mi + range + 1, max.length()); xi < xn; xi++) {
8493                if (!matchFlags[xi] && c1 == max.charAt(xi)) {
8494                    matchIndexes[mi] = xi;
8495                    matchFlags[xi] = true;
8496                    matches++;
8497                    break;
8498                }
8499            }
8500        }
8501        final char[] ms1 = new char[matches];
8502        final char[] ms2 = new char[matches];
8503        for (int i = 0, si = 0; i < min.length(); i++) {
8504            if (matchIndexes[i] != -1) {
8505                ms1[si] = min.charAt(i);
8506                si++;
8507            }
8508        }
8509        for (int i = 0, si = 0; i < max.length(); i++) {
8510            if (matchFlags[i]) {
8511                ms2[si] = max.charAt(i);
8512                si++;
8513            }
8514        }
8515        int transpositions = 0;
8516        for (int mi = 0; mi < ms1.length; mi++) {
8517            if (ms1[mi] != ms2[mi]) {
8518                transpositions++;
8519            }
8520        }
8521        int prefix = 0;
8522        for (int mi = 0; mi < min.length(); mi++) {
8523            if (first.charAt(mi) == second.charAt(mi)) {
8524                prefix++;
8525            } else {
8526                break;
8527            }
8528        }
8529        return new int[] { matches, transpositions / 2, prefix, max.length() };
8530    }
8531
8532    /**
8533     * <p>Find the Fuzzy Distance which indicates the similarity score between two Strings.</p>
8534     *
8535     * <p>This string matching algorithm is similar to the algorithms of editors such as Sublime Text,
8536     * TextMate, Atom and others. One point is given for every matched character. Subsequent
8537     * matches yield two bonus points. A higher score indicates a higher similarity.</p>
8538     *
8539     * <pre>
8540     * StringUtils.getFuzzyDistance(null, null, null)                                    = IllegalArgumentException
8541     * StringUtils.getFuzzyDistance("", "", Locale.ENGLISH)                              = 0
8542     * StringUtils.getFuzzyDistance("Workshop", "b", Locale.ENGLISH)                     = 0
8543     * StringUtils.getFuzzyDistance("Room", "o", Locale.ENGLISH)                         = 1
8544     * StringUtils.getFuzzyDistance("Workshop", "w", Locale.ENGLISH)                     = 1
8545     * StringUtils.getFuzzyDistance("Workshop", "ws", Locale.ENGLISH)                    = 2
8546     * StringUtils.getFuzzyDistance("Workshop", "wo", Locale.ENGLISH)                    = 4
8547     * StringUtils.getFuzzyDistance("Apache Software Foundation", "asf", Locale.ENGLISH) = 3
8548     * </pre>
8549     *
8550     * @param term a full term that should be matched against, must not be null
8551     * @param query the query that will be matched against a term, must not be null
8552     * @param locale This string matching logic is case insensitive. A locale is necessary to normalize
8553     *  both Strings to lower case.
8554     * @return result score
8555     * @throws IllegalArgumentException if either String input {@code null} or Locale input {@code null}
8556     * @since 3.4
8557     * @deprecated as of 3.6, use commons-text
8558     * <a href="https://commons.apache.org/proper/commons-text/javadocs/api-release/org/apache/commons/text/similarity/FuzzyScore.html">
8559     * FuzzyScore</a> instead
8560     */
8561    @Deprecated
8562    public static int getFuzzyDistance(final CharSequence term, final CharSequence query, final Locale locale) {
8563        if (term == null || query == null) {
8564            throw new IllegalArgumentException("Strings must not be null");
8565        } else if (locale == null) {
8566            throw new IllegalArgumentException("Locale must not be null");
8567        }
8568
8569        // fuzzy logic is case insensitive. We normalize the Strings to lower
8570        // case right from the start. Turning characters to lower case
8571        // via Character.toLowerCase(char) is unfortunately insufficient
8572        // as it does not accept a locale.
8573        final String termLowerCase = term.toString().toLowerCase(locale);
8574        final String queryLowerCase = query.toString().toLowerCase(locale);
8575
8576        // the resulting score
8577        int score = 0;
8578
8579        // the position in the term which will be scanned next for potential
8580        // query character matches
8581        int termIndex = 0;
8582
8583        // index of the previously matched character in the term
8584        int previousMatchingCharacterIndex = Integer.MIN_VALUE;
8585
8586        for (int queryIndex = 0; queryIndex < queryLowerCase.length(); queryIndex++) {
8587            final char queryChar = queryLowerCase.charAt(queryIndex);
8588
8589            boolean termCharacterMatchFound = false;
8590            for (; termIndex < termLowerCase.length() && !termCharacterMatchFound; termIndex++) {
8591                final char termChar = termLowerCase.charAt(termIndex);
8592
8593                if (queryChar == termChar) {
8594                    // simple character matches result in one point
8595                    score++;
8596
8597                    // subsequent character matches further improve
8598                    // the score.
8599                    if (previousMatchingCharacterIndex + 1 == termIndex) {
8600                        score += 2;
8601                    }
8602
8603                    previousMatchingCharacterIndex = termIndex;
8604
8605                    // we can leave the nested loop. Every character in the
8606                    // query can match at most one character in the term.
8607                    termCharacterMatchFound = true;
8608                }
8609            }
8610        }
8611
8612        return score;
8613    }
8614
8615    // startsWith
8616    //-----------------------------------------------------------------------
8617
8618    /**
8619     * <p>Check if a CharSequence starts with a specified prefix.</p>
8620     *
8621     * <p>{@code null}s are handled without exceptions. Two {@code null}
8622     * references are considered to be equal. The comparison is case sensitive.</p>
8623     *
8624     * <pre>
8625     * StringUtils.startsWith(null, null)      = true
8626     * StringUtils.startsWith(null, "abc")     = false
8627     * StringUtils.startsWith("abcdef", null)  = false
8628     * StringUtils.startsWith("abcdef", "abc") = true
8629     * StringUtils.startsWith("ABCDEF", "abc") = false
8630     * </pre>
8631     *
8632     * @see java.lang.String#startsWith(String)
8633     * @param str  the CharSequence to check, may be null
8634     * @param prefix the prefix to find, may be null
8635     * @return {@code true} if the CharSequence starts with the prefix, case sensitive, or
8636     *  both {@code null}
8637     * @since 2.4
8638     * @since 3.0 Changed signature from startsWith(String, String) to startsWith(CharSequence, CharSequence)
8639     */
8640    public static boolean startsWith(final CharSequence str, final CharSequence prefix) {
8641        return startsWith(str, prefix, false);
8642    }
8643
8644    /**
8645     * <p>Case insensitive check if a CharSequence starts with a specified prefix.</p>
8646     *
8647     * <p>{@code null}s are handled without exceptions. Two {@code null}
8648     * references are considered to be equal. The comparison is case insensitive.</p>
8649     *
8650     * <pre>
8651     * StringUtils.startsWithIgnoreCase(null, null)      = true
8652     * StringUtils.startsWithIgnoreCase(null, "abc")     = false
8653     * StringUtils.startsWithIgnoreCase("abcdef", null)  = false
8654     * StringUtils.startsWithIgnoreCase("abcdef", "abc") = true
8655     * StringUtils.startsWithIgnoreCase("ABCDEF", "abc") = true
8656     * </pre>
8657     *
8658     * @see java.lang.String#startsWith(String)
8659     * @param str  the CharSequence to check, may be null
8660     * @param prefix the prefix to find, may be null
8661     * @return {@code true} if the CharSequence starts with the prefix, case insensitive, or
8662     *  both {@code null}
8663     * @since 2.4
8664     * @since 3.0 Changed signature from startsWithIgnoreCase(String, String) to startsWithIgnoreCase(CharSequence, CharSequence)
8665     */
8666    public static boolean startsWithIgnoreCase(final CharSequence str, final CharSequence prefix) {
8667        return startsWith(str, prefix, true);
8668    }
8669
8670    /**
8671     * <p>Check if a CharSequence starts with a specified prefix (optionally case insensitive).</p>
8672     *
8673     * @see java.lang.String#startsWith(String)
8674     * @param str  the CharSequence to check, may be null
8675     * @param prefix the prefix to find, may be null
8676     * @param ignoreCase indicates whether the compare should ignore case
8677     *  (case insensitive) or not.
8678     * @return {@code true} if the CharSequence starts with the prefix or
8679     *  both {@code null}
8680     */
8681    private static boolean startsWith(final CharSequence str, final CharSequence prefix, final boolean ignoreCase) {
8682        if (str == null || prefix == null) {
8683            return str == prefix;
8684        }
8685        if (prefix.length() > str.length()) {
8686            return false;
8687        }
8688        return CharSequenceUtils.regionMatches(str, ignoreCase, 0, prefix, 0, prefix.length());
8689    }
8690
8691    /**
8692     * <p>Check if a CharSequence starts with any of the provided case-sensitive prefixes.</p>
8693     *
8694     * <pre>
8695     * StringUtils.startsWithAny(null, null)      = false
8696     * StringUtils.startsWithAny(null, new String[] {"abc"})  = false
8697     * StringUtils.startsWithAny("abcxyz", null)     = false
8698     * StringUtils.startsWithAny("abcxyz", new String[] {""}) = true
8699     * StringUtils.startsWithAny("abcxyz", new String[] {"abc"}) = true
8700     * StringUtils.startsWithAny("abcxyz", new String[] {null, "xyz", "abc"}) = true
8701     * StringUtils.startsWithAny("abcxyz", null, "xyz", "ABCX") = false
8702     * StringUtils.startsWithAny("ABCXYZ", null, "xyz", "abc") = false
8703     * </pre>
8704     *
8705     * @param sequence the CharSequence to check, may be null
8706     * @param searchStrings the case-sensitive CharSequence prefixes, may be empty or contain {@code null}
8707     * @see StringUtils#startsWith(CharSequence, CharSequence)
8708     * @return {@code true} if the input {@code sequence} is {@code null} AND no {@code searchStrings} are provided, or
8709     *   the input {@code sequence} begins with any of the provided case-sensitive {@code searchStrings}.
8710     * @since 2.5
8711     * @since 3.0 Changed signature from startsWithAny(String, String[]) to startsWithAny(CharSequence, CharSequence...)
8712     */
8713    public static boolean startsWithAny(final CharSequence sequence, final CharSequence... searchStrings) {
8714        if (isEmpty(sequence) || ArrayUtils.isEmpty(searchStrings)) {
8715            return false;
8716        }
8717        for (final CharSequence searchString : searchStrings) {
8718            if (startsWith(sequence, searchString)) {
8719                return true;
8720            }
8721        }
8722        return false;
8723    }
8724
8725    // endsWith
8726    //-----------------------------------------------------------------------
8727
8728    /**
8729     * <p>Check if a CharSequence ends with a specified suffix.</p>
8730     *
8731     * <p>{@code null}s are handled without exceptions. Two {@code null}
8732     * references are considered to be equal. The comparison is case sensitive.</p>
8733     *
8734     * <pre>
8735     * StringUtils.endsWith(null, null)      = true
8736     * StringUtils.endsWith(null, "def")     = false
8737     * StringUtils.endsWith("abcdef", null)  = false
8738     * StringUtils.endsWith("abcdef", "def") = true
8739     * StringUtils.endsWith("ABCDEF", "def") = false
8740     * StringUtils.endsWith("ABCDEF", "cde") = false
8741     * StringUtils.endsWith("ABCDEF", "")    = true
8742     * </pre>
8743     *
8744     * @see java.lang.String#endsWith(String)
8745     * @param str  the CharSequence to check, may be null
8746     * @param suffix the suffix to find, may be null
8747     * @return {@code true} if the CharSequence ends with the suffix, case sensitive, or
8748     *  both {@code null}
8749     * @since 2.4
8750     * @since 3.0 Changed signature from endsWith(String, String) to endsWith(CharSequence, CharSequence)
8751     */
8752    public static boolean endsWith(final CharSequence str, final CharSequence suffix) {
8753        return endsWith(str, suffix, false);
8754    }
8755
8756    /**
8757     * <p>Case insensitive check if a CharSequence ends with a specified suffix.</p>
8758     *
8759     * <p>{@code null}s are handled without exceptions. Two {@code null}
8760     * references are considered to be equal. The comparison is case insensitive.</p>
8761     *
8762     * <pre>
8763     * StringUtils.endsWithIgnoreCase(null, null)      = true
8764     * StringUtils.endsWithIgnoreCase(null, "def")     = false
8765     * StringUtils.endsWithIgnoreCase("abcdef", null)  = false
8766     * StringUtils.endsWithIgnoreCase("abcdef", "def") = true
8767     * StringUtils.endsWithIgnoreCase("ABCDEF", "def") = true
8768     * StringUtils.endsWithIgnoreCase("ABCDEF", "cde") = false
8769     * </pre>
8770     *
8771     * @see java.lang.String#endsWith(String)
8772     * @param str  the CharSequence to check, may be null
8773     * @param suffix the suffix to find, may be null
8774     * @return {@code true} if the CharSequence ends with the suffix, case insensitive, or
8775     *  both {@code null}
8776     * @since 2.4
8777     * @since 3.0 Changed signature from endsWithIgnoreCase(String, String) to endsWithIgnoreCase(CharSequence, CharSequence)
8778     */
8779    public static boolean endsWithIgnoreCase(final CharSequence str, final CharSequence suffix) {
8780        return endsWith(str, suffix, true);
8781    }
8782
8783    /**
8784     * <p>Check if a CharSequence ends with a specified suffix (optionally case insensitive).</p>
8785     *
8786     * @see java.lang.String#endsWith(String)
8787     * @param str  the CharSequence to check, may be null
8788     * @param suffix the suffix to find, may be null
8789     * @param ignoreCase indicates whether the compare should ignore case
8790     *  (case insensitive) or not.
8791     * @return {@code true} if the CharSequence starts with the prefix or
8792     *  both {@code null}
8793     */
8794    private static boolean endsWith(final CharSequence str, final CharSequence suffix, final boolean ignoreCase) {
8795        if (str == null || suffix == null) {
8796            return str == suffix;
8797        }
8798        if (suffix.length() > str.length()) {
8799            return false;
8800        }
8801        final int strOffset = str.length() - suffix.length();
8802        return CharSequenceUtils.regionMatches(str, ignoreCase, strOffset, suffix, 0, suffix.length());
8803    }
8804
8805    /**
8806     * <p>
8807     * Similar to <a
8808     * href="http://www.w3.org/TR/xpath/#function-normalize-space">http://www.w3.org/TR/xpath/#function-normalize
8809     * -space</a>
8810     * </p>
8811     * <p>
8812     * The function returns the argument string with whitespace normalized by using
8813     * <code>{@link #trim(String)}</code> to remove leading and trailing whitespace
8814     * and then replacing sequences of whitespace characters by a single space.
8815     * </p>
8816     * In XML Whitespace characters are the same as those allowed by the <a
8817     * href="http://www.w3.org/TR/REC-xml/#NT-S">S</a> production, which is S ::= (#x20 | #x9 | #xD | #xA)+
8818     * <p>
8819     * Java's regexp pattern \s defines whitespace as [ \t\n\x0B\f\r]
8820     *
8821     * <p>For reference:</p>
8822     * <ul>
8823     * <li>\x0B = vertical tab</li>
8824     * <li>\f = #xC = form feed</li>
8825     * <li>#x20 = space</li>
8826     * <li>#x9 = \t</li>
8827     * <li>#xA = \n</li>
8828     * <li>#xD = \r</li>
8829     * </ul>
8830     *
8831     * <p>
8832     * The difference is that Java's whitespace includes vertical tab and form feed, which this functional will also
8833     * normalize. Additionally <code>{@link #trim(String)}</code> removes control characters (char &lt;= 32) from both
8834     * ends of this String.
8835     * </p>
8836     *
8837     * @see Pattern
8838     * @see #trim(String)
8839     * @see <a
8840     *      href="http://www.w3.org/TR/xpath/#function-normalize-space">http://www.w3.org/TR/xpath/#function-normalize-space</a>
8841     * @param str the source String to normalize whitespaces from, may be null
8842     * @return the modified string with whitespace normalized, {@code null} if null String input
8843     *
8844     * @since 3.0
8845     */
8846    public static String normalizeSpace(final String str) {
8847        // LANG-1020: Improved performance significantly by normalizing manually instead of using regex
8848        // See https://github.com/librucha/commons-lang-normalizespaces-benchmark for performance test
8849        if (isEmpty(str)) {
8850            return str;
8851        }
8852        final int size = str.length();
8853        final char[] newChars = new char[size];
8854        int count = 0;
8855        int whitespacesCount = 0;
8856        boolean startWhitespaces = true;
8857        for (int i = 0; i < size; i++) {
8858            final char actualChar = str.charAt(i);
8859            final boolean isWhitespace = Character.isWhitespace(actualChar);
8860            if (isWhitespace) {
8861                if (whitespacesCount == 0 && !startWhitespaces) {
8862                    newChars[count++] = SPACE.charAt(0);
8863                }
8864                whitespacesCount++;
8865            } else {
8866                startWhitespaces = false;
8867                newChars[count++] = (actualChar == 160 ? 32 : actualChar);
8868                whitespacesCount = 0;
8869            }
8870        }
8871        if (startWhitespaces) {
8872            return EMPTY;
8873        }
8874        return new String(newChars, 0, count - (whitespacesCount > 0 ? 1 : 0)).trim();
8875    }
8876
8877    /**
8878     * <p>Check if a CharSequence ends with any of the provided case-sensitive suffixes.</p>
8879     *
8880     * <pre>
8881     * StringUtils.endsWithAny(null, null)      = false
8882     * StringUtils.endsWithAny(null, new String[] {"abc"})  = false
8883     * StringUtils.endsWithAny("abcxyz", null)     = false
8884     * StringUtils.endsWithAny("abcxyz", new String[] {""}) = true
8885     * StringUtils.endsWithAny("abcxyz", new String[] {"xyz"}) = true
8886     * StringUtils.endsWithAny("abcxyz", new String[] {null, "xyz", "abc"}) = true
8887     * StringUtils.endsWithAny("abcXYZ", "def", "XYZ") = true
8888     * StringUtils.endsWithAny("abcXYZ", "def", "xyz") = false
8889     * </pre>
8890     *
8891     * @param sequence  the CharSequence to check, may be null
8892     * @param searchStrings the case-sensitive CharSequences to find, may be empty or contain {@code null}
8893     * @see StringUtils#endsWith(CharSequence, CharSequence)
8894     * @return {@code true} if the input {@code sequence} is {@code null} AND no {@code searchStrings} are provided, or
8895     *   the input {@code sequence} ends in any of the provided case-sensitive {@code searchStrings}.
8896     * @since 3.0
8897     */
8898    public static boolean endsWithAny(final CharSequence sequence, final CharSequence... searchStrings) {
8899        if (isEmpty(sequence) || ArrayUtils.isEmpty(searchStrings)) {
8900            return false;
8901        }
8902        for (final CharSequence searchString : searchStrings) {
8903            if (endsWith(sequence, searchString)) {
8904                return true;
8905            }
8906        }
8907        return false;
8908    }
8909
8910    /**
8911     * Appends the suffix to the end of the string if the string does not
8912     * already end with the suffix.
8913     *
8914     * @param str The string.
8915     * @param suffix The suffix to append to the end of the string.
8916     * @param ignoreCase Indicates whether the compare should ignore case.
8917     * @param suffixes Additional suffixes that are valid terminators (optional).
8918     *
8919     * @return A new String if suffix was appended, the same string otherwise.
8920     */
8921    private static String appendIfMissing(final String str, final CharSequence suffix, final boolean ignoreCase, final CharSequence... suffixes) {
8922        if (str == null || isEmpty(suffix) || endsWith(str, suffix, ignoreCase)) {
8923            return str;
8924        }
8925        if (suffixes != null && suffixes.length > 0) {
8926            for (final CharSequence s : suffixes) {
8927                if (endsWith(str, s, ignoreCase)) {
8928                    return str;
8929                }
8930            }
8931        }
8932        return str + suffix.toString();
8933    }
8934
8935    /**
8936     * Appends the suffix to the end of the string if the string does not
8937     * already end with any of the suffixes.
8938     *
8939     * <pre>
8940     * StringUtils.appendIfMissing(null, null) = null
8941     * StringUtils.appendIfMissing("abc", null) = "abc"
8942     * StringUtils.appendIfMissing("", "xyz") = "xyz"
8943     * StringUtils.appendIfMissing("abc", "xyz") = "abcxyz"
8944     * StringUtils.appendIfMissing("abcxyz", "xyz") = "abcxyz"
8945     * StringUtils.appendIfMissing("abcXYZ", "xyz") = "abcXYZxyz"
8946     * </pre>
8947     * <p>With additional suffixes,</p>
8948     * <pre>
8949     * StringUtils.appendIfMissing(null, null, null) = null
8950     * StringUtils.appendIfMissing("abc", null, null) = "abc"
8951     * StringUtils.appendIfMissing("", "xyz", null) = "xyz"
8952     * StringUtils.appendIfMissing("abc", "xyz", new CharSequence[]{null}) = "abcxyz"
8953     * StringUtils.appendIfMissing("abc", "xyz", "") = "abc"
8954     * StringUtils.appendIfMissing("abc", "xyz", "mno") = "abcxyz"
8955     * StringUtils.appendIfMissing("abcxyz", "xyz", "mno") = "abcxyz"
8956     * StringUtils.appendIfMissing("abcmno", "xyz", "mno") = "abcmno"
8957     * StringUtils.appendIfMissing("abcXYZ", "xyz", "mno") = "abcXYZxyz"
8958     * StringUtils.appendIfMissing("abcMNO", "xyz", "mno") = "abcMNOxyz"
8959     * </pre>
8960     *
8961     * @param str The string.
8962     * @param suffix The suffix to append to the end of the string.
8963     * @param suffixes Additional suffixes that are valid terminators.
8964     *
8965     * @return A new String if suffix was appended, the same string otherwise.
8966     *
8967     * @since 3.2
8968     */
8969    public static String appendIfMissing(final String str, final CharSequence suffix, final CharSequence... suffixes) {
8970        return appendIfMissing(str, suffix, false, suffixes);
8971    }
8972
8973    /**
8974     * Appends the suffix to the end of the string if the string does not
8975     * already end, case insensitive, with any of the suffixes.
8976     *
8977     * <pre>
8978     * StringUtils.appendIfMissingIgnoreCase(null, null) = null
8979     * StringUtils.appendIfMissingIgnoreCase("abc", null) = "abc"
8980     * StringUtils.appendIfMissingIgnoreCase("", "xyz") = "xyz"
8981     * StringUtils.appendIfMissingIgnoreCase("abc", "xyz") = "abcxyz"
8982     * StringUtils.appendIfMissingIgnoreCase("abcxyz", "xyz") = "abcxyz"
8983     * StringUtils.appendIfMissingIgnoreCase("abcXYZ", "xyz") = "abcXYZ"
8984     * </pre>
8985     * <p>With additional suffixes,</p>
8986     * <pre>
8987     * StringUtils.appendIfMissingIgnoreCase(null, null, null) = null
8988     * StringUtils.appendIfMissingIgnoreCase("abc", null, null) = "abc"
8989     * StringUtils.appendIfMissingIgnoreCase("", "xyz", null) = "xyz"
8990     * StringUtils.appendIfMissingIgnoreCase("abc", "xyz", new CharSequence[]{null}) = "abcxyz"
8991     * StringUtils.appendIfMissingIgnoreCase("abc", "xyz", "") = "abc"
8992     * StringUtils.appendIfMissingIgnoreCase("abc", "xyz", "mno") = "axyz"
8993     * StringUtils.appendIfMissingIgnoreCase("abcxyz", "xyz", "mno") = "abcxyz"
8994     * StringUtils.appendIfMissingIgnoreCase("abcmno", "xyz", "mno") = "abcmno"
8995     * StringUtils.appendIfMissingIgnoreCase("abcXYZ", "xyz", "mno") = "abcXYZ"
8996     * StringUtils.appendIfMissingIgnoreCase("abcMNO", "xyz", "mno") = "abcMNO"
8997     * </pre>
8998     *
8999     * @param str The string.
9000     * @param suffix The suffix to append to the end of the string.
9001     * @param suffixes Additional suffixes that are valid terminators.
9002     *
9003     * @return A new String if suffix was appended, the same string otherwise.
9004     *
9005     * @since 3.2
9006     */
9007    public static String appendIfMissingIgnoreCase(final String str, final CharSequence suffix, final CharSequence... suffixes) {
9008        return appendIfMissing(str, suffix, true, suffixes);
9009    }
9010
9011    /**
9012     * Prepends the prefix to the start of the string if the string does not
9013     * already start with any of the prefixes.
9014     *
9015     * @param str The string.
9016     * @param prefix The prefix to prepend to the start of the string.
9017     * @param ignoreCase Indicates whether the compare should ignore case.
9018     * @param prefixes Additional prefixes that are valid (optional).
9019     *
9020     * @return A new String if prefix was prepended, the same string otherwise.
9021     */
9022    private static String prependIfMissing(final String str, final CharSequence prefix, final boolean ignoreCase, final CharSequence... prefixes) {
9023        if (str == null || isEmpty(prefix) || startsWith(str, prefix, ignoreCase)) {
9024            return str;
9025        }
9026        if (prefixes != null && prefixes.length > 0) {
9027            for (final CharSequence p : prefixes) {
9028                if (startsWith(str, p, ignoreCase)) {
9029                    return str;
9030                }
9031            }
9032        }
9033        return prefix.toString() + str;
9034    }
9035
9036    /**
9037     * Prepends the prefix to the start of the string if the string does not
9038     * already start with any of the prefixes.
9039     *
9040     * <pre>
9041     * StringUtils.prependIfMissing(null, null) = null
9042     * StringUtils.prependIfMissing("abc", null) = "abc"
9043     * StringUtils.prependIfMissing("", "xyz") = "xyz"
9044     * StringUtils.prependIfMissing("abc", "xyz") = "xyzabc"
9045     * StringUtils.prependIfMissing("xyzabc", "xyz") = "xyzabc"
9046     * StringUtils.prependIfMissing("XYZabc", "xyz") = "xyzXYZabc"
9047     * </pre>
9048     * <p>With additional prefixes,</p>
9049     * <pre>
9050     * StringUtils.prependIfMissing(null, null, null) = null
9051     * StringUtils.prependIfMissing("abc", null, null) = "abc"
9052     * StringUtils.prependIfMissing("", "xyz", null) = "xyz"
9053     * StringUtils.prependIfMissing("abc", "xyz", new CharSequence[]{null}) = "xyzabc"
9054     * StringUtils.prependIfMissing("abc", "xyz", "") = "abc"
9055     * StringUtils.prependIfMissing("abc", "xyz", "mno") = "xyzabc"
9056     * StringUtils.prependIfMissing("xyzabc", "xyz", "mno") = "xyzabc"
9057     * StringUtils.prependIfMissing("mnoabc", "xyz", "mno") = "mnoabc"
9058     * StringUtils.prependIfMissing("XYZabc", "xyz", "mno") = "xyzXYZabc"
9059     * StringUtils.prependIfMissing("MNOabc", "xyz", "mno") = "xyzMNOabc"
9060     * </pre>
9061     *
9062     * @param str The string.
9063     * @param prefix The prefix to prepend to the start of the string.
9064     * @param prefixes Additional prefixes that are valid.
9065     *
9066     * @return A new String if prefix was prepended, the same string otherwise.
9067     *
9068     * @since 3.2
9069     */
9070    public static String prependIfMissing(final String str, final CharSequence prefix, final CharSequence... prefixes) {
9071        return prependIfMissing(str, prefix, false, prefixes);
9072    }
9073
9074    /**
9075     * Prepends the prefix to the start of the string if the string does not
9076     * already start, case insensitive, with any of the prefixes.
9077     *
9078     * <pre>
9079     * StringUtils.prependIfMissingIgnoreCase(null, null) = null
9080     * StringUtils.prependIfMissingIgnoreCase("abc", null) = "abc"
9081     * StringUtils.prependIfMissingIgnoreCase("", "xyz") = "xyz"
9082     * StringUtils.prependIfMissingIgnoreCase("abc", "xyz") = "xyzabc"
9083     * StringUtils.prependIfMissingIgnoreCase("xyzabc", "xyz") = "xyzabc"
9084     * StringUtils.prependIfMissingIgnoreCase("XYZabc", "xyz") = "XYZabc"
9085     * </pre>
9086     * <p>With additional prefixes,</p>
9087     * <pre>
9088     * StringUtils.prependIfMissingIgnoreCase(null, null, null) = null
9089     * StringUtils.prependIfMissingIgnoreCase("abc", null, null) = "abc"
9090     * StringUtils.prependIfMissingIgnoreCase("", "xyz", null) = "xyz"
9091     * StringUtils.prependIfMissingIgnoreCase("abc", "xyz", new CharSequence[]{null}) = "xyzabc"
9092     * StringUtils.prependIfMissingIgnoreCase("abc", "xyz", "") = "abc"
9093     * StringUtils.prependIfMissingIgnoreCase("abc", "xyz", "mno") = "xyzabc"
9094     * StringUtils.prependIfMissingIgnoreCase("xyzabc", "xyz", "mno") = "xyzabc"
9095     * StringUtils.prependIfMissingIgnoreCase("mnoabc", "xyz", "mno") = "mnoabc"
9096     * StringUtils.prependIfMissingIgnoreCase("XYZabc", "xyz", "mno") = "XYZabc"
9097     * StringUtils.prependIfMissingIgnoreCase("MNOabc", "xyz", "mno") = "MNOabc"
9098     * </pre>
9099     *
9100     * @param str The string.
9101     * @param prefix The prefix to prepend to the start of the string.
9102     * @param prefixes Additional prefixes that are valid (optional).
9103     *
9104     * @return A new String if prefix was prepended, the same string otherwise.
9105     *
9106     * @since 3.2
9107     */
9108    public static String prependIfMissingIgnoreCase(final String str, final CharSequence prefix, final CharSequence... prefixes) {
9109        return prependIfMissing(str, prefix, true, prefixes);
9110    }
9111
9112    /**
9113     * Converts a <code>byte[]</code> to a String using the specified character encoding.
9114     *
9115     * @param bytes
9116     *            the byte array to read from
9117     * @param charsetName
9118     *            the encoding to use, if null then use the platform default
9119     * @return a new String
9120     * @throws UnsupportedEncodingException
9121     *             If the named charset is not supported
9122     * @throws NullPointerException
9123     *             if the input is null
9124     * @deprecated use {@link StringUtils#toEncodedString(byte[], Charset)} instead of String constants in your code
9125     * @since 3.1
9126     */
9127    @Deprecated
9128    public static String toString(final byte[] bytes, final String charsetName) throws UnsupportedEncodingException {
9129        return charsetName != null ? new String(bytes, charsetName) : new String(bytes, Charset.defaultCharset());
9130    }
9131
9132    /**
9133     * Converts a <code>byte[]</code> to a String using the specified character encoding.
9134     *
9135     * @param bytes
9136     *            the byte array to read from
9137     * @param charset
9138     *            the encoding to use, if null then use the platform default
9139     * @return a new String
9140     * @throws NullPointerException
9141     *             if {@code bytes} is null
9142     * @since 3.2
9143     * @since 3.3 No longer throws {@link UnsupportedEncodingException}.
9144     */
9145    public static String toEncodedString(final byte[] bytes, final Charset charset) {
9146        return new String(bytes, charset != null ? charset : Charset.defaultCharset());
9147    }
9148
9149    /**
9150     * <p>
9151     * Wraps a string with a char.
9152     * </p>
9153     *
9154     * <pre>
9155     * StringUtils.wrap(null, *)        = null
9156     * StringUtils.wrap("", *)          = ""
9157     * StringUtils.wrap("ab", '\0')     = "ab"
9158     * StringUtils.wrap("ab", 'x')      = "xabx"
9159     * StringUtils.wrap("ab", '\'')     = "'ab'"
9160     * StringUtils.wrap("\"ab\"", '\"') = "\"\"ab\"\""
9161     * </pre>
9162     *
9163     * @param str
9164     *            the string to be wrapped, may be {@code null}
9165     * @param wrapWith
9166     *            the char that will wrap {@code str}
9167     * @return the wrapped string, or {@code null} if {@code str==null}
9168     * @since 3.4
9169     */
9170    public static String wrap(final String str, final char wrapWith) {
9171
9172        if (isEmpty(str) || wrapWith == CharUtils.NUL) {
9173            return str;
9174        }
9175
9176        return wrapWith + str + wrapWith;
9177    }
9178
9179    /**
9180     * <p>
9181     * Wraps a String with another String.
9182     * </p>
9183     *
9184     * <p>
9185     * A {@code null} input String returns {@code null}.
9186     * </p>
9187     *
9188     * <pre>
9189     * StringUtils.wrap(null, *)         = null
9190     * StringUtils.wrap("", *)           = ""
9191     * StringUtils.wrap("ab", null)      = "ab"
9192     * StringUtils.wrap("ab", "x")       = "xabx"
9193     * StringUtils.wrap("ab", "\"")      = "\"ab\""
9194     * StringUtils.wrap("\"ab\"", "\"")  = "\"\"ab\"\""
9195     * StringUtils.wrap("ab", "'")       = "'ab'"
9196     * StringUtils.wrap("'abcd'", "'")   = "''abcd''"
9197     * StringUtils.wrap("\"abcd\"", "'") = "'\"abcd\"'"
9198     * StringUtils.wrap("'abcd'", "\"")  = "\"'abcd'\""
9199     * </pre>
9200     *
9201     * @param str
9202     *            the String to be wrapper, may be null
9203     * @param wrapWith
9204     *            the String that will wrap str
9205     * @return wrapped String, {@code null} if null String input
9206     * @since 3.4
9207     */
9208    public static String wrap(final String str, final String wrapWith) {
9209
9210        if (isEmpty(str) || isEmpty(wrapWith)) {
9211            return str;
9212        }
9213
9214        return wrapWith.concat(str).concat(wrapWith);
9215    }
9216
9217    /**
9218     * <p>
9219     * Wraps a string with a char if that char is missing from the start or end of the given string.
9220     * </p>
9221     *
9222     * <pre>
9223     * StringUtils.wrap(null, *)        = null
9224     * StringUtils.wrap("", *)          = ""
9225     * StringUtils.wrap("ab", '\0')     = "ab"
9226     * StringUtils.wrap("ab", 'x')      = "xabx"
9227     * StringUtils.wrap("ab", '\'')     = "'ab'"
9228     * StringUtils.wrap("\"ab\"", '\"') = "\"ab\""
9229     * StringUtils.wrap("/", '/')  = "/"
9230     * StringUtils.wrap("a/b/c", '/')  = "/a/b/c/"
9231     * StringUtils.wrap("/a/b/c", '/')  = "/a/b/c/"
9232     * StringUtils.wrap("a/b/c/", '/')  = "/a/b/c/"
9233     * </pre>
9234     *
9235     * @param str
9236     *            the string to be wrapped, may be {@code null}
9237     * @param wrapWith
9238     *            the char that will wrap {@code str}
9239     * @return the wrapped string, or {@code null} if {@code str==null}
9240     * @since 3.5
9241     */
9242    public static String wrapIfMissing(final String str, final char wrapWith) {
9243        if (isEmpty(str) || wrapWith == CharUtils.NUL) {
9244            return str;
9245        }
9246        final StringBuilder builder = new StringBuilder(str.length() + 2);
9247        if (str.charAt(0) != wrapWith) {
9248            builder.append(wrapWith);
9249        }
9250        builder.append(str);
9251        if (str.charAt(str.length() - 1) != wrapWith) {
9252            builder.append(wrapWith);
9253        }
9254        return builder.toString();
9255    }
9256
9257    /**
9258     * <p>
9259     * Wraps a string with a string if that string is missing from the start or end of the given string.
9260     * </p>
9261     *
9262     * <pre>
9263     * StringUtils.wrap(null, *)         = null
9264     * StringUtils.wrap("", *)           = ""
9265     * StringUtils.wrap("ab", null)      = "ab"
9266     * StringUtils.wrap("ab", "x")       = "xabx"
9267     * StringUtils.wrap("ab", "\"")      = "\"ab\""
9268     * StringUtils.wrap("\"ab\"", "\"")  = "\"ab\""
9269     * StringUtils.wrap("ab", "'")       = "'ab'"
9270     * StringUtils.wrap("'abcd'", "'")   = "'abcd'"
9271     * StringUtils.wrap("\"abcd\"", "'") = "'\"abcd\"'"
9272     * StringUtils.wrap("'abcd'", "\"")  = "\"'abcd'\""
9273     * StringUtils.wrap("/", "/")  = "/"
9274     * StringUtils.wrap("a/b/c", "/")  = "/a/b/c/"
9275     * StringUtils.wrap("/a/b/c", "/")  = "/a/b/c/"
9276     * StringUtils.wrap("a/b/c/", "/")  = "/a/b/c/"
9277     * </pre>
9278     *
9279     * @param str
9280     *            the string to be wrapped, may be {@code null}
9281     * @param wrapWith
9282     *            the char that will wrap {@code str}
9283     * @return the wrapped string, or {@code null} if {@code str==null}
9284     * @since 3.5
9285     */
9286    public static String wrapIfMissing(final String str, final String wrapWith) {
9287        if (isEmpty(str) || isEmpty(wrapWith)) {
9288            return str;
9289        }
9290        final StringBuilder builder = new StringBuilder(str.length() + wrapWith.length() + wrapWith.length());
9291        if (!str.startsWith(wrapWith)) {
9292            builder.append(wrapWith);
9293        }
9294        builder.append(str);
9295        if (!str.endsWith(wrapWith)) {
9296            builder.append(wrapWith);
9297        }
9298        return builder.toString();
9299    }
9300
9301    /**
9302     * <p>
9303     * Unwraps a given string from anther string.
9304     * </p>
9305     *
9306     * <pre>
9307     * StringUtils.unwrap(null, null)         = null
9308     * StringUtils.unwrap(null, "")           = null
9309     * StringUtils.unwrap(null, "1")          = null
9310     * StringUtils.unwrap("\'abc\'", "\'")    = "abc"
9311     * StringUtils.unwrap("\"abc\"", "\"")    = "abc"
9312     * StringUtils.unwrap("AABabcBAA", "AA")  = "BabcB"
9313     * StringUtils.unwrap("A", "#")           = "A"
9314     * StringUtils.unwrap("#A", "#")          = "#A"
9315     * StringUtils.unwrap("A#", "#")          = "A#"
9316     * </pre>
9317     *
9318     * @param str
9319     *          the String to be unwrapped, can be null
9320     * @param wrapToken
9321     *          the String used to unwrap
9322     * @return unwrapped String or the original string
9323     *          if it is not quoted properly with the wrapToken
9324     * @since 3.6
9325     */
9326    public static String unwrap(final String str, final String wrapToken) {
9327        if (isEmpty(str) || isEmpty(wrapToken)) {
9328            return str;
9329        }
9330
9331        if (startsWith(str, wrapToken) && endsWith(str, wrapToken)) {
9332            final int startIndex = str.indexOf(wrapToken);
9333            final int endIndex = str.lastIndexOf(wrapToken);
9334            final int wrapLength = wrapToken.length();
9335            if (startIndex != -1 && endIndex != -1) {
9336                return str.substring(startIndex + wrapLength, endIndex);
9337            }
9338        }
9339
9340        return str;
9341    }
9342
9343    /**
9344     * <p>
9345     * Unwraps a given string from a character.
9346     * </p>
9347     *
9348     * <pre>
9349     * StringUtils.unwrap(null, null)         = null
9350     * StringUtils.unwrap(null, '\0')         = null
9351     * StringUtils.unwrap(null, '1')          = null
9352     * StringUtils.unwrap("\'abc\'", '\'')    = "abc"
9353     * StringUtils.unwrap("AABabcBAA", 'A')  = "ABabcBA"
9354     * StringUtils.unwrap("A", '#')           = "A"
9355     * StringUtils.unwrap("#A", '#')          = "#A"
9356     * StringUtils.unwrap("A#", '#')          = "A#"
9357     * </pre>
9358     *
9359     * @param str
9360     *          the String to be unwrapped, can be null
9361     * @param wrapChar
9362     *          the character used to unwrap
9363     * @return unwrapped String or the original string
9364     *          if it is not quoted properly with the wrapChar
9365     * @since 3.6
9366     */
9367    public static String unwrap(final String str, final char wrapChar) {
9368        if (isEmpty(str) || wrapChar == CharUtils.NUL) {
9369            return str;
9370        }
9371
9372        if (str.charAt(0) == wrapChar && str.charAt(str.length() - 1) == wrapChar) {
9373            final int startIndex = 0;
9374            final int endIndex = str.length() - 1;
9375            if (endIndex != -1) {
9376                return str.substring(startIndex + 1, endIndex);
9377            }
9378        }
9379
9380        return str;
9381    }
9382
9383    /**
9384     * <p>Converts a {@code CharSequence} into an array of code points.</p>
9385     *
9386     * <p>Valid pairs of surrogate code units will be converted into a single supplementary
9387     * code point. Isolated surrogate code units (i.e. a high surrogate not followed by a low surrogate or
9388     * a low surrogate not preceded by a high surrogate) will be returned as-is.</p>
9389     *
9390     * <pre>
9391     * StringUtils.toCodePoints(null)   =  null
9392     * StringUtils.toCodePoints("")     =  []  // empty array
9393     * </pre>
9394     *
9395     * @param str the character sequence to convert
9396     * @return an array of code points
9397     * @since 3.6
9398     */
9399    public static int[] toCodePoints(final CharSequence str) {
9400        if (str == null) {
9401            return null;
9402        }
9403        if (str.length() == 0) {
9404            return ArrayUtils.EMPTY_INT_ARRAY;
9405        }
9406
9407        final String s = str.toString();
9408        final int[] result = new int[s.codePointCount(0, s.length())];
9409        int index = 0;
9410        for (int i = 0; i < result.length; i++) {
9411            result[i] = s.codePointAt(index);
9412            index += Character.charCount(result[i]);
9413        }
9414        return result;
9415    }
9416}