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