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     */
4593    public static String joinWith(final String separator, final Object... objects) {
4594        if (objects == null) {
4595            throw new IllegalArgumentException("Object varargs must not be null");
4596        }
4597
4598        final String sanitizedSeparator = defaultString(separator, StringUtils.EMPTY);
4599
4600        final StringBuilder result = new StringBuilder();
4601
4602        final Iterator<Object> iterator = Arrays.asList(objects).iterator();
4603        while (iterator.hasNext()) {
4604            @SuppressWarnings("deprecation") // o.k. to use as long as we do not require java 7 or greater
4605            final String value = ObjectUtils.toString(iterator.next());
4606            result.append(value);
4607
4608            if (iterator.hasNext()) {
4609                result.append(sanitizedSeparator);
4610            }
4611        }
4612
4613        return result.toString();
4614    }
4615
4616    // Delete
4617    //-----------------------------------------------------------------------
4618    /**
4619     * <p>Deletes all whitespaces from a String as defined by
4620     * {@link Character#isWhitespace(char)}.</p>
4621     *
4622     * <pre>
4623     * StringUtils.deleteWhitespace(null)         = null
4624     * StringUtils.deleteWhitespace("")           = ""
4625     * StringUtils.deleteWhitespace("abc")        = "abc"
4626     * StringUtils.deleteWhitespace("   ab  c  ") = "abc"
4627     * </pre>
4628     *
4629     * @param str  the String to delete whitespace from, may be null
4630     * @return the String without whitespaces, {@code null} if null String input
4631     */
4632    public static String deleteWhitespace(final String str) {
4633        if (isEmpty(str)) {
4634            return str;
4635        }
4636        final int sz = str.length();
4637        final char[] chs = new char[sz];
4638        int count = 0;
4639        for (int i = 0; i < sz; i++) {
4640            if (!Character.isWhitespace(str.charAt(i))) {
4641                chs[count++] = str.charAt(i);
4642            }
4643        }
4644        if (count == sz) {
4645            return str;
4646        }
4647        return new String(chs, 0, count);
4648    }
4649
4650    // Remove
4651    //-----------------------------------------------------------------------
4652    /**
4653     * <p>Removes a substring only if it is at the beginning of a source string,
4654     * otherwise returns the source string.</p>
4655     *
4656     * <p>A {@code null} source string will return {@code null}.
4657     * An empty ("") source string will return the empty string.
4658     * A {@code null} search string will return the source string.</p>
4659     *
4660     * <pre>
4661     * StringUtils.removeStart(null, *)      = null
4662     * StringUtils.removeStart("", *)        = ""
4663     * StringUtils.removeStart(*, null)      = *
4664     * StringUtils.removeStart("www.domain.com", "www.")   = "domain.com"
4665     * StringUtils.removeStart("domain.com", "www.")       = "domain.com"
4666     * StringUtils.removeStart("www.domain.com", "domain") = "www.domain.com"
4667     * StringUtils.removeStart("abc", "")    = "abc"
4668     * </pre>
4669     *
4670     * @param str  the source String to search, may be null
4671     * @param remove  the String to search for and remove, may be null
4672     * @return the substring with the string removed if found,
4673     *  {@code null} if null String input
4674     * @since 2.1
4675     */
4676    public static String removeStart(final String str, final String remove) {
4677        if (isEmpty(str) || isEmpty(remove)) {
4678            return str;
4679        }
4680        if (str.startsWith(remove)){
4681            return str.substring(remove.length());
4682        }
4683        return str;
4684    }
4685
4686    /**
4687     * <p>Case insensitive removal of a substring if it is at the beginning of a source string,
4688     * otherwise returns the source string.</p>
4689     *
4690     * <p>A {@code null} source string will return {@code null}.
4691     * An empty ("") source string will return the empty string.
4692     * A {@code null} search string will return the source string.</p>
4693     *
4694     * <pre>
4695     * StringUtils.removeStartIgnoreCase(null, *)      = null
4696     * StringUtils.removeStartIgnoreCase("", *)        = ""
4697     * StringUtils.removeStartIgnoreCase(*, null)      = *
4698     * StringUtils.removeStartIgnoreCase("www.domain.com", "www.")   = "domain.com"
4699     * StringUtils.removeStartIgnoreCase("www.domain.com", "WWW.")   = "domain.com"
4700     * StringUtils.removeStartIgnoreCase("domain.com", "www.")       = "domain.com"
4701     * StringUtils.removeStartIgnoreCase("www.domain.com", "domain") = "www.domain.com"
4702     * StringUtils.removeStartIgnoreCase("abc", "")    = "abc"
4703     * </pre>
4704     *
4705     * @param str  the source String to search, may be null
4706     * @param remove  the String to search for (case insensitive) and remove, may be null
4707     * @return the substring with the string removed if found,
4708     *  {@code null} if null String input
4709     * @since 2.4
4710     */
4711    public static String removeStartIgnoreCase(final String str, final String remove) {
4712        if (isEmpty(str) || isEmpty(remove)) {
4713            return str;
4714        }
4715        if (startsWithIgnoreCase(str, remove)) {
4716            return str.substring(remove.length());
4717        }
4718        return str;
4719    }
4720
4721    /**
4722     * <p>Removes a substring only if it is at the end of a source string,
4723     * otherwise returns the source string.</p>
4724     *
4725     * <p>A {@code null} source string will return {@code null}.
4726     * An empty ("") source string will return the empty string.
4727     * A {@code null} search string will return the source string.</p>
4728     *
4729     * <pre>
4730     * StringUtils.removeEnd(null, *)      = null
4731     * StringUtils.removeEnd("", *)        = ""
4732     * StringUtils.removeEnd(*, null)      = *
4733     * StringUtils.removeEnd("www.domain.com", ".com.")  = "www.domain.com"
4734     * StringUtils.removeEnd("www.domain.com", ".com")   = "www.domain"
4735     * StringUtils.removeEnd("www.domain.com", "domain") = "www.domain.com"
4736     * StringUtils.removeEnd("abc", "")    = "abc"
4737     * </pre>
4738     *
4739     * @param str  the source String to search, may be null
4740     * @param remove  the String to search for and remove, may be null
4741     * @return the substring with the string removed if found,
4742     *  {@code null} if null String input
4743     * @since 2.1
4744     */
4745    public static String removeEnd(final String str, final String remove) {
4746        if (isEmpty(str) || isEmpty(remove)) {
4747            return str;
4748        }
4749        if (str.endsWith(remove)) {
4750            return str.substring(0, str.length() - remove.length());
4751        }
4752        return str;
4753    }
4754
4755    /**
4756     * <p>Case insensitive removal of a substring if it is at the end of a source string,
4757     * otherwise returns the source string.</p>
4758     *
4759     * <p>A {@code null} source string will return {@code null}.
4760     * An empty ("") source string will return the empty string.
4761     * A {@code null} search string will return the source string.</p>
4762     *
4763     * <pre>
4764     * StringUtils.removeEndIgnoreCase(null, *)      = null
4765     * StringUtils.removeEndIgnoreCase("", *)        = ""
4766     * StringUtils.removeEndIgnoreCase(*, null)      = *
4767     * StringUtils.removeEndIgnoreCase("www.domain.com", ".com.")  = "www.domain.com"
4768     * StringUtils.removeEndIgnoreCase("www.domain.com", ".com")   = "www.domain"
4769     * StringUtils.removeEndIgnoreCase("www.domain.com", "domain") = "www.domain.com"
4770     * StringUtils.removeEndIgnoreCase("abc", "")    = "abc"
4771     * StringUtils.removeEndIgnoreCase("www.domain.com", ".COM") = "www.domain")
4772     * StringUtils.removeEndIgnoreCase("www.domain.COM", ".com") = "www.domain")
4773     * </pre>
4774     *
4775     * @param str  the source String to search, may be null
4776     * @param remove  the String to search for (case insensitive) and remove, may be null
4777     * @return the substring with the string removed if found,
4778     *  {@code null} if null String input
4779     * @since 2.4
4780     */
4781    public static String removeEndIgnoreCase(final String str, final String remove) {
4782        if (isEmpty(str) || isEmpty(remove)) {
4783            return str;
4784        }
4785        if (endsWithIgnoreCase(str, remove)) {
4786            return str.substring(0, str.length() - remove.length());
4787        }
4788        return str;
4789    }
4790
4791    /**
4792     * <p>Removes all occurrences of a substring from within the source string.</p>
4793     *
4794     * <p>A {@code null} source string will return {@code null}.
4795     * An empty ("") source string will return the empty string.
4796     * A {@code null} remove string will return the source string.
4797     * An empty ("") remove string will return the source string.</p>
4798     *
4799     * <pre>
4800     * StringUtils.remove(null, *)        = null
4801     * StringUtils.remove("", *)          = ""
4802     * StringUtils.remove(*, null)        = *
4803     * StringUtils.remove(*, "")          = *
4804     * StringUtils.remove("queued", "ue") = "qd"
4805     * StringUtils.remove("queued", "zz") = "queued"
4806     * </pre>
4807     *
4808     * @param str  the source String to search, may be null
4809     * @param remove  the String to search for and remove, may be null
4810     * @return the substring with the string removed if found,
4811     *  {@code null} if null String input
4812     * @since 2.1
4813     */
4814    public static String remove(final String str, final String remove) {
4815        if (isEmpty(str) || isEmpty(remove)) {
4816            return str;
4817        }
4818        return replace(str, remove, EMPTY, -1);
4819    }
4820
4821    /**
4822     * <p>Removes all occurrences of a character from within the source string.</p>
4823     *
4824     * <p>A {@code null} source string will return {@code null}.
4825     * An empty ("") source string will return the empty string.</p>
4826     *
4827     * <pre>
4828     * StringUtils.remove(null, *)       = null
4829     * StringUtils.remove("", *)         = ""
4830     * StringUtils.remove("queued", 'u') = "qeed"
4831     * StringUtils.remove("queued", 'z') = "queued"
4832     * </pre>
4833     *
4834     * @param str  the source String to search, may be null
4835     * @param remove  the char to search for and remove, may be null
4836     * @return the substring with the char removed if found,
4837     *  {@code null} if null String input
4838     * @since 2.1
4839     */
4840    public static String remove(final String str, final char remove) {
4841        if (isEmpty(str) || str.indexOf(remove) == INDEX_NOT_FOUND) {
4842            return str;
4843        }
4844        final char[] chars = str.toCharArray();
4845        int pos = 0;
4846        for (int i = 0; i < chars.length; i++) {
4847            if (chars[i] != remove) {
4848                chars[pos++] = chars[i];
4849            }
4850        }
4851        return new String(chars, 0, pos);
4852    }
4853
4854    /**
4855     * <p>Removes each substring of the text String that matches the given regular expression.</p>
4856     *
4857     * This method is a {@code null} safe equivalent to:
4858     * <ul>
4859     *  <li>{@code text.replaceAll(regex, StringUtils.EMPTY)}</li>
4860     *  <li>{@code Pattern.compile(regex).matcher(text).replaceAll(StringUtils.EMPTY)}</li>
4861     * </ul>
4862     *
4863     * <p>A {@code null} reference passed to this method is a no-op.</p>
4864     *
4865     * <p>Unlike in the {@link #removePattern(String, String)} method, the {@link Pattern#DOTALL} option
4866     * is NOT automatically added.
4867     * To use the DOTALL option prepend <code>"(?s)"</code> to the regex.
4868     * DOTALL is also know as single-line mode in Perl.</p>
4869     *
4870     * <pre>
4871     * StringUtils.removeAll(null, *)      = null
4872     * StringUtils.removeAll("any", null)  = "any"
4873     * StringUtils.removeAll("any", "")    = "any"
4874     * StringUtils.removeAll("any", ".*")  = ""
4875     * StringUtils.removeAll("any", ".+")  = ""
4876     * StringUtils.removeAll("abc", ".?")  = ""
4877     * StringUtils.removeAll("A&lt;__&gt;\n&lt;__&gt;B", "&lt;.*&gt;")      = "A\nB"
4878     * StringUtils.removeAll("A&lt;__&gt;\n&lt;__&gt;B", "(?s)&lt;.*&gt;")  = "AB"
4879     * StringUtils.removeAll("ABCabc123abc", "[a-z]")     = "ABC123"
4880     * </pre>
4881     *
4882     * @param text  text to remove from, may be null
4883     * @param regex  the regular expression to which this string is to be matched
4884     * @return  the text with any removes processed,
4885     *              {@code null} if null String input
4886     *
4887     * @throws  java.util.regex.PatternSyntaxException
4888     *              if the regular expression's syntax is invalid
4889     *
4890     * @see #replaceAll(String, String, String)
4891     * @see #removePattern(String, String)
4892     * @see String#replaceAll(String, String)
4893     * @see java.util.regex.Pattern
4894     * @see java.util.regex.Pattern#DOTALL
4895     * @since 3.5
4896     */
4897    public static String removeAll(final String text, final String regex) {
4898        return replaceAll(text, regex, StringUtils.EMPTY);
4899    }
4900
4901    /**
4902     * <p>Removes the first substring of the text string that matches the given regular expression.</p>
4903     *
4904     * This method is a {@code null} safe equivalent to:
4905     * <ul>
4906     *  <li>{@code text.replaceFirst(regex, StringUtils.EMPTY)}</li>
4907     *  <li>{@code Pattern.compile(regex).matcher(text).replaceFirst(StringUtils.EMPTY)}</li>
4908     * </ul>
4909     *
4910     * <p>A {@code null} reference passed to this method is a no-op.</p>
4911     *
4912     * <p>The {@link Pattern#DOTALL} option is NOT automatically added.
4913     * To use the DOTALL option prepend <code>"(?s)"</code> to the regex.
4914     * DOTALL is also know as single-line mode in Perl.</p>
4915     *
4916     * <pre>
4917     * StringUtils.removeFirst(null, *)      = null
4918     * StringUtils.removeFirst("any", null)  = "any"
4919     * StringUtils.removeFirst("any", "")    = "any"
4920     * StringUtils.removeFirst("any", ".*")  = ""
4921     * StringUtils.removeFirst("any", ".+")  = ""
4922     * StringUtils.removeFirst("abc", ".?")  = "bc"
4923     * StringUtils.removeFirst("A&lt;__&gt;\n&lt;__&gt;B", "&lt;.*&gt;")      = "A\n&lt;__&gt;B"
4924     * StringUtils.removeFirst("A&lt;__&gt;\n&lt;__&gt;B", "(?s)&lt;.*&gt;")  = "AB"
4925     * StringUtils.removeFirst("ABCabc123", "[a-z]")          = "ABCbc123"
4926     * StringUtils.removeFirst("ABCabc123abc", "[a-z]+")      = "ABC123abc"
4927     * </pre>
4928     *
4929     * @param text  text to remove from, may be null
4930     * @param regex  the regular expression to which this string is to be matched
4931     * @return  the text with the first replacement processed,
4932     *              {@code null} if null String input
4933     *
4934     * @throws  java.util.regex.PatternSyntaxException
4935     *              if the regular expression's syntax is invalid
4936     *
4937     * @see #replaceFirst(String, String, String)
4938     * @see String#replaceFirst(String, String)
4939     * @see java.util.regex.Pattern
4940     * @see java.util.regex.Pattern#DOTALL
4941     * @since 3.5
4942     */
4943    public static String removeFirst(final String text, final String regex) {
4944        return replaceFirst(text, regex, StringUtils.EMPTY);
4945    }
4946
4947    // Replacing
4948    //-----------------------------------------------------------------------
4949    /**
4950     * <p>Replaces a String with another String inside a larger String, once.</p>
4951     *
4952     * <p>A {@code null} reference passed to this method is a no-op.</p>
4953     *
4954     * <pre>
4955     * StringUtils.replaceOnce(null, *, *)        = null
4956     * StringUtils.replaceOnce("", *, *)          = ""
4957     * StringUtils.replaceOnce("any", null, *)    = "any"
4958     * StringUtils.replaceOnce("any", *, null)    = "any"
4959     * StringUtils.replaceOnce("any", "", *)      = "any"
4960     * StringUtils.replaceOnce("aba", "a", null)  = "aba"
4961     * StringUtils.replaceOnce("aba", "a", "")    = "ba"
4962     * StringUtils.replaceOnce("aba", "a", "z")   = "zba"
4963     * </pre>
4964     *
4965     * @see #replace(String text, String searchString, String replacement, int max)
4966     * @param text  text to search and replace in, may be null
4967     * @param searchString  the String to search for, may be null
4968     * @param replacement  the String to replace with, may be null
4969     * @return the text with any replacements processed,
4970     *  {@code null} if null String input
4971     */
4972    public static String replaceOnce(final String text, final String searchString, final String replacement) {
4973        return replace(text, searchString, replacement, 1);
4974    }
4975
4976    /**
4977     * <p>Replaces each substring of the source String that matches the given regular expression with the given
4978     * replacement using the {@link Pattern#DOTALL} option. DOTALL is also know as single-line mode in Perl.</p>
4979     *
4980     * This call is a {@code null} safe equivalent to:
4981     * <ul>
4982     * <li>{@code source.replaceAll(&quot;(?s)&quot; + regex, replacement)}</li>
4983     * <li>{@code Pattern.compile(regex, Pattern.DOTALL).matcher(source).replaceAll(replacement)}</li>
4984     * </ul>
4985     *
4986     * <p>A {@code null} reference passed to this method is a no-op.</p>
4987     *
4988     * <pre>
4989     * StringUtils.replacePattern(null, *, *)       = null
4990     * StringUtils.replacePattern("any", null, *)   = "any"
4991     * StringUtils.replacePattern("any", *, null)   = "any"
4992     * StringUtils.replacePattern("", "", "zzz")    = "zzz"
4993     * StringUtils.replacePattern("", ".*", "zzz")  = "zzz"
4994     * StringUtils.replacePattern("", ".+", "zzz")  = ""
4995     * StringUtils.replacePattern("&lt;__&gt;\n&lt;__&gt;", "&lt;.*&gt;", "z")       = "z"
4996     * StringUtils.replacePattern("ABCabc123", "[a-z]", "_")       = "ABC___123"
4997     * StringUtils.replacePattern("ABCabc123", "[^A-Z0-9]+", "_")  = "ABC_123"
4998     * StringUtils.replacePattern("ABCabc123", "[^A-Z0-9]+", "")   = "ABC123"
4999     * StringUtils.replacePattern("Lorem ipsum  dolor   sit", "( +)([a-z]+)", "_$2")  = "Lorem_ipsum_dolor_sit"
5000     * </pre>
5001     *
5002     * @param source
5003     *            the source string
5004     * @param regex
5005     *            the regular expression to which this string is to be matched
5006     * @param replacement
5007     *            the string to be substituted for each match
5008     * @return The resulting {@code String}
5009     * @see #replaceAll(String, String, String)
5010     * @see String#replaceAll(String, String)
5011     * @see Pattern#DOTALL
5012     * @since 3.2
5013     * @since 3.5 Changed {@code null} reference passed to this method is a no-op.
5014     */
5015    public static String replacePattern(final String source, final String regex, final String replacement) {
5016        if (source == null || regex == null|| replacement == null ) {
5017            return source;
5018        }
5019        return Pattern.compile(regex, Pattern.DOTALL).matcher(source).replaceAll(replacement);
5020    }
5021
5022    /**
5023     * <p>Removes each substring of the source String that matches the given regular expression using the DOTALL option.
5024     * </p>
5025     *
5026     * This call is a {@code null} safe equivalent to:
5027     * <ul>
5028     * <li>{@code source.replaceAll(&quot;(?s)&quot; + regex, StringUtils.EMPTY)}</li>
5029     * <li>{@code Pattern.compile(regex, Pattern.DOTALL).matcher(source).replaceAll(StringUtils.EMPTY)}</li>
5030     * </ul>
5031     *
5032     * <p>A {@code null} reference passed to this method is a no-op.</p>
5033     *
5034     * <pre>
5035     * StringUtils.removePattern(null, *)       = null
5036     * StringUtils.removePattern("any", null)   = "any"
5037     * StringUtils.removePattern("A&lt;__&gt;\n&lt;__&gt;B", "&lt;.*&gt;")  = "AB"
5038     * StringUtils.removePattern("ABCabc123", "[a-z]")    = "ABC123"
5039     * </pre>
5040     *
5041     * @param source
5042     *            the source string
5043     * @param regex
5044     *            the regular expression to which this string is to be matched
5045     * @return The resulting {@code String}
5046     * @see #replacePattern(String, String, String)
5047     * @see String#replaceAll(String, String)
5048     * @see Pattern#DOTALL
5049     * @since 3.2
5050     * @since 3.5 Changed {@code null} reference passed to this method is a no-op.
5051     */
5052    public static String removePattern(final String source, final String regex) {
5053        return replacePattern(source, regex, StringUtils.EMPTY);
5054    }
5055
5056    /**
5057     * <p>Replaces each substring of the text String that matches the given regular expression
5058     * with the given replacement.</p>
5059     *
5060     * This method is a {@code null} safe equivalent to:
5061     * <ul>
5062     *  <li>{@code text.replaceAll(regex, replacement)}</li>
5063     *  <li>{@code Pattern.compile(regex).matcher(text).replaceAll(replacement)}</li>
5064     * </ul>
5065     *
5066     * <p>A {@code null} reference passed to this method is a no-op.</p>
5067     *
5068     * <p>Unlike in the {@link #replacePattern(String, String, String)} method, the {@link Pattern#DOTALL} option
5069     * is NOT automatically added.
5070     * To use the DOTALL option prepend <code>"(?s)"</code> to the regex.
5071     * DOTALL is also know as single-line mode in Perl.</p>
5072     *
5073     * <pre>
5074     * StringUtils.replaceAll(null, *, *)       = null
5075     * StringUtils.replaceAll("any", null, *)   = "any"
5076     * StringUtils.replaceAll("any", *, null)   = "any"
5077     * StringUtils.replaceAll("", "", "zzz")    = "zzz"
5078     * StringUtils.replaceAll("", ".*", "zzz")  = "zzz"
5079     * StringUtils.replaceAll("", ".+", "zzz")  = ""
5080     * StringUtils.replaceAll("abc", "", "ZZ")  = "ZZaZZbZZcZZ"
5081     * StringUtils.replaceAll("&lt;__&gt;\n&lt;__&gt;", "&lt;.*&gt;", "z")      = "z\nz"
5082     * StringUtils.replaceAll("&lt;__&gt;\n&lt;__&gt;", "(?s)&lt;.*&gt;", "z")  = "z"
5083     * StringUtils.replaceAll("ABCabc123", "[a-z]", "_")       = "ABC___123"
5084     * StringUtils.replaceAll("ABCabc123", "[^A-Z0-9]+", "_")  = "ABC_123"
5085     * StringUtils.replaceAll("ABCabc123", "[^A-Z0-9]+", "")   = "ABC123"
5086     * StringUtils.replaceAll("Lorem ipsum  dolor   sit", "( +)([a-z]+)", "_$2")  = "Lorem_ipsum_dolor_sit"
5087     * </pre>
5088     *
5089     * @param text  text to search and replace in, may be null
5090     * @param regex  the regular expression to which this string is to be matched
5091     * @param replacement  the string to be substituted for each match
5092     * @return  the text with any replacements processed,
5093     *              {@code null} if null String input
5094     *
5095     * @throws  java.util.regex.PatternSyntaxException
5096     *              if the regular expression's syntax is invalid
5097     *
5098     * @see #replacePattern(String, String, String)
5099     * @see String#replaceAll(String, String)
5100     * @see java.util.regex.Pattern
5101     * @see java.util.regex.Pattern#DOTALL
5102     * @since 3.5
5103     */
5104    public static String replaceAll(final String text, final String regex, final String replacement) {
5105        if (text == null || regex == null|| replacement == null ) {
5106            return text;
5107        }
5108        return text.replaceAll(regex, replacement);
5109    }
5110
5111    /**
5112     * <p>Replaces the first substring of the text string that matches the given regular expression
5113     * with the given replacement.</p>
5114     *
5115     * This method is a {@code null} safe equivalent to:
5116     * <ul>
5117     *  <li>{@code text.replaceFirst(regex, replacement)}</li>
5118     *  <li>{@code Pattern.compile(regex).matcher(text).replaceFirst(replacement)}</li>
5119     * </ul>
5120     *
5121     * <p>A {@code null} reference passed to this method is a no-op.</p>
5122     *
5123     * <p>The {@link Pattern#DOTALL} option is NOT automatically added.
5124     * To use the DOTALL option prepend <code>"(?s)"</code> to the regex.
5125     * DOTALL is also know as single-line mode in Perl.</p>
5126     *
5127     * <pre>
5128     * StringUtils.replaceFirst(null, *, *)       = null
5129     * StringUtils.replaceFirst("any", null, *)   = "any"
5130     * StringUtils.replaceFirst("any", *, null)   = "any"
5131     * StringUtils.replaceFirst("", "", "zzz")    = "zzz"
5132     * StringUtils.replaceFirst("", ".*", "zzz")  = "zzz"
5133     * StringUtils.replaceFirst("", ".+", "zzz")  = ""
5134     * StringUtils.replaceFirst("abc", "", "ZZ")  = "ZZabc"
5135     * StringUtils.replaceFirst("&lt;__&gt;\n&lt;__&gt;", "&lt;.*&gt;", "z")      = "z\n&lt;__&gt;"
5136     * StringUtils.replaceFirst("&lt;__&gt;\n&lt;__&gt;", "(?s)&lt;.*&gt;", "z")  = "z"
5137     * StringUtils.replaceFirst("ABCabc123", "[a-z]", "_")          = "ABC_bc123"
5138     * StringUtils.replaceFirst("ABCabc123abc", "[^A-Z0-9]+", "_")  = "ABC_123abc"
5139     * StringUtils.replaceFirst("ABCabc123abc", "[^A-Z0-9]+", "")   = "ABC123abc"
5140     * StringUtils.replaceFirst("Lorem ipsum  dolor   sit", "( +)([a-z]+)", "_$2")  = "Lorem_ipsum  dolor   sit"
5141     * </pre>
5142     *
5143     * @param text  text to search and replace in, may be null
5144     * @param regex  the regular expression to which this string is to be matched
5145     * @param replacement  the string to be substituted for the first match
5146     * @return  the text with the first replacement processed,
5147     *              {@code null} if null String input
5148     *
5149     * @throws  java.util.regex.PatternSyntaxException
5150     *              if the regular expression's syntax is invalid
5151     *
5152     * @see String#replaceFirst(String, String)
5153     * @see java.util.regex.Pattern
5154     * @see java.util.regex.Pattern#DOTALL
5155     * @since 3.5
5156     */
5157    public static String replaceFirst(final String text, final String regex, final String replacement) {
5158        if (text == null || regex == null|| replacement == null ) {
5159            return text;
5160        }
5161        return text.replaceFirst(regex, replacement);
5162    }
5163
5164    /**
5165     * <p>Replaces all occurrences of a String within another String.</p>
5166     *
5167     * <p>A {@code null} reference passed to this method is a no-op.</p>
5168     *
5169     * <pre>
5170     * StringUtils.replace(null, *, *)        = null
5171     * StringUtils.replace("", *, *)          = ""
5172     * StringUtils.replace("any", null, *)    = "any"
5173     * StringUtils.replace("any", *, null)    = "any"
5174     * StringUtils.replace("any", "", *)      = "any"
5175     * StringUtils.replace("aba", "a", null)  = "aba"
5176     * StringUtils.replace("aba", "a", "")    = "b"
5177     * StringUtils.replace("aba", "a", "z")   = "zbz"
5178     * </pre>
5179     *
5180     * @see #replace(String text, String searchString, String replacement, int max)
5181     * @param text  text to search and replace in, may be null
5182     * @param searchString  the String to search for, may be null
5183     * @param replacement  the String to replace it with, may be null
5184     * @return the text with any replacements processed,
5185     *  {@code null} if null String input
5186     */
5187    public static String replace(final String text, final String searchString, final String replacement) {
5188        return replace(text, searchString, replacement, -1);
5189    }
5190
5191    /**
5192     * <p>Replaces a String with another String inside a larger String,
5193     * for the first {@code max} values of the search String.</p>
5194     *
5195     * <p>A {@code null} reference passed to this method is a no-op.</p>
5196     *
5197     * <pre>
5198     * StringUtils.replace(null, *, *, *)         = null
5199     * StringUtils.replace("", *, *, *)           = ""
5200     * StringUtils.replace("any", null, *, *)     = "any"
5201     * StringUtils.replace("any", *, null, *)     = "any"
5202     * StringUtils.replace("any", "", *, *)       = "any"
5203     * StringUtils.replace("any", *, *, 0)        = "any"
5204     * StringUtils.replace("abaa", "a", null, -1) = "abaa"
5205     * StringUtils.replace("abaa", "a", "", -1)   = "b"
5206     * StringUtils.replace("abaa", "a", "z", 0)   = "abaa"
5207     * StringUtils.replace("abaa", "a", "z", 1)   = "zbaa"
5208     * StringUtils.replace("abaa", "a", "z", 2)   = "zbza"
5209     * StringUtils.replace("abaa", "a", "z", -1)  = "zbzz"
5210     * </pre>
5211     *
5212     * @param text  text to search and replace in, may be null
5213     * @param searchString  the String to search for, may be null
5214     * @param replacement  the String to replace it with, may be null
5215     * @param max  maximum number of values to replace, or {@code -1} if no maximum
5216     * @return the text with any replacements processed,
5217     *  {@code null} if null String input
5218     */
5219    public static String replace(final String text, final String searchString, final String replacement, int max) {
5220        if (isEmpty(text) || isEmpty(searchString) || replacement == null || max == 0) {
5221            return text;
5222        }
5223        int start = 0;
5224        int end = text.indexOf(searchString, start);
5225        if (end == INDEX_NOT_FOUND) {
5226            return text;
5227        }
5228        final int replLength = searchString.length();
5229        int increase = replacement.length() - replLength;
5230        increase = increase < 0 ? 0 : increase;
5231        increase *= max < 0 ? 16 : max > 64 ? 64 : max;
5232        final StringBuilder buf = new StringBuilder(text.length() + increase);
5233        while (end != INDEX_NOT_FOUND) {
5234            buf.append(text.substring(start, end)).append(replacement);
5235            start = end + replLength;
5236            if (--max == 0) {
5237                break;
5238            }
5239            end = text.indexOf(searchString, start);
5240        }
5241        buf.append(text.substring(start));
5242        return buf.toString();
5243    }
5244
5245    /**
5246     * <p>
5247     * Replaces all occurrences of Strings within another String.
5248     * </p>
5249     *
5250     * <p>
5251     * A {@code null} reference passed to this method is a no-op, or if
5252     * any "search string" or "string to replace" is null, that replace will be
5253     * ignored. This will not repeat. For repeating replaces, call the
5254     * overloaded method.
5255     * </p>
5256     *
5257     * <pre>
5258     *  StringUtils.replaceEach(null, *, *)        = null
5259     *  StringUtils.replaceEach("", *, *)          = ""
5260     *  StringUtils.replaceEach("aba", null, null) = "aba"
5261     *  StringUtils.replaceEach("aba", new String[0], null) = "aba"
5262     *  StringUtils.replaceEach("aba", null, new String[0]) = "aba"
5263     *  StringUtils.replaceEach("aba", new String[]{"a"}, null)  = "aba"
5264     *  StringUtils.replaceEach("aba", new String[]{"a"}, new String[]{""})  = "b"
5265     *  StringUtils.replaceEach("aba", new String[]{null}, new String[]{"a"})  = "aba"
5266     *  StringUtils.replaceEach("abcde", new String[]{"ab", "d"}, new String[]{"w", "t"})  = "wcte"
5267     *  (example of how it does not repeat)
5268     *  StringUtils.replaceEach("abcde", new String[]{"ab", "d"}, new String[]{"d", "t"})  = "dcte"
5269     * </pre>
5270     *
5271     * @param text
5272     *            text to search and replace in, no-op if null
5273     * @param searchList
5274     *            the Strings to search for, no-op if null
5275     * @param replacementList
5276     *            the Strings to replace them with, no-op if null
5277     * @return the text with any replacements processed, {@code null} if
5278     *         null String input
5279     * @throws IllegalArgumentException
5280     *             if the lengths of the arrays are not the same (null is ok,
5281     *             and/or size 0)
5282     * @since 2.4
5283     */
5284    public static String replaceEach(final String text, final String[] searchList, final String[] replacementList) {
5285        return replaceEach(text, searchList, replacementList, false, 0);
5286    }
5287
5288    /**
5289     * <p>
5290     * Replaces all occurrences of Strings within another String.
5291     * </p>
5292     *
5293     * <p>
5294     * A {@code null} reference passed to this method is a no-op, or if
5295     * any "search string" or "string to replace" is null, that replace will be
5296     * ignored.
5297     * </p>
5298     *
5299     * <pre>
5300     *  StringUtils.replaceEachRepeatedly(null, *, *) = null
5301     *  StringUtils.replaceEachRepeatedly("", *, *) = ""
5302     *  StringUtils.replaceEachRepeatedly("aba", null, null) = "aba"
5303     *  StringUtils.replaceEachRepeatedly("aba", new String[0], null) = "aba"
5304     *  StringUtils.replaceEachRepeatedly("aba", null, new String[0]) = "aba"
5305     *  StringUtils.replaceEachRepeatedly("aba", new String[]{"a"}, null) = "aba"
5306     *  StringUtils.replaceEachRepeatedly("aba", new String[]{"a"}, new String[]{""}) = "b"
5307     *  StringUtils.replaceEachRepeatedly("aba", new String[]{null}, new String[]{"a"}) = "aba"
5308     *  StringUtils.replaceEachRepeatedly("abcde", new String[]{"ab", "d"}, new String[]{"w", "t"}) = "wcte"
5309     *  (example of how it repeats)
5310     *  StringUtils.replaceEachRepeatedly("abcde", new String[]{"ab", "d"}, new String[]{"d", "t"}) = "tcte"
5311     *  StringUtils.replaceEachRepeatedly("abcde", new String[]{"ab", "d"}, new String[]{"d", "ab"}) = IllegalStateException
5312     * </pre>
5313     *
5314     * @param text
5315     *            text to search and replace in, no-op if null
5316     * @param searchList
5317     *            the Strings to search for, no-op if null
5318     * @param replacementList
5319     *            the Strings to replace them with, no-op if null
5320     * @return the text with any replacements processed, {@code null} if
5321     *         null String input
5322     * @throws IllegalStateException
5323     *             if the search is repeating and there is an endless loop due
5324     *             to outputs of one being inputs to another
5325     * @throws IllegalArgumentException
5326     *             if the lengths of the arrays are not the same (null is ok,
5327     *             and/or size 0)
5328     * @since 2.4
5329     */
5330    public static String replaceEachRepeatedly(final String text, final String[] searchList, final String[] replacementList) {
5331        // timeToLive should be 0 if not used or nothing to replace, else it's
5332        // the length of the replace array
5333        final int timeToLive = searchList == null ? 0 : searchList.length;
5334        return replaceEach(text, searchList, replacementList, true, timeToLive);
5335    }
5336
5337    /**
5338     * <p>
5339     * Replace all occurrences of Strings within another String.
5340     * This is a private recursive helper method for {@link #replaceEachRepeatedly(String, String[], String[])} and
5341     * {@link #replaceEach(String, String[], String[])}
5342     * </p>
5343     *
5344     * <p>
5345     * A {@code null} reference passed to this method is a no-op, or if
5346     * any "search string" or "string to replace" is null, that replace will be
5347     * ignored.
5348     * </p>
5349     *
5350     * <pre>
5351     *  StringUtils.replaceEach(null, *, *, *, *) = null
5352     *  StringUtils.replaceEach("", *, *, *, *) = ""
5353     *  StringUtils.replaceEach("aba", null, null, *, *) = "aba"
5354     *  StringUtils.replaceEach("aba", new String[0], null, *, *) = "aba"
5355     *  StringUtils.replaceEach("aba", null, new String[0], *, *) = "aba"
5356     *  StringUtils.replaceEach("aba", new String[]{"a"}, null, *, *) = "aba"
5357     *  StringUtils.replaceEach("aba", new String[]{"a"}, new String[]{""}, *, >=0) = "b"
5358     *  StringUtils.replaceEach("aba", new String[]{null}, new String[]{"a"}, *, >=0) = "aba"
5359     *  StringUtils.replaceEach("abcde", new String[]{"ab", "d"}, new String[]{"w", "t"}, *, >=0) = "wcte"
5360     *  (example of how it repeats)
5361     *  StringUtils.replaceEach("abcde", new String[]{"ab", "d"}, new String[]{"d", "t"}, false, >=0) = "dcte"
5362     *  StringUtils.replaceEach("abcde", new String[]{"ab", "d"}, new String[]{"d", "t"}, true, >=2) = "tcte"
5363     *  StringUtils.replaceEach("abcde", new String[]{"ab", "d"}, new String[]{"d", "ab"}, *, *) = IllegalStateException
5364     * </pre>
5365     *
5366     * @param text
5367     *            text to search and replace in, no-op if null
5368     * @param searchList
5369     *            the Strings to search for, no-op if null
5370     * @param replacementList
5371     *            the Strings to replace them with, no-op if null
5372     * @param repeat if true, then replace repeatedly
5373     *       until there are no more possible replacements or timeToLive < 0
5374     * @param timeToLive
5375     *            if less than 0 then there is a circular reference and endless
5376     *            loop
5377     * @return the text with any replacements processed, {@code null} if
5378     *         null String input
5379     * @throws IllegalStateException
5380     *             if the search is repeating and there is an endless loop due
5381     *             to outputs of one being inputs to another
5382     * @throws IllegalArgumentException
5383     *             if the lengths of the arrays are not the same (null is ok,
5384     *             and/or size 0)
5385     * @since 2.4
5386     */
5387    private static String replaceEach(
5388            final String text, final String[] searchList, final String[] replacementList, final boolean repeat, final int timeToLive) {
5389
5390        // mchyzer Performance note: This creates very few new objects (one major goal)
5391        // let me know if there are performance requests, we can create a harness to measure
5392
5393        if (text == null || text.isEmpty() || searchList == null ||
5394                searchList.length == 0 || replacementList == null || replacementList.length == 0) {
5395            return text;
5396        }
5397
5398        // if recursing, this shouldn't be less than 0
5399        if (timeToLive < 0) {
5400            throw new IllegalStateException("Aborting to protect against StackOverflowError - " +
5401                                            "output of one loop is the input of another");
5402        }
5403
5404        final int searchLength = searchList.length;
5405        final int replacementLength = replacementList.length;
5406
5407        // make sure lengths are ok, these need to be equal
5408        if (searchLength != replacementLength) {
5409            throw new IllegalArgumentException("Search and Replace array lengths don't match: "
5410                + searchLength
5411                + " vs "
5412                + replacementLength);
5413        }
5414
5415        // keep track of which still have matches
5416        final boolean[] noMoreMatchesForReplIndex = new boolean[searchLength];
5417
5418        // index on index that the match was found
5419        int textIndex = -1;
5420        int replaceIndex = -1;
5421        int tempIndex = -1;
5422
5423        // index of replace array that will replace the search string found
5424        // NOTE: logic duplicated below START
5425        for (int i = 0; i < searchLength; i++) {
5426            if (noMoreMatchesForReplIndex[i] || searchList[i] == null ||
5427                    searchList[i].isEmpty() || replacementList[i] == null) {
5428                continue;
5429            }
5430            tempIndex = text.indexOf(searchList[i]);
5431
5432            // see if we need to keep searching for this
5433            if (tempIndex == -1) {
5434                noMoreMatchesForReplIndex[i] = true;
5435            } else {
5436                if (textIndex == -1 || tempIndex < textIndex) {
5437                    textIndex = tempIndex;
5438                    replaceIndex = i;
5439                }
5440            }
5441        }
5442        // NOTE: logic mostly below END
5443
5444        // no search strings found, we are done
5445        if (textIndex == -1) {
5446            return text;
5447        }
5448
5449        int start = 0;
5450
5451        // get a good guess on the size of the result buffer so it doesn't have to double if it goes over a bit
5452        int increase = 0;
5453
5454        // count the replacement text elements that are larger than their corresponding text being replaced
5455        for (int i = 0; i < searchList.length; i++) {
5456            if (searchList[i] == null || replacementList[i] == null) {
5457                continue;
5458            }
5459            final int greater = replacementList[i].length() - searchList[i].length();
5460            if (greater > 0) {
5461                increase += 3 * greater; // assume 3 matches
5462            }
5463        }
5464        // have upper-bound at 20% increase, then let Java take over
5465        increase = Math.min(increase, text.length() / 5);
5466
5467        final StringBuilder buf = new StringBuilder(text.length() + increase);
5468
5469        while (textIndex != -1) {
5470
5471            for (int i = start; i < textIndex; i++) {
5472                buf.append(text.charAt(i));
5473            }
5474            buf.append(replacementList[replaceIndex]);
5475
5476            start = textIndex + searchList[replaceIndex].length();
5477
5478            textIndex = -1;
5479            replaceIndex = -1;
5480            tempIndex = -1;
5481            // find the next earliest match
5482            // NOTE: logic mostly duplicated above START
5483            for (int i = 0; i < searchLength; i++) {
5484                if (noMoreMatchesForReplIndex[i] || searchList[i] == null ||
5485                        searchList[i].isEmpty() || replacementList[i] == null) {
5486                    continue;
5487                }
5488                tempIndex = text.indexOf(searchList[i], start);
5489
5490                // see if we need to keep searching for this
5491                if (tempIndex == -1) {
5492                    noMoreMatchesForReplIndex[i] = true;
5493                } else {
5494                    if (textIndex == -1 || tempIndex < textIndex) {
5495                        textIndex = tempIndex;
5496                        replaceIndex = i;
5497                    }
5498                }
5499            }
5500            // NOTE: logic duplicated above END
5501
5502        }
5503        final int textLength = text.length();
5504        for (int i = start; i < textLength; i++) {
5505            buf.append(text.charAt(i));
5506        }
5507        final String result = buf.toString();
5508        if (!repeat) {
5509            return result;
5510        }
5511
5512        return replaceEach(result, searchList, replacementList, repeat, timeToLive - 1);
5513    }
5514
5515    // Replace, character based
5516    //-----------------------------------------------------------------------
5517    /**
5518     * <p>Replaces all occurrences of a character in a String with another.
5519     * This is a null-safe version of {@link String#replace(char, char)}.</p>
5520     *
5521     * <p>A {@code null} string input returns {@code null}.
5522     * An empty ("") string input returns an empty string.</p>
5523     *
5524     * <pre>
5525     * StringUtils.replaceChars(null, *, *)        = null
5526     * StringUtils.replaceChars("", *, *)          = ""
5527     * StringUtils.replaceChars("abcba", 'b', 'y') = "aycya"
5528     * StringUtils.replaceChars("abcba", 'z', 'y') = "abcba"
5529     * </pre>
5530     *
5531     * @param str  String to replace characters in, may be null
5532     * @param searchChar  the character to search for, may be null
5533     * @param replaceChar  the character to replace, may be null
5534     * @return modified String, {@code null} if null string input
5535     * @since 2.0
5536     */
5537    public static String replaceChars(final String str, final char searchChar, final char replaceChar) {
5538        if (str == null) {
5539            return null;
5540        }
5541        return str.replace(searchChar, replaceChar);
5542    }
5543
5544    /**
5545     * <p>Replaces multiple characters in a String in one go.
5546     * This method can also be used to delete characters.</p>
5547     *
5548     * <p>For example:<br>
5549     * <code>replaceChars(&quot;hello&quot;, &quot;ho&quot;, &quot;jy&quot;) = jelly</code>.</p>
5550     *
5551     * <p>A {@code null} string input returns {@code null}.
5552     * An empty ("") string input returns an empty string.
5553     * A null or empty set of search characters returns the input string.</p>
5554     *
5555     * <p>The length of the search characters should normally equal the length
5556     * of the replace characters.
5557     * If the search characters is longer, then the extra search characters
5558     * are deleted.
5559     * If the search characters is shorter, then the extra replace characters
5560     * are ignored.</p>
5561     *
5562     * <pre>
5563     * StringUtils.replaceChars(null, *, *)           = null
5564     * StringUtils.replaceChars("", *, *)             = ""
5565     * StringUtils.replaceChars("abc", null, *)       = "abc"
5566     * StringUtils.replaceChars("abc", "", *)         = "abc"
5567     * StringUtils.replaceChars("abc", "b", null)     = "ac"
5568     * StringUtils.replaceChars("abc", "b", "")       = "ac"
5569     * StringUtils.replaceChars("abcba", "bc", "yz")  = "ayzya"
5570     * StringUtils.replaceChars("abcba", "bc", "y")   = "ayya"
5571     * StringUtils.replaceChars("abcba", "bc", "yzx") = "ayzya"
5572     * </pre>
5573     *
5574     * @param str  String to replace characters in, may be null
5575     * @param searchChars  a set of characters to search for, may be null
5576     * @param replaceChars  a set of characters to replace, may be null
5577     * @return modified String, {@code null} if null string input
5578     * @since 2.0
5579     */
5580    public static String replaceChars(final String str, final String searchChars, String replaceChars) {
5581        if (isEmpty(str) || isEmpty(searchChars)) {
5582            return str;
5583        }
5584        if (replaceChars == null) {
5585            replaceChars = EMPTY;
5586        }
5587        boolean modified = false;
5588        final int replaceCharsLength = replaceChars.length();
5589        final int strLength = str.length();
5590        final StringBuilder buf = new StringBuilder(strLength);
5591        for (int i = 0; i < strLength; i++) {
5592            final char ch = str.charAt(i);
5593            final int index = searchChars.indexOf(ch);
5594            if (index >= 0) {
5595                modified = true;
5596                if (index < replaceCharsLength) {
5597                    buf.append(replaceChars.charAt(index));
5598                }
5599            } else {
5600                buf.append(ch);
5601            }
5602        }
5603        if (modified) {
5604            return buf.toString();
5605        }
5606        return str;
5607    }
5608
5609    // Overlay
5610    //-----------------------------------------------------------------------
5611    /**
5612     * <p>Overlays part of a String with another String.</p>
5613     *
5614     * <p>A {@code null} string input returns {@code null}.
5615     * A negative index is treated as zero.
5616     * An index greater than the string length is treated as the string length.
5617     * The start index is always the smaller of the two indices.</p>
5618     *
5619     * <pre>
5620     * StringUtils.overlay(null, *, *, *)            = null
5621     * StringUtils.overlay("", "abc", 0, 0)          = "abc"
5622     * StringUtils.overlay("abcdef", null, 2, 4)     = "abef"
5623     * StringUtils.overlay("abcdef", "", 2, 4)       = "abef"
5624     * StringUtils.overlay("abcdef", "", 4, 2)       = "abef"
5625     * StringUtils.overlay("abcdef", "zzzz", 2, 4)   = "abzzzzef"
5626     * StringUtils.overlay("abcdef", "zzzz", 4, 2)   = "abzzzzef"
5627     * StringUtils.overlay("abcdef", "zzzz", -1, 4)  = "zzzzef"
5628     * StringUtils.overlay("abcdef", "zzzz", 2, 8)   = "abzzzz"
5629     * StringUtils.overlay("abcdef", "zzzz", -2, -3) = "zzzzabcdef"
5630     * StringUtils.overlay("abcdef", "zzzz", 8, 10)  = "abcdefzzzz"
5631     * </pre>
5632     *
5633     * @param str  the String to do overlaying in, may be null
5634     * @param overlay  the String to overlay, may be null
5635     * @param start  the position to start overlaying at
5636     * @param end  the position to stop overlaying before
5637     * @return overlayed String, {@code null} if null String input
5638     * @since 2.0
5639     */
5640    public static String overlay(final String str, String overlay, int start, int end) {
5641        if (str == null) {
5642            return null;
5643        }
5644        if (overlay == null) {
5645            overlay = EMPTY;
5646        }
5647        final int len = str.length();
5648        if (start < 0) {
5649            start = 0;
5650        }
5651        if (start > len) {
5652            start = len;
5653        }
5654        if (end < 0) {
5655            end = 0;
5656        }
5657        if (end > len) {
5658            end = len;
5659        }
5660        if (start > end) {
5661            final int temp = start;
5662            start = end;
5663            end = temp;
5664        }
5665        return new StringBuilder(len + start - end + overlay.length() + 1)
5666            .append(str.substring(0, start))
5667            .append(overlay)
5668            .append(str.substring(end))
5669            .toString();
5670    }
5671
5672    // Chomping
5673    //-----------------------------------------------------------------------
5674    /**
5675     * <p>Removes one newline from end of a String if it's there,
5676     * otherwise leave it alone.  A newline is &quot;{@code \n}&quot;,
5677     * &quot;{@code \r}&quot;, or &quot;{@code \r\n}&quot;.</p>
5678     *
5679     * <p>NOTE: This method changed in 2.0.
5680     * It now more closely matches Perl chomp.</p>
5681     *
5682     * <pre>
5683     * StringUtils.chomp(null)          = null
5684     * StringUtils.chomp("")            = ""
5685     * StringUtils.chomp("abc \r")      = "abc "
5686     * StringUtils.chomp("abc\n")       = "abc"
5687     * StringUtils.chomp("abc\r\n")     = "abc"
5688     * StringUtils.chomp("abc\r\n\r\n") = "abc\r\n"
5689     * StringUtils.chomp("abc\n\r")     = "abc\n"
5690     * StringUtils.chomp("abc\n\rabc")  = "abc\n\rabc"
5691     * StringUtils.chomp("\r")          = ""
5692     * StringUtils.chomp("\n")          = ""
5693     * StringUtils.chomp("\r\n")        = ""
5694     * </pre>
5695     *
5696     * @param str  the String to chomp a newline from, may be null
5697     * @return String without newline, {@code null} if null String input
5698     */
5699    public static String chomp(final String str) {
5700        if (isEmpty(str)) {
5701            return str;
5702        }
5703
5704        if (str.length() == 1) {
5705            final char ch = str.charAt(0);
5706            if (ch == CharUtils.CR || ch == CharUtils.LF) {
5707                return EMPTY;
5708            }
5709            return str;
5710        }
5711
5712        int lastIdx = str.length() - 1;
5713        final char last = str.charAt(lastIdx);
5714
5715        if (last == CharUtils.LF) {
5716            if (str.charAt(lastIdx - 1) == CharUtils.CR) {
5717                lastIdx--;
5718            }
5719        } else if (last != CharUtils.CR) {
5720            lastIdx++;
5721        }
5722        return str.substring(0, lastIdx);
5723    }
5724
5725    /**
5726     * <p>Removes {@code separator} from the end of
5727     * {@code str} if it's there, otherwise leave it alone.</p>
5728     *
5729     * <p>NOTE: This method changed in version 2.0.
5730     * It now more closely matches Perl chomp.
5731     * For the previous behavior, use {@link #substringBeforeLast(String, String)}.
5732     * This method uses {@link String#endsWith(String)}.</p>
5733     *
5734     * <pre>
5735     * StringUtils.chomp(null, *)         = null
5736     * StringUtils.chomp("", *)           = ""
5737     * StringUtils.chomp("foobar", "bar") = "foo"
5738     * StringUtils.chomp("foobar", "baz") = "foobar"
5739     * StringUtils.chomp("foo", "foo")    = ""
5740     * StringUtils.chomp("foo ", "foo")   = "foo "
5741     * StringUtils.chomp(" foo", "foo")   = " "
5742     * StringUtils.chomp("foo", "foooo")  = "foo"
5743     * StringUtils.chomp("foo", "")       = "foo"
5744     * StringUtils.chomp("foo", null)     = "foo"
5745     * </pre>
5746     *
5747     * @param str  the String to chomp from, may be null
5748     * @param separator  separator String, may be null
5749     * @return String without trailing separator, {@code null} if null String input
5750     * @deprecated This feature will be removed in Lang 4.0, use {@link StringUtils#removeEnd(String, String)} instead
5751     */
5752    @Deprecated
5753    public static String chomp(final String str, final String separator) {
5754        return removeEnd(str,separator);
5755    }
5756
5757    // Chopping
5758    //-----------------------------------------------------------------------
5759    /**
5760     * <p>Remove the last character from a String.</p>
5761     *
5762     * <p>If the String ends in {@code \r\n}, then remove both
5763     * of them.</p>
5764     *
5765     * <pre>
5766     * StringUtils.chop(null)          = null
5767     * StringUtils.chop("")            = ""
5768     * StringUtils.chop("abc \r")      = "abc "
5769     * StringUtils.chop("abc\n")       = "abc"
5770     * StringUtils.chop("abc\r\n")     = "abc"
5771     * StringUtils.chop("abc")         = "ab"
5772     * StringUtils.chop("abc\nabc")    = "abc\nab"
5773     * StringUtils.chop("a")           = ""
5774     * StringUtils.chop("\r")          = ""
5775     * StringUtils.chop("\n")          = ""
5776     * StringUtils.chop("\r\n")        = ""
5777     * </pre>
5778     *
5779     * @param str  the String to chop last character from, may be null
5780     * @return String without last character, {@code null} if null String input
5781     */
5782    public static String chop(final String str) {
5783        if (str == null) {
5784            return null;
5785        }
5786        final int strLen = str.length();
5787        if (strLen < 2) {
5788            return EMPTY;
5789        }
5790        final int lastIdx = strLen - 1;
5791        final String ret = str.substring(0, lastIdx);
5792        final char last = str.charAt(lastIdx);
5793        if (last == CharUtils.LF && ret.charAt(lastIdx - 1) == CharUtils.CR) {
5794            return ret.substring(0, lastIdx - 1);
5795        }
5796        return ret;
5797    }
5798
5799    // Conversion
5800    //-----------------------------------------------------------------------
5801
5802    // Padding
5803    //-----------------------------------------------------------------------
5804    /**
5805     * <p>Repeat a String {@code repeat} times to form a
5806     * new String.</p>
5807     *
5808     * <pre>
5809     * StringUtils.repeat(null, 2) = null
5810     * StringUtils.repeat("", 0)   = ""
5811     * StringUtils.repeat("", 2)   = ""
5812     * StringUtils.repeat("a", 3)  = "aaa"
5813     * StringUtils.repeat("ab", 2) = "abab"
5814     * StringUtils.repeat("a", -2) = ""
5815     * </pre>
5816     *
5817     * @param str  the String to repeat, may be null
5818     * @param repeat  number of times to repeat str, negative treated as zero
5819     * @return a new String consisting of the original String repeated,
5820     *  {@code null} if null String input
5821     */
5822    public static String repeat(final String str, final int repeat) {
5823        // Performance tuned for 2.0 (JDK1.4)
5824
5825        if (str == null) {
5826            return null;
5827        }
5828        if (repeat <= 0) {
5829            return EMPTY;
5830        }
5831        final int inputLength = str.length();
5832        if (repeat == 1 || inputLength == 0) {
5833            return str;
5834        }
5835        if (inputLength == 1 && repeat <= PAD_LIMIT) {
5836            return repeat(str.charAt(0), repeat);
5837        }
5838
5839        final int outputLength = inputLength * repeat;
5840        switch (inputLength) {
5841            case 1 :
5842                return repeat(str.charAt(0), repeat);
5843            case 2 :
5844                final char ch0 = str.charAt(0);
5845                final char ch1 = str.charAt(1);
5846                final char[] output2 = new char[outputLength];
5847                for (int i = repeat * 2 - 2; i >= 0; i--, i--) {
5848                    output2[i] = ch0;
5849                    output2[i + 1] = ch1;
5850                }
5851                return new String(output2);
5852            default :
5853                final StringBuilder buf = new StringBuilder(outputLength);
5854                for (int i = 0; i < repeat; i++) {
5855                    buf.append(str);
5856                }
5857                return buf.toString();
5858        }
5859    }
5860
5861    /**
5862     * <p>Repeat a String {@code repeat} times to form a
5863     * new String, with a String separator injected each time. </p>
5864     *
5865     * <pre>
5866     * StringUtils.repeat(null, null, 2) = null
5867     * StringUtils.repeat(null, "x", 2)  = null
5868     * StringUtils.repeat("", null, 0)   = ""
5869     * StringUtils.repeat("", "", 2)     = ""
5870     * StringUtils.repeat("", "x", 3)    = "xxx"
5871     * StringUtils.repeat("?", ", ", 3)  = "?, ?, ?"
5872     * </pre>
5873     *
5874     * @param str        the String to repeat, may be null
5875     * @param separator  the String to inject, may be null
5876     * @param repeat     number of times to repeat str, negative treated as zero
5877     * @return a new String consisting of the original String repeated,
5878     *  {@code null} if null String input
5879     * @since 2.5
5880     */
5881    public static String repeat(final String str, final String separator, final int repeat) {
5882        if(str == null || separator == null) {
5883            return repeat(str, repeat);
5884        }
5885        // given that repeat(String, int) is quite optimized, better to rely on it than try and splice this into it
5886        final String result = repeat(str + separator, repeat);
5887        return removeEnd(result, separator);
5888    }
5889
5890    /**
5891     * <p>Returns padding using the specified delimiter repeated
5892     * to a given length.</p>
5893     *
5894     * <pre>
5895     * StringUtils.repeat('e', 0)  = ""
5896     * StringUtils.repeat('e', 3)  = "eee"
5897     * StringUtils.repeat('e', -2) = ""
5898     * </pre>
5899     *
5900     * <p>Note: this method doesn't not support padding with
5901     * <a href="http://www.unicode.org/glossary/#supplementary_character">Unicode Supplementary Characters</a>
5902     * as they require a pair of {@code char}s to be represented.
5903     * If you are needing to support full I18N of your applications
5904     * consider using {@link #repeat(String, int)} instead.
5905     * </p>
5906     *
5907     * @param ch  character to repeat
5908     * @param repeat  number of times to repeat char, negative treated as zero
5909     * @return String with repeated character
5910     * @see #repeat(String, int)
5911     */
5912    public static String repeat(final char ch, final int repeat) {
5913        if (repeat <= 0) {
5914            return EMPTY;
5915        }
5916        final char[] buf = new char[repeat];
5917        for (int i = repeat - 1; i >= 0; i--) {
5918            buf[i] = ch;
5919        }
5920        return new String(buf);
5921    }
5922
5923    /**
5924     * <p>Right pad a String with spaces (' ').</p>
5925     *
5926     * <p>The String is padded to the size of {@code size}.</p>
5927     *
5928     * <pre>
5929     * StringUtils.rightPad(null, *)   = null
5930     * StringUtils.rightPad("", 3)     = "   "
5931     * StringUtils.rightPad("bat", 3)  = "bat"
5932     * StringUtils.rightPad("bat", 5)  = "bat  "
5933     * StringUtils.rightPad("bat", 1)  = "bat"
5934     * StringUtils.rightPad("bat", -1) = "bat"
5935     * </pre>
5936     *
5937     * @param str  the String to pad out, may be null
5938     * @param size  the size to pad to
5939     * @return right padded String or original String if no padding is necessary,
5940     *  {@code null} if null String input
5941     */
5942    public static String rightPad(final String str, final int size) {
5943        return rightPad(str, size, ' ');
5944    }
5945
5946    /**
5947     * <p>Right pad a String with a specified character.</p>
5948     *
5949     * <p>The String is padded to the size of {@code size}.</p>
5950     *
5951     * <pre>
5952     * StringUtils.rightPad(null, *, *)     = null
5953     * StringUtils.rightPad("", 3, 'z')     = "zzz"
5954     * StringUtils.rightPad("bat", 3, 'z')  = "bat"
5955     * StringUtils.rightPad("bat", 5, 'z')  = "batzz"
5956     * StringUtils.rightPad("bat", 1, 'z')  = "bat"
5957     * StringUtils.rightPad("bat", -1, 'z') = "bat"
5958     * </pre>
5959     *
5960     * @param str  the String to pad out, may be null
5961     * @param size  the size to pad to
5962     * @param padChar  the character to pad with
5963     * @return right padded String or original String if no padding is necessary,
5964     *  {@code null} if null String input
5965     * @since 2.0
5966     */
5967    public static String rightPad(final String str, final int size, final char padChar) {
5968        if (str == null) {
5969            return null;
5970        }
5971        final int pads = size - str.length();
5972        if (pads <= 0) {
5973            return str; // returns original String when possible
5974        }
5975        if (pads > PAD_LIMIT) {
5976            return rightPad(str, size, String.valueOf(padChar));
5977        }
5978        return str.concat(repeat(padChar, pads));
5979    }
5980
5981    /**
5982     * <p>Right pad a String with a specified String.</p>
5983     *
5984     * <p>The String is padded to the size of {@code size}.</p>
5985     *
5986     * <pre>
5987     * StringUtils.rightPad(null, *, *)      = null
5988     * StringUtils.rightPad("", 3, "z")      = "zzz"
5989     * StringUtils.rightPad("bat", 3, "yz")  = "bat"
5990     * StringUtils.rightPad("bat", 5, "yz")  = "batyz"
5991     * StringUtils.rightPad("bat", 8, "yz")  = "batyzyzy"
5992     * StringUtils.rightPad("bat", 1, "yz")  = "bat"
5993     * StringUtils.rightPad("bat", -1, "yz") = "bat"
5994     * StringUtils.rightPad("bat", 5, null)  = "bat  "
5995     * StringUtils.rightPad("bat", 5, "")    = "bat  "
5996     * </pre>
5997     *
5998     * @param str  the String to pad out, may be null
5999     * @param size  the size to pad to
6000     * @param padStr  the String to pad with, null or empty treated as single space
6001     * @return right padded String or original String if no padding is necessary,
6002     *  {@code null} if null String input
6003     */
6004    public static String rightPad(final String str, final int size, String padStr) {
6005        if (str == null) {
6006            return null;
6007        }
6008        if (isEmpty(padStr)) {
6009            padStr = SPACE;
6010        }
6011        final int padLen = padStr.length();
6012        final int strLen = str.length();
6013        final int pads = size - strLen;
6014        if (pads <= 0) {
6015            return str; // returns original String when possible
6016        }
6017        if (padLen == 1 && pads <= PAD_LIMIT) {
6018            return rightPad(str, size, padStr.charAt(0));
6019        }
6020
6021        if (pads == padLen) {
6022            return str.concat(padStr);
6023        } else if (pads < padLen) {
6024            return str.concat(padStr.substring(0, pads));
6025        } else {
6026            final char[] padding = new char[pads];
6027            final char[] padChars = padStr.toCharArray();
6028            for (int i = 0; i < pads; i++) {
6029                padding[i] = padChars[i % padLen];
6030            }
6031            return str.concat(new String(padding));
6032        }
6033    }
6034
6035    /**
6036     * <p>Left pad a String with spaces (' ').</p>
6037     *
6038     * <p>The String is padded to the size of {@code size}.</p>
6039     *
6040     * <pre>
6041     * StringUtils.leftPad(null, *)   = null
6042     * StringUtils.leftPad("", 3)     = "   "
6043     * StringUtils.leftPad("bat", 3)  = "bat"
6044     * StringUtils.leftPad("bat", 5)  = "  bat"
6045     * StringUtils.leftPad("bat", 1)  = "bat"
6046     * StringUtils.leftPad("bat", -1) = "bat"
6047     * </pre>
6048     *
6049     * @param str  the String to pad out, may be null
6050     * @param size  the size to pad to
6051     * @return left padded String or original String if no padding is necessary,
6052     *  {@code null} if null String input
6053     */
6054    public static String leftPad(final String str, final int size) {
6055        return leftPad(str, size, ' ');
6056    }
6057
6058    /**
6059     * <p>Left pad a String with a specified character.</p>
6060     *
6061     * <p>Pad to a size of {@code size}.</p>
6062     *
6063     * <pre>
6064     * StringUtils.leftPad(null, *, *)     = null
6065     * StringUtils.leftPad("", 3, 'z')     = "zzz"
6066     * StringUtils.leftPad("bat", 3, 'z')  = "bat"
6067     * StringUtils.leftPad("bat", 5, 'z')  = "zzbat"
6068     * StringUtils.leftPad("bat", 1, 'z')  = "bat"
6069     * StringUtils.leftPad("bat", -1, 'z') = "bat"
6070     * </pre>
6071     *
6072     * @param str  the String to pad out, may be null
6073     * @param size  the size to pad to
6074     * @param padChar  the character to pad with
6075     * @return left padded String or original String if no padding is necessary,
6076     *  {@code null} if null String input
6077     * @since 2.0
6078     */
6079    public static String leftPad(final String str, final int size, final char padChar) {
6080        if (str == null) {
6081            return null;
6082        }
6083        final int pads = size - str.length();
6084        if (pads <= 0) {
6085            return str; // returns original String when possible
6086        }
6087        if (pads > PAD_LIMIT) {
6088            return leftPad(str, size, String.valueOf(padChar));
6089        }
6090        return repeat(padChar, pads).concat(str);
6091    }
6092
6093    /**
6094     * <p>Left pad a String with a specified String.</p>
6095     *
6096     * <p>Pad to a size of {@code size}.</p>
6097     *
6098     * <pre>
6099     * StringUtils.leftPad(null, *, *)      = null
6100     * StringUtils.leftPad("", 3, "z")      = "zzz"
6101     * StringUtils.leftPad("bat", 3, "yz")  = "bat"
6102     * StringUtils.leftPad("bat", 5, "yz")  = "yzbat"
6103     * StringUtils.leftPad("bat", 8, "yz")  = "yzyzybat"
6104     * StringUtils.leftPad("bat", 1, "yz")  = "bat"
6105     * StringUtils.leftPad("bat", -1, "yz") = "bat"
6106     * StringUtils.leftPad("bat", 5, null)  = "  bat"
6107     * StringUtils.leftPad("bat", 5, "")    = "  bat"
6108     * </pre>
6109     *
6110     * @param str  the String to pad out, may be null
6111     * @param size  the size to pad to
6112     * @param padStr  the String to pad with, null or empty treated as single space
6113     * @return left padded String or original String if no padding is necessary,
6114     *  {@code null} if null String input
6115     */
6116    public static String leftPad(final String str, final int size, String padStr) {
6117        if (str == null) {
6118            return null;
6119        }
6120        if (isEmpty(padStr)) {
6121            padStr = SPACE;
6122        }
6123        final int padLen = padStr.length();
6124        final int strLen = str.length();
6125        final int pads = size - strLen;
6126        if (pads <= 0) {
6127            return str; // returns original String when possible
6128        }
6129        if (padLen == 1 && pads <= PAD_LIMIT) {
6130            return leftPad(str, size, padStr.charAt(0));
6131        }
6132
6133        if (pads == padLen) {
6134            return padStr.concat(str);
6135        } else if (pads < padLen) {
6136            return padStr.substring(0, pads).concat(str);
6137        } else {
6138            final char[] padding = new char[pads];
6139            final char[] padChars = padStr.toCharArray();
6140            for (int i = 0; i < pads; i++) {
6141                padding[i] = padChars[i % padLen];
6142            }
6143            return new String(padding).concat(str);
6144        }
6145    }
6146
6147    /**
6148     * Gets a CharSequence length or {@code 0} if the CharSequence is
6149     * {@code null}.
6150     *
6151     * @param cs
6152     *            a CharSequence or {@code null}
6153     * @return CharSequence length or {@code 0} if the CharSequence is
6154     *         {@code null}.
6155     * @since 2.4
6156     * @since 3.0 Changed signature from length(String) to length(CharSequence)
6157     */
6158    public static int length(final CharSequence cs) {
6159        return cs == null ? 0 : cs.length();
6160    }
6161
6162    // Centering
6163    //-----------------------------------------------------------------------
6164    /**
6165     * <p>Centers a String in a larger String of size {@code size}
6166     * using the space character (' ').</p>
6167     *
6168     * <p>If the size is less than the String length, the String is returned.
6169     * A {@code null} String returns {@code null}.
6170     * A negative size is treated as zero.</p>
6171     *
6172     * <p>Equivalent to {@code center(str, size, " ")}.</p>
6173     *
6174     * <pre>
6175     * StringUtils.center(null, *)   = null
6176     * StringUtils.center("", 4)     = "    "
6177     * StringUtils.center("ab", -1)  = "ab"
6178     * StringUtils.center("ab", 4)   = " ab "
6179     * StringUtils.center("abcd", 2) = "abcd"
6180     * StringUtils.center("a", 4)    = " a  "
6181     * </pre>
6182     *
6183     * @param str  the String to center, may be null
6184     * @param size  the int size of new String, negative treated as zero
6185     * @return centered String, {@code null} if null String input
6186     */
6187    public static String center(final String str, final int size) {
6188        return center(str, size, ' ');
6189    }
6190
6191    /**
6192     * <p>Centers a String in a larger String of size {@code size}.
6193     * Uses a supplied character as the value to pad the String with.</p>
6194     *
6195     * <p>If the size is less than the String length, the String is returned.
6196     * A {@code null} String returns {@code null}.
6197     * A negative size is treated as zero.</p>
6198     *
6199     * <pre>
6200     * StringUtils.center(null, *, *)     = null
6201     * StringUtils.center("", 4, ' ')     = "    "
6202     * StringUtils.center("ab", -1, ' ')  = "ab"
6203     * StringUtils.center("ab", 4, ' ')   = " ab "
6204     * StringUtils.center("abcd", 2, ' ') = "abcd"
6205     * StringUtils.center("a", 4, ' ')    = " a  "
6206     * StringUtils.center("a", 4, 'y')    = "yayy"
6207     * </pre>
6208     *
6209     * @param str  the String to center, may be null
6210     * @param size  the int size of new String, negative treated as zero
6211     * @param padChar  the character to pad the new String with
6212     * @return centered String, {@code null} if null String input
6213     * @since 2.0
6214     */
6215    public static String center(String str, final int size, final char padChar) {
6216        if (str == null || size <= 0) {
6217            return str;
6218        }
6219        final int strLen = str.length();
6220        final int pads = size - strLen;
6221        if (pads <= 0) {
6222            return str;
6223        }
6224        str = leftPad(str, strLen + pads / 2, padChar);
6225        str = rightPad(str, size, padChar);
6226        return str;
6227    }
6228
6229    /**
6230     * <p>Centers a String in a larger String of size {@code size}.
6231     * Uses a supplied String as the value to pad the String with.</p>
6232     *
6233     * <p>If the size is less than the String length, the String is returned.
6234     * A {@code null} String returns {@code null}.
6235     * A negative size is treated as zero.</p>
6236     *
6237     * <pre>
6238     * StringUtils.center(null, *, *)     = null
6239     * StringUtils.center("", 4, " ")     = "    "
6240     * StringUtils.center("ab", -1, " ")  = "ab"
6241     * StringUtils.center("ab", 4, " ")   = " ab "
6242     * StringUtils.center("abcd", 2, " ") = "abcd"
6243     * StringUtils.center("a", 4, " ")    = " a  "
6244     * StringUtils.center("a", 4, "yz")   = "yayz"
6245     * StringUtils.center("abc", 7, null) = "  abc  "
6246     * StringUtils.center("abc", 7, "")   = "  abc  "
6247     * </pre>
6248     *
6249     * @param str  the String to center, may be null
6250     * @param size  the int size of new String, negative treated as zero
6251     * @param padStr  the String to pad the new String with, must not be null or empty
6252     * @return centered String, {@code null} if null String input
6253     * @throws IllegalArgumentException if padStr is {@code null} or empty
6254     */
6255    public static String center(String str, final int size, String padStr) {
6256        if (str == null || size <= 0) {
6257            return str;
6258        }
6259        if (isEmpty(padStr)) {
6260            padStr = SPACE;
6261        }
6262        final int strLen = str.length();
6263        final int pads = size - strLen;
6264        if (pads <= 0) {
6265            return str;
6266        }
6267        str = leftPad(str, strLen + pads / 2, padStr);
6268        str = rightPad(str, size, padStr);
6269        return str;
6270    }
6271
6272    // Case conversion
6273    //-----------------------------------------------------------------------
6274    /**
6275     * <p>Converts a String to upper case as per {@link String#toUpperCase()}.</p>
6276     *
6277     * <p>A {@code null} input String returns {@code null}.</p>
6278     *
6279     * <pre>
6280     * StringUtils.upperCase(null)  = null
6281     * StringUtils.upperCase("")    = ""
6282     * StringUtils.upperCase("aBc") = "ABC"
6283     * </pre>
6284     *
6285     * <p><strong>Note:</strong> As described in the documentation for {@link String#toUpperCase()},
6286     * the result of this method is affected by the current locale.
6287     * For platform-independent case transformations, the method {@link #lowerCase(String, Locale)}
6288     * should be used with a specific locale (e.g. {@link Locale#ENGLISH}).</p>
6289     *
6290     * @param str  the String to upper case, may be null
6291     * @return the upper cased String, {@code null} if null String input
6292     */
6293    public static String upperCase(final String str) {
6294        if (str == null) {
6295            return null;
6296        }
6297        return str.toUpperCase();
6298    }
6299
6300    /**
6301     * <p>Converts a String to upper case as per {@link String#toUpperCase(Locale)}.</p>
6302     *
6303     * <p>A {@code null} input String returns {@code null}.</p>
6304     *
6305     * <pre>
6306     * StringUtils.upperCase(null, Locale.ENGLISH)  = null
6307     * StringUtils.upperCase("", Locale.ENGLISH)    = ""
6308     * StringUtils.upperCase("aBc", Locale.ENGLISH) = "ABC"
6309     * </pre>
6310     *
6311     * @param str  the String to upper case, may be null
6312     * @param locale  the locale that defines the case transformation rules, must not be null
6313     * @return the upper cased String, {@code null} if null String input
6314     * @since 2.5
6315     */
6316    public static String upperCase(final String str, final Locale locale) {
6317        if (str == null) {
6318            return null;
6319        }
6320        return str.toUpperCase(locale);
6321    }
6322
6323    /**
6324     * <p>Converts a String to lower case as per {@link String#toLowerCase()}.</p>
6325     *
6326     * <p>A {@code null} input String returns {@code null}.</p>
6327     *
6328     * <pre>
6329     * StringUtils.lowerCase(null)  = null
6330     * StringUtils.lowerCase("")    = ""
6331     * StringUtils.lowerCase("aBc") = "abc"
6332     * </pre>
6333     *
6334     * <p><strong>Note:</strong> As described in the documentation for {@link String#toLowerCase()},
6335     * the result of this method is affected by the current locale.
6336     * For platform-independent case transformations, the method {@link #lowerCase(String, Locale)}
6337     * should be used with a specific locale (e.g. {@link Locale#ENGLISH}).</p>
6338     *
6339     * @param str  the String to lower case, may be null
6340     * @return the lower cased String, {@code null} if null String input
6341     */
6342    public static String lowerCase(final String str) {
6343        if (str == null) {
6344            return null;
6345        }
6346        return str.toLowerCase();
6347    }
6348
6349    /**
6350     * <p>Converts a String to lower case as per {@link String#toLowerCase(Locale)}.</p>
6351     *
6352     * <p>A {@code null} input String returns {@code null}.</p>
6353     *
6354     * <pre>
6355     * StringUtils.lowerCase(null, Locale.ENGLISH)  = null
6356     * StringUtils.lowerCase("", Locale.ENGLISH)    = ""
6357     * StringUtils.lowerCase("aBc", Locale.ENGLISH) = "abc"
6358     * </pre>
6359     *
6360     * @param str  the String to lower case, may be null
6361     * @param locale  the locale that defines the case transformation rules, must not be null
6362     * @return the lower cased String, {@code null} if null String input
6363     * @since 2.5
6364     */
6365    public static String lowerCase(final String str, final Locale locale) {
6366        if (str == null) {
6367            return null;
6368        }
6369        return str.toLowerCase(locale);
6370    }
6371
6372    /**
6373     * <p>Capitalizes a String changing the first character to title case as
6374     * per {@link Character#toTitleCase(char)}. No other characters are changed.</p>
6375     *
6376     * <p>For a word based algorithm, see {@link org.apache.commons.lang3.text.WordUtils#capitalize(String)}.
6377     * A {@code null} input String returns {@code null}.</p>
6378     *
6379     * <pre>
6380     * StringUtils.capitalize(null)  = null
6381     * StringUtils.capitalize("")    = ""
6382     * StringUtils.capitalize("cat") = "Cat"
6383     * StringUtils.capitalize("cAt") = "CAt"
6384     * StringUtils.capitalize("'cat'") = "'cat'"
6385     * </pre>
6386     *
6387     * @param str the String to capitalize, may be null
6388     * @return the capitalized String, {@code null} if null String input
6389     * @see org.apache.commons.lang3.text.WordUtils#capitalize(String)
6390     * @see #uncapitalize(String)
6391     * @since 2.0
6392     */
6393    public static String capitalize(final String str) {
6394        int strLen;
6395        if (str == null || (strLen = str.length()) == 0) {
6396            return str;
6397        }
6398
6399        final char firstChar = str.charAt(0);
6400        final char newChar = Character.toTitleCase(firstChar);
6401        if (firstChar == newChar) {
6402            // already capitalized
6403            return str;
6404        }
6405
6406        char[] newChars = new char[strLen];
6407        newChars[0] = newChar;
6408        str.getChars(1,strLen, newChars, 1);
6409        return String.valueOf(newChars);
6410    }
6411
6412    /**
6413     * <p>Uncapitalizes a String, changing the first character to lower case as
6414     * per {@link Character#toLowerCase(char)}. No other characters are changed.</p>
6415     *
6416     * <p>For a word based algorithm, see {@link org.apache.commons.lang3.text.WordUtils#uncapitalize(String)}.
6417     * A {@code null} input String returns {@code null}.</p>
6418     *
6419     * <pre>
6420     * StringUtils.uncapitalize(null)  = null
6421     * StringUtils.uncapitalize("")    = ""
6422     * StringUtils.uncapitalize("cat") = "cat"
6423     * StringUtils.uncapitalize("Cat") = "cat"
6424     * StringUtils.uncapitalize("CAT") = "cAT"
6425     * </pre>
6426     *
6427     * @param str the String to uncapitalize, may be null
6428     * @return the uncapitalized String, {@code null} if null String input
6429     * @see org.apache.commons.lang3.text.WordUtils#uncapitalize(String)
6430     * @see #capitalize(String)
6431     * @since 2.0
6432     */
6433    public static String uncapitalize(final String str) {
6434        int strLen;
6435        if (str == null || (strLen = str.length()) == 0) {
6436            return str;
6437        }
6438
6439        final char firstChar = str.charAt(0);
6440        final char newChar = Character.toLowerCase(firstChar);
6441        if (firstChar == newChar) {
6442            // already uncapitalized
6443            return str;
6444        }
6445
6446        char[] newChars = new char[strLen];
6447        newChars[0] = newChar;
6448        str.getChars(1,strLen, newChars, 1);
6449        return String.valueOf(newChars);
6450    }
6451
6452    /**
6453     * <p>Swaps the case of a String changing upper and title case to
6454     * lower case, and lower case to upper case.</p>
6455     *
6456     * <ul>
6457     *  <li>Upper case character converts to Lower case</li>
6458     *  <li>Title case character converts to Lower case</li>
6459     *  <li>Lower case character converts to Upper case</li>
6460     * </ul>
6461     *
6462     * <p>For a word based algorithm, see {@link org.apache.commons.lang3.text.WordUtils#swapCase(String)}.
6463     * A {@code null} input String returns {@code null}.</p>
6464     *
6465     * <pre>
6466     * StringUtils.swapCase(null)                 = null
6467     * StringUtils.swapCase("")                   = ""
6468     * StringUtils.swapCase("The dog has a BONE") = "tHE DOG HAS A bone"
6469     * </pre>
6470     *
6471     * <p>NOTE: This method changed in Lang version 2.0.
6472     * It no longer performs a word based algorithm.
6473     * If you only use ASCII, you will notice no change.
6474     * That functionality is available in org.apache.commons.lang3.text.WordUtils.</p>
6475     *
6476     * @param str  the String to swap case, may be null
6477     * @return the changed String, {@code null} if null String input
6478     */
6479    public static String swapCase(final String str) {
6480        if (StringUtils.isEmpty(str)) {
6481            return str;
6482        }
6483
6484        final char[] buffer = str.toCharArray();
6485
6486        for (int i = 0; i < buffer.length; i++) {
6487            final char ch = buffer[i];
6488            if (Character.isUpperCase(ch)) {
6489                buffer[i] = Character.toLowerCase(ch);
6490            } else if (Character.isTitleCase(ch)) {
6491                buffer[i] = Character.toLowerCase(ch);
6492            } else if (Character.isLowerCase(ch)) {
6493                buffer[i] = Character.toUpperCase(ch);
6494            }
6495        }
6496        return new String(buffer);
6497    }
6498
6499    // Count matches
6500    //-----------------------------------------------------------------------
6501    /**
6502     * <p>Counts how many times the substring appears in the larger string.</p>
6503     *
6504     * <p>A {@code null} or empty ("") String input returns {@code 0}.</p>
6505     *
6506     * <pre>
6507     * StringUtils.countMatches(null, *)       = 0
6508     * StringUtils.countMatches("", *)         = 0
6509     * StringUtils.countMatches("abba", null)  = 0
6510     * StringUtils.countMatches("abba", "")    = 0
6511     * StringUtils.countMatches("abba", "a")   = 2
6512     * StringUtils.countMatches("abba", "ab")  = 1
6513     * StringUtils.countMatches("abba", "xxx") = 0
6514     * </pre>
6515     *
6516     * @param str  the CharSequence to check, may be null
6517     * @param sub  the substring to count, may be null
6518     * @return the number of occurrences, 0 if either CharSequence is {@code null}
6519     * @since 3.0 Changed signature from countMatches(String, String) to countMatches(CharSequence, CharSequence)
6520     */
6521    public static int countMatches(final CharSequence str, final CharSequence sub) {
6522        if (isEmpty(str) || isEmpty(sub)) {
6523            return 0;
6524        }
6525        int count = 0;
6526        int idx = 0;
6527        while ((idx = CharSequenceUtils.indexOf(str, sub, idx)) != INDEX_NOT_FOUND) {
6528            count++;
6529            idx += sub.length();
6530        }
6531        return count;
6532    }
6533
6534    /**
6535     * <p>Counts how many times the char appears in the given string.</p>
6536     *
6537     * <p>A {@code null} or empty ("") String input returns {@code 0}.</p>
6538     *
6539     * <pre>
6540     * StringUtils.countMatches(null, *)       = 0
6541     * StringUtils.countMatches("", *)         = 0
6542     * StringUtils.countMatches("abba", 0)  = 0
6543     * StringUtils.countMatches("abba", 'a')   = 2
6544     * StringUtils.countMatches("abba", 'b')  = 2
6545     * StringUtils.countMatches("abba", 'x') = 0
6546     * </pre>
6547     *
6548     * @param str  the CharSequence to check, may be null
6549     * @param ch  the char to count
6550     * @return the number of occurrences, 0 if the CharSequence is {@code null}
6551     * @since 3.4
6552     */
6553    public static int countMatches(final CharSequence str, final char ch) {
6554        if (isEmpty(str)) {
6555            return 0;
6556        }
6557        int count = 0;
6558        // We could also call str.toCharArray() for faster look ups but that would generate more garbage.
6559        for (int i = 0; i < str.length(); i++) {
6560            if (ch == str.charAt(i)) {
6561                count++;
6562            }
6563        }
6564        return count;
6565    }
6566
6567    // Character Tests
6568    //-----------------------------------------------------------------------
6569    /**
6570     * <p>Checks if the CharSequence contains only Unicode letters.</p>
6571     *
6572     * <p>{@code null} will return {@code false}.
6573     * An empty CharSequence (length()=0) will return {@code false}.</p>
6574     *
6575     * <pre>
6576     * StringUtils.isAlpha(null)   = false
6577     * StringUtils.isAlpha("")     = false
6578     * StringUtils.isAlpha("  ")   = false
6579     * StringUtils.isAlpha("abc")  = true
6580     * StringUtils.isAlpha("ab2c") = false
6581     * StringUtils.isAlpha("ab-c") = false
6582     * </pre>
6583     *
6584     * @param cs  the CharSequence to check, may be null
6585     * @return {@code true} if only contains letters, and is non-null
6586     * @since 3.0 Changed signature from isAlpha(String) to isAlpha(CharSequence)
6587     * @since 3.0 Changed "" to return false and not true
6588     */
6589    public static boolean isAlpha(final CharSequence cs) {
6590        if (isEmpty(cs)) {
6591            return false;
6592        }
6593        final int sz = cs.length();
6594        for (int i = 0; i < sz; i++) {
6595            if (Character.isLetter(cs.charAt(i)) == false) {
6596                return false;
6597            }
6598        }
6599        return true;
6600    }
6601
6602    /**
6603     * <p>Checks if the CharSequence contains only Unicode letters and
6604     * space (' ').</p>
6605     *
6606     * <p>{@code null} will return {@code false}
6607     * An empty CharSequence (length()=0) will return {@code true}.</p>
6608     *
6609     * <pre>
6610     * StringUtils.isAlphaSpace(null)   = false
6611     * StringUtils.isAlphaSpace("")     = true
6612     * StringUtils.isAlphaSpace("  ")   = true
6613     * StringUtils.isAlphaSpace("abc")  = true
6614     * StringUtils.isAlphaSpace("ab c") = true
6615     * StringUtils.isAlphaSpace("ab2c") = false
6616     * StringUtils.isAlphaSpace("ab-c") = false
6617     * </pre>
6618     *
6619     * @param cs  the CharSequence to check, may be null
6620     * @return {@code true} if only contains letters and space,
6621     *  and is non-null
6622     * @since 3.0 Changed signature from isAlphaSpace(String) to isAlphaSpace(CharSequence)
6623     */
6624    public static boolean isAlphaSpace(final CharSequence cs) {
6625        if (cs == null) {
6626            return false;
6627        }
6628        final int sz = cs.length();
6629        for (int i = 0; i < sz; i++) {
6630            if (Character.isLetter(cs.charAt(i)) == false && cs.charAt(i) != ' ') {
6631                return false;
6632            }
6633        }
6634        return true;
6635    }
6636
6637    /**
6638     * <p>Checks if the CharSequence contains only Unicode letters or digits.</p>
6639     *
6640     * <p>{@code null} will return {@code false}.
6641     * An empty CharSequence (length()=0) will return {@code false}.</p>
6642     *
6643     * <pre>
6644     * StringUtils.isAlphanumeric(null)   = false
6645     * StringUtils.isAlphanumeric("")     = false
6646     * StringUtils.isAlphanumeric("  ")   = false
6647     * StringUtils.isAlphanumeric("abc")  = true
6648     * StringUtils.isAlphanumeric("ab c") = false
6649     * StringUtils.isAlphanumeric("ab2c") = true
6650     * StringUtils.isAlphanumeric("ab-c") = false
6651     * </pre>
6652     *
6653     * @param cs  the CharSequence to check, may be null
6654     * @return {@code true} if only contains letters or digits,
6655     *  and is non-null
6656     * @since 3.0 Changed signature from isAlphanumeric(String) to isAlphanumeric(CharSequence)
6657     * @since 3.0 Changed "" to return false and not true
6658     */
6659    public static boolean isAlphanumeric(final CharSequence cs) {
6660        if (isEmpty(cs)) {
6661            return false;
6662        }
6663        final int sz = cs.length();
6664        for (int i = 0; i < sz; i++) {
6665            if (Character.isLetterOrDigit(cs.charAt(i)) == false) {
6666                return false;
6667            }
6668        }
6669        return true;
6670    }
6671
6672    /**
6673     * <p>Checks if the CharSequence contains only Unicode letters, digits
6674     * or space ({@code ' '}).</p>
6675     *
6676     * <p>{@code null} will return {@code false}.
6677     * An empty CharSequence (length()=0) will return {@code true}.</p>
6678     *
6679     * <pre>
6680     * StringUtils.isAlphanumericSpace(null)   = false
6681     * StringUtils.isAlphanumericSpace("")     = true
6682     * StringUtils.isAlphanumericSpace("  ")   = true
6683     * StringUtils.isAlphanumericSpace("abc")  = true
6684     * StringUtils.isAlphanumericSpace("ab c") = true
6685     * StringUtils.isAlphanumericSpace("ab2c") = true
6686     * StringUtils.isAlphanumericSpace("ab-c") = false
6687     * </pre>
6688     *
6689     * @param cs  the CharSequence to check, may be null
6690     * @return {@code true} if only contains letters, digits or space,
6691     *  and is non-null
6692     * @since 3.0 Changed signature from isAlphanumericSpace(String) to isAlphanumericSpace(CharSequence)
6693     */
6694    public static boolean isAlphanumericSpace(final CharSequence cs) {
6695        if (cs == null) {
6696            return false;
6697        }
6698        final int sz = cs.length();
6699        for (int i = 0; i < sz; i++) {
6700            if (Character.isLetterOrDigit(cs.charAt(i)) == false && cs.charAt(i) != ' ') {
6701                return false;
6702            }
6703        }
6704        return true;
6705    }
6706
6707    /**
6708     * <p>Checks if the CharSequence contains only ASCII printable characters.</p>
6709     *
6710     * <p>{@code null} will return {@code false}.
6711     * An empty CharSequence (length()=0) will return {@code true}.</p>
6712     *
6713     * <pre>
6714     * StringUtils.isAsciiPrintable(null)     = false
6715     * StringUtils.isAsciiPrintable("")       = true
6716     * StringUtils.isAsciiPrintable(" ")      = true
6717     * StringUtils.isAsciiPrintable("Ceki")   = true
6718     * StringUtils.isAsciiPrintable("ab2c")   = true
6719     * StringUtils.isAsciiPrintable("!ab-c~") = true
6720     * StringUtils.isAsciiPrintable("\u0020") = true
6721     * StringUtils.isAsciiPrintable("\u0021") = true
6722     * StringUtils.isAsciiPrintable("\u007e") = true
6723     * StringUtils.isAsciiPrintable("\u007f") = false
6724     * StringUtils.isAsciiPrintable("Ceki G\u00fclc\u00fc") = false
6725     * </pre>
6726     *
6727     * @param cs the CharSequence to check, may be null
6728     * @return {@code true} if every character is in the range
6729     *  32 thru 126
6730     * @since 2.1
6731     * @since 3.0 Changed signature from isAsciiPrintable(String) to isAsciiPrintable(CharSequence)
6732     */
6733    public static boolean isAsciiPrintable(final CharSequence cs) {
6734        if (cs == null) {
6735            return false;
6736        }
6737        final int sz = cs.length();
6738        for (int i = 0; i < sz; i++) {
6739            if (CharUtils.isAsciiPrintable(cs.charAt(i)) == false) {
6740                return false;
6741            }
6742        }
6743        return true;
6744    }
6745
6746    /**
6747     * <p>Checks if the CharSequence contains only Unicode digits.
6748     * A decimal point is not a Unicode digit and returns false.</p>
6749     *
6750     * <p>{@code null} will return {@code false}.
6751     * An empty CharSequence (length()=0) will return {@code false}.</p>
6752     *
6753     * <p>Note that the method does not allow for a leading sign, either positive or negative.
6754     * Also, if a String passes the numeric test, it may still generate a NumberFormatException
6755     * when parsed by Integer.parseInt or Long.parseLong, e.g. if the value is outside the range
6756     * for int or long respectively.</p>
6757     *
6758     * <pre>
6759     * StringUtils.isNumeric(null)   = false
6760     * StringUtils.isNumeric("")     = false
6761     * StringUtils.isNumeric("  ")   = false
6762     * StringUtils.isNumeric("123")  = true
6763     * StringUtils.isNumeric("\u0967\u0968\u0969")  = true
6764     * StringUtils.isNumeric("12 3") = false
6765     * StringUtils.isNumeric("ab2c") = false
6766     * StringUtils.isNumeric("12-3") = false
6767     * StringUtils.isNumeric("12.3") = false
6768     * StringUtils.isNumeric("-123") = false
6769     * StringUtils.isNumeric("+123") = false
6770     * </pre>
6771     *
6772     * @param cs  the CharSequence to check, may be null
6773     * @return {@code true} if only contains digits, and is non-null
6774     * @since 3.0 Changed signature from isNumeric(String) to isNumeric(CharSequence)
6775     * @since 3.0 Changed "" to return false and not true
6776     */
6777    public static boolean isNumeric(final CharSequence cs) {
6778        if (isEmpty(cs)) {
6779            return false;
6780        }
6781        final int sz = cs.length();
6782        for (int i = 0; i < sz; i++) {
6783            if (!Character.isDigit(cs.charAt(i))) {
6784                return false;
6785            }
6786        }
6787        return true;
6788    }
6789
6790    /**
6791     * <p>Checks if the CharSequence contains only Unicode digits or space
6792     * ({@code ' '}).
6793     * A decimal point is not a Unicode digit and returns false.</p>
6794     *
6795     * <p>{@code null} will return {@code false}.
6796     * An empty CharSequence (length()=0) will return {@code true}.</p>
6797     *
6798     * <pre>
6799     * StringUtils.isNumericSpace(null)   = false
6800     * StringUtils.isNumericSpace("")     = true
6801     * StringUtils.isNumericSpace("  ")   = true
6802     * StringUtils.isNumericSpace("123")  = true
6803     * StringUtils.isNumericSpace("12 3") = true
6804     * StringUtils.isNumeric("\u0967\u0968\u0969")  = true
6805     * StringUtils.isNumeric("\u0967\u0968 \u0969")  = true
6806     * StringUtils.isNumericSpace("ab2c") = false
6807     * StringUtils.isNumericSpace("12-3") = false
6808     * StringUtils.isNumericSpace("12.3") = false
6809     * </pre>
6810     *
6811     * @param cs  the CharSequence to check, may be null
6812     * @return {@code true} if only contains digits or space,
6813     *  and is non-null
6814     * @since 3.0 Changed signature from isNumericSpace(String) to isNumericSpace(CharSequence)
6815     */
6816    public static boolean isNumericSpace(final CharSequence cs) {
6817        if (cs == null) {
6818            return false;
6819        }
6820        final int sz = cs.length();
6821        for (int i = 0; i < sz; i++) {
6822            if (Character.isDigit(cs.charAt(i)) == false && cs.charAt(i) != ' ') {
6823                return false;
6824            }
6825        }
6826        return true;
6827    }
6828
6829    /**
6830     * <p>Checks if the CharSequence contains only whitespace.</p>
6831     *
6832     * <p>{@code null} will return {@code false}.
6833     * An empty CharSequence (length()=0) will return {@code true}.</p>
6834     *
6835     * <pre>
6836     * StringUtils.isWhitespace(null)   = false
6837     * StringUtils.isWhitespace("")     = true
6838     * StringUtils.isWhitespace("  ")   = true
6839     * StringUtils.isWhitespace("abc")  = false
6840     * StringUtils.isWhitespace("ab2c") = false
6841     * StringUtils.isWhitespace("ab-c") = false
6842     * </pre>
6843     *
6844     * @param cs  the CharSequence to check, may be null
6845     * @return {@code true} if only contains whitespace, and is non-null
6846     * @since 2.0
6847     * @since 3.0 Changed signature from isWhitespace(String) to isWhitespace(CharSequence)
6848     */
6849    public static boolean isWhitespace(final CharSequence cs) {
6850        if (cs == null) {
6851            return false;
6852        }
6853        final int sz = cs.length();
6854        for (int i = 0; i < sz; i++) {
6855            if (Character.isWhitespace(cs.charAt(i)) == false) {
6856                return false;
6857            }
6858        }
6859        return true;
6860    }
6861
6862    /**
6863     * <p>Checks if the CharSequence contains only lowercase characters.</p>
6864     *
6865     * <p>{@code null} will return {@code false}.
6866     * An empty CharSequence (length()=0) will return {@code false}.</p>
6867     *
6868     * <pre>
6869     * StringUtils.isAllLowerCase(null)   = false
6870     * StringUtils.isAllLowerCase("")     = false
6871     * StringUtils.isAllLowerCase("  ")   = false
6872     * StringUtils.isAllLowerCase("abc")  = true
6873     * StringUtils.isAllLowerCase("abC")  = false
6874     * StringUtils.isAllLowerCase("ab c") = false
6875     * StringUtils.isAllLowerCase("ab1c") = false
6876     * StringUtils.isAllLowerCase("ab/c") = false
6877     * </pre>
6878     *
6879     * @param cs  the CharSequence to check, may be null
6880     * @return {@code true} if only contains lowercase characters, and is non-null
6881     * @since 2.5
6882     * @since 3.0 Changed signature from isAllLowerCase(String) to isAllLowerCase(CharSequence)
6883     */
6884    public static boolean isAllLowerCase(final CharSequence cs) {
6885        if (cs == null || isEmpty(cs)) {
6886            return false;
6887        }
6888        final int sz = cs.length();
6889        for (int i = 0; i < sz; i++) {
6890            if (Character.isLowerCase(cs.charAt(i)) == false) {
6891                return false;
6892            }
6893        }
6894        return true;
6895    }
6896
6897    /**
6898     * <p>Checks if the CharSequence contains only uppercase characters.</p>
6899     *
6900     * <p>{@code null} will return {@code false}.
6901     * An empty String (length()=0) will return {@code false}.</p>
6902     *
6903     * <pre>
6904     * StringUtils.isAllUpperCase(null)   = false
6905     * StringUtils.isAllUpperCase("")     = false
6906     * StringUtils.isAllUpperCase("  ")   = false
6907     * StringUtils.isAllUpperCase("ABC")  = true
6908     * StringUtils.isAllUpperCase("aBC")  = false
6909     * StringUtils.isAllUpperCase("A C")  = false
6910     * StringUtils.isAllUpperCase("A1C")  = false
6911     * StringUtils.isAllUpperCase("A/C")  = false
6912     * </pre>
6913     *
6914     * @param cs the CharSequence to check, may be null
6915     * @return {@code true} if only contains uppercase characters, and is non-null
6916     * @since 2.5
6917     * @since 3.0 Changed signature from isAllUpperCase(String) to isAllUpperCase(CharSequence)
6918     */
6919    public static boolean isAllUpperCase(final CharSequence cs) {
6920        if (cs == null || isEmpty(cs)) {
6921            return false;
6922        }
6923        final int sz = cs.length();
6924        for (int i = 0; i < sz; i++) {
6925            if (Character.isUpperCase(cs.charAt(i)) == false) {
6926                return false;
6927            }
6928        }
6929        return true;
6930    }
6931
6932    // Defaults
6933    //-----------------------------------------------------------------------
6934    /**
6935     * <p>Returns either the passed in String,
6936     * or if the String is {@code null}, an empty String ("").</p>
6937     *
6938     * <pre>
6939     * StringUtils.defaultString(null)  = ""
6940     * StringUtils.defaultString("")    = ""
6941     * StringUtils.defaultString("bat") = "bat"
6942     * </pre>
6943     *
6944     * @see ObjectUtils#toString(Object)
6945     * @see String#valueOf(Object)
6946     * @param str  the String to check, may be null
6947     * @return the passed in String, or the empty String if it
6948     *  was {@code null}
6949     */
6950    public static String defaultString(final String str) {
6951        return str == null ? EMPTY : str;
6952    }
6953
6954    /**
6955     * <p>Returns either the passed in String, or if the String is
6956     * {@code null}, the value of {@code defaultStr}.</p>
6957     *
6958     * <pre>
6959     * StringUtils.defaultString(null, "NULL")  = "NULL"
6960     * StringUtils.defaultString("", "NULL")    = ""
6961     * StringUtils.defaultString("bat", "NULL") = "bat"
6962     * </pre>
6963     *
6964     * @see ObjectUtils#toString(Object,String)
6965     * @see String#valueOf(Object)
6966     * @param str  the String to check, may be null
6967     * @param defaultStr  the default String to return
6968     *  if the input is {@code null}, may be null
6969     * @return the passed in String, or the default if it was {@code null}
6970     */
6971    public static String defaultString(final String str, final String defaultStr) {
6972        return str == null ? defaultStr : str;
6973    }
6974
6975    /**
6976     * <p>Returns either the passed in CharSequence, or if the CharSequence is
6977     * whitespace, empty ("") or {@code null}, the value of {@code defaultStr}.</p>
6978     *
6979     * <pre>
6980     * StringUtils.defaultIfBlank(null, "NULL")  = "NULL"
6981     * StringUtils.defaultIfBlank("", "NULL")    = "NULL"
6982     * StringUtils.defaultIfBlank(" ", "NULL")   = "NULL"
6983     * StringUtils.defaultIfBlank("bat", "NULL") = "bat"
6984     * StringUtils.defaultIfBlank("", null)      = null
6985     * </pre>
6986     * @param <T> the specific kind of CharSequence
6987     * @param str the CharSequence to check, may be null
6988     * @param defaultStr  the default CharSequence to return
6989     *  if the input is whitespace, empty ("") or {@code null}, may be null
6990     * @return the passed in CharSequence, or the default
6991     * @see StringUtils#defaultString(String, String)
6992     */
6993    public static <T extends CharSequence> T defaultIfBlank(final T str, final T defaultStr) {
6994        return isBlank(str) ? defaultStr : str;
6995    }
6996
6997    /**
6998     * <p>Returns either the passed in CharSequence, or if the CharSequence is
6999     * empty or {@code null}, the value of {@code defaultStr}.</p>
7000     *
7001     * <pre>
7002     * StringUtils.defaultIfEmpty(null, "NULL")  = "NULL"
7003     * StringUtils.defaultIfEmpty("", "NULL")    = "NULL"
7004     * StringUtils.defaultIfEmpty(" ", "NULL")   = " "
7005     * StringUtils.defaultIfEmpty("bat", "NULL") = "bat"
7006     * StringUtils.defaultIfEmpty("", null)      = null
7007     * </pre>
7008     * @param <T> the specific kind of CharSequence
7009     * @param str  the CharSequence to check, may be null
7010     * @param defaultStr  the default CharSequence to return
7011     *  if the input is empty ("") or {@code null}, may be null
7012     * @return the passed in CharSequence, or the default
7013     * @see StringUtils#defaultString(String, String)
7014     */
7015    public static <T extends CharSequence> T defaultIfEmpty(final T str, final T defaultStr) {
7016        return isEmpty(str) ? defaultStr : str;
7017    }
7018
7019    // Rotating (circular shift)
7020    //-----------------------------------------------------------------------
7021    /**
7022     * <p>Rotate (circular shift) a String of {@code shift} characters.</p>
7023     * <ul>
7024     *  <li>If {@code shift > 0}, right circular shift (ex : ABCDEF =&gt; FABCDE)</li>
7025     *  <li>If {@code shift < 0}, left circular shift (ex : ABCDEF =&gt; BCDEFA)</li>
7026     * </ul>
7027     *
7028     * <pre>
7029     * StringUtils.rotate(null, *)        = null
7030     * StringUtils.rotate("", *)          = ""
7031     * StringUtils.rotate("abcdefg", 0)   = "abcdefg"
7032     * StringUtils.rotate("abcdefg", 2)   = "fgabcde"
7033     * StringUtils.rotate("abcdefg", -2)  = "cdefgab"
7034     * StringUtils.rotate("abcdefg", 7)   = "abcdefg"
7035     * StringUtils.rotate("abcdefg", -7)  = "abcdefg"
7036     * StringUtils.rotate("abcdefg", 9)   = "fgabcde"
7037     * StringUtils.rotate("abcdefg", -9)  = "cdefgab"
7038     * </pre>
7039     *
7040     * @param str  the String to rotate, may be null
7041     * @param shift  number of time to shift (positive : right shift, negative : left shift)
7042     * @return the rotated String,
7043     *          or the original String if {@code shift == 0},
7044     *          or {@code null} if null String input
7045     */
7046    public static String rotate(String str, int shift) {
7047        if (str == null) {
7048            return null;
7049        }
7050
7051        final int strLen = str.length();
7052        if (shift == 0 || strLen == 0 || shift % strLen == 0) {
7053            return str;
7054        }
7055
7056        final StringBuilder builder = new StringBuilder(strLen);
7057        final int offset = - (shift % strLen);
7058        builder.append(substring(str, offset));
7059        builder.append(substring(str, 0, offset));
7060        return builder.toString();
7061    }
7062
7063    // Reversing
7064    //-----------------------------------------------------------------------
7065    /**
7066     * <p>Reverses a String as per {@link StringBuilder#reverse()}.</p>
7067     *
7068     * <p>A {@code null} String returns {@code null}.</p>
7069     *
7070     * <pre>
7071     * StringUtils.reverse(null)  = null
7072     * StringUtils.reverse("")    = ""
7073     * StringUtils.reverse("bat") = "tab"
7074     * </pre>
7075     *
7076     * @param str  the String to reverse, may be null
7077     * @return the reversed String, {@code null} if null String input
7078     */
7079    public static String reverse(final String str) {
7080        if (str == null) {
7081            return null;
7082        }
7083        return new StringBuilder(str).reverse().toString();
7084    }
7085
7086    /**
7087     * <p>Reverses a String that is delimited by a specific character.</p>
7088     *
7089     * <p>The Strings between the delimiters are not reversed.
7090     * Thus java.lang.String becomes String.lang.java (if the delimiter
7091     * is {@code '.'}).</p>
7092     *
7093     * <pre>
7094     * StringUtils.reverseDelimited(null, *)      = null
7095     * StringUtils.reverseDelimited("", *)        = ""
7096     * StringUtils.reverseDelimited("a.b.c", 'x') = "a.b.c"
7097     * StringUtils.reverseDelimited("a.b.c", ".") = "c.b.a"
7098     * </pre>
7099     *
7100     * @param str  the String to reverse, may be null
7101     * @param separatorChar  the separator character to use
7102     * @return the reversed String, {@code null} if null String input
7103     * @since 2.0
7104     */
7105    public static String reverseDelimited(final String str, final char separatorChar) {
7106        if (str == null) {
7107            return null;
7108        }
7109        // could implement manually, but simple way is to reuse other,
7110        // probably slower, methods.
7111        final String[] strs = split(str, separatorChar);
7112        ArrayUtils.reverse(strs);
7113        return join(strs, separatorChar);
7114    }
7115
7116    // Abbreviating
7117    //-----------------------------------------------------------------------
7118    /**
7119     * <p>Abbreviates a String using ellipses. This will turn
7120     * "Now is the time for all good men" into "Now is the time for..."</p>
7121     *
7122     * <p>Specifically:</p>
7123     * <ul>
7124     *   <li>If the number of characters in {@code str} is less than or equal to 
7125     *       {@code maxWidth}, return {@code str}.</li>
7126     *   <li>Else abbreviate it to {@code (substring(str, 0, max-3) + "...")}.</li>
7127     *   <li>If {@code maxWidth} is less than {@code 4}, throw an
7128     *       {@code IllegalArgumentException}.</li>
7129     *   <li>In no case will it return a String of length greater than
7130     *       {@code maxWidth}.</li>
7131     * </ul>
7132     *
7133     * <pre>
7134     * StringUtils.abbreviate(null, *)      = null
7135     * StringUtils.abbreviate("", 4)        = ""
7136     * StringUtils.abbreviate("abcdefg", 6) = "abc..."
7137     * StringUtils.abbreviate("abcdefg", 7) = "abcdefg"
7138     * StringUtils.abbreviate("abcdefg", 8) = "abcdefg"
7139     * StringUtils.abbreviate("abcdefg", 4) = "a..."
7140     * StringUtils.abbreviate("abcdefg", 3) = IllegalArgumentException
7141     * </pre>
7142     *
7143     * @param str  the String to check, may be null
7144     * @param maxWidth  maximum length of result String, must be at least 4
7145     * @return abbreviated String, {@code null} if null String input
7146     * @throws IllegalArgumentException if the width is too small
7147     * @since 2.0
7148     */
7149    public static String abbreviate(final String str, final int maxWidth) {
7150        return abbreviate(str, 0, maxWidth);
7151    }
7152
7153    /**
7154     * <p>Abbreviates a String using ellipses. This will turn
7155     * "Now is the time for all good men" into "...is the time for..."</p>
7156     *
7157     * <p>Works like {@code abbreviate(String, int)}, but allows you to specify
7158     * a "left edge" offset.  Note that this left edge is not necessarily going to
7159     * be the leftmost character in the result, or the first character following the
7160     * ellipses, but it will appear somewhere in the result.
7161     *
7162     * <p>In no case will it return a String of length greater than
7163     * {@code maxWidth}.</p>
7164     *
7165     * <pre>
7166     * StringUtils.abbreviate(null, *, *)                = null
7167     * StringUtils.abbreviate("", 0, 4)                  = ""
7168     * StringUtils.abbreviate("abcdefghijklmno", -1, 10) = "abcdefg..."
7169     * StringUtils.abbreviate("abcdefghijklmno", 0, 10)  = "abcdefg..."
7170     * StringUtils.abbreviate("abcdefghijklmno", 1, 10)  = "abcdefg..."
7171     * StringUtils.abbreviate("abcdefghijklmno", 4, 10)  = "abcdefg..."
7172     * StringUtils.abbreviate("abcdefghijklmno", 5, 10)  = "...fghi..."
7173     * StringUtils.abbreviate("abcdefghijklmno", 6, 10)  = "...ghij..."
7174     * StringUtils.abbreviate("abcdefghijklmno", 8, 10)  = "...ijklmno"
7175     * StringUtils.abbreviate("abcdefghijklmno", 10, 10) = "...ijklmno"
7176     * StringUtils.abbreviate("abcdefghijklmno", 12, 10) = "...ijklmno"
7177     * StringUtils.abbreviate("abcdefghij", 0, 3)        = IllegalArgumentException
7178     * StringUtils.abbreviate("abcdefghij", 5, 6)        = IllegalArgumentException
7179     * </pre>
7180     *
7181     * @param str  the String to check, may be null
7182     * @param offset  left edge of source String
7183     * @param maxWidth  maximum length of result String, must be at least 4
7184     * @return abbreviated String, {@code null} if null String input
7185     * @throws IllegalArgumentException if the width is too small
7186     * @since 2.0
7187     */
7188    public static String abbreviate(final String str, int offset, final int maxWidth) {
7189        if (str == null) {
7190            return null;
7191        }
7192        if (maxWidth < 4) {
7193            throw new IllegalArgumentException("Minimum abbreviation width is 4");
7194        }
7195        if (str.length() <= maxWidth) {
7196            return str;
7197        }
7198        if (offset > str.length()) {
7199            offset = str.length();
7200        }
7201        if (str.length() - offset < maxWidth - 3) {
7202            offset = str.length() - (maxWidth - 3);
7203        }
7204        final String abrevMarker = "...";
7205        if (offset <= 4) {
7206            return str.substring(0, maxWidth - 3) + abrevMarker;
7207        }
7208        if (maxWidth < 7) {
7209            throw new IllegalArgumentException("Minimum abbreviation width with offset is 7");
7210        }
7211        if (offset + maxWidth - 3 < str.length()) {
7212            return abrevMarker + abbreviate(str.substring(offset), maxWidth - 3);
7213        }
7214        return abrevMarker + str.substring(str.length() - (maxWidth - 3));
7215    }
7216
7217    /**
7218     * <p>Abbreviates a String to the length passed, replacing the middle characters with the supplied
7219     * replacement String.</p>
7220     *
7221     * <p>This abbreviation only occurs if the following criteria is met:</p>
7222     * <ul>
7223     * <li>Neither the String for abbreviation nor the replacement String are null or empty </li>
7224     * <li>The length to truncate to is less than the length of the supplied String</li>
7225     * <li>The length to truncate to is greater than 0</li>
7226     * <li>The abbreviated String will have enough room for the length supplied replacement String
7227     * and the first and last characters of the supplied String for abbreviation</li>
7228     * </ul>
7229     * <p>Otherwise, the returned String will be the same as the supplied String for abbreviation.
7230     * </p>
7231     *
7232     * <pre>
7233     * StringUtils.abbreviateMiddle(null, null, 0)      = null
7234     * StringUtils.abbreviateMiddle("abc", null, 0)      = "abc"
7235     * StringUtils.abbreviateMiddle("abc", ".", 0)      = "abc"
7236     * StringUtils.abbreviateMiddle("abc", ".", 3)      = "abc"
7237     * StringUtils.abbreviateMiddle("abcdef", ".", 4)     = "ab.f"
7238     * </pre>
7239     *
7240     * @param str  the String to abbreviate, may be null
7241     * @param middle the String to replace the middle characters with, may be null
7242     * @param length the length to abbreviate {@code str} to.
7243     * @return the abbreviated String if the above criteria is met, or the original String supplied for abbreviation.
7244     * @since 2.5
7245     */
7246    public static String abbreviateMiddle(final String str, final String middle, final int length) {
7247        if (isEmpty(str) || isEmpty(middle)) {
7248            return str;
7249        }
7250
7251        if (length >= str.length() || length < middle.length()+2) {
7252            return str;
7253        }
7254
7255        final int targetSting = length-middle.length();
7256        final int startOffset = targetSting/2+targetSting%2;
7257        final int endOffset = str.length()-targetSting/2;
7258
7259        final StringBuilder builder = new StringBuilder(length);
7260        builder.append(str.substring(0,startOffset));
7261        builder.append(middle);
7262        builder.append(str.substring(endOffset));
7263
7264        return builder.toString();
7265    }
7266
7267    // Difference
7268    //-----------------------------------------------------------------------
7269    /**
7270     * <p>Compares two Strings, and returns the portion where they differ.
7271     * More precisely, return the remainder of the second String,
7272     * starting from where it's different from the first. This means that
7273     * the difference between "abc" and "ab" is the empty String and not "c". </p>
7274     *
7275     * <p>For example,
7276     * {@code difference("i am a machine", "i am a robot") -> "robot"}.</p>
7277     *
7278     * <pre>
7279     * StringUtils.difference(null, null) = null
7280     * StringUtils.difference("", "") = ""
7281     * StringUtils.difference("", "abc") = "abc"
7282     * StringUtils.difference("abc", "") = ""
7283     * StringUtils.difference("abc", "abc") = ""
7284     * StringUtils.difference("abc", "ab") = ""
7285     * StringUtils.difference("ab", "abxyz") = "xyz"
7286     * StringUtils.difference("abcde", "abxyz") = "xyz"
7287     * StringUtils.difference("abcde", "xyz") = "xyz"
7288     * </pre>
7289     *
7290     * @param str1  the first String, may be null
7291     * @param str2  the second String, may be null
7292     * @return the portion of str2 where it differs from str1; returns the
7293     * empty String if they are equal
7294     * @see #indexOfDifference(CharSequence,CharSequence)
7295     * @since 2.0
7296     */
7297    public static String difference(final String str1, final String str2) {
7298        if (str1 == null) {
7299            return str2;
7300        }
7301        if (str2 == null) {
7302            return str1;
7303        }
7304        final int at = indexOfDifference(str1, str2);
7305        if (at == INDEX_NOT_FOUND) {
7306            return EMPTY;
7307        }
7308        return str2.substring(at);
7309    }
7310
7311    /**
7312     * <p>Compares two CharSequences, and returns the index at which the
7313     * CharSequences begin to differ.</p>
7314     *
7315     * <p>For example,
7316     * {@code indexOfDifference("i am a machine", "i am a robot") -> 7}</p>
7317     *
7318     * <pre>
7319     * StringUtils.indexOfDifference(null, null) = -1
7320     * StringUtils.indexOfDifference("", "") = -1
7321     * StringUtils.indexOfDifference("", "abc") = 0
7322     * StringUtils.indexOfDifference("abc", "") = 0
7323     * StringUtils.indexOfDifference("abc", "abc") = -1
7324     * StringUtils.indexOfDifference("ab", "abxyz") = 2
7325     * StringUtils.indexOfDifference("abcde", "abxyz") = 2
7326     * StringUtils.indexOfDifference("abcde", "xyz") = 0
7327     * </pre>
7328     *
7329     * @param cs1  the first CharSequence, may be null
7330     * @param cs2  the second CharSequence, may be null
7331     * @return the index where cs1 and cs2 begin to differ; -1 if they are equal
7332     * @since 2.0
7333     * @since 3.0 Changed signature from indexOfDifference(String, String) to
7334     * indexOfDifference(CharSequence, CharSequence)
7335     */
7336    public static int indexOfDifference(final CharSequence cs1, final CharSequence cs2) {
7337        if (cs1 == cs2) {
7338            return INDEX_NOT_FOUND;
7339        }
7340        if (cs1 == null || cs2 == null) {
7341            return 0;
7342        }
7343        int i;
7344        for (i = 0; i < cs1.length() && i < cs2.length(); ++i) {
7345            if (cs1.charAt(i) != cs2.charAt(i)) {
7346                break;
7347            }
7348        }
7349        if (i < cs2.length() || i < cs1.length()) {
7350            return i;
7351        }
7352        return INDEX_NOT_FOUND;
7353    }
7354
7355    /**
7356     * <p>Compares all CharSequences in an array and returns the index at which the
7357     * CharSequences begin to differ.</p>
7358     *
7359     * <p>For example,
7360     * <code>indexOfDifference(new String[] {"i am a machine", "i am a robot"}) -&gt; 7</code></p>
7361     *
7362     * <pre>
7363     * StringUtils.indexOfDifference(null) = -1
7364     * StringUtils.indexOfDifference(new String[] {}) = -1
7365     * StringUtils.indexOfDifference(new String[] {"abc"}) = -1
7366     * StringUtils.indexOfDifference(new String[] {null, null}) = -1
7367     * StringUtils.indexOfDifference(new String[] {"", ""}) = -1
7368     * StringUtils.indexOfDifference(new String[] {"", null}) = 0
7369     * StringUtils.indexOfDifference(new String[] {"abc", null, null}) = 0
7370     * StringUtils.indexOfDifference(new String[] {null, null, "abc"}) = 0
7371     * StringUtils.indexOfDifference(new String[] {"", "abc"}) = 0
7372     * StringUtils.indexOfDifference(new String[] {"abc", ""}) = 0
7373     * StringUtils.indexOfDifference(new String[] {"abc", "abc"}) = -1
7374     * StringUtils.indexOfDifference(new String[] {"abc", "a"}) = 1
7375     * StringUtils.indexOfDifference(new String[] {"ab", "abxyz"}) = 2
7376     * StringUtils.indexOfDifference(new String[] {"abcde", "abxyz"}) = 2
7377     * StringUtils.indexOfDifference(new String[] {"abcde", "xyz"}) = 0
7378     * StringUtils.indexOfDifference(new String[] {"xyz", "abcde"}) = 0
7379     * StringUtils.indexOfDifference(new String[] {"i am a machine", "i am a robot"}) = 7
7380     * </pre>
7381     *
7382     * @param css  array of CharSequences, entries may be null
7383     * @return the index where the strings begin to differ; -1 if they are all equal
7384     * @since 2.4
7385     * @since 3.0 Changed signature from indexOfDifference(String...) to indexOfDifference(CharSequence...)
7386     */
7387    public static int indexOfDifference(final CharSequence... css) {
7388        if (css == null || css.length <= 1) {
7389            return INDEX_NOT_FOUND;
7390        }
7391        boolean anyStringNull = false;
7392        boolean allStringsNull = true;
7393        final int arrayLen = css.length;
7394        int shortestStrLen = Integer.MAX_VALUE;
7395        int longestStrLen = 0;
7396
7397        // find the min and max string lengths; this avoids checking to make
7398        // sure we are not exceeding the length of the string each time through
7399        // the bottom loop.
7400        for (int i = 0; i < arrayLen; i++) {
7401            if (css[i] == null) {
7402                anyStringNull = true;
7403                shortestStrLen = 0;
7404            } else {
7405                allStringsNull = false;
7406                shortestStrLen = Math.min(css[i].length(), shortestStrLen);
7407                longestStrLen = Math.max(css[i].length(), longestStrLen);
7408            }
7409        }
7410
7411        // handle lists containing all nulls or all empty strings
7412        if (allStringsNull || longestStrLen == 0 && !anyStringNull) {
7413            return INDEX_NOT_FOUND;
7414        }
7415
7416        // handle lists containing some nulls or some empty strings
7417        if (shortestStrLen == 0) {
7418            return 0;
7419        }
7420
7421        // find the position with the first difference across all strings
7422        int firstDiff = -1;
7423        for (int stringPos = 0; stringPos < shortestStrLen; stringPos++) {
7424            final char comparisonChar = css[0].charAt(stringPos);
7425            for (int arrayPos = 1; arrayPos < arrayLen; arrayPos++) {
7426                if (css[arrayPos].charAt(stringPos) != comparisonChar) {
7427                    firstDiff = stringPos;
7428                    break;
7429                }
7430            }
7431            if (firstDiff != -1) {
7432                break;
7433            }
7434        }
7435
7436        if (firstDiff == -1 && shortestStrLen != longestStrLen) {
7437            // we compared all of the characters up to the length of the
7438            // shortest string and didn't find a match, but the string lengths
7439            // vary, so return the length of the shortest string.
7440            return shortestStrLen;
7441        }
7442        return firstDiff;
7443    }
7444
7445    /**
7446     * <p>Compares all Strings in an array and returns the initial sequence of
7447     * characters that is common to all of them.</p>
7448     *
7449     * <p>For example,
7450     * <code>getCommonPrefix(new String[] {"i am a machine", "i am a robot"}) -&gt; "i am a "</code></p>
7451     *
7452     * <pre>
7453     * StringUtils.getCommonPrefix(null) = ""
7454     * StringUtils.getCommonPrefix(new String[] {}) = ""
7455     * StringUtils.getCommonPrefix(new String[] {"abc"}) = "abc"
7456     * StringUtils.getCommonPrefix(new String[] {null, null}) = ""
7457     * StringUtils.getCommonPrefix(new String[] {"", ""}) = ""
7458     * StringUtils.getCommonPrefix(new String[] {"", null}) = ""
7459     * StringUtils.getCommonPrefix(new String[] {"abc", null, null}) = ""
7460     * StringUtils.getCommonPrefix(new String[] {null, null, "abc"}) = ""
7461     * StringUtils.getCommonPrefix(new String[] {"", "abc"}) = ""
7462     * StringUtils.getCommonPrefix(new String[] {"abc", ""}) = ""
7463     * StringUtils.getCommonPrefix(new String[] {"abc", "abc"}) = "abc"
7464     * StringUtils.getCommonPrefix(new String[] {"abc", "a"}) = "a"
7465     * StringUtils.getCommonPrefix(new String[] {"ab", "abxyz"}) = "ab"
7466     * StringUtils.getCommonPrefix(new String[] {"abcde", "abxyz"}) = "ab"
7467     * StringUtils.getCommonPrefix(new String[] {"abcde", "xyz"}) = ""
7468     * StringUtils.getCommonPrefix(new String[] {"xyz", "abcde"}) = ""
7469     * StringUtils.getCommonPrefix(new String[] {"i am a machine", "i am a robot"}) = "i am a "
7470     * </pre>
7471     *
7472     * @param strs  array of String objects, entries may be null
7473     * @return the initial sequence of characters that are common to all Strings
7474     * in the array; empty String if the array is null, the elements are all null
7475     * or if there is no common prefix.
7476     * @since 2.4
7477     */
7478    public static String getCommonPrefix(final String... strs) {
7479        if (strs == null || strs.length == 0) {
7480            return EMPTY;
7481        }
7482        final int smallestIndexOfDiff = indexOfDifference(strs);
7483        if (smallestIndexOfDiff == INDEX_NOT_FOUND) {
7484            // all strings were identical
7485            if (strs[0] == null) {
7486                return EMPTY;
7487            }
7488            return strs[0];
7489        } else if (smallestIndexOfDiff == 0) {
7490            // there were no common initial characters
7491            return EMPTY;
7492        } else {
7493            // we found a common initial character sequence
7494            return strs[0].substring(0, smallestIndexOfDiff);
7495        }
7496    }
7497
7498    // Misc
7499    //-----------------------------------------------------------------------
7500    /**
7501     * <p>Find the Levenshtein distance between two Strings.</p>
7502     *
7503     * <p>This is the number of changes needed to change one String into
7504     * another, where each change is a single character modification (deletion,
7505     * insertion or substitution).</p>
7506     *
7507     * <p>The previous implementation of the Levenshtein distance algorithm
7508     * was from <a href="https://web.archive.org/web/20120604192456/http://www.merriampark.com/ld.htm">
7509     * https://web.archive.org/web/20120604192456/http://www.merriampark.com/ld.htm</a></p>
7510     *
7511     * <p>Chas Emerick has written an implementation in Java, which avoids an OutOfMemoryError
7512     * which can occur when my Java implementation is used with very large strings.<br>
7513     * This implementation of the Levenshtein distance algorithm
7514     * is from <a href="https://web.archive.org/web/20120526085419/http://www.merriampark.com/ldjava.htm">
7515     * https://web.archive.org/web/20120526085419/http://www.merriampark.com/ldjava.htm</a></p>
7516     *
7517     * <pre>
7518     * StringUtils.getLevenshteinDistance(null, *)             = IllegalArgumentException
7519     * StringUtils.getLevenshteinDistance(*, null)             = IllegalArgumentException
7520     * StringUtils.getLevenshteinDistance("","")               = 0
7521     * StringUtils.getLevenshteinDistance("","a")              = 1
7522     * StringUtils.getLevenshteinDistance("aaapppp", "")       = 7
7523     * StringUtils.getLevenshteinDistance("frog", "fog")       = 1
7524     * StringUtils.getLevenshteinDistance("fly", "ant")        = 3
7525     * StringUtils.getLevenshteinDistance("elephant", "hippo") = 7
7526     * StringUtils.getLevenshteinDistance("hippo", "elephant") = 7
7527     * StringUtils.getLevenshteinDistance("hippo", "zzzzzzzz") = 8
7528     * StringUtils.getLevenshteinDistance("hello", "hallo")    = 1
7529     * </pre>
7530     *
7531     * @param s  the first String, must not be null
7532     * @param t  the second String, must not be null
7533     * @return result distance
7534     * @throws IllegalArgumentException if either String input {@code null}
7535     * @since 3.0 Changed signature from getLevenshteinDistance(String, String) to
7536     * getLevenshteinDistance(CharSequence, CharSequence)
7537     */
7538    public static int getLevenshteinDistance(CharSequence s, CharSequence t) {
7539        if (s == null || t == null) {
7540            throw new IllegalArgumentException("Strings must not be null");
7541        }
7542
7543        /*
7544           The difference between this impl. and the previous is that, rather
7545           than creating and retaining a matrix of size s.length() + 1 by t.length() + 1,
7546           we maintain two single-dimensional arrays of length s.length() + 1.  The first, d,
7547           is the 'current working' distance array that maintains the newest distance cost
7548           counts as we iterate through the characters of String s.  Each time we increment
7549           the index of String t we are comparing, d is copied to p, the second int[].  Doing so
7550           allows us to retain the previous cost counts as required by the algorithm (taking
7551           the minimum of the cost count to the left, up one, and diagonally up and to the left
7552           of the current cost count being calculated).  (Note that the arrays aren't really
7553           copied anymore, just switched...this is clearly much better than cloning an array
7554           or doing a System.arraycopy() each time  through the outer loop.)
7555
7556           Effectively, the difference between the two implementations is this one does not
7557           cause an out of memory condition when calculating the LD over two very large strings.
7558         */
7559
7560        int n = s.length(); // length of s
7561        int m = t.length(); // length of t
7562
7563        if (n == 0) {
7564            return m;
7565        } else if (m == 0) {
7566            return n;
7567        }
7568
7569        if (n > m) {
7570            // swap the input strings to consume less memory
7571            final CharSequence tmp = s;
7572            s = t;
7573            t = tmp;
7574            n = m;
7575            m = t.length();
7576        }
7577
7578        int p[] = new int[n + 1]; //'previous' cost array, horizontally
7579        int d[] = new int[n + 1]; // cost array, horizontally
7580        int _d[]; //placeholder to assist in swapping p and d
7581
7582        // indexes into strings s and t
7583        int i; // iterates through s
7584        int j; // iterates through t
7585
7586        char t_j; // jth character of t
7587
7588        int cost; // cost
7589
7590        for (i = 0; i <= n; i++) {
7591            p[i] = i;
7592        }
7593
7594        for (j = 1; j <= m; j++) {
7595            t_j = t.charAt(j - 1);
7596            d[0] = j;
7597
7598            for (i = 1; i <= n; i++) {
7599                cost = s.charAt(i - 1) == t_j ? 0 : 1;
7600                // minimum of cell to the left+1, to the top+1, diagonally left and up +cost
7601                d[i] = Math.min(Math.min(d[i - 1] + 1, p[i] + 1), p[i - 1] + cost);
7602            }
7603
7604            // copy current distance counts to 'previous row' distance counts
7605            _d = p;
7606            p = d;
7607            d = _d;
7608        }
7609
7610        // our last action in the above loop was to switch d and p, so p now
7611        // actually has the most recent cost counts
7612        return p[n];
7613    }
7614
7615    /**
7616     * <p>Find the Levenshtein distance between two Strings if it's less than or equal to a given
7617     * threshold.</p>
7618     *
7619     * <p>This is the number of changes needed to change one String into
7620     * another, where each change is a single character modification (deletion,
7621     * insertion or substitution).</p>
7622     *
7623     * <p>This implementation follows from Algorithms on Strings, Trees and Sequences by Dan Gusfield
7624     * and Chas Emerick's implementation of the Levenshtein distance algorithm from
7625     * <a href="http://www.merriampark.com/ld.htm">http://www.merriampark.com/ld.htm</a></p>
7626     *
7627     * <pre>
7628     * StringUtils.getLevenshteinDistance(null, *, *)             = IllegalArgumentException
7629     * StringUtils.getLevenshteinDistance(*, null, *)             = IllegalArgumentException
7630     * StringUtils.getLevenshteinDistance(*, *, -1)               = IllegalArgumentException
7631     * StringUtils.getLevenshteinDistance("","", 0)               = 0
7632     * StringUtils.getLevenshteinDistance("aaapppp", "", 8)       = 7
7633     * StringUtils.getLevenshteinDistance("aaapppp", "", 7)       = 7
7634     * StringUtils.getLevenshteinDistance("aaapppp", "", 6))      = -1
7635     * StringUtils.getLevenshteinDistance("elephant", "hippo", 7) = 7
7636     * StringUtils.getLevenshteinDistance("elephant", "hippo", 6) = -1
7637     * StringUtils.getLevenshteinDistance("hippo", "elephant", 7) = 7
7638     * StringUtils.getLevenshteinDistance("hippo", "elephant", 6) = -1
7639     * </pre>
7640     *
7641     * @param s  the first String, must not be null
7642     * @param t  the second String, must not be null
7643     * @param threshold the target threshold, must not be negative
7644     * @return result distance, or {@code -1} if the distance would be greater than the threshold
7645     * @throws IllegalArgumentException if either String input {@code null} or negative threshold
7646     */
7647    public static int getLevenshteinDistance(CharSequence s, CharSequence t, final int threshold) {
7648        if (s == null || t == null) {
7649            throw new IllegalArgumentException("Strings must not be null");
7650        }
7651        if (threshold < 0) {
7652            throw new IllegalArgumentException("Threshold must not be negative");
7653        }
7654
7655        /*
7656        This implementation only computes the distance if it's less than or equal to the
7657        threshold value, returning -1 if it's greater.  The advantage is performance: unbounded
7658        distance is O(nm), but a bound of k allows us to reduce it to O(km) time by only
7659        computing a diagonal stripe of width 2k + 1 of the cost table.
7660        It is also possible to use this to compute the unbounded Levenshtein distance by starting
7661        the threshold at 1 and doubling each time until the distance is found; this is O(dm), where
7662        d is the distance.
7663
7664        One subtlety comes from needing to ignore entries on the border of our stripe
7665        eg.
7666        p[] = |#|#|#|*
7667        d[] =  *|#|#|#|
7668        We must ignore the entry to the left of the leftmost member
7669        We must ignore the entry above the rightmost member
7670
7671        Another subtlety comes from our stripe running off the matrix if the strings aren't
7672        of the same size.  Since string s is always swapped to be the shorter of the two,
7673        the stripe will always run off to the upper right instead of the lower left of the matrix.
7674
7675        As a concrete example, suppose s is of length 5, t is of length 7, and our threshold is 1.
7676        In this case we're going to walk a stripe of length 3.  The matrix would look like so:
7677
7678           1 2 3 4 5
7679        1 |#|#| | | |
7680        2 |#|#|#| | |
7681        3 | |#|#|#| |
7682        4 | | |#|#|#|
7683        5 | | | |#|#|
7684        6 | | | | |#|
7685        7 | | | | | |
7686
7687        Note how the stripe leads off the table as there is no possible way to turn a string of length 5
7688        into one of length 7 in edit distance of 1.
7689
7690        Additionally, this implementation decreases memory usage by using two
7691        single-dimensional arrays and swapping them back and forth instead of allocating
7692        an entire n by m matrix.  This requires a few minor changes, such as immediately returning
7693        when it's detected that the stripe has run off the matrix and initially filling the arrays with
7694        large values so that entries we don't compute are ignored.
7695
7696        See Algorithms on Strings, Trees and Sequences by Dan Gusfield for some discussion.
7697         */
7698
7699        int n = s.length(); // length of s
7700        int m = t.length(); // length of t
7701
7702        // if one string is empty, the edit distance is necessarily the length of the other
7703        if (n == 0) {
7704            return m <= threshold ? m : -1;
7705        } else if (m == 0) {
7706            return n <= threshold ? n : -1;
7707        }
7708        // no need to calculate the distance if the length difference is greater than the threshold
7709        else if (Math.abs(n - m) > threshold) {
7710            return -1;
7711        }
7712
7713        if (n > m) {
7714            // swap the two strings to consume less memory
7715            final CharSequence tmp = s;
7716            s = t;
7717            t = tmp;
7718            n = m;
7719            m = t.length();
7720        }
7721
7722        int p[] = new int[n + 1]; // 'previous' cost array, horizontally
7723        int d[] = new int[n + 1]; // cost array, horizontally
7724        int _d[]; // placeholder to assist in swapping p and d
7725
7726        // fill in starting table values
7727        final int boundary = Math.min(n, threshold) + 1;
7728        for (int i = 0; i < boundary; i++) {
7729            p[i] = i;
7730        }
7731        // these fills ensure that the value above the rightmost entry of our
7732        // stripe will be ignored in following loop iterations
7733        Arrays.fill(p, boundary, p.length, Integer.MAX_VALUE);
7734        Arrays.fill(d, Integer.MAX_VALUE);
7735
7736        // iterates through t
7737        for (int j = 1; j <= m; j++) {
7738            final char t_j = t.charAt(j - 1); // jth character of t
7739            d[0] = j;
7740
7741            // compute stripe indices, constrain to array size
7742            final int min = Math.max(1, j - threshold);
7743            final int max = j > Integer.MAX_VALUE - threshold ? n : Math.min(n, j + threshold);
7744
7745            // the stripe may lead off of the table if s and t are of different sizes
7746            if (min > max) {
7747                return -1;
7748            }
7749
7750            // ignore entry left of leftmost
7751            if (min > 1) {
7752                d[min - 1] = Integer.MAX_VALUE;
7753            }
7754
7755            // iterates through [min, max] in s
7756            for (int i = min; i <= max; i++) {
7757                if (s.charAt(i - 1) == t_j) {
7758                    // diagonally left and up
7759                    d[i] = p[i - 1];
7760                } else {
7761                    // 1 + minimum of cell to the left, to the top, diagonally left and up
7762                    d[i] = 1 + Math.min(Math.min(d[i - 1], p[i]), p[i - 1]);
7763                }
7764            }
7765
7766            // copy current distance counts to 'previous row' distance counts
7767            _d = p;
7768            p = d;
7769            d = _d;
7770        }
7771
7772        // if p[n] is greater than the threshold, there's no guarantee on it being the correct
7773        // distance
7774        if (p[n] <= threshold) {
7775            return p[n];
7776        }
7777        return -1;
7778    }
7779    
7780    /**
7781     * <p>Find the Jaro Winkler Distance which indicates the similarity score between two Strings.</p>
7782     *
7783     * <p>The Jaro measure is the weighted sum of percentage of matched characters from each file and transposed characters. 
7784     * Winkler increased this measure for matching initial characters.</p>
7785     *
7786     * <p>This implementation is based on the Jaro Winkler similarity algorithm
7787     * 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>
7788     * 
7789     * <pre>
7790     * StringUtils.getJaroWinklerDistance(null, null)          = IllegalArgumentException
7791     * StringUtils.getJaroWinklerDistance("","")               = 0.0
7792     * StringUtils.getJaroWinklerDistance("","a")              = 0.0
7793     * StringUtils.getJaroWinklerDistance("aaapppp", "")       = 0.0
7794     * StringUtils.getJaroWinklerDistance("frog", "fog")       = 0.93
7795     * StringUtils.getJaroWinklerDistance("fly", "ant")        = 0.0
7796     * StringUtils.getJaroWinklerDistance("elephant", "hippo") = 0.44
7797     * StringUtils.getJaroWinklerDistance("hippo", "elephant") = 0.44
7798     * StringUtils.getJaroWinklerDistance("hippo", "zzzzzzzz") = 0.0
7799     * StringUtils.getJaroWinklerDistance("hello", "hallo")    = 0.88
7800     * StringUtils.getJaroWinklerDistance("ABC Corporation", "ABC Corp") = 0.93
7801     * StringUtils.getJaroWinklerDistance("D N H Enterprises Inc", "D &amp; H Enterprises, Inc.") = 0.95
7802     * StringUtils.getJaroWinklerDistance("My Gym Children's Fitness Center", "My Gym. Childrens Fitness") = 0.92
7803     * StringUtils.getJaroWinklerDistance("PENNSYLVANIA", "PENNCISYLVNIA") = 0.88
7804     * </pre>
7805     *
7806     * @param first the first String, must not be null
7807     * @param second the second String, must not be null
7808     * @return result distance
7809     * @throws IllegalArgumentException if either String input {@code null}
7810     * @since 3.3
7811     */
7812    public static double getJaroWinklerDistance(final CharSequence first, final CharSequence second) {
7813        final double DEFAULT_SCALING_FACTOR = 0.1;
7814
7815        if (first == null || second == null) {
7816            throw new IllegalArgumentException("Strings must not be null");
7817        }
7818
7819        int[] mtp = matches(first, second);
7820        double m = mtp[0];
7821        if (m == 0) {
7822            return 0D;
7823        }
7824        double j = ((m / first.length() + m / second.length() + (m - mtp[1]) / m)) / 3;
7825        double jw = j < 0.7D ? j : j + Math.min(DEFAULT_SCALING_FACTOR, 1D / mtp[3]) * mtp[2] * (1D - j);
7826        return Math.round(jw * 100.0D) / 100.0D;
7827    }
7828
7829    private static int[] matches(final CharSequence first, final CharSequence second) {
7830        CharSequence max, min;
7831        if (first.length() > second.length()) {
7832            max = first;
7833            min = second;
7834        } else {
7835            max = second;
7836            min = first;
7837        }
7838        int range = Math.max(max.length() / 2 - 1, 0);
7839        int[] matchIndexes = new int[min.length()];
7840        Arrays.fill(matchIndexes, -1);
7841        boolean[] matchFlags = new boolean[max.length()];
7842        int matches = 0;
7843        for (int mi = 0; mi < min.length(); mi++) {
7844            char c1 = min.charAt(mi);
7845            for (int xi = Math.max(mi - range, 0), xn = Math.min(mi + range + 1, max.length()); xi < xn; xi++) {
7846                if (!matchFlags[xi] && c1 == max.charAt(xi)) {
7847                    matchIndexes[mi] = xi;
7848                    matchFlags[xi] = true;
7849                    matches++;
7850                    break;
7851                }
7852            }
7853        }
7854        char[] ms1 = new char[matches];
7855        char[] ms2 = new char[matches];
7856        for (int i = 0, si = 0; i < min.length(); i++) {
7857            if (matchIndexes[i] != -1) {
7858                ms1[si] = min.charAt(i);
7859                si++;
7860            }
7861        }
7862        for (int i = 0, si = 0; i < max.length(); i++) {
7863            if (matchFlags[i]) {
7864                ms2[si] = max.charAt(i);
7865                si++;
7866            }
7867        }
7868        int transpositions = 0;
7869        for (int mi = 0; mi < ms1.length; mi++) {
7870            if (ms1[mi] != ms2[mi]) {
7871                transpositions++;
7872            }
7873        }
7874        int prefix = 0;
7875        for (int mi = 0; mi < min.length(); mi++) {
7876            if (first.charAt(mi) == second.charAt(mi)) {
7877                prefix++;
7878            } else {
7879                break;
7880            }
7881        }
7882        return new int[] { matches, transpositions / 2, prefix, max.length() };
7883    }
7884
7885    /**
7886     * <p>Find the Fuzzy Distance which indicates the similarity score between two Strings.</p>
7887     *
7888     * <p>This string matching algorithm is similar to the algorithms of editors such as Sublime Text,
7889     * TextMate, Atom and others. One point is given for every matched character. Subsequent
7890     * matches yield two bonus points. A higher score indicates a higher similarity.</p>
7891     *
7892     * <pre>
7893     * StringUtils.getFuzzyDistance(null, null, null)                                    = IllegalArgumentException
7894     * StringUtils.getFuzzyDistance("", "", Locale.ENGLISH)                              = 0
7895     * StringUtils.getFuzzyDistance("Workshop", "b", Locale.ENGLISH)                     = 0
7896     * StringUtils.getFuzzyDistance("Room", "o", Locale.ENGLISH)                         = 1
7897     * StringUtils.getFuzzyDistance("Workshop", "w", Locale.ENGLISH)                     = 1
7898     * StringUtils.getFuzzyDistance("Workshop", "ws", Locale.ENGLISH)                    = 2
7899     * StringUtils.getFuzzyDistance("Workshop", "wo", Locale.ENGLISH)                    = 4
7900     * StringUtils.getFuzzyDistance("Apache Software Foundation", "asf", Locale.ENGLISH) = 3
7901     * </pre>
7902     *
7903     * @param term a full term that should be matched against, must not be null
7904     * @param query the query that will be matched against a term, must not be null
7905     * @param locale This string matching logic is case insensitive. A locale is necessary to normalize
7906     *  both Strings to lower case.
7907     * @return result score
7908     * @throws IllegalArgumentException if either String input {@code null} or Locale input {@code null}
7909     * @since 3.4
7910     */
7911    public static int getFuzzyDistance(final CharSequence term, final CharSequence query, final Locale locale) {
7912        if (term == null || query == null) {
7913            throw new IllegalArgumentException("Strings must not be null");
7914        } else if (locale == null) {
7915            throw new IllegalArgumentException("Locale must not be null");
7916        }
7917
7918        // fuzzy logic is case insensitive. We normalize the Strings to lower
7919        // case right from the start. Turning characters to lower case
7920        // via Character.toLowerCase(char) is unfortunately insufficient
7921        // as it does not accept a locale.
7922        final String termLowerCase = term.toString().toLowerCase(locale);
7923        final String queryLowerCase = query.toString().toLowerCase(locale);
7924
7925        // the resulting score
7926        int score = 0;
7927
7928        // the position in the term which will be scanned next for potential
7929        // query character matches
7930        int termIndex = 0;
7931
7932        // index of the previously matched character in the term
7933        int previousMatchingCharacterIndex = Integer.MIN_VALUE;
7934
7935        for (int queryIndex = 0; queryIndex < queryLowerCase.length(); queryIndex++) {
7936            final char queryChar = queryLowerCase.charAt(queryIndex);
7937
7938            boolean termCharacterMatchFound = false;
7939            for (; termIndex < termLowerCase.length() && !termCharacterMatchFound; termIndex++) {
7940                final char termChar = termLowerCase.charAt(termIndex);
7941
7942                if (queryChar == termChar) {
7943                    // simple character matches result in one point
7944                    score++;
7945
7946                    // subsequent character matches further improve
7947                    // the score.
7948                    if (previousMatchingCharacterIndex + 1 == termIndex) {
7949                        score += 2;
7950                    }
7951
7952                    previousMatchingCharacterIndex = termIndex;
7953
7954                    // we can leave the nested loop. Every character in the
7955                    // query can match at most one character in the term.
7956                    termCharacterMatchFound = true;
7957                }
7958            }
7959        }
7960
7961        return score;
7962    }
7963
7964    // startsWith
7965    //-----------------------------------------------------------------------
7966
7967    /**
7968     * <p>Check if a CharSequence starts with a specified prefix.</p>
7969     *
7970     * <p>{@code null}s are handled without exceptions. Two {@code null}
7971     * references are considered to be equal. The comparison is case sensitive.</p>
7972     *
7973     * <pre>
7974     * StringUtils.startsWith(null, null)      = true
7975     * StringUtils.startsWith(null, "abc")     = false
7976     * StringUtils.startsWith("abcdef", null)  = false
7977     * StringUtils.startsWith("abcdef", "abc") = true
7978     * StringUtils.startsWith("ABCDEF", "abc") = false
7979     * </pre>
7980     *
7981     * @see java.lang.String#startsWith(String)
7982     * @param str  the CharSequence to check, may be null
7983     * @param prefix the prefix to find, may be null
7984     * @return {@code true} if the CharSequence starts with the prefix, case sensitive, or
7985     *  both {@code null}
7986     * @since 2.4
7987     * @since 3.0 Changed signature from startsWith(String, String) to startsWith(CharSequence, CharSequence)
7988     */
7989    public static boolean startsWith(final CharSequence str, final CharSequence prefix) {
7990        return startsWith(str, prefix, false);
7991    }
7992
7993    /**
7994     * <p>Case insensitive check if a CharSequence starts with a specified prefix.</p>
7995     *
7996     * <p>{@code null}s are handled without exceptions. Two {@code null}
7997     * references are considered to be equal. The comparison is case insensitive.</p>
7998     *
7999     * <pre>
8000     * StringUtils.startsWithIgnoreCase(null, null)      = true
8001     * StringUtils.startsWithIgnoreCase(null, "abc")     = false
8002     * StringUtils.startsWithIgnoreCase("abcdef", null)  = false
8003     * StringUtils.startsWithIgnoreCase("abcdef", "abc") = true
8004     * StringUtils.startsWithIgnoreCase("ABCDEF", "abc") = true
8005     * </pre>
8006     *
8007     * @see java.lang.String#startsWith(String)
8008     * @param str  the CharSequence to check, may be null
8009     * @param prefix the prefix to find, may be null
8010     * @return {@code true} if the CharSequence starts with the prefix, case insensitive, or
8011     *  both {@code null}
8012     * @since 2.4
8013     * @since 3.0 Changed signature from startsWithIgnoreCase(String, String) to startsWithIgnoreCase(CharSequence, CharSequence)
8014     */
8015    public static boolean startsWithIgnoreCase(final CharSequence str, final CharSequence prefix) {
8016        return startsWith(str, prefix, true);
8017    }
8018
8019    /**
8020     * <p>Check if a CharSequence starts with a specified prefix (optionally case insensitive).</p>
8021     *
8022     * @see java.lang.String#startsWith(String)
8023     * @param str  the CharSequence to check, may be null
8024     * @param prefix the prefix to find, may be null
8025     * @param ignoreCase indicates whether the compare should ignore case
8026     *  (case insensitive) or not.
8027     * @return {@code true} if the CharSequence starts with the prefix or
8028     *  both {@code null}
8029     */
8030    private static boolean startsWith(final CharSequence str, final CharSequence prefix, final boolean ignoreCase) {
8031        if (str == null || prefix == null) {
8032            return str == null && prefix == null;
8033        }
8034        if (prefix.length() > str.length()) {
8035            return false;
8036        }
8037        return CharSequenceUtils.regionMatches(str, ignoreCase, 0, prefix, 0, prefix.length());
8038    }
8039
8040    /**
8041     * <p>Check if a CharSequence starts with any of the provided case-sensitive prefixes.</p>
8042     *
8043     * <pre>
8044     * StringUtils.startsWithAny(null, null)      = false
8045     * StringUtils.startsWithAny(null, new String[] {"abc"})  = false
8046     * StringUtils.startsWithAny("abcxyz", null)     = false
8047     * StringUtils.startsWithAny("abcxyz", new String[] {""}) = true
8048     * StringUtils.startsWithAny("abcxyz", new String[] {"abc"}) = true
8049     * StringUtils.startsWithAny("abcxyz", new String[] {null, "xyz", "abc"}) = true
8050     * StringUtils.startsWithAny("abcxyz", null, "xyz", "ABCX") = false
8051     * StringUtils.startsWithAny("ABCXYZ", null, "xyz", "abc") = false
8052     * </pre>
8053     *
8054     * @param sequence the CharSequence to check, may be null
8055     * @param searchStrings the case-sensitive CharSequence prefixes, may be empty or contain {@code null}
8056     * @see StringUtils#startsWith(CharSequence, CharSequence)
8057     * @return {@code true} if the input {@code sequence} is {@code null} AND no {@code searchStrings} are provided, or
8058     *   the input {@code sequence} begins with any of the provided case-sensitive {@code searchStrings}.
8059     * @since 2.5
8060     * @since 3.0 Changed signature from startsWithAny(String, String[]) to startsWithAny(CharSequence, CharSequence...)
8061     */
8062    public static boolean startsWithAny(final CharSequence sequence, final CharSequence... searchStrings) {
8063        if (isEmpty(sequence) || ArrayUtils.isEmpty(searchStrings)) {
8064            return false;
8065        }
8066        for (final CharSequence searchString : searchStrings) {
8067            if (startsWith(sequence, searchString)) {
8068                return true;
8069            }
8070        }
8071        return false;
8072    }
8073
8074    // endsWith
8075    //-----------------------------------------------------------------------
8076
8077    /**
8078     * <p>Check if a CharSequence ends with a specified suffix.</p>
8079     *
8080     * <p>{@code null}s are handled without exceptions. Two {@code null}
8081     * references are considered to be equal. The comparison is case sensitive.</p>
8082     *
8083     * <pre>
8084     * StringUtils.endsWith(null, null)      = true
8085     * StringUtils.endsWith(null, "def")     = false
8086     * StringUtils.endsWith("abcdef", null)  = false
8087     * StringUtils.endsWith("abcdef", "def") = true
8088     * StringUtils.endsWith("ABCDEF", "def") = false
8089     * StringUtils.endsWith("ABCDEF", "cde") = false
8090     * StringUtils.endsWith("ABCDEF", "")    = true
8091     * </pre>
8092     *
8093     * @see java.lang.String#endsWith(String)
8094     * @param str  the CharSequence to check, may be null
8095     * @param suffix the suffix to find, may be null
8096     * @return {@code true} if the CharSequence ends with the suffix, case sensitive, or
8097     *  both {@code null}
8098     * @since 2.4
8099     * @since 3.0 Changed signature from endsWith(String, String) to endsWith(CharSequence, CharSequence)
8100     */
8101    public static boolean endsWith(final CharSequence str, final CharSequence suffix) {
8102        return endsWith(str, suffix, false);
8103    }
8104
8105    /**
8106     * <p>Case insensitive check if a CharSequence ends with a specified suffix.</p>
8107     *
8108     * <p>{@code null}s are handled without exceptions. Two {@code null}
8109     * references are considered to be equal. The comparison is case insensitive.</p>
8110     *
8111     * <pre>
8112     * StringUtils.endsWithIgnoreCase(null, null)      = true
8113     * StringUtils.endsWithIgnoreCase(null, "def")     = false
8114     * StringUtils.endsWithIgnoreCase("abcdef", null)  = false
8115     * StringUtils.endsWithIgnoreCase("abcdef", "def") = true
8116     * StringUtils.endsWithIgnoreCase("ABCDEF", "def") = true
8117     * StringUtils.endsWithIgnoreCase("ABCDEF", "cde") = false
8118     * </pre>
8119     *
8120     * @see java.lang.String#endsWith(String)
8121     * @param str  the CharSequence to check, may be null
8122     * @param suffix the suffix to find, may be null
8123     * @return {@code true} if the CharSequence ends with the suffix, case insensitive, or
8124     *  both {@code null}
8125     * @since 2.4
8126     * @since 3.0 Changed signature from endsWithIgnoreCase(String, String) to endsWithIgnoreCase(CharSequence, CharSequence)
8127     */
8128    public static boolean endsWithIgnoreCase(final CharSequence str, final CharSequence suffix) {
8129        return endsWith(str, suffix, true);
8130    }
8131
8132    /**
8133     * <p>Check if a CharSequence ends with a specified suffix (optionally case insensitive).</p>
8134     *
8135     * @see java.lang.String#endsWith(String)
8136     * @param str  the CharSequence to check, may be null
8137     * @param suffix the suffix to find, may be null
8138     * @param ignoreCase indicates whether the compare should ignore case
8139     *  (case insensitive) or not.
8140     * @return {@code true} if the CharSequence starts with the prefix or
8141     *  both {@code null}
8142     */
8143    private static boolean endsWith(final CharSequence str, final CharSequence suffix, final boolean ignoreCase) {
8144        if (str == null || suffix == null) {
8145            return str == null && suffix == null;
8146        }
8147        if (suffix.length() > str.length()) {
8148            return false;
8149        }
8150        final int strOffset = str.length() - suffix.length();
8151        return CharSequenceUtils.regionMatches(str, ignoreCase, strOffset, suffix, 0, suffix.length());
8152    }
8153
8154    /**
8155     * <p>
8156     * Similar to <a
8157     * href="http://www.w3.org/TR/xpath/#function-normalize-space">http://www.w3.org/TR/xpath/#function-normalize
8158     * -space</a>
8159     * </p>
8160     * <p>
8161     * The function returns the argument string with whitespace normalized by using
8162     * <code>{@link #trim(String)}</code> to remove leading and trailing whitespace
8163     * and then replacing sequences of whitespace characters by a single space.
8164     * </p>
8165     * In XML Whitespace characters are the same as those allowed by the <a
8166     * href="http://www.w3.org/TR/REC-xml/#NT-S">S</a> production, which is S ::= (#x20 | #x9 | #xD | #xA)+
8167     * <p>
8168     * Java's regexp pattern \s defines whitespace as [ \t\n\x0B\f\r]
8169     *
8170     * <p>For reference:</p>
8171     * <ul>
8172     * <li>\x0B = vertical tab</li>
8173     * <li>\f = #xC = form feed</li>
8174     * <li>#x20 = space</li>
8175     * <li>#x9 = \t</li>
8176     * <li>#xA = \n</li>
8177     * <li>#xD = \r</li>
8178     * </ul>
8179     *
8180     * <p>
8181     * The difference is that Java's whitespace includes vertical tab and form feed, which this functional will also
8182     * normalize. Additionally <code>{@link #trim(String)}</code> removes control characters (char &lt;= 32) from both
8183     * ends of this String.
8184     * </p>
8185     *
8186     * @see Pattern
8187     * @see #trim(String)
8188     * @see <a
8189     *      href="http://www.w3.org/TR/xpath/#function-normalize-space">http://www.w3.org/TR/xpath/#function-normalize-space</a>
8190     * @param str the source String to normalize whitespaces from, may be null
8191     * @return the modified string with whitespace normalized, {@code null} if null String input
8192     *
8193     * @since 3.0
8194     */
8195    public static String normalizeSpace(final String str) {
8196        // LANG-1020: Improved performance significantly by normalizing manually instead of using regex
8197        // See https://github.com/librucha/commons-lang-normalizespaces-benchmark for performance test
8198        if (isEmpty(str)) {
8199            return str;
8200        }
8201        final int size = str.length();
8202        final char[] newChars = new char[size];
8203        int count = 0;
8204        int whitespacesCount = 0;
8205        boolean startWhitespaces = true;
8206        for (int i = 0; i < size; i++) {
8207            char actualChar = str.charAt(i);
8208            boolean isWhitespace = Character.isWhitespace(actualChar);
8209            if (!isWhitespace) {
8210                startWhitespaces = false;
8211                newChars[count++] = (actualChar == 160 ? 32 : actualChar);
8212                whitespacesCount = 0;
8213            } else {
8214                if (whitespacesCount == 0 && !startWhitespaces) {
8215                    newChars[count++] = SPACE.charAt(0);
8216                }
8217                whitespacesCount++;
8218            }
8219        }
8220        if (startWhitespaces) {
8221            return EMPTY;
8222        }
8223        return new String(newChars, 0, count - (whitespacesCount > 0 ? 1 : 0)).trim();
8224    }
8225
8226    /**
8227     * <p>Check if a CharSequence ends with any of the provided case-sensitive suffixes.</p>
8228     *
8229     * <pre>
8230     * StringUtils.endsWithAny(null, null)      = false
8231     * StringUtils.endsWithAny(null, new String[] {"abc"})  = false
8232     * StringUtils.endsWithAny("abcxyz", null)     = false
8233     * StringUtils.endsWithAny("abcxyz", new String[] {""}) = true
8234     * StringUtils.endsWithAny("abcxyz", new String[] {"xyz"}) = true
8235     * StringUtils.endsWithAny("abcxyz", new String[] {null, "xyz", "abc"}) = true
8236     * StringUtils.endsWithAny("abcXYZ", "def", "XYZ") = true
8237     * StringUtils.endsWithAny("abcXYZ", "def", "xyz") = false
8238     * </pre>
8239     *
8240     * @param sequence  the CharSequence to check, may be null
8241     * @param searchStrings the case-sensitive CharSequences to find, may be empty or contain {@code null}
8242     * @see StringUtils#endsWith(CharSequence, CharSequence)
8243     * @return {@code true} if the input {@code sequence} is {@code null} AND no {@code searchStrings} are provided, or
8244     *   the input {@code sequence} ends in any of the provided case-sensitive {@code searchStrings}.
8245     * @since 3.0
8246     */
8247    public static boolean endsWithAny(final CharSequence sequence, final CharSequence... searchStrings) {
8248        if (isEmpty(sequence) || ArrayUtils.isEmpty(searchStrings)) {
8249            return false;
8250        }
8251        for (final CharSequence searchString : searchStrings) {
8252            if (endsWith(sequence, searchString)) {
8253                return true;
8254            }
8255        }
8256        return false;
8257    }
8258
8259    /**
8260     * Appends the suffix to the end of the string if the string does not
8261     * already end with the suffix.
8262     *
8263     * @param str The string.
8264     * @param suffix The suffix to append to the end of the string.
8265     * @param ignoreCase Indicates whether the compare should ignore case.
8266     * @param suffixes Additional suffixes that are valid terminators (optional).
8267     *
8268     * @return A new String if suffix was appended, the same string otherwise.
8269     */
8270    private static String appendIfMissing(final String str, final CharSequence suffix, final boolean ignoreCase, final CharSequence... suffixes) {
8271        if (str == null || isEmpty(suffix) || endsWith(str, suffix, ignoreCase)) {
8272            return str;
8273        }
8274        if (suffixes != null && suffixes.length > 0) {
8275            for (final CharSequence s : suffixes) {
8276                if (endsWith(str, s, ignoreCase)) {
8277                    return str;
8278                }
8279            }
8280        }
8281        return str + suffix.toString();
8282    }
8283
8284    /**
8285     * Appends the suffix to the end of the string if the string does not
8286     * already end with any of the suffixes.
8287     *
8288     * <pre>
8289     * StringUtils.appendIfMissing(null, null) = null
8290     * StringUtils.appendIfMissing("abc", null) = "abc"
8291     * StringUtils.appendIfMissing("", "xyz") = "xyz"
8292     * StringUtils.appendIfMissing("abc", "xyz") = "abcxyz"
8293     * StringUtils.appendIfMissing("abcxyz", "xyz") = "abcxyz"
8294     * StringUtils.appendIfMissing("abcXYZ", "xyz") = "abcXYZxyz"
8295     * </pre>
8296     * <p>With additional suffixes,</p>
8297     * <pre>
8298     * StringUtils.appendIfMissing(null, null, null) = null
8299     * StringUtils.appendIfMissing("abc", null, null) = "abc"
8300     * StringUtils.appendIfMissing("", "xyz", null) = "xyz"
8301     * StringUtils.appendIfMissing("abc", "xyz", new CharSequence[]{null}) = "abcxyz"
8302     * StringUtils.appendIfMissing("abc", "xyz", "") = "abc"
8303     * StringUtils.appendIfMissing("abc", "xyz", "mno") = "abcxyz"
8304     * StringUtils.appendIfMissing("abcxyz", "xyz", "mno") = "abcxyz"
8305     * StringUtils.appendIfMissing("abcmno", "xyz", "mno") = "abcmno"
8306     * StringUtils.appendIfMissing("abcXYZ", "xyz", "mno") = "abcXYZxyz"
8307     * StringUtils.appendIfMissing("abcMNO", "xyz", "mno") = "abcMNOxyz"
8308     * </pre>
8309     *
8310     * @param str The string.
8311     * @param suffix The suffix to append to the end of the string.
8312     * @param suffixes Additional suffixes that are valid terminators.
8313     *
8314     * @return A new String if suffix was appended, the same string otherwise.
8315     *
8316     * @since 3.2
8317     */
8318    public static String appendIfMissing(final String str, final CharSequence suffix, final CharSequence... suffixes) {
8319        return appendIfMissing(str, suffix, false, suffixes);
8320    }
8321
8322    /**
8323     * Appends the suffix to the end of the string if the string does not
8324     * already end, case insensitive, with any of the suffixes.
8325     *
8326     * <pre>
8327     * StringUtils.appendIfMissingIgnoreCase(null, null) = null
8328     * StringUtils.appendIfMissingIgnoreCase("abc", null) = "abc"
8329     * StringUtils.appendIfMissingIgnoreCase("", "xyz") = "xyz"
8330     * StringUtils.appendIfMissingIgnoreCase("abc", "xyz") = "abcxyz"
8331     * StringUtils.appendIfMissingIgnoreCase("abcxyz", "xyz") = "abcxyz"
8332     * StringUtils.appendIfMissingIgnoreCase("abcXYZ", "xyz") = "abcXYZ"
8333     * </pre>
8334     * <p>With additional suffixes,</p>
8335     * <pre>
8336     * StringUtils.appendIfMissingIgnoreCase(null, null, null) = null
8337     * StringUtils.appendIfMissingIgnoreCase("abc", null, null) = "abc"
8338     * StringUtils.appendIfMissingIgnoreCase("", "xyz", null) = "xyz"
8339     * StringUtils.appendIfMissingIgnoreCase("abc", "xyz", new CharSequence[]{null}) = "abcxyz"
8340     * StringUtils.appendIfMissingIgnoreCase("abc", "xyz", "") = "abc"
8341     * StringUtils.appendIfMissingIgnoreCase("abc", "xyz", "mno") = "axyz"
8342     * StringUtils.appendIfMissingIgnoreCase("abcxyz", "xyz", "mno") = "abcxyz"
8343     * StringUtils.appendIfMissingIgnoreCase("abcmno", "xyz", "mno") = "abcmno"
8344     * StringUtils.appendIfMissingIgnoreCase("abcXYZ", "xyz", "mno") = "abcXYZ"
8345     * StringUtils.appendIfMissingIgnoreCase("abcMNO", "xyz", "mno") = "abcMNO"
8346     * </pre>
8347     *
8348     * @param str The string.
8349     * @param suffix The suffix to append to the end of the string.
8350     * @param suffixes Additional suffixes that are valid terminators.
8351     *
8352     * @return A new String if suffix was appended, the same string otherwise.
8353     *
8354     * @since 3.2
8355     */
8356    public static String appendIfMissingIgnoreCase(final String str, final CharSequence suffix, final CharSequence... suffixes) {
8357        return appendIfMissing(str, suffix, true, suffixes);
8358    }
8359
8360    /**
8361     * Prepends the prefix to the start of the string if the string does not
8362     * already start with any of the prefixes.
8363     *
8364     * @param str The string.
8365     * @param prefix The prefix to prepend to the start of the string.
8366     * @param ignoreCase Indicates whether the compare should ignore case.
8367     * @param prefixes Additional prefixes that are valid (optional).
8368     *
8369     * @return A new String if prefix was prepended, the same string otherwise.
8370     */
8371    private static String prependIfMissing(final String str, final CharSequence prefix, final boolean ignoreCase, final CharSequence... prefixes) {
8372        if (str == null || isEmpty(prefix) || startsWith(str, prefix, ignoreCase)) {
8373            return str;
8374        }
8375        if (prefixes != null && prefixes.length > 0) {
8376            for (final CharSequence p : prefixes) {
8377                if (startsWith(str, p, ignoreCase)) {
8378                    return str;
8379                }
8380            }
8381        }
8382        return prefix.toString() + str;
8383    }
8384
8385    /**
8386     * Prepends the prefix to the start of the string if the string does not
8387     * already start with any of the prefixes.
8388     *
8389     * <pre>
8390     * StringUtils.prependIfMissing(null, null) = null
8391     * StringUtils.prependIfMissing("abc", null) = "abc"
8392     * StringUtils.prependIfMissing("", "xyz") = "xyz"
8393     * StringUtils.prependIfMissing("abc", "xyz") = "xyzabc"
8394     * StringUtils.prependIfMissing("xyzabc", "xyz") = "xyzabc"
8395     * StringUtils.prependIfMissing("XYZabc", "xyz") = "xyzXYZabc"
8396     * </pre>
8397     * <p>With additional prefixes,</p>
8398     * <pre>
8399     * StringUtils.prependIfMissing(null, null, null) = null
8400     * StringUtils.prependIfMissing("abc", null, null) = "abc"
8401     * StringUtils.prependIfMissing("", "xyz", null) = "xyz"
8402     * StringUtils.prependIfMissing("abc", "xyz", new CharSequence[]{null}) = "xyzabc"
8403     * StringUtils.prependIfMissing("abc", "xyz", "") = "abc"
8404     * StringUtils.prependIfMissing("abc", "xyz", "mno") = "xyzabc"
8405     * StringUtils.prependIfMissing("xyzabc", "xyz", "mno") = "xyzabc"
8406     * StringUtils.prependIfMissing("mnoabc", "xyz", "mno") = "mnoabc"
8407     * StringUtils.prependIfMissing("XYZabc", "xyz", "mno") = "xyzXYZabc"
8408     * StringUtils.prependIfMissing("MNOabc", "xyz", "mno") = "xyzMNOabc"
8409     * </pre>
8410     *
8411     * @param str The string.
8412     * @param prefix The prefix to prepend to the start of the string.
8413     * @param prefixes Additional prefixes that are valid.
8414     *
8415     * @return A new String if prefix was prepended, the same string otherwise.
8416     *
8417     * @since 3.2
8418     */
8419    public static String prependIfMissing(final String str, final CharSequence prefix, final CharSequence... prefixes) {
8420        return prependIfMissing(str, prefix, false, prefixes);
8421    }
8422
8423    /**
8424     * Prepends the prefix to the start of the string if the string does not
8425     * already start, case insensitive, with any of the prefixes.
8426     *
8427     * <pre>
8428     * StringUtils.prependIfMissingIgnoreCase(null, null) = null
8429     * StringUtils.prependIfMissingIgnoreCase("abc", null) = "abc"
8430     * StringUtils.prependIfMissingIgnoreCase("", "xyz") = "xyz"
8431     * StringUtils.prependIfMissingIgnoreCase("abc", "xyz") = "xyzabc"
8432     * StringUtils.prependIfMissingIgnoreCase("xyzabc", "xyz") = "xyzabc"
8433     * StringUtils.prependIfMissingIgnoreCase("XYZabc", "xyz") = "XYZabc"
8434     * </pre>
8435     * <p>With additional prefixes,</p>
8436     * <pre>
8437     * StringUtils.prependIfMissingIgnoreCase(null, null, null) = null
8438     * StringUtils.prependIfMissingIgnoreCase("abc", null, null) = "abc"
8439     * StringUtils.prependIfMissingIgnoreCase("", "xyz", null) = "xyz"
8440     * StringUtils.prependIfMissingIgnoreCase("abc", "xyz", new CharSequence[]{null}) = "xyzabc"
8441     * StringUtils.prependIfMissingIgnoreCase("abc", "xyz", "") = "abc"
8442     * StringUtils.prependIfMissingIgnoreCase("abc", "xyz", "mno") = "xyzabc"
8443     * StringUtils.prependIfMissingIgnoreCase("xyzabc", "xyz", "mno") = "xyzabc"
8444     * StringUtils.prependIfMissingIgnoreCase("mnoabc", "xyz", "mno") = "mnoabc"
8445     * StringUtils.prependIfMissingIgnoreCase("XYZabc", "xyz", "mno") = "XYZabc"
8446     * StringUtils.prependIfMissingIgnoreCase("MNOabc", "xyz", "mno") = "MNOabc"
8447     * </pre>
8448     *
8449     * @param str The string.
8450     * @param prefix The prefix to prepend to the start of the string.
8451     * @param prefixes Additional prefixes that are valid (optional).
8452     *
8453     * @return A new String if prefix was prepended, the same string otherwise.
8454     *
8455     * @since 3.2
8456     */
8457    public static String prependIfMissingIgnoreCase(final String str, final CharSequence prefix, final CharSequence... prefixes) {
8458        return prependIfMissing(str, prefix, true, prefixes);
8459    }
8460
8461    /**
8462     * Converts a <code>byte[]</code> to a String using the specified character encoding.
8463     *
8464     * @param bytes
8465     *            the byte array to read from
8466     * @param charsetName
8467     *            the encoding to use, if null then use the platform default
8468     * @return a new String
8469     * @throws UnsupportedEncodingException
8470     *             If the named charset is not supported
8471     * @throws NullPointerException
8472     *             if the input is null
8473     * @deprecated use {@link StringUtils#toEncodedString(byte[], Charset)} instead of String constants in your code
8474     * @since 3.1
8475     */
8476    @Deprecated
8477    public static String toString(final byte[] bytes, final String charsetName) throws UnsupportedEncodingException {
8478        return charsetName != null ? new String(bytes, charsetName) : new String(bytes, Charset.defaultCharset());
8479    }
8480
8481    /**
8482     * Converts a <code>byte[]</code> to a String using the specified character encoding.
8483     * 
8484     * @param bytes
8485     *            the byte array to read from
8486     * @param charset
8487     *            the encoding to use, if null then use the platform default
8488     * @return a new String
8489     * @throws NullPointerException
8490     *             if {@code bytes} is null
8491     * @since 3.2
8492     * @since 3.3 No longer throws {@link UnsupportedEncodingException}.
8493     */
8494    public static String toEncodedString(final byte[] bytes, final Charset charset) {
8495        return new String(bytes, charset != null ? charset : Charset.defaultCharset());
8496    }
8497
8498    /**
8499     * <p>
8500     * Wraps a string with a char.
8501     * </p>
8502     * 
8503     * <pre>
8504     * StringUtils.wrap(null, *)        = null
8505     * StringUtils.wrap("", *)          = ""
8506     * StringUtils.wrap("ab", '\0')     = "ab"
8507     * StringUtils.wrap("ab", 'x')      = "xabx"
8508     * StringUtils.wrap("ab", '\'')     = "'ab'"
8509     * StringUtils.wrap("\"ab\"", '\"') = "\"\"ab\"\""
8510     * </pre>
8511     * 
8512     * @param str
8513     *            the string to be wrapped, may be {@code null}
8514     * @param wrapWith
8515     *            the char that will wrap {@code str}
8516     * @return the wrapped string, or {@code null} if {@code str==null}
8517     * @since 3.4
8518     */
8519    public static String wrap(final String str, final char wrapWith) {
8520
8521        if (isEmpty(str) || wrapWith == '\0') {
8522            return str;
8523        }
8524
8525        return wrapWith + str + wrapWith;
8526    }
8527
8528    /**
8529     * <p>
8530     * Wraps a String with another String.
8531     * </p>
8532     * 
8533     * <p>
8534     * A {@code null} input String returns {@code null}.
8535     * </p>
8536     * 
8537     * <pre>
8538     * StringUtils.wrap(null, *)         = null
8539     * StringUtils.wrap("", *)           = ""
8540     * StringUtils.wrap("ab", null)      = "ab"
8541     * StringUtils.wrap("ab", "x")       = "xabx"
8542     * StringUtils.wrap("ab", "\"")      = "\"ab\""
8543     * StringUtils.wrap("\"ab\"", "\"")  = "\"\"ab\"\""
8544     * StringUtils.wrap("ab", "'")       = "'ab'"
8545     * StringUtils.wrap("'abcd'", "'")   = "''abcd''"
8546     * StringUtils.wrap("\"abcd\"", "'") = "'\"abcd\"'"
8547     * StringUtils.wrap("'abcd'", "\"")  = "\"'abcd'\""
8548     * </pre>
8549     * 
8550     * @param str
8551     *            the String to be wrapper, may be null
8552     * @param wrapWith
8553     *            the String that will wrap str
8554     * @return wrapped String, {@code null} if null String input
8555     * @since 3.4
8556     */
8557    public static String wrap(final String str, final String wrapWith) {
8558
8559        if (isEmpty(str) || isEmpty(wrapWith)) {
8560            return str;
8561        }
8562
8563        return wrapWith.concat(str).concat(wrapWith);
8564    }
8565
8566    /**
8567     * <p>
8568     * Wraps a string with a char if that char is missing from the start or end of the given string.
8569     * </p>
8570     * 
8571     * <pre>
8572     * StringUtils.wrap(null, *)        = null
8573     * StringUtils.wrap("", *)          = ""
8574     * StringUtils.wrap("ab", '\0')     = "ab"
8575     * StringUtils.wrap("ab", 'x')      = "xabx"
8576     * StringUtils.wrap("ab", '\'')     = "'ab'"
8577     * StringUtils.wrap("\"ab\"", '\"') = "\"ab\""
8578     * StringUtils.wrap("/", '/')  = "/"
8579     * StringUtils.wrap("a/b/c", '/')  = "/a/b/c/"
8580     * StringUtils.wrap("/a/b/c", '/')  = "/a/b/c/"
8581     * StringUtils.wrap("a/b/c/", '/')  = "/a/b/c/"
8582     * </pre>
8583     * 
8584     * @param str
8585     *            the string to be wrapped, may be {@code null}
8586     * @param wrapWith
8587     *            the char that will wrap {@code str}
8588     * @return the wrapped string, or {@code null} if {@code str==null}
8589     * @since 3.5
8590     */
8591    public static String wrapIfMissing(final String str, final char wrapWith) {
8592        if (isEmpty(str) || wrapWith == '\0') {
8593            return str;
8594        }
8595        StringBuilder builder = new StringBuilder(str.length() + 2);
8596        if (str.charAt(0) != wrapWith) {
8597            builder.append(wrapWith);
8598        }
8599        builder.append(str);
8600        if (str.charAt(str.length() - 1) != wrapWith) {
8601            builder.append(wrapWith);
8602        }
8603        return builder.toString();
8604    }
8605
8606    /**
8607     * <p>
8608     * Wraps a string with a string if that string is missing from the start or end of the given string.
8609     * </p>
8610     * 
8611     * <pre>
8612     * StringUtils.wrap(null, *)         = null
8613     * StringUtils.wrap("", *)           = ""
8614     * StringUtils.wrap("ab", null)      = "ab"
8615     * StringUtils.wrap("ab", "x")       = "xabx"
8616     * StringUtils.wrap("ab", "\"")      = "\"ab\""
8617     * StringUtils.wrap("\"ab\"", "\"")  = "\"ab\""
8618     * StringUtils.wrap("ab", "'")       = "'ab'"
8619     * StringUtils.wrap("'abcd'", "'")   = "'abcd'"
8620     * StringUtils.wrap("\"abcd\"", "'") = "'\"abcd\"'"
8621     * StringUtils.wrap("'abcd'", "\"")  = "\"'abcd'\""
8622     * StringUtils.wrap("/", "/")  = "/"
8623     * StringUtils.wrap("a/b/c", "/")  = "/a/b/c/"
8624     * StringUtils.wrap("/a/b/c", "/")  = "/a/b/c/"
8625     * StringUtils.wrap("a/b/c/", "/")  = "/a/b/c/"
8626     * </pre>
8627     * 
8628     * @param str
8629     *            the string to be wrapped, may be {@code null}
8630     * @param wrapWith
8631     *            the char that will wrap {@code str}
8632     * @return the wrapped string, or {@code null} if {@code str==null}
8633     * @since 3.5
8634     */
8635    public static String wrapIfMissing(final String str, final String wrapWith) {
8636        if (isEmpty(str) || isEmpty(wrapWith)) {
8637            return str;
8638        }
8639        StringBuilder builder = new StringBuilder(str.length() + wrapWith.length() + wrapWith.length());
8640        if (!str.startsWith(wrapWith)) {
8641            builder.append(wrapWith);
8642        }
8643        builder.append(str);
8644        if (!str.endsWith(wrapWith)) {
8645            builder.append(wrapWith);
8646        }
8647        return builder.toString();
8648    }
8649
8650}