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