001/*
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements.  See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License.  You may obtain a copy of the License at
008 *
009 *      http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017package org.apache.commons.lang3;
018
019import java.io.UnsupportedEncodingException;
020import java.nio.charset.Charset;
021import java.text.Normalizer;
022import java.util.ArrayList;
023import java.util.Arrays;
024import java.util.Iterator;
025import java.util.List;
026import java.util.Locale;
027import java.util.Objects;
028import java.util.regex.Pattern;
029
030/**
031 * <p>Operations on {@link java.lang.String} that are
032 * {@code null} safe.</p>
033 *
034 * <ul>
035 *  <li><b>IsEmpty/IsBlank</b>
036 *      - checks if a String contains text</li>
037 *  <li><b>Trim/Strip</b>
038 *      - removes leading and trailing whitespace</li>
039 *  <li><b>Equals/Compare</b>
040 *      - compares two strings null-safe</li>
041 *  <li><b>startsWith</b>
042 *      - check if a String starts with a prefix null-safe</li>
043 *  <li><b>endsWith</b>
044 *      - check if a String ends with a suffix null-safe</li>
045 *  <li><b>IndexOf/LastIndexOf/Contains</b>
046 *      - null-safe index-of checks
047 *  <li><b>IndexOfAny/LastIndexOfAny/IndexOfAnyBut/LastIndexOfAnyBut</b>
048 *      - index-of any of a set of Strings</li>
049 *  <li><b>ContainsOnly/ContainsNone/ContainsAny</b>
050 *      - does String contains only/none/any of these characters</li>
051 *  <li><b>Substring/Left/Right/Mid</b>
052 *      - null-safe substring extractions</li>
053 *  <li><b>SubstringBefore/SubstringAfter/SubstringBetween</b>
054 *      - substring extraction relative to other strings</li>
055 *  <li><b>Split/Join</b>
056 *      - splits a String into an array of substrings and vice versa</li>
057 *  <li><b>Remove/Delete</b>
058 *      - removes part of a String</li>
059 *  <li><b>Replace/Overlay</b>
060 *      - Searches a String and replaces one String with another</li>
061 *  <li><b>Chomp/Chop</b>
062 *      - removes the last part of a String</li>
063 *  <li><b>AppendIfMissing</b>
064 *      - appends a suffix to the end of the String if not present</li>
065 *  <li><b>PrependIfMissing</b>
066 *      - prepends a prefix to the start of the String if not present</li>
067 *  <li><b>LeftPad/RightPad/Center/Repeat</b>
068 *      - pads a String</li>
069 *  <li><b>UpperCase/LowerCase/SwapCase/Capitalize/Uncapitalize</b>
070 *      - changes the case of a String</li>
071 *  <li><b>CountMatches</b>
072 *      - counts the number of occurrences of one String in another</li>
073 *  <li><b>IsAlpha/IsNumeric/IsWhitespace/IsAsciiPrintable</b>
074 *      - checks the characters in a String</li>
075 *  <li><b>DefaultString</b>
076 *      - protects against a null input String</li>
077 *  <li><b>Rotate</b>
078 *      - rotate (circular shift) a String</li>
079 *  <li><b>Reverse/ReverseDelimited</b>
080 *      - reverses a String</li>
081 *  <li><b>Abbreviate</b>
082 *      - abbreviates a string using ellipsis or another given String</li>
083 *  <li><b>Difference</b>
084 *      - compares Strings and reports on their differences</li>
085 *  <li><b>LevenshteinDistance</b>
086 *      - the number of changes needed to change one String into another</li>
087 * </ul>
088 *
089 * <p>The {@code StringUtils} class defines certain words related to
090 * String handling.</p>
091 *
092 * <ul>
093 *  <li>null - {@code null}</li>
094 *  <li>empty - a zero-length string ({@code ""})</li>
095 *  <li>space - the space character ({@code ' '}, char 32)</li>
096 *  <li>whitespace - the characters defined by {@link Character#isWhitespace(char)}</li>
097 *  <li>trim - the characters &lt;= 32 as in {@link String#trim()}</li>
098 * </ul>
099 *
100 * <p>{@code StringUtils} handles {@code null} input Strings quietly.
101 * That is to say that a {@code null} input will return {@code null}.
102 * Where a {@code boolean} or {@code int} is being returned
103 * details vary by method.</p>
104 *
105 * <p>A side effect of the {@code null} handling is that a
106 * {@code NullPointerException} should be considered a bug in
107 * {@code StringUtils}.</p>
108 *
109 * <p>Methods in this class give sample code to explain their operation.
110 * The symbol {@code *} is used to indicate any input including {@code null}.</p>
111 *
112 * <p>#ThreadSafe#</p>
113 * @see java.lang.String
114 * @since 1.0
115 */
116//@Immutable
117public class StringUtils {
118    // Performance testing notes (JDK 1.4, Jul03, scolebourne)
119    // Whitespace:
120    // Character.isWhitespace() is faster than WHITESPACE.indexOf()
121    // where WHITESPACE is a string of all whitespace characters
122    //
123    // Character access:
124    // String.charAt(n) versus toCharArray(), then array[n]
125    // String.charAt(n) is about 15% worse for a 10K string
126    // They are about equal for a length 50 string
127    // String.charAt(n) is about 4 times better for a length 3 string
128    // String.charAt(n) is best bet overall
129    //
130    // Append:
131    // String.concat about twice as fast as StringBuffer.append
132    // (not sure who tested this)
133
134    /**
135     * A String for a space character.
136     *
137     * @since 3.2
138     */
139    public static final String SPACE = " ";
140
141    /**
142     * The empty String {@code ""}.
143     * @since 2.0
144     */
145    public static final String EMPTY = "";
146
147    /**
148     * A String for linefeed LF ("\n").
149     *
150     * @see <a href="http://docs.oracle.com/javase/specs/jls/se7/html/jls-3.html#jls-3.10.6">JLF: Escape Sequences
151     *      for Character and String Literals</a>
152     * @since 3.2
153     */
154    public static final String LF = "\n";
155
156    /**
157     * A String for carriage return CR ("\r").
158     *
159     * @see <a href="http://docs.oracle.com/javase/specs/jls/se7/html/jls-3.html#jls-3.10.6">JLF: Escape Sequences
160     *      for Character and String Literals</a>
161     * @since 3.2
162     */
163    public static final String CR = "\r";
164
165    /**
166     * Represents a failed index search.
167     * @since 2.1
168     */
169    public static final int INDEX_NOT_FOUND = -1;
170
171    /**
172     * <p>The maximum size to which the padding constant(s) can expand.</p>
173     */
174    private static final int PAD_LIMIT = 8192;
175
176    /**
177     * <p>{@code StringUtils} instances should NOT be constructed in
178     * standard programming. Instead, the class should be used as
179     * {@code StringUtils.trim(" foo ");}.</p>
180     *
181     * <p>This constructor is public to permit tools that require a JavaBean
182     * instance to operate.</p>
183     */
184    public StringUtils() {
185        super();
186    }
187
188    // Empty checks
189    //-----------------------------------------------------------------------
190    /**
191     * <p>Checks if a CharSequence is empty ("") or null.</p>
192     *
193     * <pre>
194     * StringUtils.isEmpty(null)      = true
195     * StringUtils.isEmpty("")        = true
196     * StringUtils.isEmpty(" ")       = false
197     * StringUtils.isEmpty("bob")     = false
198     * StringUtils.isEmpty("  bob  ") = false
199     * </pre>
200     *
201     * <p>NOTE: This method changed in Lang version 2.0.
202     * It no longer trims the CharSequence.
203     * That functionality is available in isBlank().</p>
204     *
205     * @param cs  the CharSequence to check, may be null
206     * @return {@code true} if the CharSequence is empty or null
207     * @since 3.0 Changed signature from isEmpty(String) to isEmpty(CharSequence)
208     */
209    public static boolean isEmpty(final CharSequence cs) {
210        return cs == null || cs.length() == 0;
211    }
212
213    /**
214     * <p>Checks if a CharSequence is not empty ("") and not null.</p>
215     *
216     * <pre>
217     * StringUtils.isNotEmpty(null)      = false
218     * StringUtils.isNotEmpty("")        = false
219     * StringUtils.isNotEmpty(" ")       = true
220     * StringUtils.isNotEmpty("bob")     = true
221     * StringUtils.isNotEmpty("  bob  ") = true
222     * </pre>
223     *
224     * @param cs  the CharSequence to check, may be null
225     * @return {@code true} if the CharSequence is not empty and not null
226     * @since 3.0 Changed signature from isNotEmpty(String) to isNotEmpty(CharSequence)
227     */
228    public static boolean isNotEmpty(final CharSequence cs) {
229        return !isEmpty(cs);
230    }
231
232    /**
233     * <p>Checks if any of the CharSequences are empty ("") or null.</p>
234     *
235     * <pre>
236     * StringUtils.isAnyEmpty(null)             = true
237     * StringUtils.isAnyEmpty(null, "foo")      = true
238     * StringUtils.isAnyEmpty("", "bar")        = true
239     * StringUtils.isAnyEmpty("bob", "")        = true
240     * StringUtils.isAnyEmpty("  bob  ", null)  = true
241     * StringUtils.isAnyEmpty(" ", "bar")       = false
242     * StringUtils.isAnyEmpty("foo", "bar")     = false
243     * StringUtils.isAnyEmpty(new String[]{})   = false
244     * StringUtils.isAnyEmpty(new String[]{""}) = true
245     * </pre>
246     *
247     * @param css  the CharSequences to check, may be null or empty
248     * @return {@code true} if any of the CharSequences are empty or null
249     * @since 3.2
250     */
251    public static boolean isAnyEmpty(final CharSequence... css) {
252      if (ArrayUtils.isEmpty(css)) {
253        return false;
254      }
255      for (final CharSequence cs : css){
256        if (isEmpty(cs)) {
257          return true;
258        }
259      }
260      return false;
261    }
262
263    /**
264     * <p>Checks if none of the CharSequences are empty ("") or null.</p>
265     *
266     * <pre>
267     * StringUtils.isNoneEmpty(null)             = false
268     * StringUtils.isNoneEmpty(null, "foo")      = false
269     * StringUtils.isNoneEmpty("", "bar")        = false
270     * StringUtils.isNoneEmpty("bob", "")        = false
271     * StringUtils.isNoneEmpty("  bob  ", null)  = false
272     * StringUtils.isNoneEmpty(new String[] {})  = true
273     * StringUtils.isNoneEmpty(new String[]{""}) = false
274     * StringUtils.isNoneEmpty(" ", "bar")       = true
275     * StringUtils.isNoneEmpty("foo", "bar")     = true
276     * </pre>
277     *
278     * @param css  the CharSequences to check, may be null or empty
279     * @return {@code true} if none of the CharSequences are empty or null
280     * @since 3.2
281     */
282    public static boolean isNoneEmpty(final CharSequence... css) {
283      return !isAnyEmpty(css);
284    }
285
286    /**
287     * <p>Checks if all of the CharSequences are empty ("") or null.</p>
288     *
289     * <pre>
290     * StringUtils.isAllEmpty(null)             = true
291     * StringUtils.isAllEmpty(null, "")         = true
292     * StringUtils.isAllEmpty(new String[] {})  = true
293     * StringUtils.isAllEmpty(null, "foo")      = false
294     * StringUtils.isAllEmpty("", "bar")        = false
295     * StringUtils.isAllEmpty("bob", "")        = false
296     * StringUtils.isAllEmpty("  bob  ", null)  = false
297     * StringUtils.isAllEmpty(" ", "bar")       = false
298     * StringUtils.isAllEmpty("foo", "bar")     = false
299     * </pre>
300     *
301     * @param css  the CharSequences to check, may be null or empty
302     * @return {@code true} if all of the CharSequences are empty or null
303     * @since 3.6
304     */
305    public static boolean isAllEmpty(final CharSequence... css) {
306        if (ArrayUtils.isEmpty(css)) {
307            return true;
308        }
309        for (final CharSequence cs : css) {
310            if (isNotEmpty(cs)) {
311                return false;
312            }
313        }
314        return true;
315    }
316
317    /**
318     * <p>Checks if a CharSequence is empty (""), null or whitespace only.</p>
319     *
320     * <p>Whitespace is defined by {@link Character#isWhitespace(char)}.</p>
321     *
322     * <pre>
323     * StringUtils.isBlank(null)      = true
324     * StringUtils.isBlank("")        = true
325     * StringUtils.isBlank(" ")       = true
326     * StringUtils.isBlank("bob")     = false
327     * StringUtils.isBlank("  bob  ") = false
328     * </pre>
329     *
330     * @param cs  the CharSequence to check, may be null
331     * @return {@code true} if the CharSequence is null, empty or whitespace only
332     * @since 2.0
333     * @since 3.0 Changed signature from isBlank(String) to isBlank(CharSequence)
334     */
335    public static boolean isBlank(final CharSequence cs) {
336        int strLen;
337        if (cs == null || (strLen = cs.length()) == 0) {
338            return true;
339        }
340        for (int i = 0; i < strLen; i++) {
341            if (Character.isWhitespace(cs.charAt(i)) == false) {
342                return false;
343            }
344        }
345        return true;
346    }
347
348    /**
349     * <p>Checks if a CharSequence is not empty (""), not null and not whitespace only.</p>
350     *
351     * <p>Whitespace is defined by {@link Character#isWhitespace(char)}.</p>
352     *
353     * <pre>
354     * StringUtils.isNotBlank(null)      = false
355     * StringUtils.isNotBlank("")        = false
356     * StringUtils.isNotBlank(" ")       = false
357     * StringUtils.isNotBlank("bob")     = true
358     * StringUtils.isNotBlank("  bob  ") = true
359     * </pre>
360     *
361     * @param cs  the CharSequence to check, may be null
362     * @return {@code true} if the CharSequence is
363     *  not empty and not null and not whitespace only
364     * @since 2.0
365     * @since 3.0 Changed signature from isNotBlank(String) to isNotBlank(CharSequence)
366     */
367    public static boolean isNotBlank(final CharSequence cs) {
368        return !isBlank(cs);
369    }
370
371    /**
372     * <p>Checks if any of the CharSequences are empty ("") or null or whitespace only.</p>
373     *
374     * <p>Whitespace is defined by {@link Character#isWhitespace(char)}.</p>
375     *
376     * <pre>
377     * StringUtils.isAnyBlank(null)             = true
378     * StringUtils.isAnyBlank(null, "foo")      = true
379     * StringUtils.isAnyBlank(null, null)       = true
380     * StringUtils.isAnyBlank("", "bar")        = true
381     * StringUtils.isAnyBlank("bob", "")        = true
382     * StringUtils.isAnyBlank("  bob  ", null)  = true
383     * StringUtils.isAnyBlank(" ", "bar")       = true
384     * StringUtils.isAnyBlank(new String[] {})  = false
385     * StringUtils.isAnyBlank(new String[]{""}) = true
386     * StringUtils.isAnyBlank("foo", "bar")     = false
387     * </pre>
388     *
389     * @param css  the CharSequences to check, may be null or empty
390     * @return {@code true} if any of the CharSequences are empty or null or whitespace only
391     * @since 3.2
392     */
393    public static boolean isAnyBlank(final CharSequence... css) {
394      if (ArrayUtils.isEmpty(css)) {
395        return false;
396      }
397      for (final CharSequence cs : css){
398        if (isBlank(cs)) {
399          return true;
400        }
401      }
402      return false;
403    }
404
405    /**
406     * <p>Checks if none of the CharSequences are empty (""), null or whitespace only.</p>
407     *
408     * <p>Whitespace is defined by {@link Character#isWhitespace(char)}.</p>
409     *
410     * <pre>
411     * StringUtils.isNoneBlank(null)             = false
412     * StringUtils.isNoneBlank(null, "foo")      = false
413     * StringUtils.isNoneBlank(null, null)       = false
414     * StringUtils.isNoneBlank("", "bar")        = false
415     * StringUtils.isNoneBlank("bob", "")        = false
416     * StringUtils.isNoneBlank("  bob  ", null)  = false
417     * StringUtils.isNoneBlank(" ", "bar")       = false
418     * StringUtils.isNoneBlank(new String[] {})  = true
419     * StringUtils.isNoneBlank(new String[]{""}) = false
420     * StringUtils.isNoneBlank("foo", "bar")     = true
421     * </pre>
422     *
423     * @param css  the CharSequences to check, may be null or empty
424     * @return {@code true} if none of the CharSequences are empty or null or whitespace only
425     * @since 3.2
426     */
427    public static boolean isNoneBlank(final CharSequence... css) {
428      return !isAnyBlank(css);
429    }
430
431    /**
432     * <p>Checks if all of the CharSequences are empty (""), null or whitespace only.</p>
433     *
434     * <p>Whitespace is defined by {@link Character#isWhitespace(char)}.</p>
435     *
436     * <pre>
437     * StringUtils.isAllBlank(null)             = true
438     * StringUtils.isAllBlank(null, "foo")      = false
439     * StringUtils.isAllBlank(null, null)       = true
440     * StringUtils.isAllBlank("", "bar")        = false
441     * StringUtils.isAllBlank("bob", "")        = false
442     * StringUtils.isAllBlank("  bob  ", null)  = false
443     * StringUtils.isAllBlank(" ", "bar")       = false
444     * StringUtils.isAllBlank("foo", "bar")     = false
445     * StringUtils.isAllBlank(new String[] {})  = true
446     * </pre>
447     *
448     * @param css  the CharSequences to check, may be null or empty
449     * @return {@code true} if all of the CharSequences are empty or null or whitespace only
450     * @since 3.6
451     */
452    public static boolean isAllBlank(final CharSequence... css) {
453        if (ArrayUtils.isEmpty(css)) {
454            return true;
455        }
456        for (final CharSequence cs : css) {
457            if (isNotBlank(cs)) {
458               return false;
459            }
460        }
461        return true;
462    }
463
464    // Trim
465    //-----------------------------------------------------------------------
466    /**
467     * <p>Removes control characters (char &lt;= 32) from both
468     * ends of this String, handling {@code null} by returning
469     * {@code null}.</p>
470     *
471     * <p>The String is trimmed using {@link String#trim()}.
472     * Trim removes start and end characters &lt;= 32.
473     * To strip whitespace use {@link #strip(String)}.</p>
474     *
475     * <p>To trim your choice of characters, use the
476     * {@link #strip(String, String)} methods.</p>
477     *
478     * <pre>
479     * StringUtils.trim(null)          = null
480     * StringUtils.trim("")            = ""
481     * StringUtils.trim("     ")       = ""
482     * StringUtils.trim("abc")         = "abc"
483     * StringUtils.trim("    abc    ") = "abc"
484     * </pre>
485     *
486     * @param str  the String to be trimmed, may be null
487     * @return the trimmed string, {@code null} if null String input
488     */
489    public static String trim(final String str) {
490        return str == null ? null : str.trim();
491    }
492
493    /**
494     * <p>Removes control characters (char &lt;= 32) from both
495     * ends of this String returning {@code null} if the String is
496     * empty ("") after the trim or if it is {@code null}.
497     *
498     * <p>The String is trimmed using {@link String#trim()}.
499     * Trim removes start and end characters &lt;= 32.
500     * To strip whitespace use {@link #stripToNull(String)}.</p>
501     *
502     * <pre>
503     * StringUtils.trimToNull(null)          = null
504     * StringUtils.trimToNull("")            = null
505     * StringUtils.trimToNull("     ")       = null
506     * StringUtils.trimToNull("abc")         = "abc"
507     * StringUtils.trimToNull("    abc    ") = "abc"
508     * </pre>
509     *
510     * @param str  the String to be trimmed, may be null
511     * @return the trimmed String,
512     *  {@code null} if only chars &lt;= 32, empty or null String input
513     * @since 2.0
514     */
515    public static String trimToNull(final String str) {
516        final String ts = trim(str);
517        return isEmpty(ts) ? null : ts;
518    }
519
520    /**
521     * <p>Removes control characters (char &lt;= 32) from both
522     * ends of this String returning an empty String ("") if the String
523     * is empty ("") after the trim or if it is {@code null}.
524     *
525     * <p>The String is trimmed using {@link String#trim()}.
526     * Trim removes start and end characters &lt;= 32.
527     * To strip whitespace use {@link #stripToEmpty(String)}.</p>
528     *
529     * <pre>
530     * StringUtils.trimToEmpty(null)          = ""
531     * StringUtils.trimToEmpty("")            = ""
532     * StringUtils.trimToEmpty("     ")       = ""
533     * StringUtils.trimToEmpty("abc")         = "abc"
534     * StringUtils.trimToEmpty("    abc    ") = "abc"
535     * </pre>
536     *
537     * @param str  the String to be trimmed, may be null
538     * @return the trimmed String, or an empty String if {@code null} input
539     * @since 2.0
540     */
541    public static String trimToEmpty(final String str) {
542        return str == null ? EMPTY : str.trim();
543    }
544
545    /**
546     * <p>Truncates a String. This will turn
547     * "Now is the time for all good men" into "Now is the time for".</p>
548     *
549     * <p>Specifically:</p>
550     * <ul>
551     *   <li>If {@code str} is less than {@code maxWidth} characters
552     *       long, return it.</li>
553     *   <li>Else truncate it to {@code substring(str, 0, maxWidth)}.</li>
554     *   <li>If {@code maxWidth} is less than {@code 0}, throw an
555     *       {@code IllegalArgumentException}.</li>
556     *   <li>In no case will it return a String of length greater than
557     *       {@code maxWidth}.</li>
558     * </ul>
559     *
560     * <pre>
561     * StringUtils.truncate(null, 0)       = null
562     * StringUtils.truncate(null, 2)       = null
563     * StringUtils.truncate("", 4)         = ""
564     * StringUtils.truncate("abcdefg", 4)  = "abcd"
565     * StringUtils.truncate("abcdefg", 6)  = "abcdef"
566     * StringUtils.truncate("abcdefg", 7)  = "abcdefg"
567     * StringUtils.truncate("abcdefg", 8)  = "abcdefg"
568     * StringUtils.truncate("abcdefg", -1) = throws an IllegalArgumentException
569     * </pre>
570     *
571     * @param str  the String to truncate, may be null
572     * @param maxWidth  maximum length of result String, must be positive
573     * @return truncated String, {@code null} if null String input
574     * @since 3.5
575     */
576    public static String truncate(final String str, final int maxWidth) {
577        return truncate(str, 0, maxWidth);
578    }
579
580    /**
581     * <p>Truncates a String. This will turn
582     * "Now is the time for all good men" into "is the time for all".</p>
583     *
584     * <p>Works like {@code truncate(String, int)}, but allows you to specify
585     * a "left edge" offset.
586     *
587     * <p>Specifically:</p>
588     * <ul>
589     *   <li>If {@code str} is less than {@code maxWidth} characters
590     *       long, return it.</li>
591     *   <li>Else truncate it to {@code substring(str, offset, maxWidth)}.</li>
592     *   <li>If {@code maxWidth} is less than {@code 0}, throw an
593     *       {@code IllegalArgumentException}.</li>
594     *   <li>If {@code offset} is less than {@code 0}, throw an
595     *       {@code IllegalArgumentException}.</li>
596     *   <li>In no case will it return a String of length greater than
597     *       {@code maxWidth}.</li>
598     * </ul>
599     *
600     * <pre>
601     * StringUtils.truncate(null, 0, 0) = null
602     * StringUtils.truncate(null, 2, 4) = null
603     * StringUtils.truncate("", 0, 10) = ""
604     * StringUtils.truncate("", 2, 10) = ""
605     * StringUtils.truncate("abcdefghij", 0, 3) = "abc"
606     * StringUtils.truncate("abcdefghij", 5, 6) = "fghij"
607     * StringUtils.truncate("raspberry peach", 10, 15) = "peach"
608     * StringUtils.truncate("abcdefghijklmno", 0, 10) = "abcdefghij"
609     * StringUtils.truncate("abcdefghijklmno", -1, 10) = throws an IllegalArgumentException
610     * StringUtils.truncate("abcdefghijklmno", Integer.MIN_VALUE, 10) = "abcdefghij"
611     * StringUtils.truncate("abcdefghijklmno", Integer.MIN_VALUE, Integer.MAX_VALUE) = "abcdefghijklmno"
612     * StringUtils.truncate("abcdefghijklmno", 0, Integer.MAX_VALUE) = "abcdefghijklmno"
613     * StringUtils.truncate("abcdefghijklmno", 1, 10) = "bcdefghijk"
614     * StringUtils.truncate("abcdefghijklmno", 2, 10) = "cdefghijkl"
615     * StringUtils.truncate("abcdefghijklmno", 3, 10) = "defghijklm"
616     * StringUtils.truncate("abcdefghijklmno", 4, 10) = "efghijklmn"
617     * StringUtils.truncate("abcdefghijklmno", 5, 10) = "fghijklmno"
618     * StringUtils.truncate("abcdefghijklmno", 5, 5) = "fghij"
619     * StringUtils.truncate("abcdefghijklmno", 5, 3) = "fgh"
620     * StringUtils.truncate("abcdefghijklmno", 10, 3) = "klm"
621     * StringUtils.truncate("abcdefghijklmno", 10, Integer.MAX_VALUE) = "klmno"
622     * StringUtils.truncate("abcdefghijklmno", 13, 1) = "n"
623     * StringUtils.truncate("abcdefghijklmno", 13, Integer.MAX_VALUE) = "no"
624     * StringUtils.truncate("abcdefghijklmno", 14, 1) = "o"
625     * StringUtils.truncate("abcdefghijklmno", 14, Integer.MAX_VALUE) = "o"
626     * StringUtils.truncate("abcdefghijklmno", 15, 1) = ""
627     * StringUtils.truncate("abcdefghijklmno", 15, Integer.MAX_VALUE) = ""
628     * StringUtils.truncate("abcdefghijklmno", Integer.MAX_VALUE, Integer.MAX_VALUE) = ""
629     * StringUtils.truncate("abcdefghij", 3, -1) = throws an IllegalArgumentException
630     * StringUtils.truncate("abcdefghij", -2, 4) = throws an IllegalArgumentException
631     * </pre>
632     *
633     * @param str  the String to check, may be null
634     * @param offset  left edge of source String
635     * @param maxWidth  maximum length of result String, must be positive
636     * @return truncated String, {@code null} if null String input
637     * @since 3.5
638     */
639    public static String truncate(final String str, final int offset, final int maxWidth) {
640        if (offset < 0) {
641            throw new IllegalArgumentException("offset cannot be negative");
642        }
643        if (maxWidth < 0) {
644            throw new IllegalArgumentException("maxWith cannot be negative");
645        }
646        if (str == null) {
647            return null;
648        }
649        if (offset > str.length()) {
650            return EMPTY;
651        }
652        if (str.length() > maxWidth) {
653            final int ix = offset + maxWidth > str.length() ? str.length() : offset + maxWidth;
654            return str.substring(offset, ix);
655        }
656        return str.substring(offset);
657    }
658
659    // Stripping
660    //-----------------------------------------------------------------------
661    /**
662     * <p>Strips whitespace from the start and end of a String.</p>
663     *
664     * <p>This is similar to {@link #trim(String)} but removes whitespace.
665     * Whitespace is defined by {@link Character#isWhitespace(char)}.</p>
666     *
667     * <p>A {@code null} input String returns {@code null}.</p>
668     *
669     * <pre>
670     * StringUtils.strip(null)     = null
671     * StringUtils.strip("")       = ""
672     * StringUtils.strip("   ")    = ""
673     * StringUtils.strip("abc")    = "abc"
674     * StringUtils.strip("  abc")  = "abc"
675     * StringUtils.strip("abc  ")  = "abc"
676     * StringUtils.strip(" abc ")  = "abc"
677     * StringUtils.strip(" ab c ") = "ab c"
678     * </pre>
679     *
680     * @param str  the String to remove whitespace from, may be null
681     * @return the stripped String, {@code null} if null String input
682     */
683    public static String strip(final String str) {
684        return strip(str, null);
685    }
686
687    /**
688     * <p>Strips whitespace from the start and end of a String  returning
689     * {@code null} if the String is empty ("") after the strip.</p>
690     *
691     * <p>This is similar to {@link #trimToNull(String)} but removes whitespace.
692     * Whitespace is defined by {@link Character#isWhitespace(char)}.</p>
693     *
694     * <pre>
695     * StringUtils.stripToNull(null)     = null
696     * StringUtils.stripToNull("")       = null
697     * StringUtils.stripToNull("   ")    = null
698     * StringUtils.stripToNull("abc")    = "abc"
699     * StringUtils.stripToNull("  abc")  = "abc"
700     * StringUtils.stripToNull("abc  ")  = "abc"
701     * StringUtils.stripToNull(" abc ")  = "abc"
702     * StringUtils.stripToNull(" ab c ") = "ab c"
703     * </pre>
704     *
705     * @param str  the String to be stripped, may be null
706     * @return the stripped String,
707     *  {@code null} if whitespace, empty or null String input
708     * @since 2.0
709     */
710    public static String stripToNull(String str) {
711        if (str == null) {
712            return null;
713        }
714        str = strip(str, null);
715        return str.isEmpty() ? null : str;
716    }
717
718    /**
719     * <p>Strips whitespace from the start and end of a String  returning
720     * an empty String if {@code null} input.</p>
721     *
722     * <p>This is similar to {@link #trimToEmpty(String)} but removes whitespace.
723     * Whitespace is defined by {@link Character#isWhitespace(char)}.</p>
724     *
725     * <pre>
726     * StringUtils.stripToEmpty(null)     = ""
727     * StringUtils.stripToEmpty("")       = ""
728     * StringUtils.stripToEmpty("   ")    = ""
729     * StringUtils.stripToEmpty("abc")    = "abc"
730     * StringUtils.stripToEmpty("  abc")  = "abc"
731     * StringUtils.stripToEmpty("abc  ")  = "abc"
732     * StringUtils.stripToEmpty(" abc ")  = "abc"
733     * StringUtils.stripToEmpty(" ab c ") = "ab c"
734     * </pre>
735     *
736     * @param str  the String to be stripped, may be null
737     * @return the trimmed String, or an empty String if {@code null} input
738     * @since 2.0
739     */
740    public static String stripToEmpty(final String str) {
741        return str == null ? EMPTY : strip(str, null);
742    }
743
744    /**
745     * <p>Strips any of a set of characters from the start and end of a String.
746     * This is similar to {@link String#trim()} but allows the characters
747     * to be stripped to be controlled.</p>
748     *
749     * <p>A {@code null} input String returns {@code null}.
750     * An empty string ("") input returns the empty string.</p>
751     *
752     * <p>If the stripChars String is {@code null}, whitespace is
753     * stripped as defined by {@link Character#isWhitespace(char)}.
754     * Alternatively use {@link #strip(String)}.</p>
755     *
756     * <pre>
757     * StringUtils.strip(null, *)          = null
758     * StringUtils.strip("", *)            = ""
759     * StringUtils.strip("abc", null)      = "abc"
760     * StringUtils.strip("  abc", null)    = "abc"
761     * StringUtils.strip("abc  ", null)    = "abc"
762     * StringUtils.strip(" abc ", null)    = "abc"
763     * StringUtils.strip("  abcyx", "xyz") = "  abc"
764     * </pre>
765     *
766     * @param str  the String to remove characters from, may be null
767     * @param stripChars  the characters to remove, null treated as whitespace
768     * @return the stripped String, {@code null} if null String input
769     */
770    public static String strip(String str, final String stripChars) {
771        if (isEmpty(str)) {
772            return str;
773        }
774        str = stripStart(str, stripChars);
775        return stripEnd(str, stripChars);
776    }
777
778    /**
779     * <p>Strips any of a set of characters from the start of a String.</p>
780     *
781     * <p>A {@code null} input String returns {@code null}.
782     * An empty string ("") input returns the empty string.</p>
783     *
784     * <p>If the stripChars String is {@code null}, whitespace is
785     * stripped as defined by {@link Character#isWhitespace(char)}.</p>
786     *
787     * <pre>
788     * StringUtils.stripStart(null, *)          = null
789     * StringUtils.stripStart("", *)            = ""
790     * StringUtils.stripStart("abc", "")        = "abc"
791     * StringUtils.stripStart("abc", null)      = "abc"
792     * StringUtils.stripStart("  abc", null)    = "abc"
793     * StringUtils.stripStart("abc  ", null)    = "abc  "
794     * StringUtils.stripStart(" abc ", null)    = "abc "
795     * StringUtils.stripStart("yxabc  ", "xyz") = "abc  "
796     * </pre>
797     *
798     * @param str  the String to remove characters from, may be null
799     * @param stripChars  the characters to remove, null treated as whitespace
800     * @return the stripped String, {@code null} if null String input
801     */
802    public static String stripStart(final String str, final String stripChars) {
803        int strLen;
804        if (str == null || (strLen = str.length()) == 0) {
805            return str;
806        }
807        int start = 0;
808        if (stripChars == null) {
809            while (start != strLen && Character.isWhitespace(str.charAt(start))) {
810                start++;
811            }
812        } else if (stripChars.isEmpty()) {
813            return str;
814        } else {
815            while (start != strLen && stripChars.indexOf(str.charAt(start)) != INDEX_NOT_FOUND) {
816                start++;
817            }
818        }
819        return str.substring(start);
820    }
821
822    /**
823     * <p>Strips any of a set of characters from the end of a String.</p>
824     *
825     * <p>A {@code null} input String returns {@code null}.
826     * An empty string ("") input returns the empty string.</p>
827     *
828     * <p>If the stripChars String is {@code null}, whitespace is
829     * stripped as defined by {@link Character#isWhitespace(char)}.</p>
830     *
831     * <pre>
832     * StringUtils.stripEnd(null, *)          = null
833     * StringUtils.stripEnd("", *)            = ""
834     * StringUtils.stripEnd("abc", "")        = "abc"
835     * StringUtils.stripEnd("abc", null)      = "abc"
836     * StringUtils.stripEnd("  abc", null)    = "  abc"
837     * StringUtils.stripEnd("abc  ", null)    = "abc"
838     * StringUtils.stripEnd(" abc ", null)    = " abc"
839     * StringUtils.stripEnd("  abcyx", "xyz") = "  abc"
840     * StringUtils.stripEnd("120.00", ".0")   = "12"
841     * </pre>
842     *
843     * @param str  the String to remove characters from, may be null
844     * @param stripChars  the set of characters to remove, null treated as whitespace
845     * @return the stripped String, {@code null} if null String input
846     */
847    public static String stripEnd(final String str, final String stripChars) {
848        int end;
849        if (str == null || (end = str.length()) == 0) {
850            return str;
851        }
852
853        if (stripChars == null) {
854            while (end != 0 && Character.isWhitespace(str.charAt(end - 1))) {
855                end--;
856            }
857        } else if (stripChars.isEmpty()) {
858            return str;
859        } else {
860            while (end != 0 && stripChars.indexOf(str.charAt(end - 1)) != INDEX_NOT_FOUND) {
861                end--;
862            }
863        }
864        return str.substring(0, end);
865    }
866
867    // StripAll
868    //-----------------------------------------------------------------------
869    /**
870     * <p>Strips whitespace from the start and end of every String in an array.
871     * Whitespace is defined by {@link Character#isWhitespace(char)}.</p>
872     *
873     * <p>A new array is returned each time, except for length zero.
874     * A {@code null} array will return {@code null}.
875     * An empty array will return itself.
876     * A {@code null} array entry will be ignored.</p>
877     *
878     * <pre>
879     * StringUtils.stripAll(null)             = null
880     * StringUtils.stripAll([])               = []
881     * StringUtils.stripAll(["abc", "  abc"]) = ["abc", "abc"]
882     * StringUtils.stripAll(["abc  ", null])  = ["abc", null]
883     * </pre>
884     *
885     * @param strs  the array to remove whitespace from, may be null
886     * @return the stripped Strings, {@code null} if null array input
887     */
888    public static String[] stripAll(final String... strs) {
889        return stripAll(strs, null);
890    }
891
892    /**
893     * <p>Strips any of a set of characters from the start and end of every
894     * String in an array.</p>
895     * <p>Whitespace is defined by {@link Character#isWhitespace(char)}.</p>
896     *
897     * <p>A new array is returned each time, except for length zero.
898     * A {@code null} array will return {@code null}.
899     * An empty array will return itself.
900     * A {@code null} array entry will be ignored.
901     * A {@code null} stripChars will strip whitespace as defined by
902     * {@link Character#isWhitespace(char)}.</p>
903     *
904     * <pre>
905     * StringUtils.stripAll(null, *)                = null
906     * StringUtils.stripAll([], *)                  = []
907     * StringUtils.stripAll(["abc", "  abc"], null) = ["abc", "abc"]
908     * StringUtils.stripAll(["abc  ", null], null)  = ["abc", null]
909     * StringUtils.stripAll(["abc  ", null], "yz")  = ["abc  ", null]
910     * StringUtils.stripAll(["yabcz", null], "yz")  = ["abc", null]
911     * </pre>
912     *
913     * @param strs  the array to remove characters from, may be null
914     * @param stripChars  the characters to remove, null treated as whitespace
915     * @return the stripped Strings, {@code null} if null array input
916     */
917    public static String[] stripAll(final String[] strs, final String stripChars) {
918        int strsLen;
919        if (strs == null || (strsLen = strs.length) == 0) {
920            return strs;
921        }
922        final String[] newArr = new String[strsLen];
923        for (int i = 0; i < strsLen; i++) {
924            newArr[i] = strip(strs[i], stripChars);
925        }
926        return newArr;
927    }
928
929    /**
930     * <p>Removes diacritics (~= accents) from a string. The case will not be altered.</p>
931     * <p>For instance, '&agrave;' will be replaced by 'a'.</p>
932     * <p>Note that ligatures will be left as is.</p>
933     *
934     * <pre>
935     * StringUtils.stripAccents(null)                = null
936     * StringUtils.stripAccents("")                  = ""
937     * StringUtils.stripAccents("control")           = "control"
938     * StringUtils.stripAccents("&eacute;clair")     = "eclair"
939     * </pre>
940     *
941     * @param input String to be stripped
942     * @return input text with diacritics removed
943     *
944     * @since 3.0
945     */
946    // 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).
947    public static String stripAccents(final String input) {
948        if(input == null) {
949            return null;
950        }
951        final Pattern pattern = Pattern.compile("\\p{InCombiningDiacriticalMarks}+");//$NON-NLS-1$
952        final StringBuilder decomposed = new StringBuilder(Normalizer.normalize(input, Normalizer.Form.NFD));
953        convertRemainingAccentCharacters(decomposed);
954        // Note that this doesn't correctly remove ligatures...
955        return pattern.matcher(decomposed).replaceAll(StringUtils.EMPTY);
956    }
957
958    private static void convertRemainingAccentCharacters(final StringBuilder decomposed) {
959        for (int i = 0; i < decomposed.length(); i++) {
960            if (decomposed.charAt(i) == '\u0141') {
961                decomposed.deleteCharAt(i);
962                decomposed.insert(i, 'L');
963            } else if (decomposed.charAt(i) == '\u0142') {
964                decomposed.deleteCharAt(i);
965                decomposed.insert(i, 'l');
966            }
967        }
968    }
969
970    // Equals
971    //-----------------------------------------------------------------------
972    /**
973     * <p>Compares two CharSequences, returning {@code true} if they represent
974     * equal sequences of characters.</p>
975     *
976     * <p>{@code null}s are handled without exceptions. Two {@code null}
977     * references are considered to be equal. The comparison is case sensitive.</p>
978     *
979     * <pre>
980     * StringUtils.equals(null, null)   = true
981     * StringUtils.equals(null, "abc")  = false
982     * StringUtils.equals("abc", null)  = false
983     * StringUtils.equals("abc", "abc") = true
984     * StringUtils.equals("abc", "ABC") = false
985     * </pre>
986     *
987     * @see Object#equals(Object)
988     * @param cs1  the first CharSequence, may be {@code null}
989     * @param cs2  the second CharSequence, may be {@code null}
990     * @return {@code true} if the CharSequences are equal (case-sensitive), or both {@code null}
991     * @since 3.0 Changed signature from equals(String, String) to equals(CharSequence, CharSequence)
992     */
993    public static boolean equals(final CharSequence cs1, final CharSequence cs2) {
994        if (cs1 == cs2) {
995            return true;
996        }
997        if (cs1 == null || cs2 == null) {
998            return false;
999        }
1000        if (cs1.length() != cs2.length()) {
1001            return false;
1002        }
1003        if (cs1 instanceof String && cs2 instanceof String) {
1004            return cs1.equals(cs2);
1005        }
1006        return CharSequenceUtils.regionMatches(cs1, false, 0, cs2, 0, cs1.length());
1007    }
1008
1009    /**
1010     * <p>Compares two CharSequences, returning {@code true} if they represent
1011     * equal sequences of characters, ignoring case.</p>
1012     *
1013     * <p>{@code null}s are handled without exceptions. Two {@code null}
1014     * references are considered equal. Comparison is case insensitive.</p>
1015     *
1016     * <pre>
1017     * StringUtils.equalsIgnoreCase(null, null)   = true
1018     * StringUtils.equalsIgnoreCase(null, "abc")  = false
1019     * StringUtils.equalsIgnoreCase("abc", null)  = false
1020     * StringUtils.equalsIgnoreCase("abc", "abc") = true
1021     * StringUtils.equalsIgnoreCase("abc", "ABC") = true
1022     * </pre>
1023     *
1024     * @param str1  the first CharSequence, may be null
1025     * @param str2  the second CharSequence, may be null
1026     * @return {@code true} if the CharSequence are equal, case insensitive, or
1027     *  both {@code null}
1028     * @since 3.0 Changed signature from equalsIgnoreCase(String, String) to equalsIgnoreCase(CharSequence, CharSequence)
1029     */
1030    public static boolean equalsIgnoreCase(final CharSequence str1, final CharSequence str2) {
1031        if (str1 == null || str2 == null) {
1032            return str1 == str2;
1033        } else if (str1 == str2) {
1034            return true;
1035        } else if (str1.length() != str2.length()) {
1036            return false;
1037        } else {
1038            return CharSequenceUtils.regionMatches(str1, true, 0, str2, 0, str1.length());
1039        }
1040    }
1041
1042    // Compare
1043    //-----------------------------------------------------------------------
1044    /**
1045     * <p>Compare two Strings lexicographically, as per {@link String#compareTo(String)}, returning :</p>
1046     * <ul>
1047     *  <li>{@code int = 0}, if {@code str1} is equal to {@code str2} (or both {@code null})</li>
1048     *  <li>{@code int < 0}, if {@code str1} is less than {@code str2}</li>
1049     *  <li>{@code int > 0}, if {@code str1} is greater than {@code str2}</li>
1050     * </ul>
1051     *
1052     * <p>This is a {@code null} safe version of :</p>
1053     * <blockquote><pre>str1.compareTo(str2)</pre></blockquote>
1054     *
1055     * <p>{@code null} value is considered less than non-{@code null} value.
1056     * Two {@code null} references are considered equal.</p>
1057     *
1058     * <pre>
1059     * StringUtils.compare(null, null)   = 0
1060     * StringUtils.compare(null , "a")   &lt; 0
1061     * StringUtils.compare("a", null)    &gt; 0
1062     * StringUtils.compare("abc", "abc") = 0
1063     * StringUtils.compare("a", "b")     &lt; 0
1064     * StringUtils.compare("b", "a")     &gt; 0
1065     * StringUtils.compare("a", "B")     &gt; 0
1066     * StringUtils.compare("ab", "abc")  &lt; 0
1067     * </pre>
1068     *
1069     * @see #compare(String, String, boolean)
1070     * @see String#compareTo(String)
1071     * @param str1  the String to compare from
1072     * @param str2  the String to compare to
1073     * @return &lt; 0, 0, &gt; 0, if {@code str1} is respectively less, equal or greater than {@code str2}
1074     * @since 3.5
1075     */
1076    public static int compare(final String str1, final String str2) {
1077        return compare(str1, str2, true);
1078    }
1079
1080    /**
1081     * <p>Compare two Strings lexicographically, as per {@link String#compareTo(String)}, returning :</p>
1082     * <ul>
1083     *  <li>{@code int = 0}, if {@code str1} is equal to {@code str2} (or both {@code null})</li>
1084     *  <li>{@code int < 0}, if {@code str1} is less than {@code str2}</li>
1085     *  <li>{@code int > 0}, if {@code str1} is greater than {@code str2}</li>
1086     * </ul>
1087     *
1088     * <p>This is a {@code null} safe version of :</p>
1089     * <blockquote><pre>str1.compareTo(str2)</pre></blockquote>
1090     *
1091     * <p>{@code null} inputs are handled according to the {@code nullIsLess} parameter.
1092     * Two {@code null} references are considered equal.</p>
1093     *
1094     * <pre>
1095     * StringUtils.compare(null, null, *)     = 0
1096     * StringUtils.compare(null , "a", true)  &lt; 0
1097     * StringUtils.compare(null , "a", false) &gt; 0
1098     * StringUtils.compare("a", null, true)   &gt; 0
1099     * StringUtils.compare("a", null, false)  &lt; 0
1100     * StringUtils.compare("abc", "abc", *)   = 0
1101     * StringUtils.compare("a", "b", *)       &lt; 0
1102     * StringUtils.compare("b", "a", *)       &gt; 0
1103     * StringUtils.compare("a", "B", *)       &gt; 0
1104     * StringUtils.compare("ab", "abc", *)    &lt; 0
1105     * </pre>
1106     *
1107     * @see String#compareTo(String)
1108     * @param str1  the String to compare from
1109     * @param str2  the String to compare to
1110     * @param nullIsLess  whether consider {@code null} value less than non-{@code null} value
1111     * @return &lt; 0, 0, &gt; 0, if {@code str1} is respectively less, equal ou greater than {@code str2}
1112     * @since 3.5
1113     */
1114    public static int compare(final String str1, final String str2, final boolean nullIsLess) {
1115        if (str1 == str2) {
1116            return 0;
1117        }
1118        if (str1 == null) {
1119            return nullIsLess ? -1 : 1;
1120        }
1121        if (str2 == null) {
1122            return nullIsLess ? 1 : - 1;
1123        }
1124        return str1.compareTo(str2);
1125    }
1126
1127    /**
1128     * <p>Compare two Strings lexicographically, ignoring case differences,
1129     * as per {@link String#compareToIgnoreCase(String)}, returning :</p>
1130     * <ul>
1131     *  <li>{@code int = 0}, if {@code str1} is equal to {@code str2} (or both {@code null})</li>
1132     *  <li>{@code int < 0}, if {@code str1} is less than {@code str2}</li>
1133     *  <li>{@code int > 0}, if {@code str1} is greater than {@code str2}</li>
1134     * </ul>
1135     *
1136     * <p>This is a {@code null} safe version of :</p>
1137     * <blockquote><pre>str1.compareToIgnoreCase(str2)</pre></blockquote>
1138     *
1139     * <p>{@code null} value is considered less than non-{@code null} value.
1140     * Two {@code null} references are considered equal.
1141     * Comparison is case insensitive.</p>
1142     *
1143     * <pre>
1144     * StringUtils.compareIgnoreCase(null, null)   = 0
1145     * StringUtils.compareIgnoreCase(null , "a")   &lt; 0
1146     * StringUtils.compareIgnoreCase("a", null)    &gt; 0
1147     * StringUtils.compareIgnoreCase("abc", "abc") = 0
1148     * StringUtils.compareIgnoreCase("abc", "ABC") = 0
1149     * StringUtils.compareIgnoreCase("a", "b")     &lt; 0
1150     * StringUtils.compareIgnoreCase("b", "a")     &gt; 0
1151     * StringUtils.compareIgnoreCase("a", "B")     &lt; 0
1152     * StringUtils.compareIgnoreCase("A", "b")     &lt; 0
1153     * StringUtils.compareIgnoreCase("ab", "ABC")  &lt; 0
1154     * </pre>
1155     *
1156     * @see #compareIgnoreCase(String, String, boolean)
1157     * @see String#compareToIgnoreCase(String)
1158     * @param str1  the String to compare from
1159     * @param str2  the String to compare to
1160     * @return &lt; 0, 0, &gt; 0, if {@code str1} is respectively less, equal ou greater than {@code str2},
1161     *          ignoring case differences.
1162     * @since 3.5
1163     */
1164    public static int compareIgnoreCase(final String str1, final String str2) {
1165        return compareIgnoreCase(str1, str2, true);
1166    }
1167
1168    /**
1169     * <p>Compare two Strings lexicographically, ignoring case differences,
1170     * as per {@link String#compareToIgnoreCase(String)}, returning :</p>
1171     * <ul>
1172     *  <li>{@code int = 0}, if {@code str1} is equal to {@code str2} (or both {@code null})</li>
1173     *  <li>{@code int < 0}, if {@code str1} is less than {@code str2}</li>
1174     *  <li>{@code int > 0}, if {@code str1} is greater than {@code str2}</li>
1175     * </ul>
1176     *
1177     * <p>This is a {@code null} safe version of :</p>
1178     * <blockquote><pre>str1.compareToIgnoreCase(str2)</pre></blockquote>
1179     *
1180     * <p>{@code null} inputs are handled according to the {@code nullIsLess} parameter.
1181     * Two {@code null} references are considered equal.
1182     * Comparison is case insensitive.</p>
1183     *
1184     * <pre>
1185     * StringUtils.compareIgnoreCase(null, null, *)     = 0
1186     * StringUtils.compareIgnoreCase(null , "a", true)  &lt; 0
1187     * StringUtils.compareIgnoreCase(null , "a", false) &gt; 0
1188     * StringUtils.compareIgnoreCase("a", null, true)   &gt; 0
1189     * StringUtils.compareIgnoreCase("a", null, false)  &lt; 0
1190     * StringUtils.compareIgnoreCase("abc", "abc", *)   = 0
1191     * StringUtils.compareIgnoreCase("abc", "ABC", *)   = 0
1192     * StringUtils.compareIgnoreCase("a", "b", *)       &lt; 0
1193     * StringUtils.compareIgnoreCase("b", "a", *)       &gt; 0
1194     * StringUtils.compareIgnoreCase("a", "B", *)       &lt; 0
1195     * StringUtils.compareIgnoreCase("A", "b", *)       &lt; 0
1196     * StringUtils.compareIgnoreCase("ab", "abc", *)    &lt; 0
1197     * </pre>
1198     *
1199     * @see String#compareToIgnoreCase(String)
1200     * @param str1  the String to compare from
1201     * @param str2  the String to compare to
1202     * @param nullIsLess  whether consider {@code null} value less than non-{@code null} value
1203     * @return &lt; 0, 0, &gt; 0, if {@code str1} is respectively less, equal ou greater than {@code str2},
1204     *          ignoring case differences.
1205     * @since 3.5
1206     */
1207    public static int compareIgnoreCase(final String str1, final String str2, final boolean nullIsLess) {
1208        if (str1 == str2) {
1209            return 0;
1210        }
1211        if (str1 == null) {
1212            return nullIsLess ? -1 : 1;
1213        }
1214        if (str2 == null) {
1215            return nullIsLess ? 1 : - 1;
1216        }
1217        return str1.compareToIgnoreCase(str2);
1218    }
1219
1220    /**
1221     * <p>Compares given <code>string</code> to a CharSequences vararg of <code>searchStrings</code>,
1222     * returning {@code true} if the <code>string</code> is equal to any of the <code>searchStrings</code>.</p>
1223     *
1224     * <pre>
1225     * StringUtils.equalsAny(null, (CharSequence[]) null) = false
1226     * StringUtils.equalsAny(null, null, null)    = true
1227     * StringUtils.equalsAny(null, "abc", "def")  = false
1228     * StringUtils.equalsAny("abc", null, "def")  = false
1229     * StringUtils.equalsAny("abc", "abc", "def") = true
1230     * StringUtils.equalsAny("abc", "ABC", "DEF") = false
1231     * </pre>
1232     *
1233     * @param string to compare, may be {@code null}.
1234     * @param searchStrings a vararg of strings, may be {@code null}.
1235     * @return {@code true} if the string is equal (case-sensitive) to any other element of <code>searchStrings</code>;
1236     * {@code false} if <code>searchStrings</code> is null or contains no matches.
1237     * @since 3.5
1238     */
1239    public static boolean equalsAny(final CharSequence string, final CharSequence... searchStrings) {
1240        if (ArrayUtils.isNotEmpty(searchStrings)) {
1241            for (final CharSequence next : searchStrings) {
1242                if (equals(string, next)) {
1243                    return true;
1244                }
1245            }
1246        }
1247        return false;
1248    }
1249
1250
1251    /**
1252     * <p>Compares given <code>string</code> to a CharSequences vararg of <code>searchStrings</code>,
1253     * returning {@code true} if the <code>string</code> is equal to any of the <code>searchStrings</code>, ignoring case.</p>
1254     *
1255     * <pre>
1256     * StringUtils.equalsAnyIgnoreCase(null, (CharSequence[]) null) = false
1257     * StringUtils.equalsAnyIgnoreCase(null, null, null)    = true
1258     * StringUtils.equalsAnyIgnoreCase(null, "abc", "def")  = false
1259     * StringUtils.equalsAnyIgnoreCase("abc", null, "def")  = false
1260     * StringUtils.equalsAnyIgnoreCase("abc", "abc", "def") = true
1261     * StringUtils.equalsAnyIgnoreCase("abc", "ABC", "DEF") = true
1262     * </pre>
1263     *
1264     * @param string to compare, may be {@code null}.
1265     * @param searchStrings a vararg of strings, may be {@code null}.
1266     * @return {@code true} if the string is equal (case-insensitive) to any other element of <code>searchStrings</code>;
1267     * {@code false} if <code>searchStrings</code> is null or contains no matches.
1268     * @since 3.5
1269     */
1270    public static boolean equalsAnyIgnoreCase(final CharSequence string, final CharSequence...searchStrings) {
1271        if (ArrayUtils.isNotEmpty(searchStrings)) {
1272            for (final CharSequence next : searchStrings) {
1273                if (equalsIgnoreCase(string, next)) {
1274                    return true;
1275                }
1276            }
1277        }
1278        return false;
1279    }
1280
1281    // IndexOf
1282    //-----------------------------------------------------------------------
1283    /**
1284     * Returns the index within <code>seq</code> of the first occurrence of
1285     * the specified character. If a character with value
1286     * <code>searchChar</code> occurs in the character sequence represented by
1287     * <code>seq</code> <code>CharSequence</code> object, then the index (in Unicode
1288     * code units) of the first such occurrence is returned. For
1289     * values of <code>searchChar</code> in the range from 0 to 0xFFFF
1290     * (inclusive), this is the smallest value <i>k</i> such that:
1291     * <blockquote><pre>
1292     * this.charAt(<i>k</i>) == searchChar
1293     * </pre></blockquote>
1294     * is true. For other values of <code>searchChar</code>, it is the
1295     * smallest value <i>k</i> such that:
1296     * <blockquote><pre>
1297     * this.codePointAt(<i>k</i>) == searchChar
1298     * </pre></blockquote>
1299     * is true. In either case, if no such character occurs in <code>seq</code>,
1300     * then {@code INDEX_NOT_FOUND (-1)} is returned.
1301     *
1302     * <p>Furthermore, a {@code null} or empty ("") CharSequence will
1303     * return {@code INDEX_NOT_FOUND (-1)}.</p>
1304     *
1305     * <pre>
1306     * StringUtils.indexOf(null, *)         = -1
1307     * StringUtils.indexOf("", *)           = -1
1308     * StringUtils.indexOf("aabaabaa", 'a') = 0
1309     * StringUtils.indexOf("aabaabaa", 'b') = 2
1310     * </pre>
1311     *
1312     * @param seq  the CharSequence to check, may be null
1313     * @param searchChar  the character to find
1314     * @return the first index of the search character,
1315     *  -1 if no match or {@code null} string input
1316     * @since 2.0
1317     * @since 3.0 Changed signature from indexOf(String, int) to indexOf(CharSequence, int)
1318     * @since 3.6 Updated {@link CharSequenceUtils} call to behave more like <code>String</code>
1319     */
1320    public static int indexOf(final CharSequence seq, final int searchChar) {
1321        if (isEmpty(seq)) {
1322            return INDEX_NOT_FOUND;
1323        }
1324        return CharSequenceUtils.indexOf(seq, searchChar, 0);
1325    }
1326
1327    /**
1328     *
1329     * Returns the index within <code>seq</code> of the first occurrence of the
1330     * specified character, starting the search at the specified index.
1331     * <p>
1332     * If a character with value <code>searchChar</code> occurs in the
1333     * character sequence represented by the <code>seq</code> <code>CharSequence</code>
1334     * object at an index no smaller than <code>startPos</code>, then
1335     * the index of the first such occurrence is returned. For values
1336     * of <code>searchChar</code> in the range from 0 to 0xFFFF (inclusive),
1337     * this is the smallest value <i>k</i> such that:
1338     * <blockquote><pre>
1339     * (this.charAt(<i>k</i>) == searchChar) &amp;&amp; (<i>k</i> &gt;= startPos)
1340     * </pre></blockquote>
1341     * is true. For other values of <code>searchChar</code>, it is the
1342     * smallest value <i>k</i> such that:
1343     * <blockquote><pre>
1344     * (this.codePointAt(<i>k</i>) == searchChar) &amp;&amp; (<i>k</i> &gt;= startPos)
1345     * </pre></blockquote>
1346     * is true. In either case, if no such character occurs in <code>seq</code>
1347     * at or after position <code>startPos</code>, then
1348     * <code>-1</code> is returned.
1349     *
1350     * <p>
1351     * There is no restriction on the value of <code>startPos</code>. If it
1352     * is negative, it has the same effect as if it were zero: this entire
1353     * string may be searched. If it is greater than the length of this
1354     * string, it has the same effect as if it were equal to the length of
1355     * this string: {@code (INDEX_NOT_FOUND) -1} is returned. Furthermore, a
1356     * {@code null} or empty ("") CharSequence will
1357     * return {@code (INDEX_NOT_FOUND) -1}.
1358     *
1359     * <p>All indices are specified in <code>char</code> values
1360     * (Unicode code units).
1361     *
1362     * <pre>
1363     * StringUtils.indexOf(null, *, *)          = -1
1364     * StringUtils.indexOf("", *, *)            = -1
1365     * StringUtils.indexOf("aabaabaa", 'b', 0)  = 2
1366     * StringUtils.indexOf("aabaabaa", 'b', 3)  = 5
1367     * StringUtils.indexOf("aabaabaa", 'b', 9)  = -1
1368     * StringUtils.indexOf("aabaabaa", 'b', -1) = 2
1369     * </pre>
1370     *
1371     * @param seq  the CharSequence to check, may be null
1372     * @param searchChar  the character to find
1373     * @param startPos  the start position, negative treated as zero
1374     * @return the first index of the search character (always &ge; startPos),
1375     *  -1 if no match or {@code null} string input
1376     * @since 2.0
1377     * @since 3.0 Changed signature from indexOf(String, int, int) to indexOf(CharSequence, int, int)
1378     * @since 3.6 Updated {@link CharSequenceUtils} call to behave more like <code>String</code>
1379     */
1380    public static int indexOf(final CharSequence seq, final int searchChar, final int startPos) {
1381        if (isEmpty(seq)) {
1382            return INDEX_NOT_FOUND;
1383        }
1384        return CharSequenceUtils.indexOf(seq, searchChar, startPos);
1385    }
1386
1387    /**
1388     * <p>Finds the first index within a CharSequence, handling {@code null}.
1389     * This method uses {@link String#indexOf(String, int)} if possible.</p>
1390     *
1391     * <p>A {@code null} CharSequence will return {@code -1}.</p>
1392     *
1393     * <pre>
1394     * StringUtils.indexOf(null, *)          = -1
1395     * StringUtils.indexOf(*, null)          = -1
1396     * StringUtils.indexOf("", "")           = 0
1397     * StringUtils.indexOf("", *)            = -1 (except when * = "")
1398     * StringUtils.indexOf("aabaabaa", "a")  = 0
1399     * StringUtils.indexOf("aabaabaa", "b")  = 2
1400     * StringUtils.indexOf("aabaabaa", "ab") = 1
1401     * StringUtils.indexOf("aabaabaa", "")   = 0
1402     * </pre>
1403     *
1404     * @param seq  the CharSequence to check, may be null
1405     * @param searchSeq  the CharSequence to find, may be null
1406     * @return the first index of the search CharSequence,
1407     *  -1 if no match or {@code null} string input
1408     * @since 2.0
1409     * @since 3.0 Changed signature from indexOf(String, String) to indexOf(CharSequence, CharSequence)
1410     */
1411    public static int indexOf(final CharSequence seq, final CharSequence searchSeq) {
1412        if (seq == null || searchSeq == null) {
1413            return INDEX_NOT_FOUND;
1414        }
1415        return CharSequenceUtils.indexOf(seq, searchSeq, 0);
1416    }
1417
1418    /**
1419     * <p>Finds the first index within a CharSequence, handling {@code null}.
1420     * This method uses {@link String#indexOf(String, int)} if possible.</p>
1421     *
1422     * <p>A {@code null} CharSequence will return {@code -1}.
1423     * A negative start position is treated as zero.
1424     * An empty ("") search CharSequence always matches.
1425     * A start position greater than the string length only matches
1426     * an empty search CharSequence.</p>
1427     *
1428     * <pre>
1429     * StringUtils.indexOf(null, *, *)          = -1
1430     * StringUtils.indexOf(*, null, *)          = -1
1431     * StringUtils.indexOf("", "", 0)           = 0
1432     * StringUtils.indexOf("", *, 0)            = -1 (except when * = "")
1433     * StringUtils.indexOf("aabaabaa", "a", 0)  = 0
1434     * StringUtils.indexOf("aabaabaa", "b", 0)  = 2
1435     * StringUtils.indexOf("aabaabaa", "ab", 0) = 1
1436     * StringUtils.indexOf("aabaabaa", "b", 3)  = 5
1437     * StringUtils.indexOf("aabaabaa", "b", 9)  = -1
1438     * StringUtils.indexOf("aabaabaa", "b", -1) = 2
1439     * StringUtils.indexOf("aabaabaa", "", 2)   = 2
1440     * StringUtils.indexOf("abc", "", 9)        = 3
1441     * </pre>
1442     *
1443     * @param seq  the CharSequence to check, may be null
1444     * @param searchSeq  the CharSequence to find, may be null
1445     * @param startPos  the start position, negative treated as zero
1446     * @return the first index of the search CharSequence (always &ge; startPos),
1447     *  -1 if no match or {@code null} string input
1448     * @since 2.0
1449     * @since 3.0 Changed signature from indexOf(String, String, int) to indexOf(CharSequence, CharSequence, int)
1450     */
1451    public static int indexOf(final CharSequence seq, final CharSequence searchSeq, final int startPos) {
1452        if (seq == null || searchSeq == null) {
1453            return INDEX_NOT_FOUND;
1454        }
1455        return CharSequenceUtils.indexOf(seq, searchSeq, startPos);
1456    }
1457
1458    /**
1459     * <p>Finds the n-th index within a CharSequence, handling {@code null}.
1460     * This method uses {@link String#indexOf(String)} if possible.</p>
1461     * <p><b>Note:</b> The code starts looking for a match at the start of the target,
1462     * incrementing the starting index by one after each successful match
1463     * (unless {@code searchStr} is an empty string in which case the position
1464     * is never incremented and {@code 0} is returned immediately).
1465     * This means that matches may overlap.</p>
1466     * <p>A {@code null} CharSequence will return {@code -1}.</p>
1467     *
1468     * <pre>
1469     * StringUtils.ordinalIndexOf(null, *, *)          = -1
1470     * StringUtils.ordinalIndexOf(*, null, *)          = -1
1471     * StringUtils.ordinalIndexOf("", "", *)           = 0
1472     * StringUtils.ordinalIndexOf("aabaabaa", "a", 1)  = 0
1473     * StringUtils.ordinalIndexOf("aabaabaa", "a", 2)  = 1
1474     * StringUtils.ordinalIndexOf("aabaabaa", "b", 1)  = 2
1475     * StringUtils.ordinalIndexOf("aabaabaa", "b", 2)  = 5
1476     * StringUtils.ordinalIndexOf("aabaabaa", "ab", 1) = 1
1477     * StringUtils.ordinalIndexOf("aabaabaa", "ab", 2) = 4
1478     * StringUtils.ordinalIndexOf("aabaabaa", "", 1)   = 0
1479     * StringUtils.ordinalIndexOf("aabaabaa", "", 2)   = 0
1480     * </pre>
1481     *
1482     * <p>Matches may overlap:</p>
1483     * <pre>
1484     * StringUtils.ordinalIndexOf("ababab","aba", 1)   = 0
1485     * StringUtils.ordinalIndexOf("ababab","aba", 2)   = 2
1486     * StringUtils.ordinalIndexOf("ababab","aba", 3)   = -1
1487     *
1488     * StringUtils.ordinalIndexOf("abababab", "abab", 1) = 0
1489     * StringUtils.ordinalIndexOf("abababab", "abab", 2) = 2
1490     * StringUtils.ordinalIndexOf("abababab", "abab", 3) = 4
1491     * StringUtils.ordinalIndexOf("abababab", "abab", 4) = -1
1492     * </pre>
1493     *
1494     * <p>Note that 'head(CharSequence str, int n)' may be implemented as: </p>
1495     *
1496     * <pre>
1497     *   str.substring(0, lastOrdinalIndexOf(str, "\n", n))
1498     * </pre>
1499     *
1500     * @param str  the CharSequence to check, may be null
1501     * @param searchStr  the CharSequence to find, may be null
1502     * @param ordinal  the n-th {@code searchStr} to find
1503     * @return the n-th index of the search CharSequence,
1504     *  {@code -1} ({@code INDEX_NOT_FOUND}) if no match or {@code null} string input
1505     * @since 2.1
1506     * @since 3.0 Changed signature from ordinalIndexOf(String, String, int) to ordinalIndexOf(CharSequence, CharSequence, int)
1507     */
1508    public static int ordinalIndexOf(final CharSequence str, final CharSequence searchStr, final int ordinal) {
1509        return ordinalIndexOf(str, searchStr, ordinal, false);
1510    }
1511
1512    /**
1513     * <p>Finds the n-th index within a String, handling {@code null}.
1514     * This method uses {@link String#indexOf(String)} if possible.</p>
1515     * <p>Note that matches may overlap<p>
1516     *
1517     * <p>A {@code null} CharSequence will return {@code -1}.</p>
1518     *
1519     * @param str  the CharSequence to check, may be null
1520     * @param searchStr  the CharSequence to find, may be null
1521     * @param ordinal  the n-th {@code searchStr} to find, overlapping matches are allowed.
1522     * @param lastIndex true if lastOrdinalIndexOf() otherwise false if ordinalIndexOf()
1523     * @return the n-th index of the search CharSequence,
1524     *  {@code -1} ({@code INDEX_NOT_FOUND}) if no match or {@code null} string input
1525     */
1526    // Shared code between ordinalIndexOf(String,String,int) and lastOrdinalIndexOf(String,String,int)
1527    private static int ordinalIndexOf(final CharSequence str, final CharSequence searchStr, final int ordinal, final boolean lastIndex) {
1528        if (str == null || searchStr == null || ordinal <= 0) {
1529            return INDEX_NOT_FOUND;
1530        }
1531        if (searchStr.length() == 0) {
1532            return lastIndex ? str.length() : 0;
1533        }
1534        int found = 0;
1535        // set the initial index beyond the end of the string
1536        // this is to allow for the initial index decrement/increment
1537        int index = lastIndex ? str.length() : INDEX_NOT_FOUND;
1538        do {
1539            if (lastIndex) {
1540                index = CharSequenceUtils.lastIndexOf(str, searchStr, index - 1); // step backwards thru string
1541            } else {
1542                index = CharSequenceUtils.indexOf(str, searchStr, index + 1); // step forwards through string
1543            }
1544            if (index < 0) {
1545                return index;
1546            }
1547            found++;
1548        } while (found < ordinal);
1549        return index;
1550    }
1551
1552    /**
1553     * <p>Case in-sensitive find of the first index within a CharSequence.</p>
1554     *
1555     * <p>A {@code null} CharSequence will return {@code -1}.
1556     * A negative start position is treated as zero.
1557     * An empty ("") search CharSequence always matches.
1558     * A start position greater than the string length only matches
1559     * an empty search CharSequence.</p>
1560     *
1561     * <pre>
1562     * StringUtils.indexOfIgnoreCase(null, *)          = -1
1563     * StringUtils.indexOfIgnoreCase(*, null)          = -1
1564     * StringUtils.indexOfIgnoreCase("", "")           = 0
1565     * StringUtils.indexOfIgnoreCase("aabaabaa", "a")  = 0
1566     * StringUtils.indexOfIgnoreCase("aabaabaa", "b")  = 2
1567     * StringUtils.indexOfIgnoreCase("aabaabaa", "ab") = 1
1568     * </pre>
1569     *
1570     * @param str  the CharSequence to check, may be null
1571     * @param searchStr  the CharSequence to find, may be null
1572     * @return the first index of the search CharSequence,
1573     *  -1 if no match or {@code null} string input
1574     * @since 2.5
1575     * @since 3.0 Changed signature from indexOfIgnoreCase(String, String) to indexOfIgnoreCase(CharSequence, CharSequence)
1576     */
1577    public static int indexOfIgnoreCase(final CharSequence str, final CharSequence searchStr) {
1578        return indexOfIgnoreCase(str, searchStr, 0);
1579    }
1580
1581    /**
1582     * <p>Case in-sensitive find of the first index within a CharSequence
1583     * from the specified position.</p>
1584     *
1585     * <p>A {@code null} CharSequence will return {@code -1}.
1586     * A negative start position is treated as zero.
1587     * An empty ("") search CharSequence always matches.
1588     * A start position greater than the string length only matches
1589     * an empty search CharSequence.</p>
1590     *
1591     * <pre>
1592     * StringUtils.indexOfIgnoreCase(null, *, *)          = -1
1593     * StringUtils.indexOfIgnoreCase(*, null, *)          = -1
1594     * StringUtils.indexOfIgnoreCase("", "", 0)           = 0
1595     * StringUtils.indexOfIgnoreCase("aabaabaa", "A", 0)  = 0
1596     * StringUtils.indexOfIgnoreCase("aabaabaa", "B", 0)  = 2
1597     * StringUtils.indexOfIgnoreCase("aabaabaa", "AB", 0) = 1
1598     * StringUtils.indexOfIgnoreCase("aabaabaa", "B", 3)  = 5
1599     * StringUtils.indexOfIgnoreCase("aabaabaa", "B", 9)  = -1
1600     * StringUtils.indexOfIgnoreCase("aabaabaa", "B", -1) = 2
1601     * StringUtils.indexOfIgnoreCase("aabaabaa", "", 2)   = 2
1602     * StringUtils.indexOfIgnoreCase("abc", "", 9)        = -1
1603     * </pre>
1604     *
1605     * @param str  the CharSequence to check, may be null
1606     * @param searchStr  the CharSequence to find, may be null
1607     * @param startPos  the start position, negative treated as zero
1608     * @return the first index of the search CharSequence (always &ge; startPos),
1609     *  -1 if no match or {@code null} string input
1610     * @since 2.5
1611     * @since 3.0 Changed signature from indexOfIgnoreCase(String, String, int) to indexOfIgnoreCase(CharSequence, CharSequence, int)
1612     */
1613    public static int indexOfIgnoreCase(final CharSequence str, final CharSequence searchStr, int startPos) {
1614        if (str == null || searchStr == null) {
1615            return INDEX_NOT_FOUND;
1616        }
1617        if (startPos < 0) {
1618            startPos = 0;
1619        }
1620        final int endLimit = str.length() - searchStr.length() + 1;
1621        if (startPos > endLimit) {
1622            return INDEX_NOT_FOUND;
1623        }
1624        if (searchStr.length() == 0) {
1625            return startPos;
1626        }
1627        for (int i = startPos; i < endLimit; i++) {
1628            if (CharSequenceUtils.regionMatches(str, true, i, searchStr, 0, searchStr.length())) {
1629                return i;
1630            }
1631        }
1632        return INDEX_NOT_FOUND;
1633    }
1634
1635    // LastIndexOf
1636    //-----------------------------------------------------------------------
1637    /**
1638     * Returns the index within <code>seq</code> of the last occurrence of
1639     * the specified character. For values of <code>searchChar</code> in the
1640     * range from 0 to 0xFFFF (inclusive), the index (in Unicode code
1641     * units) returned is the largest value <i>k</i> such that:
1642     * <blockquote><pre>
1643     * this.charAt(<i>k</i>) == searchChar
1644     * </pre></blockquote>
1645     * is true. For other values of <code>searchChar</code>, it is the
1646     * largest value <i>k</i> such that:
1647     * <blockquote><pre>
1648     * this.codePointAt(<i>k</i>) == searchChar
1649     * </pre></blockquote>
1650     * is true.  In either case, if no such character occurs in this
1651     * string, then <code>-1</code> is returned. Furthermore, a {@code null} or empty ("")
1652     * <code>CharSequence</code> will return {@code -1}. The
1653     * <code>seq</code> <code>CharSequence</code> object is searched backwards
1654     * starting at the last character.
1655     *
1656     * <pre>
1657     * StringUtils.lastIndexOf(null, *)         = -1
1658     * StringUtils.lastIndexOf("", *)           = -1
1659     * StringUtils.lastIndexOf("aabaabaa", 'a') = 7
1660     * StringUtils.lastIndexOf("aabaabaa", 'b') = 5
1661     * </pre>
1662     *
1663     * @param seq  the <code>CharSequence</code> to check, may be null
1664     * @param searchChar  the character to find
1665     * @return the last index of the search character,
1666     *  -1 if no match or {@code null} string input
1667     * @since 2.0
1668     * @since 3.0 Changed signature from lastIndexOf(String, int) to lastIndexOf(CharSequence, int)
1669     * @since 3.6 Updated {@link CharSequenceUtils} call to behave more like <code>String</code>
1670     */
1671    public static int lastIndexOf(final CharSequence seq, final int searchChar) {
1672        if (isEmpty(seq)) {
1673            return INDEX_NOT_FOUND;
1674        }
1675        return CharSequenceUtils.lastIndexOf(seq, searchChar, seq.length());
1676    }
1677
1678    /**
1679     * Returns the index within <code>seq</code> of the last occurrence of
1680     * the specified character, searching backward starting at the
1681     * specified index. For values of <code>searchChar</code> in the range
1682     * from 0 to 0xFFFF (inclusive), the index returned is the largest
1683     * value <i>k</i> such that:
1684     * <blockquote><pre>
1685     * (this.charAt(<i>k</i>) == searchChar) &amp;&amp; (<i>k</i> &lt;= startPos)
1686     * </pre></blockquote>
1687     * is true. For other values of <code>searchChar</code>, it is the
1688     * largest value <i>k</i> such that:
1689     * <blockquote><pre>
1690     * (this.codePointAt(<i>k</i>) == searchChar) &amp;&amp; (<i>k</i> &lt;= startPos)
1691     * </pre></blockquote>
1692     * is true. In either case, if no such character occurs in <code>seq</code>
1693     * at or before position <code>startPos</code>, then
1694     * <code>-1</code> is returned. Furthermore, a {@code null} or empty ("")
1695     * <code>CharSequence</code> will return {@code -1}. A start position greater
1696     * than the string length searches the whole string.
1697     * The search starts at the <code>startPos</code> and works backwards;
1698     * matches starting after the start position are ignored.
1699     *
1700     * <p>All indices are specified in <code>char</code> values
1701     * (Unicode code units).
1702     *
1703     * <pre>
1704     * StringUtils.lastIndexOf(null, *, *)          = -1
1705     * StringUtils.lastIndexOf("", *,  *)           = -1
1706     * StringUtils.lastIndexOf("aabaabaa", 'b', 8)  = 5
1707     * StringUtils.lastIndexOf("aabaabaa", 'b', 4)  = 2
1708     * StringUtils.lastIndexOf("aabaabaa", 'b', 0)  = -1
1709     * StringUtils.lastIndexOf("aabaabaa", 'b', 9)  = 5
1710     * StringUtils.lastIndexOf("aabaabaa", 'b', -1) = -1
1711     * StringUtils.lastIndexOf("aabaabaa", 'a', 0)  = 0
1712     * </pre>
1713     *
1714     * @param seq  the CharSequence to check, may be null
1715     * @param searchChar  the character to find
1716     * @param startPos  the start position
1717     * @return the last index of the search character (always &le; startPos),
1718     *  -1 if no match or {@code null} string input
1719     * @since 2.0
1720     * @since 3.0 Changed signature from lastIndexOf(String, int, int) to lastIndexOf(CharSequence, int, int)
1721     */
1722    public static int lastIndexOf(final CharSequence seq, final int searchChar, final int startPos) {
1723        if (isEmpty(seq)) {
1724            return INDEX_NOT_FOUND;
1725        }
1726        return CharSequenceUtils.lastIndexOf(seq, searchChar, startPos);
1727    }
1728
1729    /**
1730     * <p>Finds the last index within a CharSequence, handling {@code null}.
1731     * This method uses {@link String#lastIndexOf(String)} if possible.</p>
1732     *
1733     * <p>A {@code null} CharSequence will return {@code -1}.</p>
1734     *
1735     * <pre>
1736     * StringUtils.lastIndexOf(null, *)          = -1
1737     * StringUtils.lastIndexOf(*, null)          = -1
1738     * StringUtils.lastIndexOf("", "")           = 0
1739     * StringUtils.lastIndexOf("aabaabaa", "a")  = 7
1740     * StringUtils.lastIndexOf("aabaabaa", "b")  = 5
1741     * StringUtils.lastIndexOf("aabaabaa", "ab") = 4
1742     * StringUtils.lastIndexOf("aabaabaa", "")   = 8
1743     * </pre>
1744     *
1745     * @param seq  the CharSequence to check, may be null
1746     * @param searchSeq  the CharSequence to find, may be null
1747     * @return the last index of the search String,
1748     *  -1 if no match or {@code null} string input
1749     * @since 2.0
1750     * @since 3.0 Changed signature from lastIndexOf(String, String) to lastIndexOf(CharSequence, CharSequence)
1751     */
1752    public static int lastIndexOf(final CharSequence seq, final CharSequence searchSeq) {
1753        if (seq == null || searchSeq == null) {
1754            return INDEX_NOT_FOUND;
1755        }
1756        return CharSequenceUtils.lastIndexOf(seq, searchSeq, seq.length());
1757    }
1758
1759    /**
1760     * <p>Finds the n-th last index within a String, handling {@code null}.
1761     * This method uses {@link String#lastIndexOf(String)}.</p>
1762     *
1763     * <p>A {@code null} String will return {@code -1}.</p>
1764     *
1765     * <pre>
1766     * StringUtils.lastOrdinalIndexOf(null, *, *)          = -1
1767     * StringUtils.lastOrdinalIndexOf(*, null, *)          = -1
1768     * StringUtils.lastOrdinalIndexOf("", "", *)           = 0
1769     * StringUtils.lastOrdinalIndexOf("aabaabaa", "a", 1)  = 7
1770     * StringUtils.lastOrdinalIndexOf("aabaabaa", "a", 2)  = 6
1771     * StringUtils.lastOrdinalIndexOf("aabaabaa", "b", 1)  = 5
1772     * StringUtils.lastOrdinalIndexOf("aabaabaa", "b", 2)  = 2
1773     * StringUtils.lastOrdinalIndexOf("aabaabaa", "ab", 1) = 4
1774     * StringUtils.lastOrdinalIndexOf("aabaabaa", "ab", 2) = 1
1775     * StringUtils.lastOrdinalIndexOf("aabaabaa", "", 1)   = 8
1776     * StringUtils.lastOrdinalIndexOf("aabaabaa", "", 2)   = 8
1777     * </pre>
1778     *
1779     * <p>Note that 'tail(CharSequence str, int n)' may be implemented as: </p>
1780     *
1781     * <pre>
1782     *   str.substring(lastOrdinalIndexOf(str, "\n", n) + 1)
1783     * </pre>
1784     *
1785     * @param str  the CharSequence to check, may be null
1786     * @param searchStr  the CharSequence to find, may be null
1787     * @param ordinal  the n-th last {@code searchStr} to find
1788     * @return the n-th last index of the search CharSequence,
1789     *  {@code -1} ({@code INDEX_NOT_FOUND}) if no match or {@code null} string input
1790     * @since 2.5
1791     * @since 3.0 Changed signature from lastOrdinalIndexOf(String, String, int) to lastOrdinalIndexOf(CharSequence, CharSequence, int)
1792     */
1793    public static int lastOrdinalIndexOf(final CharSequence str, final CharSequence searchStr, final int ordinal) {
1794        return ordinalIndexOf(str, searchStr, ordinal, true);
1795    }
1796
1797    /**
1798     * <p>Finds the last index within a CharSequence, handling {@code null}.
1799     * This method uses {@link String#lastIndexOf(String, int)} if possible.</p>
1800     *
1801     * <p>A {@code null} CharSequence will return {@code -1}.
1802     * A negative start position returns {@code -1}.
1803     * An empty ("") search CharSequence always matches unless the start position is negative.
1804     * A start position greater than the string length searches the whole string.
1805     * The search starts at the startPos and works backwards; matches starting after the start
1806     * position are ignored.
1807     * </p>
1808     *
1809     * <pre>
1810     * StringUtils.lastIndexOf(null, *, *)          = -1
1811     * StringUtils.lastIndexOf(*, null, *)          = -1
1812     * StringUtils.lastIndexOf("aabaabaa", "a", 8)  = 7
1813     * StringUtils.lastIndexOf("aabaabaa", "b", 8)  = 5
1814     * StringUtils.lastIndexOf("aabaabaa", "ab", 8) = 4
1815     * StringUtils.lastIndexOf("aabaabaa", "b", 9)  = 5
1816     * StringUtils.lastIndexOf("aabaabaa", "b", -1) = -1
1817     * StringUtils.lastIndexOf("aabaabaa", "a", 0)  = 0
1818     * StringUtils.lastIndexOf("aabaabaa", "b", 0)  = -1
1819     * StringUtils.lastIndexOf("aabaabaa", "b", 1)  = -1
1820     * StringUtils.lastIndexOf("aabaabaa", "b", 2)  = 2
1821     * StringUtils.lastIndexOf("aabaabaa", "ba", 2)  = -1
1822     * StringUtils.lastIndexOf("aabaabaa", "ba", 2)  = 2
1823     * </pre>
1824     *
1825     * @param seq  the CharSequence to check, may be null
1826     * @param searchSeq  the CharSequence to find, may be null
1827     * @param startPos  the start position, negative treated as zero
1828     * @return the last index of the search CharSequence (always &le; startPos),
1829     *  -1 if no match or {@code null} string input
1830     * @since 2.0
1831     * @since 3.0 Changed signature from lastIndexOf(String, String, int) to lastIndexOf(CharSequence, CharSequence, int)
1832     */
1833    public static int lastIndexOf(final CharSequence seq, final CharSequence searchSeq, final int startPos) {
1834        if (seq == null || searchSeq == null) {
1835            return INDEX_NOT_FOUND;
1836        }
1837        return CharSequenceUtils.lastIndexOf(seq, searchSeq, startPos);
1838    }
1839
1840    /**
1841     * <p>Case in-sensitive find of the last index within a CharSequence.</p>
1842     *
1843     * <p>A {@code null} CharSequence will return {@code -1}.
1844     * A negative start position returns {@code -1}.
1845     * An empty ("") search CharSequence always matches unless the start position is negative.
1846     * A start position greater than the string length searches the whole string.</p>
1847     *
1848     * <pre>
1849     * StringUtils.lastIndexOfIgnoreCase(null, *)          = -1
1850     * StringUtils.lastIndexOfIgnoreCase(*, null)          = -1
1851     * StringUtils.lastIndexOfIgnoreCase("aabaabaa", "A")  = 7
1852     * StringUtils.lastIndexOfIgnoreCase("aabaabaa", "B")  = 5
1853     * StringUtils.lastIndexOfIgnoreCase("aabaabaa", "AB") = 4
1854     * </pre>
1855     *
1856     * @param str  the CharSequence to check, may be null
1857     * @param searchStr  the CharSequence to find, may be null
1858     * @return the first index of the search CharSequence,
1859     *  -1 if no match or {@code null} string input
1860     * @since 2.5
1861     * @since 3.0 Changed signature from lastIndexOfIgnoreCase(String, String) to lastIndexOfIgnoreCase(CharSequence, CharSequence)
1862     */
1863    public static int lastIndexOfIgnoreCase(final CharSequence str, final CharSequence searchStr) {
1864        if (str == null || searchStr == null) {
1865            return INDEX_NOT_FOUND;
1866        }
1867        return lastIndexOfIgnoreCase(str, searchStr, str.length());
1868    }
1869
1870    /**
1871     * <p>Case in-sensitive find of the last index within a CharSequence
1872     * from the specified position.</p>
1873     *
1874     * <p>A {@code null} CharSequence will return {@code -1}.
1875     * A negative start position returns {@code -1}.
1876     * An empty ("") search CharSequence always matches unless the start position is negative.
1877     * A start position greater than the string length searches the whole string.
1878     * The search starts at the startPos and works backwards; matches starting after the start
1879     * position are ignored.
1880     * </p>
1881     *
1882     * <pre>
1883     * StringUtils.lastIndexOfIgnoreCase(null, *, *)          = -1
1884     * StringUtils.lastIndexOfIgnoreCase(*, null, *)          = -1
1885     * StringUtils.lastIndexOfIgnoreCase("aabaabaa", "A", 8)  = 7
1886     * StringUtils.lastIndexOfIgnoreCase("aabaabaa", "B", 8)  = 5
1887     * StringUtils.lastIndexOfIgnoreCase("aabaabaa", "AB", 8) = 4
1888     * StringUtils.lastIndexOfIgnoreCase("aabaabaa", "B", 9)  = 5
1889     * StringUtils.lastIndexOfIgnoreCase("aabaabaa", "B", -1) = -1
1890     * StringUtils.lastIndexOfIgnoreCase("aabaabaa", "A", 0)  = 0
1891     * StringUtils.lastIndexOfIgnoreCase("aabaabaa", "B", 0)  = -1
1892     * </pre>
1893     *
1894     * @param str  the CharSequence to check, may be null
1895     * @param searchStr  the CharSequence to find, may be null
1896     * @param startPos  the start position
1897     * @return the last index of the search CharSequence (always &le; startPos),
1898     *  -1 if no match or {@code null} input
1899     * @since 2.5
1900     * @since 3.0 Changed signature from lastIndexOfIgnoreCase(String, String, int) to lastIndexOfIgnoreCase(CharSequence, CharSequence, int)
1901     */
1902    public static int lastIndexOfIgnoreCase(final CharSequence str, final CharSequence searchStr, int startPos) {
1903        if (str == null || searchStr == null) {
1904            return INDEX_NOT_FOUND;
1905        }
1906        if (startPos > str.length() - searchStr.length()) {
1907            startPos = str.length() - searchStr.length();
1908        }
1909        if (startPos < 0) {
1910            return INDEX_NOT_FOUND;
1911        }
1912        if (searchStr.length() == 0) {
1913            return startPos;
1914        }
1915
1916        for (int i = startPos; i >= 0; i--) {
1917            if (CharSequenceUtils.regionMatches(str, true, i, searchStr, 0, searchStr.length())) {
1918                return i;
1919            }
1920        }
1921        return INDEX_NOT_FOUND;
1922    }
1923
1924    // Contains
1925    //-----------------------------------------------------------------------
1926    /**
1927     * <p>Checks if CharSequence contains a search character, handling {@code null}.
1928     * This method uses {@link String#indexOf(int)} if possible.</p>
1929     *
1930     * <p>A {@code null} or empty ("") CharSequence will return {@code false}.</p>
1931     *
1932     * <pre>
1933     * StringUtils.contains(null, *)    = false
1934     * StringUtils.contains("", *)      = false
1935     * StringUtils.contains("abc", 'a') = true
1936     * StringUtils.contains("abc", 'z') = false
1937     * </pre>
1938     *
1939     * @param seq  the CharSequence to check, may be null
1940     * @param searchChar  the character to find
1941     * @return true if the CharSequence contains the search character,
1942     *  false if not or {@code null} string input
1943     * @since 2.0
1944     * @since 3.0 Changed signature from contains(String, int) to contains(CharSequence, int)
1945     */
1946    public static boolean contains(final CharSequence seq, final int searchChar) {
1947        if (isEmpty(seq)) {
1948            return false;
1949        }
1950        return CharSequenceUtils.indexOf(seq, searchChar, 0) >= 0;
1951    }
1952
1953    /**
1954     * <p>Checks if CharSequence contains a search CharSequence, handling {@code null}.
1955     * This method uses {@link String#indexOf(String)} if possible.</p>
1956     *
1957     * <p>A {@code null} CharSequence will return {@code false}.</p>
1958     *
1959     * <pre>
1960     * StringUtils.contains(null, *)     = false
1961     * StringUtils.contains(*, null)     = false
1962     * StringUtils.contains("", "")      = true
1963     * StringUtils.contains("abc", "")   = true
1964     * StringUtils.contains("abc", "a")  = true
1965     * StringUtils.contains("abc", "z")  = false
1966     * </pre>
1967     *
1968     * @param seq  the CharSequence to check, may be null
1969     * @param searchSeq  the CharSequence to find, may be null
1970     * @return true if the CharSequence contains the search CharSequence,
1971     *  false if not or {@code null} string input
1972     * @since 2.0
1973     * @since 3.0 Changed signature from contains(String, String) to contains(CharSequence, CharSequence)
1974     */
1975    public static boolean contains(final CharSequence seq, final CharSequence searchSeq) {
1976        if (seq == null || searchSeq == null) {
1977            return false;
1978        }
1979        return CharSequenceUtils.indexOf(seq, searchSeq, 0) >= 0;
1980    }
1981
1982    /**
1983     * <p>Checks if CharSequence contains a search CharSequence irrespective of case,
1984     * handling {@code null}. Case-insensitivity is defined as by
1985     * {@link String#equalsIgnoreCase(String)}.
1986     *
1987     * <p>A {@code null} CharSequence will return {@code false}.</p>
1988     *
1989     * <pre>
1990     * StringUtils.containsIgnoreCase(null, *) = false
1991     * StringUtils.containsIgnoreCase(*, null) = false
1992     * StringUtils.containsIgnoreCase("", "") = true
1993     * StringUtils.containsIgnoreCase("abc", "") = true
1994     * StringUtils.containsIgnoreCase("abc", "a") = true
1995     * StringUtils.containsIgnoreCase("abc", "z") = false
1996     * StringUtils.containsIgnoreCase("abc", "A") = true
1997     * StringUtils.containsIgnoreCase("abc", "Z") = false
1998     * </pre>
1999     *
2000     * @param str  the CharSequence to check, may be null
2001     * @param searchStr  the CharSequence to find, may be null
2002     * @return true if the CharSequence contains the search CharSequence irrespective of
2003     * case or false if not or {@code null} string input
2004     * @since 3.0 Changed signature from containsIgnoreCase(String, String) to containsIgnoreCase(CharSequence, CharSequence)
2005     */
2006    public static boolean containsIgnoreCase(final CharSequence str, final CharSequence searchStr) {
2007        if (str == null || searchStr == null) {
2008            return false;
2009        }
2010        final int len = searchStr.length();
2011        final int max = str.length() - len;
2012        for (int i = 0; i <= max; i++) {
2013            if (CharSequenceUtils.regionMatches(str, true, i, searchStr, 0, len)) {
2014                return true;
2015            }
2016        }
2017        return false;
2018    }
2019
2020    /**
2021     * <p>Check whether the given CharSequence contains any whitespace characters.</p>
2022     *
2023     * <p>Whitespace is defined by {@link Character#isWhitespace(char)}.</p>
2024     *
2025     * @param seq the CharSequence to check (may be {@code null})
2026     * @return {@code true} if the CharSequence is not empty and
2027     * contains at least 1 (breaking) whitespace character
2028     * @since 3.0
2029     */
2030    // From org.springframework.util.StringUtils, under Apache License 2.0
2031    public static boolean containsWhitespace(final CharSequence seq) {
2032        if (isEmpty(seq)) {
2033            return false;
2034        }
2035        final int strLen = seq.length();
2036        for (int i = 0; i < strLen; i++) {
2037            if (Character.isWhitespace(seq.charAt(i))) {
2038                return true;
2039            }
2040        }
2041        return false;
2042    }
2043
2044    // IndexOfAny chars
2045    //-----------------------------------------------------------------------
2046    /**
2047     * <p>Search a CharSequence to find the first index of any
2048     * character in the given set of characters.</p>
2049     *
2050     * <p>A {@code null} String will return {@code -1}.
2051     * A {@code null} or zero length search array will return {@code -1}.</p>
2052     *
2053     * <pre>
2054     * StringUtils.indexOfAny(null, *)                = -1
2055     * StringUtils.indexOfAny("", *)                  = -1
2056     * StringUtils.indexOfAny(*, null)                = -1
2057     * StringUtils.indexOfAny(*, [])                  = -1
2058     * StringUtils.indexOfAny("zzabyycdxx",['z','a']) = 0
2059     * StringUtils.indexOfAny("zzabyycdxx",['b','y']) = 3
2060     * StringUtils.indexOfAny("aba", ['z'])           = -1
2061     * </pre>
2062     *
2063     * @param cs  the CharSequence to check, may be null
2064     * @param searchChars  the chars to search for, may be null
2065     * @return the index of any of the chars, -1 if no match or null input
2066     * @since 2.0
2067     * @since 3.0 Changed signature from indexOfAny(String, char[]) to indexOfAny(CharSequence, char...)
2068     */
2069    public static int indexOfAny(final CharSequence cs, final char... searchChars) {
2070        if (isEmpty(cs) || ArrayUtils.isEmpty(searchChars)) {
2071            return INDEX_NOT_FOUND;
2072        }
2073        final int csLen = cs.length();
2074        final int csLast = csLen - 1;
2075        final int searchLen = searchChars.length;
2076        final int searchLast = searchLen - 1;
2077        for (int i = 0; i < csLen; i++) {
2078            final char ch = cs.charAt(i);
2079            for (int j = 0; j < searchLen; j++) {
2080                if (searchChars[j] == ch) {
2081                    if (i < csLast && j < searchLast && Character.isHighSurrogate(ch)) {
2082                        // ch is a supplementary character
2083                        if (searchChars[j + 1] == cs.charAt(i + 1)) {
2084                            return i;
2085                        }
2086                    } else {
2087                        return i;
2088                    }
2089                }
2090            }
2091        }
2092        return INDEX_NOT_FOUND;
2093    }
2094
2095    /**
2096     * <p>Search a CharSequence to find the first index of any
2097     * character in the given set of characters.</p>
2098     *
2099     * <p>A {@code null} String will return {@code -1}.
2100     * A {@code null} search string will return {@code -1}.</p>
2101     *
2102     * <pre>
2103     * StringUtils.indexOfAny(null, *)            = -1
2104     * StringUtils.indexOfAny("", *)              = -1
2105     * StringUtils.indexOfAny(*, null)            = -1
2106     * StringUtils.indexOfAny(*, "")              = -1
2107     * StringUtils.indexOfAny("zzabyycdxx", "za") = 0
2108     * StringUtils.indexOfAny("zzabyycdxx", "by") = 3
2109     * StringUtils.indexOfAny("aba","z")          = -1
2110     * </pre>
2111     *
2112     * @param cs  the CharSequence to check, may be null
2113     * @param searchChars  the chars to search for, may be null
2114     * @return the index of any of the chars, -1 if no match or null input
2115     * @since 2.0
2116     * @since 3.0 Changed signature from indexOfAny(String, String) to indexOfAny(CharSequence, String)
2117     */
2118    public static int indexOfAny(final CharSequence cs, final String searchChars) {
2119        if (isEmpty(cs) || isEmpty(searchChars)) {
2120            return INDEX_NOT_FOUND;
2121        }
2122        return indexOfAny(cs, searchChars.toCharArray());
2123    }
2124
2125    // ContainsAny
2126    //-----------------------------------------------------------------------
2127    /**
2128     * <p>Checks if the CharSequence contains any character in the given
2129     * set of characters.</p>
2130     *
2131     * <p>A {@code null} CharSequence will return {@code false}.
2132     * A {@code null} or zero length search array will return {@code false}.</p>
2133     *
2134     * <pre>
2135     * StringUtils.containsAny(null, *)                = false
2136     * StringUtils.containsAny("", *)                  = false
2137     * StringUtils.containsAny(*, null)                = false
2138     * StringUtils.containsAny(*, [])                  = false
2139     * StringUtils.containsAny("zzabyycdxx",['z','a']) = true
2140     * StringUtils.containsAny("zzabyycdxx",['b','y']) = true
2141     * StringUtils.containsAny("zzabyycdxx",['z','y']) = true
2142     * StringUtils.containsAny("aba", ['z'])           = false
2143     * </pre>
2144     *
2145     * @param cs  the CharSequence to check, may be null
2146     * @param searchChars  the chars to search for, may be null
2147     * @return the {@code true} if any of the chars are found,
2148     * {@code false} if no match or null input
2149     * @since 2.4
2150     * @since 3.0 Changed signature from containsAny(String, char[]) to containsAny(CharSequence, char...)
2151     */
2152    public static boolean containsAny(final CharSequence cs, final char... searchChars) {
2153        if (isEmpty(cs) || ArrayUtils.isEmpty(searchChars)) {
2154            return false;
2155        }
2156        final int csLength = cs.length();
2157        final int searchLength = searchChars.length;
2158        final int csLast = csLength - 1;
2159        final int searchLast = searchLength - 1;
2160        for (int i = 0; i < csLength; i++) {
2161            final char ch = cs.charAt(i);
2162            for (int j = 0; j < searchLength; j++) {
2163                if (searchChars[j] == ch) {
2164                    if (Character.isHighSurrogate(ch)) {
2165                        if (j == searchLast) {
2166                            // missing low surrogate, fine, like String.indexOf(String)
2167                            return true;
2168                        }
2169                        if (i < csLast && searchChars[j + 1] == cs.charAt(i + 1)) {
2170                            return true;
2171                        }
2172                    } else {
2173                        // ch is in the Basic Multilingual Plane
2174                        return true;
2175                    }
2176                }
2177            }
2178        }
2179        return false;
2180    }
2181
2182    /**
2183     * <p>
2184     * Checks if the CharSequence contains any character in the given set of characters.
2185     * </p>
2186     *
2187     * <p>
2188     * A {@code null} CharSequence will return {@code false}. A {@code null} search CharSequence will return
2189     * {@code false}.
2190     * </p>
2191     *
2192     * <pre>
2193     * StringUtils.containsAny(null, *)               = false
2194     * StringUtils.containsAny("", *)                 = false
2195     * StringUtils.containsAny(*, null)               = false
2196     * StringUtils.containsAny(*, "")                 = false
2197     * StringUtils.containsAny("zzabyycdxx", "za")    = true
2198     * StringUtils.containsAny("zzabyycdxx", "by")    = true
2199     * StringUtils.containsAny("zzabyycdxx", "zy")    = true
2200     * StringUtils.containsAny("zzabyycdxx", "\tx")   = true
2201     * StringUtils.containsAny("zzabyycdxx", "$.#yF") = true
2202     * StringUtils.containsAny("aba","z")             = false
2203     * </pre>
2204     *
2205     * @param cs
2206     *            the CharSequence to check, may be null
2207     * @param searchChars
2208     *            the chars to search for, may be null
2209     * @return the {@code true} if any of the chars are found, {@code false} if no match or null input
2210     * @since 2.4
2211     * @since 3.0 Changed signature from containsAny(String, String) to containsAny(CharSequence, CharSequence)
2212     */
2213    public static boolean containsAny(final CharSequence cs, final CharSequence searchChars) {
2214        if (searchChars == null) {
2215            return false;
2216        }
2217        return containsAny(cs, CharSequenceUtils.toCharArray(searchChars));
2218    }
2219
2220    /**
2221     * <p>Checks if the CharSequence contains any of the CharSequences in the given array.</p>
2222     *
2223     * <p>
2224     * A {@code null} {@code cs} CharSequence will return {@code false}. A {@code null} or zero
2225     * length search array will return {@code false}.
2226     * </p>
2227     *
2228     * <pre>
2229     * StringUtils.containsAny(null, *)            = false
2230     * StringUtils.containsAny("", *)              = false
2231     * StringUtils.containsAny(*, null)            = false
2232     * StringUtils.containsAny(*, [])              = false
2233     * StringUtils.containsAny("abcd", "ab", null) = true
2234     * StringUtils.containsAny("abcd", "ab", "cd") = true
2235     * StringUtils.containsAny("abc", "d", "abc")  = true
2236     * </pre>
2237     *
2238     *
2239     * @param cs The CharSequence to check, may be null
2240     * @param searchCharSequences The array of CharSequences to search for, may be null.
2241     * Individual CharSequences may be null as well.
2242     * @return {@code true} if any of the search CharSequences are found, {@code false} otherwise
2243     * @since 3.4
2244     */
2245    public static boolean containsAny(final CharSequence cs, final CharSequence... searchCharSequences) {
2246        if (isEmpty(cs) || ArrayUtils.isEmpty(searchCharSequences)) {
2247            return false;
2248        }
2249        for (final CharSequence searchCharSequence : searchCharSequences) {
2250            if (contains(cs, searchCharSequence)) {
2251                return true;
2252            }
2253        }
2254        return false;
2255    }
2256
2257    // IndexOfAnyBut chars
2258    //-----------------------------------------------------------------------
2259    /**
2260     * <p>Searches a CharSequence to find the first index of any
2261     * character not in the given set of characters.</p>
2262     *
2263     * <p>A {@code null} CharSequence will return {@code -1}.
2264     * A {@code null} or zero length search array will return {@code -1}.</p>
2265     *
2266     * <pre>
2267     * StringUtils.indexOfAnyBut(null, *)                              = -1
2268     * StringUtils.indexOfAnyBut("", *)                                = -1
2269     * StringUtils.indexOfAnyBut(*, null)                              = -1
2270     * StringUtils.indexOfAnyBut(*, [])                                = -1
2271     * StringUtils.indexOfAnyBut("zzabyycdxx", new char[] {'z', 'a'} ) = 3
2272     * StringUtils.indexOfAnyBut("aba", new char[] {'z'} )             = 0
2273     * StringUtils.indexOfAnyBut("aba", new char[] {'a', 'b'} )        = -1
2274
2275     * </pre>
2276     *
2277     * @param cs  the CharSequence to check, may be null
2278     * @param searchChars  the chars to search for, may be null
2279     * @return the index of any of the chars, -1 if no match or null input
2280     * @since 2.0
2281     * @since 3.0 Changed signature from indexOfAnyBut(String, char[]) to indexOfAnyBut(CharSequence, char...)
2282     */
2283    public static int indexOfAnyBut(final CharSequence cs, final char... searchChars) {
2284        if (isEmpty(cs) || ArrayUtils.isEmpty(searchChars)) {
2285            return INDEX_NOT_FOUND;
2286        }
2287        final int csLen = cs.length();
2288        final int csLast = csLen - 1;
2289        final int searchLen = searchChars.length;
2290        final int searchLast = searchLen - 1;
2291        outer:
2292        for (int i = 0; i < csLen; i++) {
2293            final char ch = cs.charAt(i);
2294            for (int j = 0; j < searchLen; j++) {
2295                if (searchChars[j] == ch) {
2296                    if (i < csLast && j < searchLast && Character.isHighSurrogate(ch)) {
2297                        if (searchChars[j + 1] == cs.charAt(i + 1)) {
2298                            continue outer;
2299                        }
2300                    } else {
2301                        continue outer;
2302                    }
2303                }
2304            }
2305            return i;
2306        }
2307        return INDEX_NOT_FOUND;
2308    }
2309
2310    /**
2311     * <p>Search a CharSequence to find the first index of any
2312     * character not in the given set of characters.</p>
2313     *
2314     * <p>A {@code null} CharSequence will return {@code -1}.
2315     * A {@code null} or empty search string will return {@code -1}.</p>
2316     *
2317     * <pre>
2318     * StringUtils.indexOfAnyBut(null, *)            = -1
2319     * StringUtils.indexOfAnyBut("", *)              = -1
2320     * StringUtils.indexOfAnyBut(*, null)            = -1
2321     * StringUtils.indexOfAnyBut(*, "")              = -1
2322     * StringUtils.indexOfAnyBut("zzabyycdxx", "za") = 3
2323     * StringUtils.indexOfAnyBut("zzabyycdxx", "")   = -1
2324     * StringUtils.indexOfAnyBut("aba","ab")         = -1
2325     * </pre>
2326     *
2327     * @param seq  the CharSequence to check, may be null
2328     * @param searchChars  the chars to search for, may be null
2329     * @return the index of any of the chars, -1 if no match or null input
2330     * @since 2.0
2331     * @since 3.0 Changed signature from indexOfAnyBut(String, String) to indexOfAnyBut(CharSequence, CharSequence)
2332     */
2333    public static int indexOfAnyBut(final CharSequence seq, final CharSequence searchChars) {
2334        if (isEmpty(seq) || isEmpty(searchChars)) {
2335            return INDEX_NOT_FOUND;
2336        }
2337        final int strLen = seq.length();
2338        for (int i = 0; i < strLen; i++) {
2339            final char ch = seq.charAt(i);
2340            final boolean chFound = CharSequenceUtils.indexOf(searchChars, ch, 0) >= 0;
2341            if (i + 1 < strLen && Character.isHighSurrogate(ch)) {
2342                final char ch2 = seq.charAt(i + 1);
2343                if (chFound && CharSequenceUtils.indexOf(searchChars, ch2, 0) < 0) {
2344                    return i;
2345                }
2346            } else {
2347                if (!chFound) {
2348                    return i;
2349                }
2350            }
2351        }
2352        return INDEX_NOT_FOUND;
2353    }
2354
2355    // ContainsOnly
2356    //-----------------------------------------------------------------------
2357    /**
2358     * <p>Checks if the CharSequence contains only certain characters.</p>
2359     *
2360     * <p>A {@code null} CharSequence will return {@code false}.
2361     * A {@code null} valid character array will return {@code false}.
2362     * An empty CharSequence (length()=0) always returns {@code true}.</p>
2363     *
2364     * <pre>
2365     * StringUtils.containsOnly(null, *)       = false
2366     * StringUtils.containsOnly(*, null)       = false
2367     * StringUtils.containsOnly("", *)         = true
2368     * StringUtils.containsOnly("ab", '')      = false
2369     * StringUtils.containsOnly("abab", 'abc') = true
2370     * StringUtils.containsOnly("ab1", 'abc')  = false
2371     * StringUtils.containsOnly("abz", 'abc')  = false
2372     * </pre>
2373     *
2374     * @param cs  the String to check, may be null
2375     * @param valid  an array of valid chars, may be null
2376     * @return true if it only contains valid chars and is non-null
2377     * @since 3.0 Changed signature from containsOnly(String, char[]) to containsOnly(CharSequence, char...)
2378     */
2379    public static boolean containsOnly(final CharSequence cs, final char... valid) {
2380        // All these pre-checks are to maintain API with an older version
2381        if (valid == null || cs == null) {
2382            return false;
2383        }
2384        if (cs.length() == 0) {
2385            return true;
2386        }
2387        if (valid.length == 0) {
2388            return false;
2389        }
2390        return indexOfAnyBut(cs, valid) == INDEX_NOT_FOUND;
2391    }
2392
2393    /**
2394     * <p>Checks if the CharSequence contains only certain characters.</p>
2395     *
2396     * <p>A {@code null} CharSequence will return {@code false}.
2397     * A {@code null} valid character String will return {@code false}.
2398     * An empty String (length()=0) always returns {@code true}.</p>
2399     *
2400     * <pre>
2401     * StringUtils.containsOnly(null, *)       = false
2402     * StringUtils.containsOnly(*, null)       = false
2403     * StringUtils.containsOnly("", *)         = true
2404     * StringUtils.containsOnly("ab", "")      = false
2405     * StringUtils.containsOnly("abab", "abc") = true
2406     * StringUtils.containsOnly("ab1", "abc")  = false
2407     * StringUtils.containsOnly("abz", "abc")  = false
2408     * </pre>
2409     *
2410     * @param cs  the CharSequence to check, may be null
2411     * @param validChars  a String of valid chars, may be null
2412     * @return true if it only contains valid chars and is non-null
2413     * @since 2.0
2414     * @since 3.0 Changed signature from containsOnly(String, String) to containsOnly(CharSequence, String)
2415     */
2416    public static boolean containsOnly(final CharSequence cs, final String validChars) {
2417        if (cs == null || validChars == null) {
2418            return false;
2419        }
2420        return containsOnly(cs, validChars.toCharArray());
2421    }
2422
2423    // ContainsNone
2424    //-----------------------------------------------------------------------
2425    /**
2426     * <p>Checks that the CharSequence does not contain certain characters.</p>
2427     *
2428     * <p>A {@code null} CharSequence will return {@code true}.
2429     * A {@code null} invalid character array will return {@code true}.
2430     * An empty CharSequence (length()=0) always returns true.</p>
2431     *
2432     * <pre>
2433     * StringUtils.containsNone(null, *)       = true
2434     * StringUtils.containsNone(*, null)       = true
2435     * StringUtils.containsNone("", *)         = true
2436     * StringUtils.containsNone("ab", '')      = true
2437     * StringUtils.containsNone("abab", 'xyz') = true
2438     * StringUtils.containsNone("ab1", 'xyz')  = true
2439     * StringUtils.containsNone("abz", 'xyz')  = false
2440     * </pre>
2441     *
2442     * @param cs  the CharSequence to check, may be null
2443     * @param searchChars  an array of invalid chars, may be null
2444     * @return true if it contains none of the invalid chars, or is null
2445     * @since 2.0
2446     * @since 3.0 Changed signature from containsNone(String, char[]) to containsNone(CharSequence, char...)
2447     */
2448    public static boolean containsNone(final CharSequence cs, final char... searchChars) {
2449        if (cs == null || searchChars == null) {
2450            return true;
2451        }
2452        final int csLen = cs.length();
2453        final int csLast = csLen - 1;
2454        final int searchLen = searchChars.length;
2455        final int searchLast = searchLen - 1;
2456        for (int i = 0; i < csLen; i++) {
2457            final char ch = cs.charAt(i);
2458            for (int j = 0; j < searchLen; j++) {
2459                if (searchChars[j] == ch) {
2460                    if (Character.isHighSurrogate(ch)) {
2461                        if (j == searchLast) {
2462                            // missing low surrogate, fine, like String.indexOf(String)
2463                            return false;
2464                        }
2465                        if (i < csLast && searchChars[j + 1] == cs.charAt(i + 1)) {
2466                            return false;
2467                        }
2468                    } else {
2469                        // ch is in the Basic Multilingual Plane
2470                        return false;
2471                    }
2472                }
2473            }
2474        }
2475        return true;
2476    }
2477
2478    /**
2479     * <p>Checks that the CharSequence does not contain certain characters.</p>
2480     *
2481     * <p>A {@code null} CharSequence will return {@code true}.
2482     * A {@code null} invalid character array will return {@code true}.
2483     * An empty String ("") always returns true.</p>
2484     *
2485     * <pre>
2486     * StringUtils.containsNone(null, *)       = true
2487     * StringUtils.containsNone(*, null)       = true
2488     * StringUtils.containsNone("", *)         = true
2489     * StringUtils.containsNone("ab", "")      = true
2490     * StringUtils.containsNone("abab", "xyz") = true
2491     * StringUtils.containsNone("ab1", "xyz")  = true
2492     * StringUtils.containsNone("abz", "xyz")  = false
2493     * </pre>
2494     *
2495     * @param cs  the CharSequence to check, may be null
2496     * @param invalidChars  a String of invalid chars, may be null
2497     * @return true if it contains none of the invalid chars, or is null
2498     * @since 2.0
2499     * @since 3.0 Changed signature from containsNone(String, String) to containsNone(CharSequence, String)
2500     */
2501    public static boolean containsNone(final CharSequence cs, final String invalidChars) {
2502        if (cs == null || invalidChars == null) {
2503            return true;
2504        }
2505        return containsNone(cs, invalidChars.toCharArray());
2506    }
2507
2508    // IndexOfAny strings
2509    //-----------------------------------------------------------------------
2510    /**
2511     * <p>Find the first index of any of a set of potential substrings.</p>
2512     *
2513     * <p>A {@code null} CharSequence will return {@code -1}.
2514     * A {@code null} or zero length search array will return {@code -1}.
2515     * A {@code null} search array entry will be ignored, but a search
2516     * array containing "" will return {@code 0} if {@code str} is not
2517     * null. This method uses {@link String#indexOf(String)} if possible.</p>
2518     *
2519     * <pre>
2520     * StringUtils.indexOfAny(null, *)                     = -1
2521     * StringUtils.indexOfAny(*, null)                     = -1
2522     * StringUtils.indexOfAny(*, [])                       = -1
2523     * StringUtils.indexOfAny("zzabyycdxx", ["ab","cd"])   = 2
2524     * StringUtils.indexOfAny("zzabyycdxx", ["cd","ab"])   = 2
2525     * StringUtils.indexOfAny("zzabyycdxx", ["mn","op"])   = -1
2526     * StringUtils.indexOfAny("zzabyycdxx", ["zab","aby"]) = 1
2527     * StringUtils.indexOfAny("zzabyycdxx", [""])          = 0
2528     * StringUtils.indexOfAny("", [""])                    = 0
2529     * StringUtils.indexOfAny("", ["a"])                   = -1
2530     * </pre>
2531     *
2532     * @param str  the CharSequence to check, may be null
2533     * @param searchStrs  the CharSequences to search for, may be null
2534     * @return the first index of any of the searchStrs in str, -1 if no match
2535     * @since 3.0 Changed signature from indexOfAny(String, String[]) to indexOfAny(CharSequence, CharSequence...)
2536     */
2537    public static int indexOfAny(final CharSequence str, final CharSequence... searchStrs) {
2538        if (str == null || searchStrs == null) {
2539            return INDEX_NOT_FOUND;
2540        }
2541
2542        // String's can't have a MAX_VALUEth index.
2543        int ret = Integer.MAX_VALUE;
2544
2545        int tmp = 0;
2546        for (final CharSequence search : searchStrs) {
2547            if (search == null) {
2548                continue;
2549            }
2550            tmp = CharSequenceUtils.indexOf(str, search, 0);
2551            if (tmp == INDEX_NOT_FOUND) {
2552                continue;
2553            }
2554
2555            if (tmp < ret) {
2556                ret = tmp;
2557            }
2558        }
2559
2560        return ret == Integer.MAX_VALUE ? INDEX_NOT_FOUND : ret;
2561    }
2562
2563    /**
2564     * <p>Find the latest index of any of a set of potential substrings.</p>
2565     *
2566     * <p>A {@code null} CharSequence will return {@code -1}.
2567     * A {@code null} search array will return {@code -1}.
2568     * A {@code null} or zero length search array entry will be ignored,
2569     * but a search array containing "" will return the length of {@code str}
2570     * if {@code str} is not null. This method uses {@link String#indexOf(String)} if possible</p>
2571     *
2572     * <pre>
2573     * StringUtils.lastIndexOfAny(null, *)                   = -1
2574     * StringUtils.lastIndexOfAny(*, null)                   = -1
2575     * StringUtils.lastIndexOfAny(*, [])                     = -1
2576     * StringUtils.lastIndexOfAny(*, [null])                 = -1
2577     * StringUtils.lastIndexOfAny("zzabyycdxx", ["ab","cd"]) = 6
2578     * StringUtils.lastIndexOfAny("zzabyycdxx", ["cd","ab"]) = 6
2579     * StringUtils.lastIndexOfAny("zzabyycdxx", ["mn","op"]) = -1
2580     * StringUtils.lastIndexOfAny("zzabyycdxx", ["mn","op"]) = -1
2581     * StringUtils.lastIndexOfAny("zzabyycdxx", ["mn",""])   = 10
2582     * </pre>
2583     *
2584     * @param str  the CharSequence to check, may be null
2585     * @param searchStrs  the CharSequences to search for, may be null
2586     * @return the last index of any of the CharSequences, -1 if no match
2587     * @since 3.0 Changed signature from lastIndexOfAny(String, String[]) to lastIndexOfAny(CharSequence, CharSequence)
2588     */
2589    public static int lastIndexOfAny(final CharSequence str, final CharSequence... searchStrs) {
2590        if (str == null || searchStrs == null) {
2591            return INDEX_NOT_FOUND;
2592        }
2593        int ret = INDEX_NOT_FOUND;
2594        int tmp = 0;
2595        for (final CharSequence search : searchStrs) {
2596            if (search == null) {
2597                continue;
2598            }
2599            tmp = CharSequenceUtils.lastIndexOf(str, search, str.length());
2600            if (tmp > ret) {
2601                ret = tmp;
2602            }
2603        }
2604        return ret;
2605    }
2606
2607    // Substring
2608    //-----------------------------------------------------------------------
2609    /**
2610     * <p>Gets a substring from the specified String avoiding exceptions.</p>
2611     *
2612     * <p>A negative start position can be used to start {@code n}
2613     * characters from the end of the String.</p>
2614     *
2615     * <p>A {@code null} String will return {@code null}.
2616     * An empty ("") String will return "".</p>
2617     *
2618     * <pre>
2619     * StringUtils.substring(null, *)   = null
2620     * StringUtils.substring("", *)     = ""
2621     * StringUtils.substring("abc", 0)  = "abc"
2622     * StringUtils.substring("abc", 2)  = "c"
2623     * StringUtils.substring("abc", 4)  = ""
2624     * StringUtils.substring("abc", -2) = "bc"
2625     * StringUtils.substring("abc", -4) = "abc"
2626     * </pre>
2627     *
2628     * @param str  the String to get the substring from, may be null
2629     * @param start  the position to start from, negative means
2630     *  count back from the end of the String by this many characters
2631     * @return substring from start position, {@code null} if null String input
2632     */
2633    public static String substring(final String str, int start) {
2634        if (str == null) {
2635            return null;
2636        }
2637
2638        // handle negatives, which means last n characters
2639        if (start < 0) {
2640            start = str.length() + start; // remember start is negative
2641        }
2642
2643        if (start < 0) {
2644            start = 0;
2645        }
2646        if (start > str.length()) {
2647            return EMPTY;
2648        }
2649
2650        return str.substring(start);
2651    }
2652
2653    /**
2654     * <p>Gets a substring from the specified String avoiding exceptions.</p>
2655     *
2656     * <p>A negative start position can be used to start/end {@code n}
2657     * characters from the end of the String.</p>
2658     *
2659     * <p>The returned substring starts with the character in the {@code start}
2660     * position and ends before the {@code end} position. All position counting is
2661     * zero-based -- i.e., to start at the beginning of the string use
2662     * {@code start = 0}. Negative start and end positions can be used to
2663     * specify offsets relative to the end of the String.</p>
2664     *
2665     * <p>If {@code start} is not strictly to the left of {@code end}, ""
2666     * is returned.</p>
2667     *
2668     * <pre>
2669     * StringUtils.substring(null, *, *)    = null
2670     * StringUtils.substring("", * ,  *)    = "";
2671     * StringUtils.substring("abc", 0, 2)   = "ab"
2672     * StringUtils.substring("abc", 2, 0)   = ""
2673     * StringUtils.substring("abc", 2, 4)   = "c"
2674     * StringUtils.substring("abc", 4, 6)   = ""
2675     * StringUtils.substring("abc", 2, 2)   = ""
2676     * StringUtils.substring("abc", -2, -1) = "b"
2677     * StringUtils.substring("abc", -4, 2)  = "ab"
2678     * </pre>
2679     *
2680     * @param str  the String to get the substring from, may be null
2681     * @param start  the position to start from, negative means
2682     *  count back from the end of the String by this many characters
2683     * @param end  the position to end at (exclusive), negative means
2684     *  count back from the end of the String by this many characters
2685     * @return substring from start position to end position,
2686     *  {@code null} if null String input
2687     */
2688    public static String substring(final String str, int start, int end) {
2689        if (str == null) {
2690            return null;
2691        }
2692
2693        // handle negatives
2694        if (end < 0) {
2695            end = str.length() + end; // remember end is negative
2696        }
2697        if (start < 0) {
2698            start = str.length() + start; // remember start is negative
2699        }
2700
2701        // check length next
2702        if (end > str.length()) {
2703            end = str.length();
2704        }
2705
2706        // if start is greater than end, return ""
2707        if (start > end) {
2708            return EMPTY;
2709        }
2710
2711        if (start < 0) {
2712            start = 0;
2713        }
2714        if (end < 0) {
2715            end = 0;
2716        }
2717
2718        return str.substring(start, end);
2719    }
2720
2721    // Left/Right/Mid
2722    //-----------------------------------------------------------------------
2723    /**
2724     * <p>Gets the leftmost {@code len} characters of a String.</p>
2725     *
2726     * <p>If {@code len} characters are not available, or the
2727     * String is {@code null}, the String will be returned without
2728     * an exception. An empty String is returned if len is negative.</p>
2729     *
2730     * <pre>
2731     * StringUtils.left(null, *)    = null
2732     * StringUtils.left(*, -ve)     = ""
2733     * StringUtils.left("", *)      = ""
2734     * StringUtils.left("abc", 0)   = ""
2735     * StringUtils.left("abc", 2)   = "ab"
2736     * StringUtils.left("abc", 4)   = "abc"
2737     * </pre>
2738     *
2739     * @param str  the String to get the leftmost characters from, may be null
2740     * @param len  the length of the required String
2741     * @return the leftmost characters, {@code null} if null String input
2742     */
2743    public static String left(final String str, final int len) {
2744        if (str == null) {
2745            return null;
2746        }
2747        if (len < 0) {
2748            return EMPTY;
2749        }
2750        if (str.length() <= len) {
2751            return str;
2752        }
2753        return str.substring(0, len);
2754    }
2755
2756    /**
2757     * <p>Gets the rightmost {@code len} characters of a String.</p>
2758     *
2759     * <p>If {@code len} characters are not available, or the String
2760     * is {@code null}, the String will be returned without an
2761     * an exception. An empty String is returned if len is negative.</p>
2762     *
2763     * <pre>
2764     * StringUtils.right(null, *)    = null
2765     * StringUtils.right(*, -ve)     = ""
2766     * StringUtils.right("", *)      = ""
2767     * StringUtils.right("abc", 0)   = ""
2768     * StringUtils.right("abc", 2)   = "bc"
2769     * StringUtils.right("abc", 4)   = "abc"
2770     * </pre>
2771     *
2772     * @param str  the String to get the rightmost characters from, may be null
2773     * @param len  the length of the required String
2774     * @return the rightmost characters, {@code null} if null String input
2775     */
2776    public static String right(final String str, final int len) {
2777        if (str == null) {
2778            return null;
2779        }
2780        if (len < 0) {
2781            return EMPTY;
2782        }
2783        if (str.length() <= len) {
2784            return str;
2785        }
2786        return str.substring(str.length() - len);
2787    }
2788
2789    /**
2790     * <p>Gets {@code len} characters from the middle of a String.</p>
2791     *
2792     * <p>If {@code len} characters are not available, the remainder
2793     * of the String will be returned without an exception. If the
2794     * String is {@code null}, {@code null} will be returned.
2795     * An empty String is returned if len is negative or exceeds the
2796     * length of {@code str}.</p>
2797     *
2798     * <pre>
2799     * StringUtils.mid(null, *, *)    = null
2800     * StringUtils.mid(*, *, -ve)     = ""
2801     * StringUtils.mid("", 0, *)      = ""
2802     * StringUtils.mid("abc", 0, 2)   = "ab"
2803     * StringUtils.mid("abc", 0, 4)   = "abc"
2804     * StringUtils.mid("abc", 2, 4)   = "c"
2805     * StringUtils.mid("abc", 4, 2)   = ""
2806     * StringUtils.mid("abc", -2, 2)  = "ab"
2807     * </pre>
2808     *
2809     * @param str  the String to get the characters from, may be null
2810     * @param pos  the position to start from, negative treated as zero
2811     * @param len  the length of the required String
2812     * @return the middle characters, {@code null} if null String input
2813     */
2814    public static String mid(final String str, int pos, final int len) {
2815        if (str == null) {
2816            return null;
2817        }
2818        if (len < 0 || pos > str.length()) {
2819            return EMPTY;
2820        }
2821        if (pos < 0) {
2822            pos = 0;
2823        }
2824        if (str.length() <= pos + len) {
2825            return str.substring(pos);
2826        }
2827        return str.substring(pos, pos + len);
2828    }
2829
2830    // SubStringAfter/SubStringBefore
2831    //-----------------------------------------------------------------------
2832    /**
2833     * <p>Gets the substring before the first occurrence of a separator.
2834     * The separator is not returned.</p>
2835     *
2836     * <p>A {@code null} string input will return {@code null}.
2837     * An empty ("") string input will return the empty string.
2838     * A {@code null} separator will return the input string.</p>
2839     *
2840     * <p>If nothing is found, the string input is returned.</p>
2841     *
2842     * <pre>
2843     * StringUtils.substringBefore(null, *)      = null
2844     * StringUtils.substringBefore("", *)        = ""
2845     * StringUtils.substringBefore("abc", "a")   = ""
2846     * StringUtils.substringBefore("abcba", "b") = "a"
2847     * StringUtils.substringBefore("abc", "c")   = "ab"
2848     * StringUtils.substringBefore("abc", "d")   = "abc"
2849     * StringUtils.substringBefore("abc", "")    = ""
2850     * StringUtils.substringBefore("abc", null)  = "abc"
2851     * </pre>
2852     *
2853     * @param str  the String to get a substring from, may be null
2854     * @param separator  the String to search for, may be null
2855     * @return the substring before the first occurrence of the separator,
2856     *  {@code null} if null String input
2857     * @since 2.0
2858     */
2859    public static String substringBefore(final String str, final String separator) {
2860        if (isEmpty(str) || separator == null) {
2861            return str;
2862        }
2863        if (separator.isEmpty()) {
2864            return EMPTY;
2865        }
2866        final int pos = str.indexOf(separator);
2867        if (pos == INDEX_NOT_FOUND) {
2868            return str;
2869        }
2870        return str.substring(0, pos);
2871    }
2872
2873    /**
2874     * <p>Gets the substring after the first occurrence of a separator.
2875     * The separator is not returned.</p>
2876     *
2877     * <p>A {@code null} string input will return {@code null}.
2878     * An empty ("") string input will return the empty string.
2879     * A {@code null} separator will return the empty string if the
2880     * input string is not {@code null}.</p>
2881     *
2882     * <p>If nothing is found, the empty string is returned.</p>
2883     *
2884     * <pre>
2885     * StringUtils.substringAfter(null, *)      = null
2886     * StringUtils.substringAfter("", *)        = ""
2887     * StringUtils.substringAfter(*, null)      = ""
2888     * StringUtils.substringAfter("abc", "a")   = "bc"
2889     * StringUtils.substringAfter("abcba", "b") = "cba"
2890     * StringUtils.substringAfter("abc", "c")   = ""
2891     * StringUtils.substringAfter("abc", "d")   = ""
2892     * StringUtils.substringAfter("abc", "")    = "abc"
2893     * </pre>
2894     *
2895     * @param str  the String to get a substring from, may be null
2896     * @param separator  the String to search for, may be null
2897     * @return the substring after the first occurrence of the separator,
2898     *  {@code null} if null String input
2899     * @since 2.0
2900     */
2901    public static String substringAfter(final String str, final String separator) {
2902        if (isEmpty(str)) {
2903            return str;
2904        }
2905        if (separator == null) {
2906            return EMPTY;
2907        }
2908        final int pos = str.indexOf(separator);
2909        if (pos == INDEX_NOT_FOUND) {
2910            return EMPTY;
2911        }
2912        return str.substring(pos + separator.length());
2913    }
2914
2915    /**
2916     * <p>Gets the substring before the last occurrence of a separator.
2917     * The separator is not returned.</p>
2918     *
2919     * <p>A {@code null} string input will return {@code null}.
2920     * An empty ("") string input will return the empty string.
2921     * An empty or {@code null} separator will return the input string.</p>
2922     *
2923     * <p>If nothing is found, the string input is returned.</p>
2924     *
2925     * <pre>
2926     * StringUtils.substringBeforeLast(null, *)      = null
2927     * StringUtils.substringBeforeLast("", *)        = ""
2928     * StringUtils.substringBeforeLast("abcba", "b") = "abc"
2929     * StringUtils.substringBeforeLast("abc", "c")   = "ab"
2930     * StringUtils.substringBeforeLast("a", "a")     = ""
2931     * StringUtils.substringBeforeLast("a", "z")     = "a"
2932     * StringUtils.substringBeforeLast("a", null)    = "a"
2933     * StringUtils.substringBeforeLast("a", "")      = "a"
2934     * </pre>
2935     *
2936     * @param str  the String to get a substring from, may be null
2937     * @param separator  the String to search for, may be null
2938     * @return the substring before the last occurrence of the separator,
2939     *  {@code null} if null String input
2940     * @since 2.0
2941     */
2942    public static String substringBeforeLast(final String str, final String separator) {
2943        if (isEmpty(str) || isEmpty(separator)) {
2944            return str;
2945        }
2946        final int pos = str.lastIndexOf(separator);
2947        if (pos == INDEX_NOT_FOUND) {
2948            return str;
2949        }
2950        return str.substring(0, pos);
2951    }
2952
2953    /**
2954     * <p>Gets the substring after the last occurrence of a separator.
2955     * The separator is not returned.</p>
2956     *
2957     * <p>A {@code null} string input will return {@code null}.
2958     * An empty ("") string input will return the empty string.
2959     * An empty or {@code null} separator will return the empty string if
2960     * the input string is not {@code null}.</p>
2961     *
2962     * <p>If nothing is found, the empty string is returned.</p>
2963     *
2964     * <pre>
2965     * StringUtils.substringAfterLast(null, *)      = null
2966     * StringUtils.substringAfterLast("", *)        = ""
2967     * StringUtils.substringAfterLast(*, "")        = ""
2968     * StringUtils.substringAfterLast(*, null)      = ""
2969     * StringUtils.substringAfterLast("abc", "a")   = "bc"
2970     * StringUtils.substringAfterLast("abcba", "b") = "a"
2971     * StringUtils.substringAfterLast("abc", "c")   = ""
2972     * StringUtils.substringAfterLast("a", "a")     = ""
2973     * StringUtils.substringAfterLast("a", "z")     = ""
2974     * </pre>
2975     *
2976     * @param str  the String to get a substring from, may be null
2977     * @param separator  the String to search for, may be null
2978     * @return the substring after the last occurrence of the separator,
2979     *  {@code null} if null String input
2980     * @since 2.0
2981     */
2982    public static String substringAfterLast(final String str, final String separator) {
2983        if (isEmpty(str)) {
2984            return str;
2985        }
2986        if (isEmpty(separator)) {
2987            return EMPTY;
2988        }
2989        final int pos = str.lastIndexOf(separator);
2990        if (pos == INDEX_NOT_FOUND || pos == str.length() - separator.length()) {
2991            return EMPTY;
2992        }
2993        return str.substring(pos + separator.length());
2994    }
2995
2996    // Substring between
2997    //-----------------------------------------------------------------------
2998    /**
2999     * <p>Gets the String that is nested in between two instances of the
3000     * same String.</p>
3001     *
3002     * <p>A {@code null} input String returns {@code null}.
3003     * A {@code null} tag returns {@code null}.</p>
3004     *
3005     * <pre>
3006     * StringUtils.substringBetween(null, *)            = null
3007     * StringUtils.substringBetween("", "")             = ""
3008     * StringUtils.substringBetween("", "tag")          = null
3009     * StringUtils.substringBetween("tagabctag", null)  = null
3010     * StringUtils.substringBetween("tagabctag", "")    = ""
3011     * StringUtils.substringBetween("tagabctag", "tag") = "abc"
3012     * </pre>
3013     *
3014     * @param str  the String containing the substring, may be null
3015     * @param tag  the String before and after the substring, may be null
3016     * @return the substring, {@code null} if no match
3017     * @since 2.0
3018     */
3019    public static String substringBetween(final String str, final String tag) {
3020        return substringBetween(str, tag, tag);
3021    }
3022
3023    /**
3024     * <p>Gets the String that is nested in between two Strings.
3025     * Only the first match is returned.</p>
3026     *
3027     * <p>A {@code null} input String returns {@code null}.
3028     * A {@code null} open/close returns {@code null} (no match).
3029     * An empty ("") open and close returns an empty string.</p>
3030     *
3031     * <pre>
3032     * StringUtils.substringBetween("wx[b]yz", "[", "]") = "b"
3033     * StringUtils.substringBetween(null, *, *)          = null
3034     * StringUtils.substringBetween(*, null, *)          = null
3035     * StringUtils.substringBetween(*, *, null)          = null
3036     * StringUtils.substringBetween("", "", "")          = ""
3037     * StringUtils.substringBetween("", "", "]")         = null
3038     * StringUtils.substringBetween("", "[", "]")        = null
3039     * StringUtils.substringBetween("yabcz", "", "")     = ""
3040     * StringUtils.substringBetween("yabcz", "y", "z")   = "abc"
3041     * StringUtils.substringBetween("yabczyabcz", "y", "z")   = "abc"
3042     * </pre>
3043     *
3044     * @param str  the String containing the substring, may be null
3045     * @param open  the String before the substring, may be null
3046     * @param close  the String after the substring, may be null
3047     * @return the substring, {@code null} if no match
3048     * @since 2.0
3049     */
3050    public static String substringBetween(final String str, final String open, final String close) {
3051        if (str == null || open == null || close == null) {
3052            return null;
3053        }
3054        final int start = str.indexOf(open);
3055        if (start != INDEX_NOT_FOUND) {
3056            final int end = str.indexOf(close, start + open.length());
3057            if (end != INDEX_NOT_FOUND) {
3058                return str.substring(start + open.length(), end);
3059            }
3060        }
3061        return null;
3062    }
3063
3064    /**
3065     * <p>Searches a String for substrings delimited by a start and end tag,
3066     * returning all matching substrings in an array.</p>
3067     *
3068     * <p>A {@code null} input String returns {@code null}.
3069     * A {@code null} open/close returns {@code null} (no match).
3070     * An empty ("") open/close returns {@code null} (no match).</p>
3071     *
3072     * <pre>
3073     * StringUtils.substringsBetween("[a][b][c]", "[", "]") = ["a","b","c"]
3074     * StringUtils.substringsBetween(null, *, *)            = null
3075     * StringUtils.substringsBetween(*, null, *)            = null
3076     * StringUtils.substringsBetween(*, *, null)            = null
3077     * StringUtils.substringsBetween("", "[", "]")          = []
3078     * </pre>
3079     *
3080     * @param str  the String containing the substrings, null returns null, empty returns empty
3081     * @param open  the String identifying the start of the substring, empty returns null
3082     * @param close  the String identifying the end of the substring, empty returns null
3083     * @return a String Array of substrings, or {@code null} if no match
3084     * @since 2.3
3085     */
3086    public static String[] substringsBetween(final String str, final String open, final String close) {
3087        if (str == null || isEmpty(open) || isEmpty(close)) {
3088            return null;
3089        }
3090        final int strLen = str.length();
3091        if (strLen == 0) {
3092            return ArrayUtils.EMPTY_STRING_ARRAY;
3093        }
3094        final int closeLen = close.length();
3095        final int openLen = open.length();
3096        final List<String> list = new ArrayList<>();
3097        int pos = 0;
3098        while (pos < strLen - closeLen) {
3099            int start = str.indexOf(open, pos);
3100            if (start < 0) {
3101                break;
3102            }
3103            start += openLen;
3104            final int end = str.indexOf(close, start);
3105            if (end < 0) {
3106                break;
3107            }
3108            list.add(str.substring(start, end));
3109            pos = end + closeLen;
3110        }
3111        if (list.isEmpty()) {
3112            return null;
3113        }
3114        return list.toArray(new String [list.size()]);
3115    }
3116
3117    // Nested extraction
3118    //-----------------------------------------------------------------------
3119
3120    // Splitting
3121    //-----------------------------------------------------------------------
3122    /**
3123     * <p>Splits the provided text into an array, using whitespace as the
3124     * separator.
3125     * Whitespace is defined by {@link Character#isWhitespace(char)}.</p>
3126     *
3127     * <p>The separator is not included in the returned String array.
3128     * Adjacent separators are treated as one separator.
3129     * For more control over the split use the StrTokenizer class.</p>
3130     *
3131     * <p>A {@code null} input String returns {@code null}.</p>
3132     *
3133     * <pre>
3134     * StringUtils.split(null)       = null
3135     * StringUtils.split("")         = []
3136     * StringUtils.split("abc def")  = ["abc", "def"]
3137     * StringUtils.split("abc  def") = ["abc", "def"]
3138     * StringUtils.split(" abc ")    = ["abc"]
3139     * </pre>
3140     *
3141     * @param str  the String to parse, may be null
3142     * @return an array of parsed Strings, {@code null} if null String input
3143     */
3144    public static String[] split(final String str) {
3145        return split(str, null, -1);
3146    }
3147
3148    /**
3149     * <p>Splits the provided text into an array, separator specified.
3150     * This is an alternative to using StringTokenizer.</p>
3151     *
3152     * <p>The separator is not included in the returned String array.
3153     * Adjacent separators are treated as one separator.
3154     * For more control over the split use the StrTokenizer class.</p>
3155     *
3156     * <p>A {@code null} input String returns {@code null}.</p>
3157     *
3158     * <pre>
3159     * StringUtils.split(null, *)         = null
3160     * StringUtils.split("", *)           = []
3161     * StringUtils.split("a.b.c", '.')    = ["a", "b", "c"]
3162     * StringUtils.split("a..b.c", '.')   = ["a", "b", "c"]
3163     * StringUtils.split("a:b:c", '.')    = ["a:b:c"]
3164     * StringUtils.split("a b c", ' ')    = ["a", "b", "c"]
3165     * </pre>
3166     *
3167     * @param str  the String to parse, may be null
3168     * @param separatorChar  the character used as the delimiter
3169     * @return an array of parsed Strings, {@code null} if null String input
3170     * @since 2.0
3171     */
3172    public static String[] split(final String str, final char separatorChar) {
3173        return splitWorker(str, separatorChar, false);
3174    }
3175
3176    /**
3177     * <p>Splits the provided text into an array, separators specified.
3178     * This is an alternative to using StringTokenizer.</p>
3179     *
3180     * <p>The separator is not included in the returned String array.
3181     * Adjacent separators are treated as one separator.
3182     * For more control over the split use the StrTokenizer class.</p>
3183     *
3184     * <p>A {@code null} input String returns {@code null}.
3185     * A {@code null} separatorChars splits on whitespace.</p>
3186     *
3187     * <pre>
3188     * StringUtils.split(null, *)         = null
3189     * StringUtils.split("", *)           = []
3190     * StringUtils.split("abc def", null) = ["abc", "def"]
3191     * StringUtils.split("abc def", " ")  = ["abc", "def"]
3192     * StringUtils.split("abc  def", " ") = ["abc", "def"]
3193     * StringUtils.split("ab:cd:ef", ":") = ["ab", "cd", "ef"]
3194     * </pre>
3195     *
3196     * @param str  the String to parse, may be null
3197     * @param separatorChars  the characters used as the delimiters,
3198     *  {@code null} splits on whitespace
3199     * @return an array of parsed Strings, {@code null} if null String input
3200     */
3201    public static String[] split(final String str, final String separatorChars) {
3202        return splitWorker(str, separatorChars, -1, false);
3203    }
3204
3205    /**
3206     * <p>Splits the provided text into an array with a maximum length,
3207     * separators specified.</p>
3208     *
3209     * <p>The separator is not included in the returned String array.
3210     * Adjacent separators are treated as one separator.</p>
3211     *
3212     * <p>A {@code null} input String returns {@code null}.
3213     * A {@code null} separatorChars splits on whitespace.</p>
3214     *
3215     * <p>If more than {@code max} delimited substrings are found, the last
3216     * returned string includes all characters after the first {@code max - 1}
3217     * returned strings (including separator characters).</p>
3218     *
3219     * <pre>
3220     * StringUtils.split(null, *, *)            = null
3221     * StringUtils.split("", *, *)              = []
3222     * StringUtils.split("ab cd ef", null, 0)   = ["ab", "cd", "ef"]
3223     * StringUtils.split("ab   cd ef", null, 0) = ["ab", "cd", "ef"]
3224     * StringUtils.split("ab:cd:ef", ":", 0)    = ["ab", "cd", "ef"]
3225     * StringUtils.split("ab:cd:ef", ":", 2)    = ["ab", "cd:ef"]
3226     * </pre>
3227     *
3228     * @param str  the String to parse, may be null
3229     * @param separatorChars  the characters used as the delimiters,
3230     *  {@code null} splits on whitespace
3231     * @param max  the maximum number of elements to include in the
3232     *  array. A zero or negative value implies no limit
3233     * @return an array of parsed Strings, {@code null} if null String input
3234     */
3235    public static String[] split(final String str, final String separatorChars, final int max) {
3236        return splitWorker(str, separatorChars, max, false);
3237    }
3238
3239    /**
3240     * <p>Splits the provided text into an array, separator string specified.</p>
3241     *
3242     * <p>The separator(s) will not be included in the returned String array.
3243     * Adjacent separators are treated as one separator.</p>
3244     *
3245     * <p>A {@code null} input String returns {@code null}.
3246     * A {@code null} separator splits on whitespace.</p>
3247     *
3248     * <pre>
3249     * StringUtils.splitByWholeSeparator(null, *)               = null
3250     * StringUtils.splitByWholeSeparator("", *)                 = []
3251     * StringUtils.splitByWholeSeparator("ab de fg", null)      = ["ab", "de", "fg"]
3252     * StringUtils.splitByWholeSeparator("ab   de fg", null)    = ["ab", "de", "fg"]
3253     * StringUtils.splitByWholeSeparator("ab:cd:ef", ":")       = ["ab", "cd", "ef"]
3254     * StringUtils.splitByWholeSeparator("ab-!-cd-!-ef", "-!-") = ["ab", "cd", "ef"]
3255     * </pre>
3256     *
3257     * @param str  the String to parse, may be null
3258     * @param separator  String containing the String to be used as a delimiter,
3259     *  {@code null} splits on whitespace
3260     * @return an array of parsed Strings, {@code null} if null String was input
3261     */
3262    public static String[] splitByWholeSeparator(final String str, final String separator) {
3263        return splitByWholeSeparatorWorker( str, separator, -1, false ) ;
3264    }
3265
3266    /**
3267     * <p>Splits the provided text into an array, separator string specified.
3268     * Returns a maximum of {@code max} substrings.</p>
3269     *
3270     * <p>The separator(s) will not be included in the returned String array.
3271     * Adjacent separators are treated as one separator.</p>
3272     *
3273     * <p>A {@code null} input String returns {@code null}.
3274     * A {@code null} separator splits on whitespace.</p>
3275     *
3276     * <pre>
3277     * StringUtils.splitByWholeSeparator(null, *, *)               = null
3278     * StringUtils.splitByWholeSeparator("", *, *)                 = []
3279     * StringUtils.splitByWholeSeparator("ab de fg", null, 0)      = ["ab", "de", "fg"]
3280     * StringUtils.splitByWholeSeparator("ab   de fg", null, 0)    = ["ab", "de", "fg"]
3281     * StringUtils.splitByWholeSeparator("ab:cd:ef", ":", 2)       = ["ab", "cd:ef"]
3282     * StringUtils.splitByWholeSeparator("ab-!-cd-!-ef", "-!-", 5) = ["ab", "cd", "ef"]
3283     * StringUtils.splitByWholeSeparator("ab-!-cd-!-ef", "-!-", 2) = ["ab", "cd-!-ef"]
3284     * </pre>
3285     *
3286     * @param str  the String to parse, may be null
3287     * @param separator  String containing the String to be used as a delimiter,
3288     *  {@code null} splits on whitespace
3289     * @param max  the maximum number of elements to include in the returned
3290     *  array. A zero or negative value implies no limit.
3291     * @return an array of parsed Strings, {@code null} if null String was input
3292     */
3293    public static String[] splitByWholeSeparator( final String str, final String separator, final int max) {
3294        return splitByWholeSeparatorWorker(str, separator, max, false);
3295    }
3296
3297    /**
3298     * <p>Splits the provided text into an array, separator string specified. </p>
3299     *
3300     * <p>The separator is not included in the returned String array.
3301     * Adjacent separators are treated as separators for empty tokens.
3302     * For more control over the split use the StrTokenizer class.</p>
3303     *
3304     * <p>A {@code null} input String returns {@code null}.
3305     * A {@code null} separator splits on whitespace.</p>
3306     *
3307     * <pre>
3308     * StringUtils.splitByWholeSeparatorPreserveAllTokens(null, *)               = null
3309     * StringUtils.splitByWholeSeparatorPreserveAllTokens("", *)                 = []
3310     * StringUtils.splitByWholeSeparatorPreserveAllTokens("ab de fg", null)      = ["ab", "de", "fg"]
3311     * StringUtils.splitByWholeSeparatorPreserveAllTokens("ab   de fg", null)    = ["ab", "", "", "de", "fg"]
3312     * StringUtils.splitByWholeSeparatorPreserveAllTokens("ab:cd:ef", ":")       = ["ab", "cd", "ef"]
3313     * StringUtils.splitByWholeSeparatorPreserveAllTokens("ab-!-cd-!-ef", "-!-") = ["ab", "cd", "ef"]
3314     * </pre>
3315     *
3316     * @param str  the String to parse, may be null
3317     * @param separator  String containing the String to be used as a delimiter,
3318     *  {@code null} splits on whitespace
3319     * @return an array of parsed Strings, {@code null} if null String was input
3320     * @since 2.4
3321     */
3322    public static String[] splitByWholeSeparatorPreserveAllTokens(final String str, final String separator) {
3323        return splitByWholeSeparatorWorker(str, separator, -1, true);
3324    }
3325
3326    /**
3327     * <p>Splits the provided text into an array, separator string specified.
3328     * Returns a maximum of {@code max} substrings.</p>
3329     *
3330     * <p>The separator is not included in the returned String array.
3331     * Adjacent separators are treated as separators for empty tokens.
3332     * For more control over the split use the StrTokenizer class.</p>
3333     *
3334     * <p>A {@code null} input String returns {@code null}.
3335     * A {@code null} separator splits on whitespace.</p>
3336     *
3337     * <pre>
3338     * StringUtils.splitByWholeSeparatorPreserveAllTokens(null, *, *)               = null
3339     * StringUtils.splitByWholeSeparatorPreserveAllTokens("", *, *)                 = []
3340     * StringUtils.splitByWholeSeparatorPreserveAllTokens("ab de fg", null, 0)      = ["ab", "de", "fg"]
3341     * StringUtils.splitByWholeSeparatorPreserveAllTokens("ab   de fg", null, 0)    = ["ab", "", "", "de", "fg"]
3342     * StringUtils.splitByWholeSeparatorPreserveAllTokens("ab:cd:ef", ":", 2)       = ["ab", "cd:ef"]
3343     * StringUtils.splitByWholeSeparatorPreserveAllTokens("ab-!-cd-!-ef", "-!-", 5) = ["ab", "cd", "ef"]
3344     * StringUtils.splitByWholeSeparatorPreserveAllTokens("ab-!-cd-!-ef", "-!-", 2) = ["ab", "cd-!-ef"]
3345     * </pre>
3346     *
3347     * @param str  the String to parse, may be null
3348     * @param separator  String containing the String to be used as a delimiter,
3349     *  {@code null} splits on whitespace
3350     * @param max  the maximum number of elements to include in the returned
3351     *  array. A zero or negative value implies no limit.
3352     * @return an array of parsed Strings, {@code null} if null String was input
3353     * @since 2.4
3354     */
3355    public static String[] splitByWholeSeparatorPreserveAllTokens(final String str, final String separator, final int max) {
3356        return splitByWholeSeparatorWorker(str, separator, max, true);
3357    }
3358
3359    /**
3360     * Performs the logic for the {@code splitByWholeSeparatorPreserveAllTokens} methods.
3361     *
3362     * @param str  the String to parse, may be {@code null}
3363     * @param separator  String containing the String to be used as a delimiter,
3364     *  {@code null} splits on whitespace
3365     * @param max  the maximum number of elements to include in the returned
3366     *  array. A zero or negative value implies no limit.
3367     * @param preserveAllTokens if {@code true}, adjacent separators are
3368     * treated as empty token separators; if {@code false}, adjacent
3369     * separators are treated as one separator.
3370     * @return an array of parsed Strings, {@code null} if null String input
3371     * @since 2.4
3372     */
3373    private static String[] splitByWholeSeparatorWorker(
3374            final String str, final String separator, final int max, final boolean preserveAllTokens) {
3375        if (str == null) {
3376            return null;
3377        }
3378
3379        final int len = str.length();
3380
3381        if (len == 0) {
3382            return ArrayUtils.EMPTY_STRING_ARRAY;
3383        }
3384
3385        if (separator == null || EMPTY.equals(separator)) {
3386            // Split on whitespace.
3387            return splitWorker(str, null, max, preserveAllTokens);
3388        }
3389
3390        final int separatorLength = separator.length();
3391
3392        final ArrayList<String> substrings = new ArrayList<>();
3393        int numberOfSubstrings = 0;
3394        int beg = 0;
3395        int end = 0;
3396        while (end < len) {
3397            end = str.indexOf(separator, beg);
3398
3399            if (end > -1) {
3400                if (end > beg) {
3401                    numberOfSubstrings += 1;
3402
3403                    if (numberOfSubstrings == max) {
3404                        end = len;
3405                        substrings.add(str.substring(beg));
3406                    } else {
3407                        // The following is OK, because String.substring( beg, end ) excludes
3408                        // the character at the position 'end'.
3409                        substrings.add(str.substring(beg, end));
3410
3411                        // Set the starting point for the next search.
3412                        // The following is equivalent to beg = end + (separatorLength - 1) + 1,
3413                        // which is the right calculation:
3414                        beg = end + separatorLength;
3415                    }
3416                } else {
3417                    // We found a consecutive occurrence of the separator, so skip it.
3418                    if (preserveAllTokens) {
3419                        numberOfSubstrings += 1;
3420                        if (numberOfSubstrings == max) {
3421                            end = len;
3422                            substrings.add(str.substring(beg));
3423                        } else {
3424                            substrings.add(EMPTY);
3425                        }
3426                    }
3427                    beg = end + separatorLength;
3428                }
3429            } else {
3430                // String.substring( beg ) goes from 'beg' to the end of the String.
3431                substrings.add(str.substring(beg));
3432                end = len;
3433            }
3434        }
3435
3436        return substrings.toArray(new String[substrings.size()]);
3437    }
3438
3439    // -----------------------------------------------------------------------
3440    /**
3441     * <p>Splits the provided text into an array, using whitespace as the
3442     * separator, preserving all tokens, including empty tokens created by
3443     * adjacent separators. This is an alternative to using StringTokenizer.
3444     * Whitespace is defined by {@link Character#isWhitespace(char)}.</p>
3445     *
3446     * <p>The separator is not included in the returned String array.
3447     * Adjacent separators are treated as separators for empty tokens.
3448     * For more control over the split use the StrTokenizer class.</p>
3449     *
3450     * <p>A {@code null} input String returns {@code null}.</p>
3451     *
3452     * <pre>
3453     * StringUtils.splitPreserveAllTokens(null)       = null
3454     * StringUtils.splitPreserveAllTokens("")         = []
3455     * StringUtils.splitPreserveAllTokens("abc def")  = ["abc", "def"]
3456     * StringUtils.splitPreserveAllTokens("abc  def") = ["abc", "", "def"]
3457     * StringUtils.splitPreserveAllTokens(" abc ")    = ["", "abc", ""]
3458     * </pre>
3459     *
3460     * @param str  the String to parse, may be {@code null}
3461     * @return an array of parsed Strings, {@code null} if null String input
3462     * @since 2.1
3463     */
3464    public static String[] splitPreserveAllTokens(final String str) {
3465        return splitWorker(str, null, -1, true);
3466    }
3467
3468    /**
3469     * <p>Splits the provided text into an array, separator specified,
3470     * preserving all tokens, including empty tokens created by adjacent
3471     * separators. This is an alternative to using StringTokenizer.</p>
3472     *
3473     * <p>The separator is not included in the returned String array.
3474     * Adjacent separators are treated as separators for empty tokens.
3475     * For more control over the split use the StrTokenizer class.</p>
3476     *
3477     * <p>A {@code null} input String returns {@code null}.</p>
3478     *
3479     * <pre>
3480     * StringUtils.splitPreserveAllTokens(null, *)         = null
3481     * StringUtils.splitPreserveAllTokens("", *)           = []
3482     * StringUtils.splitPreserveAllTokens("a.b.c", '.')    = ["a", "b", "c"]
3483     * StringUtils.splitPreserveAllTokens("a..b.c", '.')   = ["a", "", "b", "c"]
3484     * StringUtils.splitPreserveAllTokens("a:b:c", '.')    = ["a:b:c"]
3485     * StringUtils.splitPreserveAllTokens("a\tb\nc", null) = ["a", "b", "c"]
3486     * StringUtils.splitPreserveAllTokens("a b c", ' ')    = ["a", "b", "c"]
3487     * StringUtils.splitPreserveAllTokens("a b c ", ' ')   = ["a", "b", "c", ""]
3488     * StringUtils.splitPreserveAllTokens("a b c  ", ' ')   = ["a", "b", "c", "", ""]
3489     * StringUtils.splitPreserveAllTokens(" a b c", ' ')   = ["", a", "b", "c"]
3490     * StringUtils.splitPreserveAllTokens("  a b c", ' ')  = ["", "", a", "b", "c"]
3491     * StringUtils.splitPreserveAllTokens(" a b c ", ' ')  = ["", a", "b", "c", ""]
3492     * </pre>
3493     *
3494     * @param str  the String to parse, may be {@code null}
3495     * @param separatorChar  the character used as the delimiter,
3496     *  {@code null} splits on whitespace
3497     * @return an array of parsed Strings, {@code null} if null String input
3498     * @since 2.1
3499     */
3500    public static String[] splitPreserveAllTokens(final String str, final char separatorChar) {
3501        return splitWorker(str, separatorChar, true);
3502    }
3503
3504    /**
3505     * Performs the logic for the {@code split} and
3506     * {@code splitPreserveAllTokens} methods that do not return a
3507     * maximum array length.
3508     *
3509     * @param str  the String to parse, may be {@code null}
3510     * @param separatorChar the separate character
3511     * @param preserveAllTokens if {@code true}, adjacent separators are
3512     * treated as empty token separators; if {@code false}, adjacent
3513     * separators are treated as one separator.
3514     * @return an array of parsed Strings, {@code null} if null String input
3515     */
3516    private static String[] splitWorker(final String str, final char separatorChar, final boolean preserveAllTokens) {
3517        // Performance tuned for 2.0 (JDK1.4)
3518
3519        if (str == null) {
3520            return null;
3521        }
3522        final int len = str.length();
3523        if (len == 0) {
3524            return ArrayUtils.EMPTY_STRING_ARRAY;
3525        }
3526        final List<String> list = new ArrayList<>();
3527        int i = 0, start = 0;
3528        boolean match = false;
3529        boolean lastMatch = false;
3530        while (i < len) {
3531            if (str.charAt(i) == separatorChar) {
3532                if (match || preserveAllTokens) {
3533                    list.add(str.substring(start, i));
3534                    match = false;
3535                    lastMatch = true;
3536                }
3537                start = ++i;
3538                continue;
3539            }
3540            lastMatch = false;
3541            match = true;
3542            i++;
3543        }
3544        if (match || preserveAllTokens && lastMatch) {
3545            list.add(str.substring(start, i));
3546        }
3547        return list.toArray(new String[list.size()]);
3548    }
3549
3550    /**
3551     * <p>Splits the provided text into an array, separators specified,
3552     * preserving all tokens, including empty tokens created by adjacent
3553     * separators. This is an alternative to using StringTokenizer.</p>
3554     *
3555     * <p>The separator is not included in the returned String array.
3556     * Adjacent separators are treated as separators for empty tokens.
3557     * For more control over the split use the StrTokenizer class.</p>
3558     *
3559     * <p>A {@code null} input String returns {@code null}.
3560     * A {@code null} separatorChars splits on whitespace.</p>
3561     *
3562     * <pre>
3563     * StringUtils.splitPreserveAllTokens(null, *)           = null
3564     * StringUtils.splitPreserveAllTokens("", *)             = []
3565     * StringUtils.splitPreserveAllTokens("abc def", null)   = ["abc", "def"]
3566     * StringUtils.splitPreserveAllTokens("abc def", " ")    = ["abc", "def"]
3567     * StringUtils.splitPreserveAllTokens("abc  def", " ")   = ["abc", "", def"]
3568     * StringUtils.splitPreserveAllTokens("ab:cd:ef", ":")   = ["ab", "cd", "ef"]
3569     * StringUtils.splitPreserveAllTokens("ab:cd:ef:", ":")  = ["ab", "cd", "ef", ""]
3570     * StringUtils.splitPreserveAllTokens("ab:cd:ef::", ":") = ["ab", "cd", "ef", "", ""]
3571     * StringUtils.splitPreserveAllTokens("ab::cd:ef", ":")  = ["ab", "", cd", "ef"]
3572     * StringUtils.splitPreserveAllTokens(":cd:ef", ":")     = ["", cd", "ef"]
3573     * StringUtils.splitPreserveAllTokens("::cd:ef", ":")    = ["", "", cd", "ef"]
3574     * StringUtils.splitPreserveAllTokens(":cd:ef:", ":")    = ["", cd", "ef", ""]
3575     * </pre>
3576     *
3577     * @param str  the String to parse, may be {@code null}
3578     * @param separatorChars  the characters used as the delimiters,
3579     *  {@code null} splits on whitespace
3580     * @return an array of parsed Strings, {@code null} if null String input
3581     * @since 2.1
3582     */
3583    public static String[] splitPreserveAllTokens(final String str, final String separatorChars) {
3584        return splitWorker(str, separatorChars, -1, true);
3585    }
3586
3587    /**
3588     * <p>Splits the provided text into an array with a maximum length,
3589     * separators specified, preserving all tokens, including empty tokens
3590     * created by adjacent separators.</p>
3591     *
3592     * <p>The separator is not included in the returned String array.
3593     * Adjacent separators are treated as separators for empty tokens.
3594     * Adjacent separators are treated as one separator.</p>
3595     *
3596     * <p>A {@code null} input String returns {@code null}.
3597     * A {@code null} separatorChars splits on whitespace.</p>
3598     *
3599     * <p>If more than {@code max} delimited substrings are found, the last
3600     * returned string includes all characters after the first {@code max - 1}
3601     * returned strings (including separator characters).</p>
3602     *
3603     * <pre>
3604     * StringUtils.splitPreserveAllTokens(null, *, *)            = null
3605     * StringUtils.splitPreserveAllTokens("", *, *)              = []
3606     * StringUtils.splitPreserveAllTokens("ab de fg", null, 0)   = ["ab", "cd", "ef"]
3607     * StringUtils.splitPreserveAllTokens("ab   de fg", null, 0) = ["ab", "cd", "ef"]
3608     * StringUtils.splitPreserveAllTokens("ab:cd:ef", ":", 0)    = ["ab", "cd", "ef"]
3609     * StringUtils.splitPreserveAllTokens("ab:cd:ef", ":", 2)    = ["ab", "cd:ef"]
3610     * StringUtils.splitPreserveAllTokens("ab   de fg", null, 2) = ["ab", "  de fg"]
3611     * StringUtils.splitPreserveAllTokens("ab   de fg", null, 3) = ["ab", "", " de fg"]
3612     * StringUtils.splitPreserveAllTokens("ab   de fg", null, 4) = ["ab", "", "", "de fg"]
3613     * </pre>
3614     *
3615     * @param str  the String to parse, may be {@code null}
3616     * @param separatorChars  the characters used as the delimiters,
3617     *  {@code null} splits on whitespace
3618     * @param max  the maximum number of elements to include in the
3619     *  array. A zero or negative value implies no limit
3620     * @return an array of parsed Strings, {@code null} if null String input
3621     * @since 2.1
3622     */
3623    public static String[] splitPreserveAllTokens(final String str, final String separatorChars, final int max) {
3624        return splitWorker(str, separatorChars, max, true);
3625    }
3626
3627    /**
3628     * Performs the logic for the {@code split} and
3629     * {@code splitPreserveAllTokens} methods that return a maximum array
3630     * length.
3631     *
3632     * @param str  the String to parse, may be {@code null}
3633     * @param separatorChars the separate character
3634     * @param max  the maximum number of elements to include in the
3635     *  array. A zero or negative value implies no limit.
3636     * @param preserveAllTokens if {@code true}, adjacent separators are
3637     * treated as empty token separators; if {@code false}, adjacent
3638     * separators are treated as one separator.
3639     * @return an array of parsed Strings, {@code null} if null String input
3640     */
3641    private static String[] splitWorker(final String str, final String separatorChars, final int max, final boolean preserveAllTokens) {
3642        // Performance tuned for 2.0 (JDK1.4)
3643        // Direct code is quicker than StringTokenizer.
3644        // Also, StringTokenizer uses isSpace() not isWhitespace()
3645
3646        if (str == null) {
3647            return null;
3648        }
3649        final int len = str.length();
3650        if (len == 0) {
3651            return ArrayUtils.EMPTY_STRING_ARRAY;
3652        }
3653        final List<String> list = new ArrayList<>();
3654        int sizePlus1 = 1;
3655        int i = 0, start = 0;
3656        boolean match = false;
3657        boolean lastMatch = false;
3658        if (separatorChars == null) {
3659            // Null separator means use whitespace
3660            while (i < len) {
3661                if (Character.isWhitespace(str.charAt(i))) {
3662                    if (match || preserveAllTokens) {
3663                        lastMatch = true;
3664                        if (sizePlus1++ == max) {
3665                            i = len;
3666                            lastMatch = false;
3667                        }
3668                        list.add(str.substring(start, i));
3669                        match = false;
3670                    }
3671                    start = ++i;
3672                    continue;
3673                }
3674                lastMatch = false;
3675                match = true;
3676                i++;
3677            }
3678        } else if (separatorChars.length() == 1) {
3679            // Optimise 1 character case
3680            final char sep = separatorChars.charAt(0);
3681            while (i < len) {
3682                if (str.charAt(i) == sep) {
3683                    if (match || preserveAllTokens) {
3684                        lastMatch = true;
3685                        if (sizePlus1++ == max) {
3686                            i = len;
3687                            lastMatch = false;
3688                        }
3689                        list.add(str.substring(start, i));
3690                        match = false;
3691                    }
3692                    start = ++i;
3693                    continue;
3694                }
3695                lastMatch = false;
3696                match = true;
3697                i++;
3698            }
3699        } else {
3700            // standard case
3701            while (i < len) {
3702                if (separatorChars.indexOf(str.charAt(i)) >= 0) {
3703                    if (match || preserveAllTokens) {
3704                        lastMatch = true;
3705                        if (sizePlus1++ == max) {
3706                            i = len;
3707                            lastMatch = false;
3708                        }
3709                        list.add(str.substring(start, i));
3710                        match = false;
3711                    }
3712                    start = ++i;
3713                    continue;
3714                }
3715                lastMatch = false;
3716                match = true;
3717                i++;
3718            }
3719        }
3720        if (match || preserveAllTokens && lastMatch) {
3721            list.add(str.substring(start, i));
3722        }
3723        return list.toArray(new String[list.size()]);
3724    }
3725
3726    /**
3727     * <p>Splits a String by Character type as returned by
3728     * {@code java.lang.Character.getType(char)}. Groups of contiguous
3729     * characters of the same type are returned as complete tokens.
3730     * <pre>
3731     * StringUtils.splitByCharacterType(null)         = null
3732     * StringUtils.splitByCharacterType("")           = []
3733     * StringUtils.splitByCharacterType("ab de fg")   = ["ab", " ", "de", " ", "fg"]
3734     * StringUtils.splitByCharacterType("ab   de fg") = ["ab", "   ", "de", " ", "fg"]
3735     * StringUtils.splitByCharacterType("ab:cd:ef")   = ["ab", ":", "cd", ":", "ef"]
3736     * StringUtils.splitByCharacterType("number5")    = ["number", "5"]
3737     * StringUtils.splitByCharacterType("fooBar")     = ["foo", "B", "ar"]
3738     * StringUtils.splitByCharacterType("foo200Bar")  = ["foo", "200", "B", "ar"]
3739     * StringUtils.splitByCharacterType("ASFRules")   = ["ASFR", "ules"]
3740     * </pre>
3741     * @param str the String to split, may be {@code null}
3742     * @return an array of parsed Strings, {@code null} if null String input
3743     * @since 2.4
3744     */
3745    public static String[] splitByCharacterType(final String str) {
3746        return splitByCharacterType(str, false);
3747    }
3748
3749    /**
3750     * <p>Splits a String by Character type as returned by
3751     * {@code java.lang.Character.getType(char)}. Groups of contiguous
3752     * characters of the same type are returned as complete tokens, with the
3753     * following exception: the character of type
3754     * {@code Character.UPPERCASE_LETTER}, if any, immediately
3755     * preceding a token of type {@code Character.LOWERCASE_LETTER}
3756     * will belong to the following token rather than to the preceding, if any,
3757     * {@code Character.UPPERCASE_LETTER} token.
3758     * <pre>
3759     * StringUtils.splitByCharacterTypeCamelCase(null)         = null
3760     * StringUtils.splitByCharacterTypeCamelCase("")           = []
3761     * StringUtils.splitByCharacterTypeCamelCase("ab de fg")   = ["ab", " ", "de", " ", "fg"]
3762     * StringUtils.splitByCharacterTypeCamelCase("ab   de fg") = ["ab", "   ", "de", " ", "fg"]
3763     * StringUtils.splitByCharacterTypeCamelCase("ab:cd:ef")   = ["ab", ":", "cd", ":", "ef"]
3764     * StringUtils.splitByCharacterTypeCamelCase("number5")    = ["number", "5"]
3765     * StringUtils.splitByCharacterTypeCamelCase("fooBar")     = ["foo", "Bar"]
3766     * StringUtils.splitByCharacterTypeCamelCase("foo200Bar")  = ["foo", "200", "Bar"]
3767     * StringUtils.splitByCharacterTypeCamelCase("ASFRules")   = ["ASF", "Rules"]
3768     * </pre>
3769     * @param str the String to split, may be {@code null}
3770     * @return an array of parsed Strings, {@code null} if null String input
3771     * @since 2.4
3772     */
3773    public static String[] splitByCharacterTypeCamelCase(final String str) {
3774        return splitByCharacterType(str, true);
3775    }
3776
3777    /**
3778     * <p>Splits a String by Character type as returned by
3779     * {@code java.lang.Character.getType(char)}. Groups of contiguous
3780     * characters of the same type are returned as complete tokens, with the
3781     * following exception: if {@code camelCase} is {@code true},
3782     * the character of type {@code Character.UPPERCASE_LETTER}, if any,
3783     * immediately preceding a token of type {@code Character.LOWERCASE_LETTER}
3784     * will belong to the following token rather than to the preceding, if any,
3785     * {@code Character.UPPERCASE_LETTER} token.
3786     * @param str the String to split, may be {@code null}
3787     * @param camelCase whether to use so-called "camel-case" for letter types
3788     * @return an array of parsed Strings, {@code null} if null String input
3789     * @since 2.4
3790     */
3791    private static String[] splitByCharacterType(final String str, final boolean camelCase) {
3792        if (str == null) {
3793            return null;
3794        }
3795        if (str.isEmpty()) {
3796            return ArrayUtils.EMPTY_STRING_ARRAY;
3797        }
3798        final char[] c = str.toCharArray();
3799        final List<String> list = new ArrayList<>();
3800        int tokenStart = 0;
3801        int currentType = Character.getType(c[tokenStart]);
3802        for (int pos = tokenStart + 1; pos < c.length; pos++) {
3803            final int type = Character.getType(c[pos]);
3804            if (type == currentType) {
3805                continue;
3806            }
3807            if (camelCase && type == Character.LOWERCASE_LETTER && currentType == Character.UPPERCASE_LETTER) {
3808                final int newTokenStart = pos - 1;
3809                if (newTokenStart != tokenStart) {
3810                    list.add(new String(c, tokenStart, newTokenStart - tokenStart));
3811                    tokenStart = newTokenStart;
3812                }
3813            } else {
3814                list.add(new String(c, tokenStart, pos - tokenStart));
3815                tokenStart = pos;
3816            }
3817            currentType = type;
3818        }
3819        list.add(new String(c, tokenStart, c.length - tokenStart));
3820        return list.toArray(new String[list.size()]);
3821    }
3822
3823    // Joining
3824    //-----------------------------------------------------------------------
3825    /**
3826     * <p>Joins the elements of the provided array into a single String
3827     * containing the provided list of elements.</p>
3828     *
3829     * <p>No separator is added to the joined String.
3830     * Null objects or empty strings within the array are represented by
3831     * empty strings.</p>
3832     *
3833     * <pre>
3834     * StringUtils.join(null)            = null
3835     * StringUtils.join([])              = ""
3836     * StringUtils.join([null])          = ""
3837     * StringUtils.join(["a", "b", "c"]) = "abc"
3838     * StringUtils.join([null, "", "a"]) = "a"
3839     * </pre>
3840     *
3841     * @param <T> the specific type of values to join together
3842     * @param elements  the values to join together, may be null
3843     * @return the joined String, {@code null} if null array input
3844     * @since 2.0
3845     * @since 3.0 Changed signature to use varargs
3846     */
3847    @SafeVarargs
3848    public static <T> String join(final T... elements) {
3849        return join(elements, null);
3850    }
3851
3852    /**
3853     * <p>Joins the elements of the provided array into a single String
3854     * containing the provided list of elements.</p>
3855     *
3856     * <p>No delimiter is added before or after the list.
3857     * Null objects or empty strings within the array are represented by
3858     * empty strings.</p>
3859     *
3860     * <pre>
3861     * StringUtils.join(null, *)               = null
3862     * StringUtils.join([], *)                 = ""
3863     * StringUtils.join([null], *)             = ""
3864     * StringUtils.join(["a", "b", "c"], ';')  = "a;b;c"
3865     * StringUtils.join(["a", "b", "c"], null) = "abc"
3866     * StringUtils.join([null, "", "a"], ';')  = ";;a"
3867     * </pre>
3868     *
3869     * @param array  the array of values to join together, may be null
3870     * @param separator  the separator character to use
3871     * @return the joined String, {@code null} if null array input
3872     * @since 2.0
3873     */
3874    public static String join(final Object[] array, final char separator) {
3875        if (array == null) {
3876            return null;
3877        }
3878        return join(array, separator, 0, array.length);
3879    }
3880
3881    /**
3882     * <p>
3883     * Joins the elements of the provided array into a single String containing the provided list of elements.
3884     * </p>
3885     *
3886     * <p>
3887     * No delimiter is added before or after the list. Null objects or empty strings within the array are represented
3888     * by empty strings.
3889     * </p>
3890     *
3891     * <pre>
3892     * StringUtils.join(null, *)               = null
3893     * StringUtils.join([], *)                 = ""
3894     * StringUtils.join([null], *)             = ""
3895     * StringUtils.join([1, 2, 3], ';')  = "1;2;3"
3896     * StringUtils.join([1, 2, 3], null) = "123"
3897     * </pre>
3898     *
3899     * @param array
3900     *            the array of values to join together, may be null
3901     * @param separator
3902     *            the separator character to use
3903     * @return the joined String, {@code null} if null array input
3904     * @since 3.2
3905     */
3906    public static String join(final long[] array, final char separator) {
3907        if (array == null) {
3908            return null;
3909        }
3910        return join(array, separator, 0, array.length);
3911    }
3912
3913    /**
3914     * <p>
3915     * Joins the elements of the provided array into a single String containing the provided list of elements.
3916     * </p>
3917     *
3918     * <p>
3919     * No delimiter is added before or after the list. Null objects or empty strings within the array are represented
3920     * by empty strings.
3921     * </p>
3922     *
3923     * <pre>
3924     * StringUtils.join(null, *)               = null
3925     * StringUtils.join([], *)                 = ""
3926     * StringUtils.join([null], *)             = ""
3927     * StringUtils.join([1, 2, 3], ';')  = "1;2;3"
3928     * StringUtils.join([1, 2, 3], null) = "123"
3929     * </pre>
3930     *
3931     * @param array
3932     *            the array of values to join together, may be null
3933     * @param separator
3934     *            the separator character to use
3935     * @return the joined String, {@code null} if null array input
3936     * @since 3.2
3937     */
3938    public static String join(final int[] array, final char separator) {
3939        if (array == null) {
3940            return null;
3941        }
3942        return join(array, separator, 0, array.length);
3943    }
3944
3945    /**
3946     * <p>
3947     * Joins the elements of the provided array into a single String containing the provided list of elements.
3948     * </p>
3949     *
3950     * <p>
3951     * No delimiter is added before or after the list. Null objects or empty strings within the array are represented
3952     * by empty strings.
3953     * </p>
3954     *
3955     * <pre>
3956     * StringUtils.join(null, *)               = null
3957     * StringUtils.join([], *)                 = ""
3958     * StringUtils.join([null], *)             = ""
3959     * StringUtils.join([1, 2, 3], ';')  = "1;2;3"
3960     * StringUtils.join([1, 2, 3], null) = "123"
3961     * </pre>
3962     *
3963     * @param array
3964     *            the array of values to join together, may be null
3965     * @param separator
3966     *            the separator character to use
3967     * @return the joined String, {@code null} if null array input
3968     * @since 3.2
3969     */
3970    public static String join(final short[] array, final char separator) {
3971        if (array == null) {
3972            return null;
3973        }
3974        return join(array, separator, 0, array.length);
3975    }
3976
3977    /**
3978     * <p>
3979     * Joins the elements of the provided array into a single String containing the provided list of elements.
3980     * </p>
3981     *
3982     * <p>
3983     * No delimiter is added before or after the list. Null objects or empty strings within the array are represented
3984     * by empty strings.
3985     * </p>
3986     *
3987     * <pre>
3988     * StringUtils.join(null, *)               = null
3989     * StringUtils.join([], *)                 = ""
3990     * StringUtils.join([null], *)             = ""
3991     * StringUtils.join([1, 2, 3], ';')  = "1;2;3"
3992     * StringUtils.join([1, 2, 3], null) = "123"
3993     * </pre>
3994     *
3995     * @param array
3996     *            the array of values to join together, may be null
3997     * @param separator
3998     *            the separator character to use
3999     * @return the joined String, {@code null} if null array input
4000     * @since 3.2
4001     */
4002    public static String join(final byte[] array, final char separator) {
4003        if (array == null) {
4004            return null;
4005        }
4006        return join(array, separator, 0, array.length);
4007    }
4008
4009    /**
4010     * <p>
4011     * Joins the elements of the provided array into a single String containing the provided list of elements.
4012     * </p>
4013     *
4014     * <p>
4015     * No delimiter is added before or after the list. Null objects or empty strings within the array are represented
4016     * by empty strings.
4017     * </p>
4018     *
4019     * <pre>
4020     * StringUtils.join(null, *)               = null
4021     * StringUtils.join([], *)                 = ""
4022     * StringUtils.join([null], *)             = ""
4023     * StringUtils.join([1, 2, 3], ';')  = "1;2;3"
4024     * StringUtils.join([1, 2, 3], null) = "123"
4025     * </pre>
4026     *
4027     * @param array
4028     *            the array of values to join together, may be null
4029     * @param separator
4030     *            the separator character to use
4031     * @return the joined String, {@code null} if null array input
4032     * @since 3.2
4033     */
4034    public static String join(final char[] array, final char separator) {
4035        if (array == null) {
4036            return null;
4037        }
4038        return join(array, separator, 0, array.length);
4039    }
4040
4041    /**
4042     * <p>
4043     * Joins the elements of the provided array into a single String containing the provided list of elements.
4044     * </p>
4045     *
4046     * <p>
4047     * No delimiter is added before or after the list. Null objects or empty strings within the array are represented
4048     * by empty strings.
4049     * </p>
4050     *
4051     * <pre>
4052     * StringUtils.join(null, *)               = null
4053     * StringUtils.join([], *)                 = ""
4054     * StringUtils.join([null], *)             = ""
4055     * StringUtils.join([1, 2, 3], ';')  = "1;2;3"
4056     * StringUtils.join([1, 2, 3], null) = "123"
4057     * </pre>
4058     *
4059     * @param array
4060     *            the array of values to join together, may be null
4061     * @param separator
4062     *            the separator character to use
4063     * @return the joined String, {@code null} if null array input
4064     * @since 3.2
4065     */
4066    public static String join(final float[] array, final char separator) {
4067        if (array == null) {
4068            return null;
4069        }
4070        return join(array, separator, 0, array.length);
4071    }
4072
4073    /**
4074     * <p>
4075     * Joins the elements of the provided array into a single String containing the provided list of elements.
4076     * </p>
4077     *
4078     * <p>
4079     * No delimiter is added before or after the list. Null objects or empty strings within the array are represented
4080     * by empty strings.
4081     * </p>
4082     *
4083     * <pre>
4084     * StringUtils.join(null, *)               = null
4085     * StringUtils.join([], *)                 = ""
4086     * StringUtils.join([null], *)             = ""
4087     * StringUtils.join([1, 2, 3], ';')  = "1;2;3"
4088     * StringUtils.join([1, 2, 3], null) = "123"
4089     * </pre>
4090     *
4091     * @param array
4092     *            the array of values to join together, may be null
4093     * @param separator
4094     *            the separator character to use
4095     * @return the joined String, {@code null} if null array input
4096     * @since 3.2
4097     */
4098    public static String join(final double[] array, final char separator) {
4099        if (array == null) {
4100            return null;
4101        }
4102        return join(array, separator, 0, array.length);
4103    }
4104
4105
4106    /**
4107     * <p>Joins the elements of the provided array into a single String
4108     * containing the provided list of elements.</p>
4109     *
4110     * <p>No delimiter is added before or after the list.
4111     * Null objects or empty strings within the array are represented by
4112     * empty strings.</p>
4113     *
4114     * <pre>
4115     * StringUtils.join(null, *)               = null
4116     * StringUtils.join([], *)                 = ""
4117     * StringUtils.join([null], *)             = ""
4118     * StringUtils.join(["a", "b", "c"], ';')  = "a;b;c"
4119     * StringUtils.join(["a", "b", "c"], null) = "abc"
4120     * StringUtils.join([null, "", "a"], ';')  = ";;a"
4121     * </pre>
4122     *
4123     * @param array  the array of values to join together, may be null
4124     * @param separator  the separator character to use
4125     * @param startIndex the first index to start joining from.  It is
4126     * an error to pass in an end index past the end of the array
4127     * @param endIndex the index to stop joining from (exclusive). It is
4128     * an error to pass in an end index past the end of the array
4129     * @return the joined String, {@code null} if null array input
4130     * @since 2.0
4131     */
4132    public static String join(final Object[] array, final char separator, final int startIndex, final int endIndex) {
4133        if (array == null) {
4134            return null;
4135        }
4136        final int noOfItems = endIndex - startIndex;
4137        if (noOfItems <= 0) {
4138            return EMPTY;
4139        }
4140        final StringBuilder buf = new StringBuilder(noOfItems * 16);
4141        for (int i = startIndex; i < endIndex; i++) {
4142            if (i > startIndex) {
4143                buf.append(separator);
4144            }
4145            if (array[i] != null) {
4146                buf.append(array[i]);
4147            }
4148        }
4149        return buf.toString();
4150    }
4151
4152    /**
4153     * <p>
4154     * Joins the elements of the provided array into a single String containing the provided list of elements.
4155     * </p>
4156     *
4157     * <p>
4158     * No delimiter is added before or after the list. Null objects or empty strings within the array are represented
4159     * by empty strings.
4160     * </p>
4161     *
4162     * <pre>
4163     * StringUtils.join(null, *)               = null
4164     * StringUtils.join([], *)                 = ""
4165     * StringUtils.join([null], *)             = ""
4166     * StringUtils.join([1, 2, 3], ';')  = "1;2;3"
4167     * StringUtils.join([1, 2, 3], null) = "123"
4168     * </pre>
4169     *
4170     * @param array
4171     *            the array of values to join together, may be null
4172     * @param separator
4173     *            the separator character to use
4174     * @param startIndex
4175     *            the first index to start joining from. It is an error to pass in an end index past the end of the
4176     *            array
4177     * @param endIndex
4178     *            the index to stop joining from (exclusive). It is an error to pass in an end index past the end of
4179     *            the array
4180     * @return the joined String, {@code null} if null array input
4181     * @since 3.2
4182     */
4183    public static String join(final long[] array, final char separator, final int startIndex, final int endIndex) {
4184        if (array == null) {
4185            return null;
4186        }
4187        final int noOfItems = endIndex - startIndex;
4188        if (noOfItems <= 0) {
4189            return EMPTY;
4190        }
4191        final StringBuilder buf = new StringBuilder(noOfItems * 16);
4192        for (int i = startIndex; i < endIndex; i++) {
4193            if (i > startIndex) {
4194                buf.append(separator);
4195            }
4196            buf.append(array[i]);
4197        }
4198        return buf.toString();
4199    }
4200
4201    /**
4202     * <p>
4203     * Joins the elements of the provided array into a single String containing the provided list of elements.
4204     * </p>
4205     *
4206     * <p>
4207     * No delimiter is added before or after the list. Null objects or empty strings within the array are represented
4208     * by empty strings.
4209     * </p>
4210     *
4211     * <pre>
4212     * StringUtils.join(null, *)               = null
4213     * StringUtils.join([], *)                 = ""
4214     * StringUtils.join([null], *)             = ""
4215     * StringUtils.join([1, 2, 3], ';')  = "1;2;3"
4216     * StringUtils.join([1, 2, 3], null) = "123"
4217     * </pre>
4218     *
4219     * @param array
4220     *            the array of values to join together, may be null
4221     * @param separator
4222     *            the separator character to use
4223     * @param startIndex
4224     *            the first index to start joining from. It is an error to pass in an end index past the end of the
4225     *            array
4226     * @param endIndex
4227     *            the index to stop joining from (exclusive). It is an error to pass in an end index past the end of
4228     *            the array
4229     * @return the joined String, {@code null} if null array input
4230     * @since 3.2
4231     */
4232    public static String join(final int[] array, final char separator, final int startIndex, final int endIndex) {
4233        if (array == null) {
4234            return null;
4235        }
4236        final int noOfItems = endIndex - startIndex;
4237        if (noOfItems <= 0) {
4238            return EMPTY;
4239        }
4240        final StringBuilder buf = new StringBuilder(noOfItems * 16);
4241        for (int i = startIndex; i < endIndex; i++) {
4242            if (i > startIndex) {
4243                buf.append(separator);
4244            }
4245            buf.append(array[i]);
4246        }
4247        return buf.toString();
4248    }
4249
4250    /**
4251     * <p>
4252     * Joins the elements of the provided array into a single String containing the provided list of elements.
4253     * </p>
4254     *
4255     * <p>
4256     * No delimiter is added before or after the list. Null objects or empty strings within the array are represented
4257     * by empty strings.
4258     * </p>
4259     *
4260     * <pre>
4261     * StringUtils.join(null, *)               = null
4262     * StringUtils.join([], *)                 = ""
4263     * StringUtils.join([null], *)             = ""
4264     * StringUtils.join([1, 2, 3], ';')  = "1;2;3"
4265     * StringUtils.join([1, 2, 3], null) = "123"
4266     * </pre>
4267     *
4268     * @param array
4269     *            the array of values to join together, may be null
4270     * @param separator
4271     *            the separator character to use
4272     * @param startIndex
4273     *            the first index to start joining from. It is an error to pass in an end index past the end of the
4274     *            array
4275     * @param endIndex
4276     *            the index to stop joining from (exclusive). It is an error to pass in an end index past the end of
4277     *            the array
4278     * @return the joined String, {@code null} if null array input
4279     * @since 3.2
4280     */
4281    public static String join(final byte[] array, final char separator, final int startIndex, final int endIndex) {
4282        if (array == null) {
4283            return null;
4284        }
4285        final int noOfItems = endIndex - startIndex;
4286        if (noOfItems <= 0) {
4287            return EMPTY;
4288        }
4289        final StringBuilder buf = new StringBuilder(noOfItems * 16);
4290        for (int i = startIndex; i < endIndex; i++) {
4291            if (i > startIndex) {
4292                buf.append(separator);
4293            }
4294            buf.append(array[i]);
4295        }
4296        return buf.toString();
4297    }
4298
4299    /**
4300     * <p>
4301     * Joins the elements of the provided array into a single String containing the provided list of elements.
4302     * </p>
4303     *
4304     * <p>
4305     * No delimiter is added before or after the list. Null objects or empty strings within the array are represented
4306     * by empty strings.
4307     * </p>
4308     *
4309     * <pre>
4310     * StringUtils.join(null, *)               = null
4311     * StringUtils.join([], *)                 = ""
4312     * StringUtils.join([null], *)             = ""
4313     * StringUtils.join([1, 2, 3], ';')  = "1;2;3"
4314     * StringUtils.join([1, 2, 3], null) = "123"
4315     * </pre>
4316     *
4317     * @param array
4318     *            the array of values to join together, may be null
4319     * @param separator
4320     *            the separator character to use
4321     * @param startIndex
4322     *            the first index to start joining from. It is an error to pass in an end index past the end of the
4323     *            array
4324     * @param endIndex
4325     *            the index to stop joining from (exclusive). It is an error to pass in an end index past the end of
4326     *            the array
4327     * @return the joined String, {@code null} if null array input
4328     * @since 3.2
4329     */
4330    public static String join(final short[] array, final char separator, final int startIndex, final int endIndex) {
4331        if (array == null) {
4332            return null;
4333        }
4334        final int noOfItems = endIndex - startIndex;
4335        if (noOfItems <= 0) {
4336            return EMPTY;
4337        }
4338        final StringBuilder buf = new StringBuilder(noOfItems * 16);
4339        for (int i = startIndex; i < endIndex; i++) {
4340            if (i > startIndex) {
4341                buf.append(separator);
4342            }
4343            buf.append(array[i]);
4344        }
4345        return buf.toString();
4346    }
4347
4348    /**
4349     * <p>
4350     * Joins the elements of the provided array into a single String containing the provided list of elements.
4351     * </p>
4352     *
4353     * <p>
4354     * No delimiter is added before or after the list. Null objects or empty strings within the array are represented
4355     * by empty strings.
4356     * </p>
4357     *
4358     * <pre>
4359     * StringUtils.join(null, *)               = null
4360     * StringUtils.join([], *)                 = ""
4361     * StringUtils.join([null], *)             = ""
4362     * StringUtils.join([1, 2, 3], ';')  = "1;2;3"
4363     * StringUtils.join([1, 2, 3], null) = "123"
4364     * </pre>
4365     *
4366     * @param array
4367     *            the array of values to join together, may be null
4368     * @param separator
4369     *            the separator character to use
4370     * @param startIndex
4371     *            the first index to start joining from. It is an error to pass in an end index past the end of the
4372     *            array
4373     * @param endIndex
4374     *            the index to stop joining from (exclusive). It is an error to pass in an end index past the end of
4375     *            the array
4376     * @return the joined String, {@code null} if null array input
4377     * @since 3.2
4378     */
4379    public static String join(final char[] array, final char separator, final int startIndex, final int endIndex) {
4380        if (array == null) {
4381            return null;
4382        }
4383        final int noOfItems = endIndex - startIndex;
4384        if (noOfItems <= 0) {
4385            return EMPTY;
4386        }
4387        final StringBuilder buf = new StringBuilder(noOfItems * 16);
4388        for (int i = startIndex; i < endIndex; i++) {
4389            if (i > startIndex) {
4390                buf.append(separator);
4391            }
4392            buf.append(array[i]);
4393        }
4394        return buf.toString();
4395    }
4396
4397    /**
4398     * <p>
4399     * Joins the elements of the provided array into a single String containing the provided list of elements.
4400     * </p>
4401     *
4402     * <p>
4403     * No delimiter is added before or after the list. Null objects or empty strings within the array are represented
4404     * by empty strings.
4405     * </p>
4406     *
4407     * <pre>
4408     * StringUtils.join(null, *)               = null
4409     * StringUtils.join([], *)                 = ""
4410     * StringUtils.join([null], *)             = ""
4411     * StringUtils.join([1, 2, 3], ';')  = "1;2;3"
4412     * StringUtils.join([1, 2, 3], null) = "123"
4413     * </pre>
4414     *
4415     * @param array
4416     *            the array of values to join together, may be null
4417     * @param separator
4418     *            the separator character to use
4419     * @param startIndex
4420     *            the first index to start joining from. It is an error to pass in an end index past the end of the
4421     *            array
4422     * @param endIndex
4423     *            the index to stop joining from (exclusive). It is an error to pass in an end index past the end of
4424     *            the array
4425     * @return the joined String, {@code null} if null array input
4426     * @since 3.2
4427     */
4428    public static String join(final double[] array, final char separator, final int startIndex, final int endIndex) {
4429        if (array == null) {
4430            return null;
4431        }
4432        final int noOfItems = endIndex - startIndex;
4433        if (noOfItems <= 0) {
4434            return EMPTY;
4435        }
4436        final StringBuilder buf = new StringBuilder(noOfItems * 16);
4437        for (int i = startIndex; i < endIndex; i++) {
4438            if (i > startIndex) {
4439                buf.append(separator);
4440            }
4441            buf.append(array[i]);
4442        }
4443        return buf.toString();
4444    }
4445
4446    /**
4447     * <p>
4448     * Joins the elements of the provided array into a single String containing the provided list of elements.
4449     * </p>
4450     *
4451     * <p>
4452     * No delimiter is added before or after the list. Null objects or empty strings within the array are represented
4453     * by empty strings.
4454     * </p>
4455     *
4456     * <pre>
4457     * StringUtils.join(null, *)               = null
4458     * StringUtils.join([], *)                 = ""
4459     * StringUtils.join([null], *)             = ""
4460     * StringUtils.join([1, 2, 3], ';')  = "1;2;3"
4461     * StringUtils.join([1, 2, 3], null) = "123"
4462     * </pre>
4463     *
4464     * @param array
4465     *            the array of values to join together, may be null
4466     * @param separator
4467     *            the separator character to use
4468     * @param startIndex
4469     *            the first index to start joining from. It is an error to pass in an end index past the end of the
4470     *            array
4471     * @param endIndex
4472     *            the index to stop joining from (exclusive). It is an error to pass in an end index past the end of
4473     *            the array
4474     * @return the joined String, {@code null} if null array input
4475     * @since 3.2
4476     */
4477    public static String join(final float[] array, final char separator, final int startIndex, final int endIndex) {
4478        if (array == null) {
4479            return null;
4480        }
4481        final int noOfItems = endIndex - startIndex;
4482        if (noOfItems <= 0) {
4483            return EMPTY;
4484        }
4485        final StringBuilder buf = new StringBuilder(noOfItems * 16);
4486        for (int i = startIndex; i < endIndex; i++) {
4487            if (i > startIndex) {
4488                buf.append(separator);
4489            }
4490            buf.append(array[i]);
4491        }
4492        return buf.toString();
4493    }
4494
4495
4496    /**
4497     * <p>Joins the elements of the provided array into a single String
4498     * containing the provided list of elements.</p>
4499     *
4500     * <p>No delimiter is added before or after the list.
4501     * A {@code null} separator is the same as an empty String ("").
4502     * Null objects or empty strings within the array are represented by
4503     * empty strings.</p>
4504     *
4505     * <pre>
4506     * StringUtils.join(null, *)                = null
4507     * StringUtils.join([], *)                  = ""
4508     * StringUtils.join([null], *)              = ""
4509     * StringUtils.join(["a", "b", "c"], "--")  = "a--b--c"
4510     * StringUtils.join(["a", "b", "c"], null)  = "abc"
4511     * StringUtils.join(["a", "b", "c"], "")    = "abc"
4512     * StringUtils.join([null, "", "a"], ',')   = ",,a"
4513     * </pre>
4514     *
4515     * @param array  the array of values to join together, may be null
4516     * @param separator  the separator character to use, null treated as ""
4517     * @return the joined String, {@code null} if null array input
4518     */
4519    public static String join(final Object[] array, final String separator) {
4520        if (array == null) {
4521            return null;
4522        }
4523        return join(array, separator, 0, array.length);
4524    }
4525
4526    /**
4527     * <p>Joins the elements of the provided array into a single String
4528     * containing the provided list of elements.</p>
4529     *
4530     * <p>No delimiter is added before or after the list.
4531     * A {@code null} separator is the same as an empty String ("").
4532     * Null objects or empty strings within the array are represented by
4533     * empty strings.</p>
4534     *
4535     * <pre>
4536     * StringUtils.join(null, *, *, *)                = null
4537     * StringUtils.join([], *, *, *)                  = ""
4538     * StringUtils.join([null], *, *, *)              = ""
4539     * StringUtils.join(["a", "b", "c"], "--", 0, 3)  = "a--b--c"
4540     * StringUtils.join(["a", "b", "c"], "--", 1, 3)  = "b--c"
4541     * StringUtils.join(["a", "b", "c"], "--", 2, 3)  = "c"
4542     * StringUtils.join(["a", "b", "c"], "--", 2, 2)  = ""
4543     * StringUtils.join(["a", "b", "c"], null, 0, 3)  = "abc"
4544     * StringUtils.join(["a", "b", "c"], "", 0, 3)    = "abc"
4545     * StringUtils.join([null, "", "a"], ',', 0, 3)   = ",,a"
4546     * </pre>
4547     *
4548     * @param array  the array of values to join together, may be null
4549     * @param separator  the separator character to use, null treated as ""
4550     * @param startIndex the first index to start joining from.
4551     * @param endIndex the index to stop joining from (exclusive).
4552     * @return the joined String, {@code null} if null array input; or the empty string
4553     * if {@code endIndex - startIndex <= 0}. The number of joined entries is given by
4554     * {@code endIndex - startIndex}
4555     * @throws ArrayIndexOutOfBoundsException ife<br>
4556     * {@code startIndex < 0} or <br>
4557     * {@code startIndex >= array.length()} or <br>
4558     * {@code endIndex < 0} or <br>
4559     * {@code endIndex > array.length()}
4560     */
4561    public static String join(final Object[] array, String separator, final int startIndex, final int endIndex) {
4562        if (array == null) {
4563            return null;
4564        }
4565        if (separator == null) {
4566            separator = EMPTY;
4567        }
4568
4569        // endIndex - startIndex > 0:   Len = NofStrings *(len(firstString) + len(separator))
4570        //           (Assuming that all Strings are roughly equally long)
4571        final int noOfItems = endIndex - startIndex;
4572        if (noOfItems <= 0) {
4573            return EMPTY;
4574        }
4575
4576        final StringBuilder buf = new StringBuilder(noOfItems * 16);
4577
4578        for (int i = startIndex; i < endIndex; i++) {
4579            if (i > startIndex) {
4580                buf.append(separator);
4581            }
4582            if (array[i] != null) {
4583                buf.append(array[i]);
4584            }
4585        }
4586        return buf.toString();
4587    }
4588
4589    /**
4590     * <p>Joins the elements of the provided {@code Iterator} into
4591     * a single String containing the provided elements.</p>
4592     *
4593     * <p>No delimiter is added before or after the list. Null objects or empty
4594     * strings within the iteration are represented by empty strings.</p>
4595     *
4596     * <p>See the examples here: {@link #join(Object[],char)}. </p>
4597     *
4598     * @param iterator  the {@code Iterator} of values to join together, may be null
4599     * @param separator  the separator character to use
4600     * @return the joined String, {@code null} if null iterator input
4601     * @since 2.0
4602     */
4603    public static String join(final Iterator<?> iterator, final char separator) {
4604
4605        // handle null, zero and one elements before building a buffer
4606        if (iterator == null) {
4607            return null;
4608        }
4609        if (!iterator.hasNext()) {
4610            return EMPTY;
4611        }
4612        final Object first = iterator.next();
4613        if (!iterator.hasNext()) {
4614            final String result = Objects.toString(first, "");
4615            return result;
4616        }
4617
4618        // two or more elements
4619        final StringBuilder buf = new StringBuilder(256); // Java default is 16, probably too small
4620        if (first != null) {
4621            buf.append(first);
4622        }
4623
4624        while (iterator.hasNext()) {
4625            buf.append(separator);
4626            final Object obj = iterator.next();
4627            if (obj != null) {
4628                buf.append(obj);
4629            }
4630        }
4631
4632        return buf.toString();
4633    }
4634
4635    /**
4636     * <p>Joins the elements of the provided {@code Iterator} into
4637     * a single String containing the provided elements.</p>
4638     *
4639     * <p>No delimiter is added before or after the list.
4640     * A {@code null} separator is the same as an empty String ("").</p>
4641     *
4642     * <p>See the examples here: {@link #join(Object[],String)}. </p>
4643     *
4644     * @param iterator  the {@code Iterator} of values to join together, may be null
4645     * @param separator  the separator character to use, null treated as ""
4646     * @return the joined String, {@code null} if null iterator input
4647     */
4648    public static String join(final Iterator<?> iterator, final String separator) {
4649
4650        // handle null, zero and one elements before building a buffer
4651        if (iterator == null) {
4652            return null;
4653        }
4654        if (!iterator.hasNext()) {
4655            return EMPTY;
4656        }
4657        final Object first = iterator.next();
4658        if (!iterator.hasNext()) {
4659            final String result = Objects.toString(first, "");
4660            return result;
4661        }
4662
4663        // two or more elements
4664        final StringBuilder buf = new StringBuilder(256); // Java default is 16, probably too small
4665        if (first != null) {
4666            buf.append(first);
4667        }
4668
4669        while (iterator.hasNext()) {
4670            if (separator != null) {
4671                buf.append(separator);
4672            }
4673            final Object obj = iterator.next();
4674            if (obj != null) {
4675                buf.append(obj);
4676            }
4677        }
4678        return buf.toString();
4679    }
4680
4681    /**
4682     * <p>Joins the elements of the provided {@code Iterable} into
4683     * a single String containing the provided elements.</p>
4684     *
4685     * <p>No delimiter is added before or after the list. Null objects or empty
4686     * strings within the iteration are represented by empty strings.</p>
4687     *
4688     * <p>See the examples here: {@link #join(Object[],char)}. </p>
4689     *
4690     * @param iterable  the {@code Iterable} providing the values to join together, may be null
4691     * @param separator  the separator character to use
4692     * @return the joined String, {@code null} if null iterator input
4693     * @since 2.3
4694     */
4695    public static String join(final Iterable<?> iterable, final char separator) {
4696        if (iterable == null) {
4697            return null;
4698        }
4699        return join(iterable.iterator(), separator);
4700    }
4701
4702    /**
4703     * <p>Joins the elements of the provided {@code Iterable} into
4704     * a single String containing the provided elements.</p>
4705     *
4706     * <p>No delimiter is added before or after the list.
4707     * A {@code null} separator is the same as an empty String ("").</p>
4708     *
4709     * <p>See the examples here: {@link #join(Object[],String)}. </p>
4710     *
4711     * @param iterable  the {@code Iterable} providing the values to join together, may be null
4712     * @param separator  the separator character to use, null treated as ""
4713     * @return the joined String, {@code null} if null iterator input
4714     * @since 2.3
4715     */
4716    public static String join(final Iterable<?> iterable, final String separator) {
4717        if (iterable == null) {
4718            return null;
4719        }
4720        return join(iterable.iterator(), separator);
4721    }
4722
4723    /**
4724     * <p>Joins the elements of the provided varargs into a
4725     * single String containing the provided elements.</p>
4726     *
4727     * <p>No delimiter is added before or after the list.
4728     * {@code null} elements and separator are treated as empty Strings ("").</p>
4729     *
4730     * <pre>
4731     * StringUtils.joinWith(",", {"a", "b"})        = "a,b"
4732     * StringUtils.joinWith(",", {"a", "b",""})     = "a,b,"
4733     * StringUtils.joinWith(",", {"a", null, "b"})  = "a,,b"
4734     * StringUtils.joinWith(null, {"a", "b"})       = "ab"
4735     * </pre>
4736     *
4737     * @param separator the separator character to use, null treated as ""
4738     * @param objects the varargs providing the values to join together. {@code null} elements are treated as ""
4739     * @return the joined String.
4740     * @throws java.lang.IllegalArgumentException if a null varargs is provided
4741     * @since 3.5
4742     */
4743    public static String joinWith(final String separator, final Object... objects) {
4744        if (objects == null) {
4745            throw new IllegalArgumentException("Object varargs must not be null");
4746        }
4747
4748        final String sanitizedSeparator = defaultString(separator, StringUtils.EMPTY);
4749
4750        final StringBuilder result = new StringBuilder();
4751
4752        final Iterator<Object> iterator = Arrays.asList(objects).iterator();
4753        while (iterator.hasNext()) {
4754            final String value = Objects.toString(iterator.next(), "");
4755            result.append(value);
4756
4757            if (iterator.hasNext()) {
4758                result.append(sanitizedSeparator);
4759            }
4760        }
4761
4762        return result.toString();
4763    }
4764
4765    // Delete
4766    //-----------------------------------------------------------------------
4767    /**
4768     * <p>Deletes all whitespaces from a String as defined by
4769     * {@link Character#isWhitespace(char)}.</p>
4770     *
4771     * <pre>
4772     * StringUtils.deleteWhitespace(null)         = null
4773     * StringUtils.deleteWhitespace("")           = ""
4774     * StringUtils.deleteWhitespace("abc")        = "abc"
4775     * StringUtils.deleteWhitespace("   ab  c  ") = "abc"
4776     * </pre>
4777     *
4778     * @param str  the String to delete whitespace from, may be null
4779     * @return the String without whitespaces, {@code null} if null String input
4780     */
4781    public static String deleteWhitespace(final String str) {
4782        if (isEmpty(str)) {
4783            return str;
4784        }
4785        final int sz = str.length();
4786        final char[] chs = new char[sz];
4787        int count = 0;
4788        for (int i = 0; i < sz; i++) {
4789            if (!Character.isWhitespace(str.charAt(i))) {
4790                chs[count++] = str.charAt(i);
4791            }
4792        }
4793        if (count == sz) {
4794            return str;
4795        }
4796        return new String(chs, 0, count);
4797    }
4798
4799    // Remove
4800    //-----------------------------------------------------------------------
4801    /**
4802     * <p>Removes a substring only if it is at the beginning of a source string,
4803     * otherwise returns the source string.</p>
4804     *
4805     * <p>A {@code null} source string will return {@code null}.
4806     * An empty ("") source string will return the empty string.
4807     * A {@code null} search string will return the source string.</p>
4808     *
4809     * <pre>
4810     * StringUtils.removeStart(null, *)      = null
4811     * StringUtils.removeStart("", *)        = ""
4812     * StringUtils.removeStart(*, null)      = *
4813     * StringUtils.removeStart("www.domain.com", "www.")   = "domain.com"
4814     * StringUtils.removeStart("domain.com", "www.")       = "domain.com"
4815     * StringUtils.removeStart("www.domain.com", "domain") = "www.domain.com"
4816     * StringUtils.removeStart("abc", "")    = "abc"
4817     * </pre>
4818     *
4819     * @param str  the source String to search, may be null
4820     * @param remove  the String to search for and remove, may be null
4821     * @return the substring with the string removed if found,
4822     *  {@code null} if null String input
4823     * @since 2.1
4824     */
4825    public static String removeStart(final String str, final String remove) {
4826        if (isEmpty(str) || isEmpty(remove)) {
4827            return str;
4828        }
4829        if (str.startsWith(remove)){
4830            return str.substring(remove.length());
4831        }
4832        return str;
4833    }
4834
4835    /**
4836     * <p>Case insensitive removal of a substring if it is at the beginning of a source string,
4837     * otherwise returns the source string.</p>
4838     *
4839     * <p>A {@code null} source string will return {@code null}.
4840     * An empty ("") source string will return the empty string.
4841     * A {@code null} search string will return the source string.</p>
4842     *
4843     * <pre>
4844     * StringUtils.removeStartIgnoreCase(null, *)      = null
4845     * StringUtils.removeStartIgnoreCase("", *)        = ""
4846     * StringUtils.removeStartIgnoreCase(*, null)      = *
4847     * StringUtils.removeStartIgnoreCase("www.domain.com", "www.")   = "domain.com"
4848     * StringUtils.removeStartIgnoreCase("www.domain.com", "WWW.")   = "domain.com"
4849     * StringUtils.removeStartIgnoreCase("domain.com", "www.")       = "domain.com"
4850     * StringUtils.removeStartIgnoreCase("www.domain.com", "domain") = "www.domain.com"
4851     * StringUtils.removeStartIgnoreCase("abc", "")    = "abc"
4852     * </pre>
4853     *
4854     * @param str  the source String to search, may be null
4855     * @param remove  the String to search for (case insensitive) and remove, may be null
4856     * @return the substring with the string removed if found,
4857     *  {@code null} if null String input
4858     * @since 2.4
4859     */
4860    public static String removeStartIgnoreCase(final String str, final String remove) {
4861        if (isEmpty(str) || isEmpty(remove)) {
4862            return str;
4863        }
4864        if (startsWithIgnoreCase(str, remove)) {
4865            return str.substring(remove.length());
4866        }
4867        return str;
4868    }
4869
4870    /**
4871     * <p>Removes a substring only if it is at the end of a source string,
4872     * otherwise returns the source string.</p>
4873     *
4874     * <p>A {@code null} source string will return {@code null}.
4875     * An empty ("") source string will return the empty string.
4876     * A {@code null} search string will return the source string.</p>
4877     *
4878     * <pre>
4879     * StringUtils.removeEnd(null, *)      = null
4880     * StringUtils.removeEnd("", *)        = ""
4881     * StringUtils.removeEnd(*, null)      = *
4882     * StringUtils.removeEnd("www.domain.com", ".com.")  = "www.domain.com"
4883     * StringUtils.removeEnd("www.domain.com", ".com")   = "www.domain"
4884     * StringUtils.removeEnd("www.domain.com", "domain") = "www.domain.com"
4885     * StringUtils.removeEnd("abc", "")    = "abc"
4886     * </pre>
4887     *
4888     * @param str  the source String to search, may be null
4889     * @param remove  the String to search for and remove, may be null
4890     * @return the substring with the string removed if found,
4891     *  {@code null} if null String input
4892     * @since 2.1
4893     */
4894    public static String removeEnd(final String str, final String remove) {
4895        if (isEmpty(str) || isEmpty(remove)) {
4896            return str;
4897        }
4898        if (str.endsWith(remove)) {
4899            return str.substring(0, str.length() - remove.length());
4900        }
4901        return str;
4902    }
4903
4904    /**
4905     * <p>Case insensitive removal of a substring if it is at the end of a source string,
4906     * otherwise returns the source string.</p>
4907     *
4908     * <p>A {@code null} source string will return {@code null}.
4909     * An empty ("") source string will return the empty string.
4910     * A {@code null} search string will return the source string.</p>
4911     *
4912     * <pre>
4913     * StringUtils.removeEndIgnoreCase(null, *)      = null
4914     * StringUtils.removeEndIgnoreCase("", *)        = ""
4915     * StringUtils.removeEndIgnoreCase(*, null)      = *
4916     * StringUtils.removeEndIgnoreCase("www.domain.com", ".com.")  = "www.domain.com"
4917     * StringUtils.removeEndIgnoreCase("www.domain.com", ".com")   = "www.domain"
4918     * StringUtils.removeEndIgnoreCase("www.domain.com", "domain") = "www.domain.com"
4919     * StringUtils.removeEndIgnoreCase("abc", "")    = "abc"
4920     * StringUtils.removeEndIgnoreCase("www.domain.com", ".COM") = "www.domain")
4921     * StringUtils.removeEndIgnoreCase("www.domain.COM", ".com") = "www.domain")
4922     * </pre>
4923     *
4924     * @param str  the source String to search, may be null
4925     * @param remove  the String to search for (case insensitive) and remove, may be null
4926     * @return the substring with the string removed if found,
4927     *  {@code null} if null String input
4928     * @since 2.4
4929     */
4930    public static String removeEndIgnoreCase(final String str, final String remove) {
4931        if (isEmpty(str) || isEmpty(remove)) {
4932            return str;
4933        }
4934        if (endsWithIgnoreCase(str, remove)) {
4935            return str.substring(0, str.length() - remove.length());
4936        }
4937        return str;
4938    }
4939
4940    /**
4941     * <p>Removes all occurrences of a substring from within the source string.</p>
4942     *
4943     * <p>A {@code null} source string will return {@code null}.
4944     * An empty ("") source string will return the empty string.
4945     * A {@code null} remove string will return the source string.
4946     * An empty ("") remove string will return the source string.</p>
4947     *
4948     * <pre>
4949     * StringUtils.remove(null, *)        = null
4950     * StringUtils.remove("", *)          = ""
4951     * StringUtils.remove(*, null)        = *
4952     * StringUtils.remove(*, "")          = *
4953     * StringUtils.remove("queued", "ue") = "qd"
4954     * StringUtils.remove("queued", "zz") = "queued"
4955     * </pre>
4956     *
4957     * @param str  the source String to search, may be null
4958     * @param remove  the String to search for and remove, may be null
4959     * @return the substring with the string removed if found,
4960     *  {@code null} if null String input
4961     * @since 2.1
4962     */
4963    public static String remove(final String str, final String remove) {
4964        if (isEmpty(str) || isEmpty(remove)) {
4965            return str;
4966        }
4967        return replace(str, remove, EMPTY, -1);
4968    }
4969
4970    /**
4971     * <p>
4972     * Case insensitive removal of all occurrences of a substring from within
4973     * the source string.
4974     * </p>
4975     *
4976     * <p>
4977     * A {@code null} source string will return {@code null}. An empty ("")
4978     * source string will return the empty string. A {@code null} remove string
4979     * will return the source string. An empty ("") remove string will return
4980     * the source string.
4981     * </p>
4982     *
4983     * <pre>
4984     * StringUtils.removeIgnoreCase(null, *)        = null
4985     * StringUtils.removeIgnoreCase("", *)          = ""
4986     * StringUtils.removeIgnoreCase(*, null)        = *
4987     * StringUtils.removeIgnoreCase(*, "")          = *
4988     * StringUtils.removeIgnoreCase("queued", "ue") = "qd"
4989     * StringUtils.removeIgnoreCase("queued", "zz") = "queued"
4990     * StringUtils.removeIgnoreCase("quEUed", "UE") = "qd"
4991     * StringUtils.removeIgnoreCase("queued", "zZ") = "queued"
4992     * </pre>
4993     *
4994     * @param str
4995     *            the source String to search, may be null
4996     * @param remove
4997     *            the String to search for (case insensitive) and remove, may be
4998     *            null
4999     * @return the substring with the string removed if found, {@code null} if
5000     *         null String input
5001     * @since 3.5
5002     */
5003    public static String removeIgnoreCase(final String str, final String remove) {
5004        if (isEmpty(str) || isEmpty(remove)) {
5005            return str;
5006        }
5007        return replaceIgnoreCase(str, remove, EMPTY, -1);
5008    }
5009
5010    /**
5011     * <p>Removes all occurrences of a character from within the source string.</p>
5012     *
5013     * <p>A {@code null} source string will return {@code null}.
5014     * An empty ("") source string will return the empty string.</p>
5015     *
5016     * <pre>
5017     * StringUtils.remove(null, *)       = null
5018     * StringUtils.remove("", *)         = ""
5019     * StringUtils.remove("queued", 'u') = "qeed"
5020     * StringUtils.remove("queued", 'z') = "queued"
5021     * </pre>
5022     *
5023     * @param str  the source String to search, may be null
5024     * @param remove  the char to search for and remove, may be null
5025     * @return the substring with the char removed if found,
5026     *  {@code null} if null String input
5027     * @since 2.1
5028     */
5029    public static String remove(final String str, final char remove) {
5030        if (isEmpty(str) || str.indexOf(remove) == INDEX_NOT_FOUND) {
5031            return str;
5032        }
5033        final char[] chars = str.toCharArray();
5034        int pos = 0;
5035        for (int i = 0; i < chars.length; i++) {
5036            if (chars[i] != remove) {
5037                chars[pos++] = chars[i];
5038            }
5039        }
5040        return new String(chars, 0, pos);
5041    }
5042
5043    /**
5044     * <p>Removes each substring of the text String that matches the given regular expression.</p>
5045     *
5046     * This method is a {@code null} safe equivalent to:
5047     * <ul>
5048     *  <li>{@code text.replaceAll(regex, StringUtils.EMPTY)}</li>
5049     *  <li>{@code Pattern.compile(regex).matcher(text).replaceAll(StringUtils.EMPTY)}</li>
5050     * </ul>
5051     *
5052     * <p>A {@code null} reference passed to this method is a no-op.</p>
5053     *
5054     * <p>Unlike in the {@link #removePattern(String, String)} method, the {@link Pattern#DOTALL} option
5055     * is NOT automatically added.
5056     * To use the DOTALL option prepend <code>"(?s)"</code> to the regex.
5057     * DOTALL is also know as single-line mode in Perl.</p>
5058     *
5059     * <pre>
5060     * StringUtils.removeAll(null, *)      = null
5061     * StringUtils.removeAll("any", null)  = "any"
5062     * StringUtils.removeAll("any", "")    = "any"
5063     * StringUtils.removeAll("any", ".*")  = ""
5064     * StringUtils.removeAll("any", ".+")  = ""
5065     * StringUtils.removeAll("abc", ".?")  = ""
5066     * StringUtils.removeAll("A&lt;__&gt;\n&lt;__&gt;B", "&lt;.*&gt;")      = "A\nB"
5067     * StringUtils.removeAll("A&lt;__&gt;\n&lt;__&gt;B", "(?s)&lt;.*&gt;")  = "AB"
5068     * StringUtils.removeAll("ABCabc123abc", "[a-z]")     = "ABC123"
5069     * </pre>
5070     *
5071     * @param text  text to remove from, may be null
5072     * @param regex  the regular expression to which this string is to be matched
5073     * @return  the text with any removes processed,
5074     *              {@code null} if null String input
5075     *
5076     * @throws  java.util.regex.PatternSyntaxException
5077     *              if the regular expression's syntax is invalid
5078     *
5079     * @see #replaceAll(String, String, String)
5080     * @see #removePattern(String, String)
5081     * @see String#replaceAll(String, String)
5082     * @see java.util.regex.Pattern
5083     * @see java.util.regex.Pattern#DOTALL
5084     * @since 3.5
5085     */
5086    public static String removeAll(final String text, final String regex) {
5087        return replaceAll(text, regex, StringUtils.EMPTY);
5088    }
5089
5090    /**
5091     * <p>Removes the first substring of the text string that matches the given regular expression.</p>
5092     *
5093     * This method is a {@code null} safe equivalent to:
5094     * <ul>
5095     *  <li>{@code text.replaceFirst(regex, StringUtils.EMPTY)}</li>
5096     *  <li>{@code Pattern.compile(regex).matcher(text).replaceFirst(StringUtils.EMPTY)}</li>
5097     * </ul>
5098     *
5099     * <p>A {@code null} reference passed to this method is a no-op.</p>
5100     *
5101     * <p>The {@link Pattern#DOTALL} option is NOT automatically added.
5102     * To use the DOTALL option prepend <code>"(?s)"</code> to the regex.
5103     * DOTALL is also know as single-line mode in Perl.</p>
5104     *
5105     * <pre>
5106     * StringUtils.removeFirst(null, *)      = null
5107     * StringUtils.removeFirst("any", null)  = "any"
5108     * StringUtils.removeFirst("any", "")    = "any"
5109     * StringUtils.removeFirst("any", ".*")  = ""
5110     * StringUtils.removeFirst("any", ".+")  = ""
5111     * StringUtils.removeFirst("abc", ".?")  = "bc"
5112     * StringUtils.removeFirst("A&lt;__&gt;\n&lt;__&gt;B", "&lt;.*&gt;")      = "A\n&lt;__&gt;B"
5113     * StringUtils.removeFirst("A&lt;__&gt;\n&lt;__&gt;B", "(?s)&lt;.*&gt;")  = "AB"
5114     * StringUtils.removeFirst("ABCabc123", "[a-z]")          = "ABCbc123"
5115     * StringUtils.removeFirst("ABCabc123abc", "[a-z]+")      = "ABC123abc"
5116     * </pre>
5117     *
5118     * @param text  text to remove from, may be null
5119     * @param regex  the regular expression to which this string is to be matched
5120     * @return  the text with the first replacement processed,
5121     *              {@code null} if null String input
5122     *
5123     * @throws  java.util.regex.PatternSyntaxException
5124     *              if the regular expression's syntax is invalid
5125     *
5126     * @see #replaceFirst(String, String, String)
5127     * @see String#replaceFirst(String, String)
5128     * @see java.util.regex.Pattern
5129     * @see java.util.regex.Pattern#DOTALL
5130     * @since 3.5
5131     */
5132    public static String removeFirst(final String text, final String regex) {
5133        return replaceFirst(text, regex, StringUtils.EMPTY);
5134    }
5135
5136    // Replacing
5137    //-----------------------------------------------------------------------
5138    /**
5139     * <p>Replaces a String with another String inside a larger String, once.</p>
5140     *
5141     * <p>A {@code null} reference passed to this method is a no-op.</p>
5142     *
5143     * <pre>
5144     * StringUtils.replaceOnce(null, *, *)        = null
5145     * StringUtils.replaceOnce("", *, *)          = ""
5146     * StringUtils.replaceOnce("any", null, *)    = "any"
5147     * StringUtils.replaceOnce("any", *, null)    = "any"
5148     * StringUtils.replaceOnce("any", "", *)      = "any"
5149     * StringUtils.replaceOnce("aba", "a", null)  = "aba"
5150     * StringUtils.replaceOnce("aba", "a", "")    = "ba"
5151     * StringUtils.replaceOnce("aba", "a", "z")   = "zba"
5152     * </pre>
5153     *
5154     * @see #replace(String text, String searchString, String replacement, int max)
5155     * @param text  text to search and replace in, may be null
5156     * @param searchString  the String to search for, may be null
5157     * @param replacement  the String to replace with, may be null
5158     * @return the text with any replacements processed,
5159     *  {@code null} if null String input
5160     */
5161    public static String replaceOnce(final String text, final String searchString, final String replacement) {
5162        return replace(text, searchString, replacement, 1);
5163    }
5164
5165    /**
5166     * <p>Case insensitively replaces a String with another String inside a larger String, once.</p>
5167     *
5168     * <p>A {@code null} reference passed to this method is a no-op.</p>
5169     *
5170     * <pre>
5171     * StringUtils.replaceOnceIgnoreCase(null, *, *)        = null
5172     * StringUtils.replaceOnceIgnoreCase("", *, *)          = ""
5173     * StringUtils.replaceOnceIgnoreCase("any", null, *)    = "any"
5174     * StringUtils.replaceOnceIgnoreCase("any", *, null)    = "any"
5175     * StringUtils.replaceOnceIgnoreCase("any", "", *)      = "any"
5176     * StringUtils.replaceOnceIgnoreCase("aba", "a", null)  = "aba"
5177     * StringUtils.replaceOnceIgnoreCase("aba", "a", "")    = "ba"
5178     * StringUtils.replaceOnceIgnoreCase("aba", "a", "z")   = "zba"
5179     * StringUtils.replaceOnceIgnoreCase("FoOFoofoo", "foo", "") = "Foofoo"
5180     * </pre>
5181     *
5182     * @see #replaceIgnoreCase(String text, String searchString, String replacement, int max)
5183     * @param text  text to search and replace in, may be null
5184     * @param searchString  the String to search for (case insensitive), may be null
5185     * @param replacement  the String to replace with, may be null
5186     * @return the text with any replacements processed,
5187     *  {@code null} if null String input
5188     * @since 3.5
5189     */
5190    public static String replaceOnceIgnoreCase(final String text, final String searchString, final String replacement) {
5191        return replaceIgnoreCase(text, searchString, replacement, 1);
5192    }
5193
5194    /**
5195     * <p>Replaces each substring of the source String that matches the given regular expression with the given
5196     * replacement using the {@link Pattern#DOTALL} option. DOTALL is also know as single-line mode in Perl.</p>
5197     *
5198     * This call is a {@code null} safe equivalent to:
5199     * <ul>
5200     * <li>{@code source.replaceAll(&quot;(?s)&quot; + regex, replacement)}</li>
5201     * <li>{@code Pattern.compile(regex, Pattern.DOTALL).matcher(source).replaceAll(replacement)}</li>
5202     * </ul>
5203     *
5204     * <p>A {@code null} reference passed to this method is a no-op.</p>
5205     *
5206     * <pre>
5207     * StringUtils.replacePattern(null, *, *)       = null
5208     * StringUtils.replacePattern("any", null, *)   = "any"
5209     * StringUtils.replacePattern("any", *, null)   = "any"
5210     * StringUtils.replacePattern("", "", "zzz")    = "zzz"
5211     * StringUtils.replacePattern("", ".*", "zzz")  = "zzz"
5212     * StringUtils.replacePattern("", ".+", "zzz")  = ""
5213     * StringUtils.replacePattern("&lt;__&gt;\n&lt;__&gt;", "&lt;.*&gt;", "z")       = "z"
5214     * StringUtils.replacePattern("ABCabc123", "[a-z]", "_")       = "ABC___123"
5215     * StringUtils.replacePattern("ABCabc123", "[^A-Z0-9]+", "_")  = "ABC_123"
5216     * StringUtils.replacePattern("ABCabc123", "[^A-Z0-9]+", "")   = "ABC123"
5217     * StringUtils.replacePattern("Lorem ipsum  dolor   sit", "( +)([a-z]+)", "_$2")  = "Lorem_ipsum_dolor_sit"
5218     * </pre>
5219     *
5220     * @param source
5221     *            the source string
5222     * @param regex
5223     *            the regular expression to which this string is to be matched
5224     * @param replacement
5225     *            the string to be substituted for each match
5226     * @return The resulting {@code String}
5227     * @see #replaceAll(String, String, String)
5228     * @see String#replaceAll(String, String)
5229     * @see Pattern#DOTALL
5230     * @since 3.2
5231     * @since 3.5 Changed {@code null} reference passed to this method is a no-op.
5232     */
5233    public static String replacePattern(final String source, final String regex, final String replacement) {
5234        if (source == null || regex == null || replacement == null) {
5235            return source;
5236        }
5237        return Pattern.compile(regex, Pattern.DOTALL).matcher(source).replaceAll(replacement);
5238    }
5239
5240    /**
5241     * <p>Removes each substring of the source String that matches the given regular expression using the DOTALL option.
5242     * </p>
5243     *
5244     * This call is a {@code null} safe equivalent to:
5245     * <ul>
5246     * <li>{@code source.replaceAll(&quot;(?s)&quot; + regex, StringUtils.EMPTY)}</li>
5247     * <li>{@code Pattern.compile(regex, Pattern.DOTALL).matcher(source).replaceAll(StringUtils.EMPTY)}</li>
5248     * </ul>
5249     *
5250     * <p>A {@code null} reference passed to this method is a no-op.</p>
5251     *
5252     * <pre>
5253     * StringUtils.removePattern(null, *)       = null
5254     * StringUtils.removePattern("any", null)   = "any"
5255     * StringUtils.removePattern("A&lt;__&gt;\n&lt;__&gt;B", "&lt;.*&gt;")  = "AB"
5256     * StringUtils.removePattern("ABCabc123", "[a-z]")    = "ABC123"
5257     * </pre>
5258     *
5259     * @param source
5260     *            the source string
5261     * @param regex
5262     *            the regular expression to which this string is to be matched
5263     * @return The resulting {@code String}
5264     * @see #replacePattern(String, String, String)
5265     * @see String#replaceAll(String, String)
5266     * @see Pattern#DOTALL
5267     * @since 3.2
5268     * @since 3.5 Changed {@code null} reference passed to this method is a no-op.
5269     */
5270    public static String removePattern(final String source, final String regex) {
5271        return replacePattern(source, regex, StringUtils.EMPTY);
5272    }
5273
5274    /**
5275     * <p>Replaces each substring of the text String that matches the given regular expression
5276     * with the given replacement.</p>
5277     *
5278     * This method is a {@code null} safe equivalent to:
5279     * <ul>
5280     *  <li>{@code text.replaceAll(regex, replacement)}</li>
5281     *  <li>{@code Pattern.compile(regex).matcher(text).replaceAll(replacement)}</li>
5282     * </ul>
5283     *
5284     * <p>A {@code null} reference passed to this method is a no-op.</p>
5285     *
5286     * <p>Unlike in the {@link #replacePattern(String, String, String)} method, the {@link Pattern#DOTALL} option
5287     * is NOT automatically added.
5288     * To use the DOTALL option prepend <code>"(?s)"</code> to the regex.
5289     * DOTALL is also know as single-line mode in Perl.</p>
5290     *
5291     * <pre>
5292     * StringUtils.replaceAll(null, *, *)       = null
5293     * StringUtils.replaceAll("any", null, *)   = "any"
5294     * StringUtils.replaceAll("any", *, null)   = "any"
5295     * StringUtils.replaceAll("", "", "zzz")    = "zzz"
5296     * StringUtils.replaceAll("", ".*", "zzz")  = "zzz"
5297     * StringUtils.replaceAll("", ".+", "zzz")  = ""
5298     * StringUtils.replaceAll("abc", "", "ZZ")  = "ZZaZZbZZcZZ"
5299     * StringUtils.replaceAll("&lt;__&gt;\n&lt;__&gt;", "&lt;.*&gt;", "z")      = "z\nz"
5300     * StringUtils.replaceAll("&lt;__&gt;\n&lt;__&gt;", "(?s)&lt;.*&gt;", "z")  = "z"
5301     * StringUtils.replaceAll("ABCabc123", "[a-z]", "_")       = "ABC___123"
5302     * StringUtils.replaceAll("ABCabc123", "[^A-Z0-9]+", "_")  = "ABC_123"
5303     * StringUtils.replaceAll("ABCabc123", "[^A-Z0-9]+", "")   = "ABC123"
5304     * StringUtils.replaceAll("Lorem ipsum  dolor   sit", "( +)([a-z]+)", "_$2")  = "Lorem_ipsum_dolor_sit"
5305     * </pre>
5306     *
5307     * @param text  text to search and replace in, may be null
5308     * @param regex  the regular expression to which this string is to be matched
5309     * @param replacement  the string to be substituted for each match
5310     * @return  the text with any replacements processed,
5311     *              {@code null} if null String input
5312     *
5313     * @throws  java.util.regex.PatternSyntaxException
5314     *              if the regular expression's syntax is invalid
5315     *
5316     * @see #replacePattern(String, String, String)
5317     * @see String#replaceAll(String, String)
5318     * @see java.util.regex.Pattern
5319     * @see java.util.regex.Pattern#DOTALL
5320     * @since 3.5
5321     */
5322    public static String replaceAll(final String text, final String regex, final String replacement) {
5323        if (text == null || regex == null|| replacement == null ) {
5324            return text;
5325        }
5326        return text.replaceAll(regex, replacement);
5327    }
5328
5329    /**
5330     * <p>Replaces the first substring of the text string that matches the given regular expression
5331     * with the given replacement.</p>
5332     *
5333     * This method is a {@code null} safe equivalent to:
5334     * <ul>
5335     *  <li>{@code text.replaceFirst(regex, replacement)}</li>
5336     *  <li>{@code Pattern.compile(regex).matcher(text).replaceFirst(replacement)}</li>
5337     * </ul>
5338     *
5339     * <p>A {@code null} reference passed to this method is a no-op.</p>
5340     *
5341     * <p>The {@link Pattern#DOTALL} option is NOT automatically added.
5342     * To use the DOTALL option prepend <code>"(?s)"</code> to the regex.
5343     * DOTALL is also know as single-line mode in Perl.</p>
5344     *
5345     * <pre>
5346     * StringUtils.replaceFirst(null, *, *)       = null
5347     * StringUtils.replaceFirst("any", null, *)   = "any"
5348     * StringUtils.replaceFirst("any", *, null)   = "any"
5349     * StringUtils.replaceFirst("", "", "zzz")    = "zzz"
5350     * StringUtils.replaceFirst("", ".*", "zzz")  = "zzz"
5351     * StringUtils.replaceFirst("", ".+", "zzz")  = ""
5352     * StringUtils.replaceFirst("abc", "", "ZZ")  = "ZZabc"
5353     * StringUtils.replaceFirst("&lt;__&gt;\n&lt;__&gt;", "&lt;.*&gt;", "z")      = "z\n&lt;__&gt;"
5354     * StringUtils.replaceFirst("&lt;__&gt;\n&lt;__&gt;", "(?s)&lt;.*&gt;", "z")  = "z"
5355     * StringUtils.replaceFirst("ABCabc123", "[a-z]", "_")          = "ABC_bc123"
5356     * StringUtils.replaceFirst("ABCabc123abc", "[^A-Z0-9]+", "_")  = "ABC_123abc"
5357     * StringUtils.replaceFirst("ABCabc123abc", "[^A-Z0-9]+", "")   = "ABC123abc"
5358     * StringUtils.replaceFirst("Lorem ipsum  dolor   sit", "( +)([a-z]+)", "_$2")  = "Lorem_ipsum  dolor   sit"
5359     * </pre>
5360     *
5361     * @param text  text to search and replace in, may be null
5362     * @param regex  the regular expression to which this string is to be matched
5363     * @param replacement  the string to be substituted for the first match
5364     * @return  the text with the first replacement processed,
5365     *              {@code null} if null String input
5366     *
5367     * @throws  java.util.regex.PatternSyntaxException
5368     *              if the regular expression's syntax is invalid
5369     *
5370     * @see String#replaceFirst(String, String)
5371     * @see java.util.regex.Pattern
5372     * @see java.util.regex.Pattern#DOTALL
5373     * @since 3.5
5374     */
5375    public static String replaceFirst(final String text, final String regex, final String replacement) {
5376        if (text == null || regex == null|| replacement == null ) {
5377            return text;
5378        }
5379        return text.replaceFirst(regex, replacement);
5380    }
5381
5382    /**
5383     * <p>Replaces all occurrences of a String within another String.</p>
5384     *
5385     * <p>A {@code null} reference passed to this method is a no-op.</p>
5386     *
5387     * <pre>
5388     * StringUtils.replace(null, *, *)        = null
5389     * StringUtils.replace("", *, *)          = ""
5390     * StringUtils.replace("any", null, *)    = "any"
5391     * StringUtils.replace("any", *, null)    = "any"
5392     * StringUtils.replace("any", "", *)      = "any"
5393     * StringUtils.replace("aba", "a", null)  = "aba"
5394     * StringUtils.replace("aba", "a", "")    = "b"
5395     * StringUtils.replace("aba", "a", "z")   = "zbz"
5396     * </pre>
5397     *
5398     * @see #replace(String text, String searchString, String replacement, int max)
5399     * @param text  text to search and replace in, may be null
5400     * @param searchString  the String to search for, may be null
5401     * @param replacement  the String to replace it with, may be null
5402     * @return the text with any replacements processed,
5403     *  {@code null} if null String input
5404     */
5405    public static String replace(final String text, final String searchString, final String replacement) {
5406        return replace(text, searchString, replacement, -1);
5407    }
5408
5409    /**
5410    * <p>Case insensitively replaces all occurrences of a String within another String.</p>
5411    *
5412    * <p>A {@code null} reference passed to this method is a no-op.</p>
5413    *
5414    * <pre>
5415    * StringUtils.replaceIgnoreCase(null, *, *)        = null
5416    * StringUtils.replaceIgnoreCase("", *, *)          = ""
5417    * StringUtils.replaceIgnoreCase("any", null, *)    = "any"
5418    * StringUtils.replaceIgnoreCase("any", *, null)    = "any"
5419    * StringUtils.replaceIgnoreCase("any", "", *)      = "any"
5420    * StringUtils.replaceIgnoreCase("aba", "a", null)  = "aba"
5421    * StringUtils.replaceIgnoreCase("abA", "A", "")    = "b"
5422    * StringUtils.replaceIgnoreCase("aba", "A", "z")   = "zbz"
5423    * </pre>
5424    *
5425    * @see #replaceIgnoreCase(String text, String searchString, String replacement, int max)
5426    * @param text  text to search and replace in, may be null
5427    * @param searchString  the String to search for (case insensitive), may be null
5428    * @param replacement  the String to replace it with, may be null
5429    * @return the text with any replacements processed,
5430    *  {@code null} if null String input
5431    * @since 3.5
5432    */
5433   public static String replaceIgnoreCase(final String text, final String searchString, final String replacement) {
5434       return replaceIgnoreCase(text, searchString, replacement, -1);
5435   }
5436
5437    /**
5438     * <p>Replaces a String with another String inside a larger String,
5439     * for the first {@code max} values of the search String.</p>
5440     *
5441     * <p>A {@code null} reference passed to this method is a no-op.</p>
5442     *
5443     * <pre>
5444     * StringUtils.replace(null, *, *, *)         = null
5445     * StringUtils.replace("", *, *, *)           = ""
5446     * StringUtils.replace("any", null, *, *)     = "any"
5447     * StringUtils.replace("any", *, null, *)     = "any"
5448     * StringUtils.replace("any", "", *, *)       = "any"
5449     * StringUtils.replace("any", *, *, 0)        = "any"
5450     * StringUtils.replace("abaa", "a", null, -1) = "abaa"
5451     * StringUtils.replace("abaa", "a", "", -1)   = "b"
5452     * StringUtils.replace("abaa", "a", "z", 0)   = "abaa"
5453     * StringUtils.replace("abaa", "a", "z", 1)   = "zbaa"
5454     * StringUtils.replace("abaa", "a", "z", 2)   = "zbza"
5455     * StringUtils.replace("abaa", "a", "z", -1)  = "zbzz"
5456     * </pre>
5457     *
5458     * @param text  text to search and replace in, may be null
5459     * @param searchString  the String to search for, may be null
5460     * @param replacement  the String to replace it with, may be null
5461     * @param max  maximum number of values to replace, or {@code -1} if no maximum
5462     * @return the text with any replacements processed,
5463     *  {@code null} if null String input
5464     */
5465    public static String replace(final String text, final String searchString, final String replacement, final int max) {
5466        return replace(text, searchString, replacement, max, false);
5467    }
5468
5469    /**
5470     * <p>Replaces a String with another String inside a larger String,
5471     * for the first {@code max} values of the search String,
5472     * case sensitively/insensisitively based on {@code ignoreCase} value.</p>
5473     *
5474     * <p>A {@code null} reference passed to this method is a no-op.</p>
5475     *
5476     * <pre>
5477     * StringUtils.replace(null, *, *, *, false)         = null
5478     * StringUtils.replace("", *, *, *, false)           = ""
5479     * StringUtils.replace("any", null, *, *, false)     = "any"
5480     * StringUtils.replace("any", *, null, *, false)     = "any"
5481     * StringUtils.replace("any", "", *, *, false)       = "any"
5482     * StringUtils.replace("any", *, *, 0, false)        = "any"
5483     * StringUtils.replace("abaa", "a", null, -1, false) = "abaa"
5484     * StringUtils.replace("abaa", "a", "", -1, false)   = "b"
5485     * StringUtils.replace("abaa", "a", "z", 0, false)   = "abaa"
5486     * StringUtils.replace("abaa", "A", "z", 1, false)   = "abaa"
5487     * StringUtils.replace("abaa", "A", "z", 1, true)   = "zbaa"
5488     * StringUtils.replace("abAa", "a", "z", 2, true)   = "zbza"
5489     * StringUtils.replace("abAa", "a", "z", -1, true)  = "zbzz"
5490     * </pre>
5491     *
5492     * @param text  text to search and replace in, may be null
5493     * @param searchString  the String to search for (case insensitive), may be null
5494     * @param replacement  the String to replace it with, may be null
5495     * @param max  maximum number of values to replace, or {@code -1} if no maximum
5496     * @param ignoreCase if true replace is case insensitive, otherwise case sensitive
5497     * @return the text with any replacements processed,
5498     *  {@code null} if null String input
5499     */
5500     private static String replace(final String text, String searchString, final String replacement, int max, final boolean ignoreCase) {
5501         if (isEmpty(text) || isEmpty(searchString) || replacement == null || max == 0) {
5502             return text;
5503         }
5504         String searchText = text;
5505         if (ignoreCase) {
5506             searchText = text.toLowerCase();
5507             searchString = searchString.toLowerCase();
5508         }
5509         int start = 0;
5510         int end = searchText.indexOf(searchString, start);
5511         if (end == INDEX_NOT_FOUND) {
5512             return text;
5513         }
5514         final int replLength = searchString.length();
5515         int increase = replacement.length() - replLength;
5516         increase = increase < 0 ? 0 : increase;
5517         increase *= max < 0 ? 16 : max > 64 ? 64 : max;
5518         final StringBuilder buf = new StringBuilder(text.length() + increase);
5519         while (end != INDEX_NOT_FOUND) {
5520             buf.append(text.substring(start, end)).append(replacement);
5521             start = end + replLength;
5522             if (--max == 0) {
5523                 break;
5524             }
5525             end = searchText.indexOf(searchString, start);
5526         }
5527         buf.append(text.substring(start));
5528         return buf.toString();
5529     }
5530
5531    /**
5532     * <p>Case insensitively replaces a String with another String inside a larger String,
5533     * for the first {@code max} values of the search String.</p>
5534     *
5535     * <p>A {@code null} reference passed to this method is a no-op.</p>
5536     *
5537     * <pre>
5538     * StringUtils.replaceIgnoreCase(null, *, *, *)         = null
5539     * StringUtils.replaceIgnoreCase("", *, *, *)           = ""
5540     * StringUtils.replaceIgnoreCase("any", null, *, *)     = "any"
5541     * StringUtils.replaceIgnoreCase("any", *, null, *)     = "any"
5542     * StringUtils.replaceIgnoreCase("any", "", *, *)       = "any"
5543     * StringUtils.replaceIgnoreCase("any", *, *, 0)        = "any"
5544     * StringUtils.replaceIgnoreCase("abaa", "a", null, -1) = "abaa"
5545     * StringUtils.replaceIgnoreCase("abaa", "a", "", -1)   = "b"
5546     * StringUtils.replaceIgnoreCase("abaa", "a", "z", 0)   = "abaa"
5547     * StringUtils.replaceIgnoreCase("abaa", "A", "z", 1)   = "zbaa"
5548     * StringUtils.replaceIgnoreCase("abAa", "a", "z", 2)   = "zbza"
5549     * StringUtils.replaceIgnoreCase("abAa", "a", "z", -1)  = "zbzz"
5550     * </pre>
5551     *
5552     * @param text  text to search and replace in, may be null
5553     * @param searchString  the String to search for (case insensitive), may be null
5554     * @param replacement  the String to replace it with, may be null
5555     * @param max  maximum number of values to replace, or {@code -1} if no maximum
5556     * @return the text with any replacements processed,
5557     *  {@code null} if null String input
5558     * @since 3.5
5559     */
5560    public static String replaceIgnoreCase(final String text, final String searchString, final String replacement, final int max) {
5561        return replace(text, searchString, replacement, max, true);
5562    }
5563
5564    /**
5565     * <p>
5566     * Replaces all occurrences of Strings within another String.
5567     * </p>
5568     *
5569     * <p>
5570     * A {@code null} reference passed to this method is a no-op, or if
5571     * any "search string" or "string to replace" is null, that replace will be
5572     * ignored. This will not repeat. For repeating replaces, call the
5573     * overloaded method.
5574     * </p>
5575     *
5576     * <pre>
5577     *  StringUtils.replaceEach(null, *, *)        = null
5578     *  StringUtils.replaceEach("", *, *)          = ""
5579     *  StringUtils.replaceEach("aba", null, null) = "aba"
5580     *  StringUtils.replaceEach("aba", new String[0], null) = "aba"
5581     *  StringUtils.replaceEach("aba", null, new String[0]) = "aba"
5582     *  StringUtils.replaceEach("aba", new String[]{"a"}, null)  = "aba"
5583     *  StringUtils.replaceEach("aba", new String[]{"a"}, new String[]{""})  = "b"
5584     *  StringUtils.replaceEach("aba", new String[]{null}, new String[]{"a"})  = "aba"
5585     *  StringUtils.replaceEach("abcde", new String[]{"ab", "d"}, new String[]{"w", "t"})  = "wcte"
5586     *  (example of how it does not repeat)
5587     *  StringUtils.replaceEach("abcde", new String[]{"ab", "d"}, new String[]{"d", "t"})  = "dcte"
5588     * </pre>
5589     *
5590     * @param text
5591     *            text to search and replace in, no-op if null
5592     * @param searchList
5593     *            the Strings to search for, no-op if null
5594     * @param replacementList
5595     *            the Strings to replace them with, no-op if null
5596     * @return the text with any replacements processed, {@code null} if
5597     *         null String input
5598     * @throws IllegalArgumentException
5599     *             if the lengths of the arrays are not the same (null is ok,
5600     *             and/or size 0)
5601     * @since 2.4
5602     */
5603    public static String replaceEach(final String text, final String[] searchList, final String[] replacementList) {
5604        return replaceEach(text, searchList, replacementList, false, 0);
5605    }
5606
5607    /**
5608     * <p>
5609     * Replaces all occurrences of Strings within another String.
5610     * </p>
5611     *
5612     * <p>
5613     * A {@code null} reference passed to this method is a no-op, or if
5614     * any "search string" or "string to replace" is null, that replace will be
5615     * ignored.
5616     * </p>
5617     *
5618     * <pre>
5619     *  StringUtils.replaceEachRepeatedly(null, *, *) = null
5620     *  StringUtils.replaceEachRepeatedly("", *, *) = ""
5621     *  StringUtils.replaceEachRepeatedly("aba", null, null) = "aba"
5622     *  StringUtils.replaceEachRepeatedly("aba", new String[0], null) = "aba"
5623     *  StringUtils.replaceEachRepeatedly("aba", null, new String[0]) = "aba"
5624     *  StringUtils.replaceEachRepeatedly("aba", new String[]{"a"}, null) = "aba"
5625     *  StringUtils.replaceEachRepeatedly("aba", new String[]{"a"}, new String[]{""}) = "b"
5626     *  StringUtils.replaceEachRepeatedly("aba", new String[]{null}, new String[]{"a"}) = "aba"
5627     *  StringUtils.replaceEachRepeatedly("abcde", new String[]{"ab", "d"}, new String[]{"w", "t"}) = "wcte"
5628     *  (example of how it repeats)
5629     *  StringUtils.replaceEachRepeatedly("abcde", new String[]{"ab", "d"}, new String[]{"d", "t"}) = "tcte"
5630     *  StringUtils.replaceEachRepeatedly("abcde", new String[]{"ab", "d"}, new String[]{"d", "ab"}) = IllegalStateException
5631     * </pre>
5632     *
5633     * @param text
5634     *            text to search and replace in, no-op if null
5635     * @param searchList
5636     *            the Strings to search for, no-op if null
5637     * @param replacementList
5638     *            the Strings to replace them with, no-op if null
5639     * @return the text with any replacements processed, {@code null} if
5640     *         null String input
5641     * @throws IllegalStateException
5642     *             if the search is repeating and there is an endless loop due
5643     *             to outputs of one being inputs to another
5644     * @throws IllegalArgumentException
5645     *             if the lengths of the arrays are not the same (null is ok,
5646     *             and/or size 0)
5647     * @since 2.4
5648     */
5649    public static String replaceEachRepeatedly(final String text, final String[] searchList, final String[] replacementList) {
5650        // timeToLive should be 0 if not used or nothing to replace, else it's
5651        // the length of the replace array
5652        final int timeToLive = searchList == null ? 0 : searchList.length;
5653        return replaceEach(text, searchList, replacementList, true, timeToLive);
5654    }
5655
5656    /**
5657     * <p>
5658     * Replace all occurrences of Strings within another String.
5659     * This is a private recursive helper method for {@link #replaceEachRepeatedly(String, String[], String[])} and
5660     * {@link #replaceEach(String, String[], String[])}
5661     * </p>
5662     *
5663     * <p>
5664     * A {@code null} reference passed to this method is a no-op, or if
5665     * any "search string" or "string to replace" is null, that replace will be
5666     * ignored.
5667     * </p>
5668     *
5669     * <pre>
5670     *  StringUtils.replaceEach(null, *, *, *, *) = null
5671     *  StringUtils.replaceEach("", *, *, *, *) = ""
5672     *  StringUtils.replaceEach("aba", null, null, *, *) = "aba"
5673     *  StringUtils.replaceEach("aba", new String[0], null, *, *) = "aba"
5674     *  StringUtils.replaceEach("aba", null, new String[0], *, *) = "aba"
5675     *  StringUtils.replaceEach("aba", new String[]{"a"}, null, *, *) = "aba"
5676     *  StringUtils.replaceEach("aba", new String[]{"a"}, new String[]{""}, *, >=0) = "b"
5677     *  StringUtils.replaceEach("aba", new String[]{null}, new String[]{"a"}, *, >=0) = "aba"
5678     *  StringUtils.replaceEach("abcde", new String[]{"ab", "d"}, new String[]{"w", "t"}, *, >=0) = "wcte"
5679     *  (example of how it repeats)
5680     *  StringUtils.replaceEach("abcde", new String[]{"ab", "d"}, new String[]{"d", "t"}, false, >=0) = "dcte"
5681     *  StringUtils.replaceEach("abcde", new String[]{"ab", "d"}, new String[]{"d", "t"}, true, >=2) = "tcte"
5682     *  StringUtils.replaceEach("abcde", new String[]{"ab", "d"}, new String[]{"d", "ab"}, *, *) = IllegalStateException
5683     * </pre>
5684     *
5685     * @param text
5686     *            text to search and replace in, no-op if null
5687     * @param searchList
5688     *            the Strings to search for, no-op if null
5689     * @param replacementList
5690     *            the Strings to replace them with, no-op if null
5691     * @param repeat if true, then replace repeatedly
5692     *       until there are no more possible replacements or timeToLive < 0
5693     * @param timeToLive
5694     *            if less than 0 then there is a circular reference and endless
5695     *            loop
5696     * @return the text with any replacements processed, {@code null} if
5697     *         null String input
5698     * @throws IllegalStateException
5699     *             if the search is repeating and there is an endless loop due
5700     *             to outputs of one being inputs to another
5701     * @throws IllegalArgumentException
5702     *             if the lengths of the arrays are not the same (null is ok,
5703     *             and/or size 0)
5704     * @since 2.4
5705     */
5706    private static String replaceEach(
5707            final String text, final String[] searchList, final String[] replacementList, final boolean repeat, final int timeToLive) {
5708
5709        // mchyzer Performance note: This creates very few new objects (one major goal)
5710        // let me know if there are performance requests, we can create a harness to measure
5711
5712        if (text == null || text.isEmpty() || searchList == null ||
5713                searchList.length == 0 || replacementList == null || replacementList.length == 0) {
5714            return text;
5715        }
5716
5717        // if recursing, this shouldn't be less than 0
5718        if (timeToLive < 0) {
5719            throw new IllegalStateException("Aborting to protect against StackOverflowError - " +
5720                                            "output of one loop is the input of another");
5721        }
5722
5723        final int searchLength = searchList.length;
5724        final int replacementLength = replacementList.length;
5725
5726        // make sure lengths are ok, these need to be equal
5727        if (searchLength != replacementLength) {
5728            throw new IllegalArgumentException("Search and Replace array lengths don't match: "
5729                + searchLength
5730                + " vs "
5731                + replacementLength);
5732        }
5733
5734        // keep track of which still have matches
5735        final boolean[] noMoreMatchesForReplIndex = new boolean[searchLength];
5736
5737        // index on index that the match was found
5738        int textIndex = -1;
5739        int replaceIndex = -1;
5740        int tempIndex = -1;
5741
5742        // index of replace array that will replace the search string found
5743        // NOTE: logic duplicated below START
5744        for (int i = 0; i < searchLength; i++) {
5745            if (noMoreMatchesForReplIndex[i] || searchList[i] == null ||
5746                    searchList[i].isEmpty() || replacementList[i] == null) {
5747                continue;
5748            }
5749            tempIndex = text.indexOf(searchList[i]);
5750
5751            // see if we need to keep searching for this
5752            if (tempIndex == -1) {
5753                noMoreMatchesForReplIndex[i] = true;
5754            } else {
5755                if (textIndex == -1 || tempIndex < textIndex) {
5756                    textIndex = tempIndex;
5757                    replaceIndex = i;
5758                }
5759            }
5760        }
5761        // NOTE: logic mostly below END
5762
5763        // no search strings found, we are done
5764        if (textIndex == -1) {
5765            return text;
5766        }
5767
5768        int start = 0;
5769
5770        // get a good guess on the size of the result buffer so it doesn't have to double if it goes over a bit
5771        int increase = 0;
5772
5773        // count the replacement text elements that are larger than their corresponding text being replaced
5774        for (int i = 0; i < searchList.length; i++) {
5775            if (searchList[i] == null || replacementList[i] == null) {
5776                continue;
5777            }
5778            final int greater = replacementList[i].length() - searchList[i].length();
5779            if (greater > 0) {
5780                increase += 3 * greater; // assume 3 matches
5781            }
5782        }
5783        // have upper-bound at 20% increase, then let Java take over
5784        increase = Math.min(increase, text.length() / 5);
5785
5786        final StringBuilder buf = new StringBuilder(text.length() + increase);
5787
5788        while (textIndex != -1) {
5789
5790            for (int i = start; i < textIndex; i++) {
5791                buf.append(text.charAt(i));
5792            }
5793            buf.append(replacementList[replaceIndex]);
5794
5795            start = textIndex + searchList[replaceIndex].length();
5796
5797            textIndex = -1;
5798            replaceIndex = -1;
5799            tempIndex = -1;
5800            // find the next earliest match
5801            // NOTE: logic mostly duplicated above START
5802            for (int i = 0; i < searchLength; i++) {
5803                if (noMoreMatchesForReplIndex[i] || searchList[i] == null ||
5804                        searchList[i].isEmpty() || replacementList[i] == null) {
5805                    continue;
5806                }
5807                tempIndex = text.indexOf(searchList[i], start);
5808
5809                // see if we need to keep searching for this
5810                if (tempIndex == -1) {
5811                    noMoreMatchesForReplIndex[i] = true;
5812                } else {
5813                    if (textIndex == -1 || tempIndex < textIndex) {
5814                        textIndex = tempIndex;
5815                        replaceIndex = i;
5816                    }
5817                }
5818            }
5819            // NOTE: logic duplicated above END
5820
5821        }
5822        final int textLength = text.length();
5823        for (int i = start; i < textLength; i++) {
5824            buf.append(text.charAt(i));
5825        }
5826        final String result = buf.toString();
5827        if (!repeat) {
5828            return result;
5829        }
5830
5831        return replaceEach(result, searchList, replacementList, repeat, timeToLive - 1);
5832    }
5833
5834    // Replace, character based
5835    //-----------------------------------------------------------------------
5836    /**
5837     * <p>Replaces all occurrences of a character in a String with another.
5838     * This is a null-safe version of {@link String#replace(char, char)}.</p>
5839     *
5840     * <p>A {@code null} string input returns {@code null}.
5841     * An empty ("") string input returns an empty string.</p>
5842     *
5843     * <pre>
5844     * StringUtils.replaceChars(null, *, *)        = null
5845     * StringUtils.replaceChars("", *, *)          = ""
5846     * StringUtils.replaceChars("abcba", 'b', 'y') = "aycya"
5847     * StringUtils.replaceChars("abcba", 'z', 'y') = "abcba"
5848     * </pre>
5849     *
5850     * @param str  String to replace characters in, may be null
5851     * @param searchChar  the character to search for, may be null
5852     * @param replaceChar  the character to replace, may be null
5853     * @return modified String, {@code null} if null string input
5854     * @since 2.0
5855     */
5856    public static String replaceChars(final String str, final char searchChar, final char replaceChar) {
5857        if (str == null) {
5858            return null;
5859        }
5860        return str.replace(searchChar, replaceChar);
5861    }
5862
5863    /**
5864     * <p>Replaces multiple characters in a String in one go.
5865     * This method can also be used to delete characters.</p>
5866     *
5867     * <p>For example:<br>
5868     * <code>replaceChars(&quot;hello&quot;, &quot;ho&quot;, &quot;jy&quot;) = jelly</code>.</p>
5869     *
5870     * <p>A {@code null} string input returns {@code null}.
5871     * An empty ("") string input returns an empty string.
5872     * A null or empty set of search characters returns the input string.</p>
5873     *
5874     * <p>The length of the search characters should normally equal the length
5875     * of the replace characters.
5876     * If the search characters is longer, then the extra search characters
5877     * are deleted.
5878     * If the search characters is shorter, then the extra replace characters
5879     * are ignored.</p>
5880     *
5881     * <pre>
5882     * StringUtils.replaceChars(null, *, *)           = null
5883     * StringUtils.replaceChars("", *, *)             = ""
5884     * StringUtils.replaceChars("abc", null, *)       = "abc"
5885     * StringUtils.replaceChars("abc", "", *)         = "abc"
5886     * StringUtils.replaceChars("abc", "b", null)     = "ac"
5887     * StringUtils.replaceChars("abc", "b", "")       = "ac"
5888     * StringUtils.replaceChars("abcba", "bc", "yz")  = "ayzya"
5889     * StringUtils.replaceChars("abcba", "bc", "y")   = "ayya"
5890     * StringUtils.replaceChars("abcba", "bc", "yzx") = "ayzya"
5891     * </pre>
5892     *
5893     * @param str  String to replace characters in, may be null
5894     * @param searchChars  a set of characters to search for, may be null
5895     * @param replaceChars  a set of characters to replace, may be null
5896     * @return modified String, {@code null} if null string input
5897     * @since 2.0
5898     */
5899    public static String replaceChars(final String str, final String searchChars, String replaceChars) {
5900        if (isEmpty(str) || isEmpty(searchChars)) {
5901            return str;
5902        }
5903        if (replaceChars == null) {
5904            replaceChars = EMPTY;
5905        }
5906        boolean modified = false;
5907        final int replaceCharsLength = replaceChars.length();
5908        final int strLength = str.length();
5909        final StringBuilder buf = new StringBuilder(strLength);
5910        for (int i = 0; i < strLength; i++) {
5911            final char ch = str.charAt(i);
5912            final int index = searchChars.indexOf(ch);
5913            if (index >= 0) {
5914                modified = true;
5915                if (index < replaceCharsLength) {
5916                    buf.append(replaceChars.charAt(index));
5917                }
5918            } else {
5919                buf.append(ch);
5920            }
5921        }
5922        if (modified) {
5923            return buf.toString();
5924        }
5925        return str;
5926    }
5927
5928    // Overlay
5929    //-----------------------------------------------------------------------
5930    /**
5931     * <p>Overlays part of a String with another String.</p>
5932     *
5933     * <p>A {@code null} string input returns {@code null}.
5934     * A negative index is treated as zero.
5935     * An index greater than the string length is treated as the string length.
5936     * The start index is always the smaller of the two indices.</p>
5937     *
5938     * <pre>
5939     * StringUtils.overlay(null, *, *, *)            = null
5940     * StringUtils.overlay("", "abc", 0, 0)          = "abc"
5941     * StringUtils.overlay("abcdef", null, 2, 4)     = "abef"
5942     * StringUtils.overlay("abcdef", "", 2, 4)       = "abef"
5943     * StringUtils.overlay("abcdef", "", 4, 2)       = "abef"
5944     * StringUtils.overlay("abcdef", "zzzz", 2, 4)   = "abzzzzef"
5945     * StringUtils.overlay("abcdef", "zzzz", 4, 2)   = "abzzzzef"
5946     * StringUtils.overlay("abcdef", "zzzz", -1, 4)  = "zzzzef"
5947     * StringUtils.overlay("abcdef", "zzzz", 2, 8)   = "abzzzz"
5948     * StringUtils.overlay("abcdef", "zzzz", -2, -3) = "zzzzabcdef"
5949     * StringUtils.overlay("abcdef", "zzzz", 8, 10)  = "abcdefzzzz"
5950     * </pre>
5951     *
5952     * @param str  the String to do overlaying in, may be null
5953     * @param overlay  the String to overlay, may be null
5954     * @param start  the position to start overlaying at
5955     * @param end  the position to stop overlaying before
5956     * @return overlayed String, {@code null} if null String input
5957     * @since 2.0
5958     */
5959    public static String overlay(final String str, String overlay, int start, int end) {
5960        if (str == null) {
5961            return null;
5962        }
5963        if (overlay == null) {
5964            overlay = EMPTY;
5965        }
5966        final int len = str.length();
5967        if (start < 0) {
5968            start = 0;
5969        }
5970        if (start > len) {
5971            start = len;
5972        }
5973        if (end < 0) {
5974            end = 0;
5975        }
5976        if (end > len) {
5977            end = len;
5978        }
5979        if (start > end) {
5980            final int temp = start;
5981            start = end;
5982            end = temp;
5983        }
5984        return new StringBuilder(len + start - end + overlay.length() + 1)
5985            .append(str.substring(0, start))
5986            .append(overlay)
5987            .append(str.substring(end))
5988            .toString();
5989    }
5990
5991    // Chomping
5992    //-----------------------------------------------------------------------
5993    /**
5994     * <p>Removes one newline from end of a String if it's there,
5995     * otherwise leave it alone.  A newline is &quot;{@code \n}&quot;,
5996     * &quot;{@code \r}&quot;, or &quot;{@code \r\n}&quot;.</p>
5997     *
5998     * <p>NOTE: This method changed in 2.0.
5999     * It now more closely matches Perl chomp.</p>
6000     *
6001     * <pre>
6002     * StringUtils.chomp(null)          = null
6003     * StringUtils.chomp("")            = ""
6004     * StringUtils.chomp("abc \r")      = "abc "
6005     * StringUtils.chomp("abc\n")       = "abc"
6006     * StringUtils.chomp("abc\r\n")     = "abc"
6007     * StringUtils.chomp("abc\r\n\r\n") = "abc\r\n"
6008     * StringUtils.chomp("abc\n\r")     = "abc\n"
6009     * StringUtils.chomp("abc\n\rabc")  = "abc\n\rabc"
6010     * StringUtils.chomp("\r")          = ""
6011     * StringUtils.chomp("\n")          = ""
6012     * StringUtils.chomp("\r\n")        = ""
6013     * </pre>
6014     *
6015     * @param str  the String to chomp a newline from, may be null
6016     * @return String without newline, {@code null} if null String input
6017     */
6018    public static String chomp(final String str) {
6019        if (isEmpty(str)) {
6020            return str;
6021        }
6022
6023        if (str.length() == 1) {
6024            final char ch = str.charAt(0);
6025            if (ch == CharUtils.CR || ch == CharUtils.LF) {
6026                return EMPTY;
6027            }
6028            return str;
6029        }
6030
6031        int lastIdx = str.length() - 1;
6032        final char last = str.charAt(lastIdx);
6033
6034        if (last == CharUtils.LF) {
6035            if (str.charAt(lastIdx - 1) == CharUtils.CR) {
6036                lastIdx--;
6037            }
6038        } else if (last != CharUtils.CR) {
6039            lastIdx++;
6040        }
6041        return str.substring(0, lastIdx);
6042    }
6043
6044    /**
6045     * <p>Removes {@code separator} from the end of
6046     * {@code str} if it's there, otherwise leave it alone.</p>
6047     *
6048     * <p>NOTE: This method changed in version 2.0.
6049     * It now more closely matches Perl chomp.
6050     * For the previous behavior, use {@link #substringBeforeLast(String, String)}.
6051     * This method uses {@link String#endsWith(String)}.</p>
6052     *
6053     * <pre>
6054     * StringUtils.chomp(null, *)         = null
6055     * StringUtils.chomp("", *)           = ""
6056     * StringUtils.chomp("foobar", "bar") = "foo"
6057     * StringUtils.chomp("foobar", "baz") = "foobar"
6058     * StringUtils.chomp("foo", "foo")    = ""
6059     * StringUtils.chomp("foo ", "foo")   = "foo "
6060     * StringUtils.chomp(" foo", "foo")   = " "
6061     * StringUtils.chomp("foo", "foooo")  = "foo"
6062     * StringUtils.chomp("foo", "")       = "foo"
6063     * StringUtils.chomp("foo", null)     = "foo"
6064     * </pre>
6065     *
6066     * @param str  the String to chomp from, may be null
6067     * @param separator  separator String, may be null
6068     * @return String without trailing separator, {@code null} if null String input
6069     * @deprecated This feature will be removed in Lang 4.0, use {@link StringUtils#removeEnd(String, String)} instead
6070     */
6071    @Deprecated
6072    public static String chomp(final String str, final String separator) {
6073        return removeEnd(str,separator);
6074    }
6075
6076    // Chopping
6077    //-----------------------------------------------------------------------
6078    /**
6079     * <p>Remove the last character from a String.</p>
6080     *
6081     * <p>If the String ends in {@code \r\n}, then remove both
6082     * of them.</p>
6083     *
6084     * <pre>
6085     * StringUtils.chop(null)          = null
6086     * StringUtils.chop("")            = ""
6087     * StringUtils.chop("abc \r")      = "abc "
6088     * StringUtils.chop("abc\n")       = "abc"
6089     * StringUtils.chop("abc\r\n")     = "abc"
6090     * StringUtils.chop("abc")         = "ab"
6091     * StringUtils.chop("abc\nabc")    = "abc\nab"
6092     * StringUtils.chop("a")           = ""
6093     * StringUtils.chop("\r")          = ""
6094     * StringUtils.chop("\n")          = ""
6095     * StringUtils.chop("\r\n")        = ""
6096     * </pre>
6097     *
6098     * @param str  the String to chop last character from, may be null
6099     * @return String without last character, {@code null} if null String input
6100     */
6101    public static String chop(final String str) {
6102        if (str == null) {
6103            return null;
6104        }
6105        final int strLen = str.length();
6106        if (strLen < 2) {
6107            return EMPTY;
6108        }
6109        final int lastIdx = strLen - 1;
6110        final String ret = str.substring(0, lastIdx);
6111        final char last = str.charAt(lastIdx);
6112        if (last == CharUtils.LF && ret.charAt(lastIdx - 1) == CharUtils.CR) {
6113            return ret.substring(0, lastIdx - 1);
6114        }
6115        return ret;
6116    }
6117
6118    // Conversion
6119    //-----------------------------------------------------------------------
6120
6121    // Padding
6122    //-----------------------------------------------------------------------
6123    /**
6124     * <p>Repeat a String {@code repeat} times to form a
6125     * new String.</p>
6126     *
6127     * <pre>
6128     * StringUtils.repeat(null, 2) = null
6129     * StringUtils.repeat("", 0)   = ""
6130     * StringUtils.repeat("", 2)   = ""
6131     * StringUtils.repeat("a", 3)  = "aaa"
6132     * StringUtils.repeat("ab", 2) = "abab"
6133     * StringUtils.repeat("a", -2) = ""
6134     * </pre>
6135     *
6136     * @param str  the String to repeat, may be null
6137     * @param repeat  number of times to repeat str, negative treated as zero
6138     * @return a new String consisting of the original String repeated,
6139     *  {@code null} if null String input
6140     */
6141    public static String repeat(final String str, final int repeat) {
6142        // Performance tuned for 2.0 (JDK1.4)
6143
6144        if (str == null) {
6145            return null;
6146        }
6147        if (repeat <= 0) {
6148            return EMPTY;
6149        }
6150        final int inputLength = str.length();
6151        if (repeat == 1 || inputLength == 0) {
6152            return str;
6153        }
6154        if (inputLength == 1 && repeat <= PAD_LIMIT) {
6155            return repeat(str.charAt(0), repeat);
6156        }
6157
6158        final int outputLength = inputLength * repeat;
6159        switch (inputLength) {
6160            case 1 :
6161                return repeat(str.charAt(0), repeat);
6162            case 2 :
6163                final char ch0 = str.charAt(0);
6164                final char ch1 = str.charAt(1);
6165                final char[] output2 = new char[outputLength];
6166                for (int i = repeat * 2 - 2; i >= 0; i--, i--) {
6167                    output2[i] = ch0;
6168                    output2[i + 1] = ch1;
6169                }
6170                return new String(output2);
6171            default :
6172                final StringBuilder buf = new StringBuilder(outputLength);
6173                for (int i = 0; i < repeat; i++) {
6174                    buf.append(str);
6175                }
6176                return buf.toString();
6177        }
6178    }
6179
6180    /**
6181     * <p>Repeat a String {@code repeat} times to form a
6182     * new String, with a String separator injected each time. </p>
6183     *
6184     * <pre>
6185     * StringUtils.repeat(null, null, 2) = null
6186     * StringUtils.repeat(null, "x", 2)  = null
6187     * StringUtils.repeat("", null, 0)   = ""
6188     * StringUtils.repeat("", "", 2)     = ""
6189     * StringUtils.repeat("", "x", 3)    = "xxx"
6190     * StringUtils.repeat("?", ", ", 3)  = "?, ?, ?"
6191     * </pre>
6192     *
6193     * @param str        the String to repeat, may be null
6194     * @param separator  the String to inject, may be null
6195     * @param repeat     number of times to repeat str, negative treated as zero
6196     * @return a new String consisting of the original String repeated,
6197     *  {@code null} if null String input
6198     * @since 2.5
6199     */
6200    public static String repeat(final String str, final String separator, final int repeat) {
6201        if(str == null || separator == null) {
6202            return repeat(str, repeat);
6203        }
6204        // given that repeat(String, int) is quite optimized, better to rely on it than try and splice this into it
6205        final String result = repeat(str + separator, repeat);
6206        return removeEnd(result, separator);
6207    }
6208
6209    /**
6210     * <p>Returns padding using the specified delimiter repeated
6211     * to a given length.</p>
6212     *
6213     * <pre>
6214     * StringUtils.repeat('e', 0)  = ""
6215     * StringUtils.repeat('e', 3)  = "eee"
6216     * StringUtils.repeat('e', -2) = ""
6217     * </pre>
6218     *
6219     * <p>Note: this method doesn't not support padding with
6220     * <a href="http://www.unicode.org/glossary/#supplementary_character">Unicode Supplementary Characters</a>
6221     * as they require a pair of {@code char}s to be represented.
6222     * If you are needing to support full I18N of your applications
6223     * consider using {@link #repeat(String, int)} instead.
6224     * </p>
6225     *
6226     * @param ch  character to repeat
6227     * @param repeat  number of times to repeat char, negative treated as zero
6228     * @return String with repeated character
6229     * @see #repeat(String, int)
6230     */
6231    public static String repeat(final char ch, final int repeat) {
6232        if (repeat <= 0) {
6233            return EMPTY;
6234        }
6235        final char[] buf = new char[repeat];
6236        for (int i = repeat - 1; i >= 0; i--) {
6237            buf[i] = ch;
6238        }
6239        return new String(buf);
6240    }
6241
6242    /**
6243     * <p>Right pad a String with spaces (' ').</p>
6244     *
6245     * <p>The String is padded to the size of {@code size}.</p>
6246     *
6247     * <pre>
6248     * StringUtils.rightPad(null, *)   = null
6249     * StringUtils.rightPad("", 3)     = "   "
6250     * StringUtils.rightPad("bat", 3)  = "bat"
6251     * StringUtils.rightPad("bat", 5)  = "bat  "
6252     * StringUtils.rightPad("bat", 1)  = "bat"
6253     * StringUtils.rightPad("bat", -1) = "bat"
6254     * </pre>
6255     *
6256     * @param str  the String to pad out, may be null
6257     * @param size  the size to pad to
6258     * @return right padded String or original String if no padding is necessary,
6259     *  {@code null} if null String input
6260     */
6261    public static String rightPad(final String str, final int size) {
6262        return rightPad(str, size, ' ');
6263    }
6264
6265    /**
6266     * <p>Right pad a String with a specified character.</p>
6267     *
6268     * <p>The String is padded to the size of {@code size}.</p>
6269     *
6270     * <pre>
6271     * StringUtils.rightPad(null, *, *)     = null
6272     * StringUtils.rightPad("", 3, 'z')     = "zzz"
6273     * StringUtils.rightPad("bat", 3, 'z')  = "bat"
6274     * StringUtils.rightPad("bat", 5, 'z')  = "batzz"
6275     * StringUtils.rightPad("bat", 1, 'z')  = "bat"
6276     * StringUtils.rightPad("bat", -1, 'z') = "bat"
6277     * </pre>
6278     *
6279     * @param str  the String to pad out, may be null
6280     * @param size  the size to pad to
6281     * @param padChar  the character to pad with
6282     * @return right padded String or original String if no padding is necessary,
6283     *  {@code null} if null String input
6284     * @since 2.0
6285     */
6286    public static String rightPad(final String str, final int size, final char padChar) {
6287        if (str == null) {
6288            return null;
6289        }
6290        final int pads = size - str.length();
6291        if (pads <= 0) {
6292            return str; // returns original String when possible
6293        }
6294        if (pads > PAD_LIMIT) {
6295            return rightPad(str, size, String.valueOf(padChar));
6296        }
6297        return str.concat(repeat(padChar, pads));
6298    }
6299
6300    /**
6301     * <p>Right pad a String with a specified String.</p>
6302     *
6303     * <p>The String is padded to the size of {@code size}.</p>
6304     *
6305     * <pre>
6306     * StringUtils.rightPad(null, *, *)      = null
6307     * StringUtils.rightPad("", 3, "z")      = "zzz"
6308     * StringUtils.rightPad("bat", 3, "yz")  = "bat"
6309     * StringUtils.rightPad("bat", 5, "yz")  = "batyz"
6310     * StringUtils.rightPad("bat", 8, "yz")  = "batyzyzy"
6311     * StringUtils.rightPad("bat", 1, "yz")  = "bat"
6312     * StringUtils.rightPad("bat", -1, "yz") = "bat"
6313     * StringUtils.rightPad("bat", 5, null)  = "bat  "
6314     * StringUtils.rightPad("bat", 5, "")    = "bat  "
6315     * </pre>
6316     *
6317     * @param str  the String to pad out, may be null
6318     * @param size  the size to pad to
6319     * @param padStr  the String to pad with, null or empty treated as single space
6320     * @return right padded String or original String if no padding is necessary,
6321     *  {@code null} if null String input
6322     */
6323    public static String rightPad(final String str, final int size, String padStr) {
6324        if (str == null) {
6325            return null;
6326        }
6327        if (isEmpty(padStr)) {
6328            padStr = SPACE;
6329        }
6330        final int padLen = padStr.length();
6331        final int strLen = str.length();
6332        final int pads = size - strLen;
6333        if (pads <= 0) {
6334            return str; // returns original String when possible
6335        }
6336        if (padLen == 1 && pads <= PAD_LIMIT) {
6337            return rightPad(str, size, padStr.charAt(0));
6338        }
6339
6340        if (pads == padLen) {
6341            return str.concat(padStr);
6342        } else if (pads < padLen) {
6343            return str.concat(padStr.substring(0, pads));
6344        } else {
6345            final char[] padding = new char[pads];
6346            final char[] padChars = padStr.toCharArray();
6347            for (int i = 0; i < pads; i++) {
6348                padding[i] = padChars[i % padLen];
6349            }
6350            return str.concat(new String(padding));
6351        }
6352    }
6353
6354    /**
6355     * <p>Left pad a String with spaces (' ').</p>
6356     *
6357     * <p>The String is padded to the size of {@code size}.</p>
6358     *
6359     * <pre>
6360     * StringUtils.leftPad(null, *)   = null
6361     * StringUtils.leftPad("", 3)     = "   "
6362     * StringUtils.leftPad("bat", 3)  = "bat"
6363     * StringUtils.leftPad("bat", 5)  = "  bat"
6364     * StringUtils.leftPad("bat", 1)  = "bat"
6365     * StringUtils.leftPad("bat", -1) = "bat"
6366     * </pre>
6367     *
6368     * @param str  the String to pad out, may be null
6369     * @param size  the size to pad to
6370     * @return left padded String or original String if no padding is necessary,
6371     *  {@code null} if null String input
6372     */
6373    public static String leftPad(final String str, final int size) {
6374        return leftPad(str, size, ' ');
6375    }
6376
6377    /**
6378     * <p>Left pad a String with a specified character.</p>
6379     *
6380     * <p>Pad to a size of {@code size}.</p>
6381     *
6382     * <pre>
6383     * StringUtils.leftPad(null, *, *)     = null
6384     * StringUtils.leftPad("", 3, 'z')     = "zzz"
6385     * StringUtils.leftPad("bat", 3, 'z')  = "bat"
6386     * StringUtils.leftPad("bat", 5, 'z')  = "zzbat"
6387     * StringUtils.leftPad("bat", 1, 'z')  = "bat"
6388     * StringUtils.leftPad("bat", -1, 'z') = "bat"
6389     * </pre>
6390     *
6391     * @param str  the String to pad out, may be null
6392     * @param size  the size to pad to
6393     * @param padChar  the character to pad with
6394     * @return left padded String or original String if no padding is necessary,
6395     *  {@code null} if null String input
6396     * @since 2.0
6397     */
6398    public static String leftPad(final String str, final int size, final char padChar) {
6399        if (str == null) {
6400            return null;
6401        }
6402        final int pads = size - str.length();
6403        if (pads <= 0) {
6404            return str; // returns original String when possible
6405        }
6406        if (pads > PAD_LIMIT) {
6407            return leftPad(str, size, String.valueOf(padChar));
6408        }
6409        return repeat(padChar, pads).concat(str);
6410    }
6411
6412    /**
6413     * <p>Left pad a String with a specified String.</p>
6414     *
6415     * <p>Pad to a size of {@code size}.</p>
6416     *
6417     * <pre>
6418     * StringUtils.leftPad(null, *, *)      = null
6419     * StringUtils.leftPad("", 3, "z")      = "zzz"
6420     * StringUtils.leftPad("bat", 3, "yz")  = "bat"
6421     * StringUtils.leftPad("bat", 5, "yz")  = "yzbat"
6422     * StringUtils.leftPad("bat", 8, "yz")  = "yzyzybat"
6423     * StringUtils.leftPad("bat", 1, "yz")  = "bat"
6424     * StringUtils.leftPad("bat", -1, "yz") = "bat"
6425     * StringUtils.leftPad("bat", 5, null)  = "  bat"
6426     * StringUtils.leftPad("bat", 5, "")    = "  bat"
6427     * </pre>
6428     *
6429     * @param str  the String to pad out, may be null
6430     * @param size  the size to pad to
6431     * @param padStr  the String to pad with, null or empty treated as single space
6432     * @return left padded String or original String if no padding is necessary,
6433     *  {@code null} if null String input
6434     */
6435    public static String leftPad(final String str, final int size, String padStr) {
6436        if (str == null) {
6437            return null;
6438        }
6439        if (isEmpty(padStr)) {
6440            padStr = SPACE;
6441        }
6442        final int padLen = padStr.length();
6443        final int strLen = str.length();
6444        final int pads = size - strLen;
6445        if (pads <= 0) {
6446            return str; // returns original String when possible
6447        }
6448        if (padLen == 1 && pads <= PAD_LIMIT) {
6449            return leftPad(str, size, padStr.charAt(0));
6450        }
6451
6452        if (pads == padLen) {
6453            return padStr.concat(str);
6454        } else if (pads < padLen) {
6455            return padStr.substring(0, pads).concat(str);
6456        } else {
6457            final char[] padding = new char[pads];
6458            final char[] padChars = padStr.toCharArray();
6459            for (int i = 0; i < pads; i++) {
6460                padding[i] = padChars[i % padLen];
6461            }
6462            return new String(padding).concat(str);
6463        }
6464    }
6465
6466    /**
6467     * Gets a CharSequence length or {@code 0} if the CharSequence is
6468     * {@code null}.
6469     *
6470     * @param cs
6471     *            a CharSequence or {@code null}
6472     * @return CharSequence length or {@code 0} if the CharSequence is
6473     *         {@code null}.
6474     * @since 2.4
6475     * @since 3.0 Changed signature from length(String) to length(CharSequence)
6476     */
6477    public static int length(final CharSequence cs) {
6478        return cs == null ? 0 : cs.length();
6479    }
6480
6481    // Centering
6482    //-----------------------------------------------------------------------
6483    /**
6484     * <p>Centers a String in a larger String of size {@code size}
6485     * using the space character (' ').</p>
6486     *
6487     * <p>If the size is less than the String length, the String is returned.
6488     * A {@code null} String returns {@code null}.
6489     * A negative size is treated as zero.</p>
6490     *
6491     * <p>Equivalent to {@code center(str, size, " ")}.</p>
6492     *
6493     * <pre>
6494     * StringUtils.center(null, *)   = null
6495     * StringUtils.center("", 4)     = "    "
6496     * StringUtils.center("ab", -1)  = "ab"
6497     * StringUtils.center("ab", 4)   = " ab "
6498     * StringUtils.center("abcd", 2) = "abcd"
6499     * StringUtils.center("a", 4)    = " a  "
6500     * </pre>
6501     *
6502     * @param str  the String to center, may be null
6503     * @param size  the int size of new String, negative treated as zero
6504     * @return centered String, {@code null} if null String input
6505     */
6506    public static String center(final String str, final int size) {
6507        return center(str, size, ' ');
6508    }
6509
6510    /**
6511     * <p>Centers a String in a larger String of size {@code size}.
6512     * Uses a supplied character as the value to pad the String with.</p>
6513     *
6514     * <p>If the size is less than the String length, the String is returned.
6515     * A {@code null} String returns {@code null}.
6516     * A negative size is treated as zero.</p>
6517     *
6518     * <pre>
6519     * StringUtils.center(null, *, *)     = null
6520     * StringUtils.center("", 4, ' ')     = "    "
6521     * StringUtils.center("ab", -1, ' ')  = "ab"
6522     * StringUtils.center("ab", 4, ' ')   = " ab "
6523     * StringUtils.center("abcd", 2, ' ') = "abcd"
6524     * StringUtils.center("a", 4, ' ')    = " a  "
6525     * StringUtils.center("a", 4, 'y')    = "yayy"
6526     * </pre>
6527     *
6528     * @param str  the String to center, may be null
6529     * @param size  the int size of new String, negative treated as zero
6530     * @param padChar  the character to pad the new String with
6531     * @return centered String, {@code null} if null String input
6532     * @since 2.0
6533     */
6534    public static String center(String str, final int size, final char padChar) {
6535        if (str == null || size <= 0) {
6536            return str;
6537        }
6538        final int strLen = str.length();
6539        final int pads = size - strLen;
6540        if (pads <= 0) {
6541            return str;
6542        }
6543        str = leftPad(str, strLen + pads / 2, padChar);
6544        str = rightPad(str, size, padChar);
6545        return str;
6546    }
6547
6548    /**
6549     * <p>Centers a String in a larger String of size {@code size}.
6550     * Uses a supplied String as the value to pad the String with.</p>
6551     *
6552     * <p>If the size is less than the String length, the String is returned.
6553     * A {@code null} String returns {@code null}.
6554     * A negative size is treated as zero.</p>
6555     *
6556     * <pre>
6557     * StringUtils.center(null, *, *)     = null
6558     * StringUtils.center("", 4, " ")     = "    "
6559     * StringUtils.center("ab", -1, " ")  = "ab"
6560     * StringUtils.center("ab", 4, " ")   = " ab "
6561     * StringUtils.center("abcd", 2, " ") = "abcd"
6562     * StringUtils.center("a", 4, " ")    = " a  "
6563     * StringUtils.center("a", 4, "yz")   = "yayz"
6564     * StringUtils.center("abc", 7, null) = "  abc  "
6565     * StringUtils.center("abc", 7, "")   = "  abc  "
6566     * </pre>
6567     *
6568     * @param str  the String to center, may be null
6569     * @param size  the int size of new String, negative treated as zero
6570     * @param padStr  the String to pad the new String with, must not be null or empty
6571     * @return centered String, {@code null} if null String input
6572     * @throws IllegalArgumentException if padStr is {@code null} or empty
6573     */
6574    public static String center(String str, final int size, String padStr) {
6575        if (str == null || size <= 0) {
6576            return str;
6577        }
6578        if (isEmpty(padStr)) {
6579            padStr = SPACE;
6580        }
6581        final int strLen = str.length();
6582        final int pads = size - strLen;
6583        if (pads <= 0) {
6584            return str;
6585        }
6586        str = leftPad(str, strLen + pads / 2, padStr);
6587        str = rightPad(str, size, padStr);
6588        return str;
6589    }
6590
6591    // Case conversion
6592    //-----------------------------------------------------------------------
6593    /**
6594     * <p>Converts a String to upper case as per {@link String#toUpperCase()}.</p>
6595     *
6596     * <p>A {@code null} input String returns {@code null}.</p>
6597     *
6598     * <pre>
6599     * StringUtils.upperCase(null)  = null
6600     * StringUtils.upperCase("")    = ""
6601     * StringUtils.upperCase("aBc") = "ABC"
6602     * </pre>
6603     *
6604     * <p><strong>Note:</strong> As described in the documentation for {@link String#toUpperCase()},
6605     * the result of this method is affected by the current locale.
6606     * For platform-independent case transformations, the method {@link #lowerCase(String, Locale)}
6607     * should be used with a specific locale (e.g. {@link Locale#ENGLISH}).</p>
6608     *
6609     * @param str  the String to upper case, may be null
6610     * @return the upper cased String, {@code null} if null String input
6611     */
6612    public static String upperCase(final String str) {
6613        if (str == null) {
6614            return null;
6615        }
6616        return str.toUpperCase();
6617    }
6618
6619    /**
6620     * <p>Converts a String to upper case as per {@link String#toUpperCase(Locale)}.</p>
6621     *
6622     * <p>A {@code null} input String returns {@code null}.</p>
6623     *
6624     * <pre>
6625     * StringUtils.upperCase(null, Locale.ENGLISH)  = null
6626     * StringUtils.upperCase("", Locale.ENGLISH)    = ""
6627     * StringUtils.upperCase("aBc", Locale.ENGLISH) = "ABC"
6628     * </pre>
6629     *
6630     * @param str  the String to upper case, may be null
6631     * @param locale  the locale that defines the case transformation rules, must not be null
6632     * @return the upper cased String, {@code null} if null String input
6633     * @since 2.5
6634     */
6635    public static String upperCase(final String str, final Locale locale) {
6636        if (str == null) {
6637            return null;
6638        }
6639        return str.toUpperCase(locale);
6640    }
6641
6642    /**
6643     * <p>Converts a String to lower case as per {@link String#toLowerCase()}.</p>
6644     *
6645     * <p>A {@code null} input String returns {@code null}.</p>
6646     *
6647     * <pre>
6648     * StringUtils.lowerCase(null)  = null
6649     * StringUtils.lowerCase("")    = ""
6650     * StringUtils.lowerCase("aBc") = "abc"
6651     * </pre>
6652     *
6653     * <p><strong>Note:</strong> As described in the documentation for {@link String#toLowerCase()},
6654     * the result of this method is affected by the current locale.
6655     * For platform-independent case transformations, the method {@link #lowerCase(String, Locale)}
6656     * should be used with a specific locale (e.g. {@link Locale#ENGLISH}).</p>
6657     *
6658     * @param str  the String to lower case, may be null
6659     * @return the lower cased String, {@code null} if null String input
6660     */
6661    public static String lowerCase(final String str) {
6662        if (str == null) {
6663            return null;
6664        }
6665        return str.toLowerCase();
6666    }
6667
6668    /**
6669     * <p>Converts a String to lower case as per {@link String#toLowerCase(Locale)}.</p>
6670     *
6671     * <p>A {@code null} input String returns {@code null}.</p>
6672     *
6673     * <pre>
6674     * StringUtils.lowerCase(null, Locale.ENGLISH)  = null
6675     * StringUtils.lowerCase("", Locale.ENGLISH)    = ""
6676     * StringUtils.lowerCase("aBc", Locale.ENGLISH) = "abc"
6677     * </pre>
6678     *
6679     * @param str  the String to lower case, may be null
6680     * @param locale  the locale that defines the case transformation rules, must not be null
6681     * @return the lower cased String, {@code null} if null String input
6682     * @since 2.5
6683     */
6684    public static String lowerCase(final String str, final Locale locale) {
6685        if (str == null) {
6686            return null;
6687        }
6688        return str.toLowerCase(locale);
6689    }
6690
6691    /**
6692     * <p>Capitalizes a String changing the first character to title case as
6693     * per {@link Character#toTitleCase(int)}. No other characters are changed.</p>
6694     *
6695     * <p>For a word based algorithm, see {@link org.apache.commons.lang3.text.WordUtils#capitalize(String)}.
6696     * A {@code null} input String returns {@code null}.</p>
6697     *
6698     * <pre>
6699     * StringUtils.capitalize(null)  = null
6700     * StringUtils.capitalize("")    = ""
6701     * StringUtils.capitalize("cat") = "Cat"
6702     * StringUtils.capitalize("cAt") = "CAt"
6703     * StringUtils.capitalize("'cat'") = "'cat'"
6704     * </pre>
6705     *
6706     * @param str the String to capitalize, may be null
6707     * @return the capitalized String, {@code null} if null String input
6708     * @see org.apache.commons.lang3.text.WordUtils#capitalize(String)
6709     * @see #uncapitalize(String)
6710     * @since 2.0
6711     */
6712    public static String capitalize(final String str) {
6713        int strLen;
6714        if (str == null || (strLen = str.length()) == 0) {
6715            return str;
6716        }
6717
6718        final int firstCodepoint = str.codePointAt(0);
6719        final int newCodePoint = Character.toTitleCase(firstCodepoint);
6720        if (firstCodepoint == newCodePoint) {
6721            // already capitalized
6722            return str;
6723        }
6724
6725        final int newCodePoints[] = new int[strLen]; // cannot be longer than the char array
6726        int outOffset = 0;
6727        newCodePoints[outOffset++] = newCodePoint; // copy the first codepoint
6728        for (int inOffset = Character.charCount(firstCodepoint); inOffset < strLen; ) {
6729            final int codepoint = str.codePointAt(inOffset);
6730            newCodePoints[outOffset++] = codepoint; // copy the remaining ones
6731            inOffset += Character.charCount(codepoint);
6732         }
6733        return new String(newCodePoints, 0, outOffset);
6734    }
6735
6736    /**
6737     * <p>Uncapitalizes a String, changing the first character to lower case as
6738     * per {@link Character#toLowerCase(int)}. No other characters are changed.</p>
6739     *
6740     * <p>For a word based algorithm, see {@link org.apache.commons.lang3.text.WordUtils#uncapitalize(String)}.
6741     * A {@code null} input String returns {@code null}.</p>
6742     *
6743     * <pre>
6744     * StringUtils.uncapitalize(null)  = null
6745     * StringUtils.uncapitalize("")    = ""
6746     * StringUtils.uncapitalize("cat") = "cat"
6747     * StringUtils.uncapitalize("Cat") = "cat"
6748     * StringUtils.uncapitalize("CAT") = "cAT"
6749     * </pre>
6750     *
6751     * @param str the String to uncapitalize, may be null
6752     * @return the uncapitalized String, {@code null} if null String input
6753     * @see org.apache.commons.lang3.text.WordUtils#uncapitalize(String)
6754     * @see #capitalize(String)
6755     * @since 2.0
6756     */
6757    public static String uncapitalize(final String str) {
6758        int strLen;
6759        if (str == null || (strLen = str.length()) == 0) {
6760            return str;
6761        }
6762
6763        final int firstCodepoint = str.codePointAt(0);
6764        final int newCodePoint = Character.toLowerCase(firstCodepoint);
6765        if (firstCodepoint == newCodePoint) {
6766            // already capitalized
6767            return str;
6768        }
6769
6770        final int newCodePoints[] = new int[strLen]; // cannot be longer than the char array
6771        int outOffset = 0;
6772        newCodePoints[outOffset++] = newCodePoint; // copy the first codepoint
6773        for (int inOffset = Character.charCount(firstCodepoint); inOffset < strLen; ) {
6774            final int codepoint = str.codePointAt(inOffset);
6775            newCodePoints[outOffset++] = codepoint; // copy the remaining ones
6776            inOffset += Character.charCount(codepoint);
6777         }
6778        return new String(newCodePoints, 0, outOffset);
6779    }
6780
6781    /**
6782     * <p>Swaps the case of a String changing upper and title case to
6783     * lower case, and lower case to upper case.</p>
6784     *
6785     * <ul>
6786     *  <li>Upper case character converts to Lower case</li>
6787     *  <li>Title case character converts to Lower case</li>
6788     *  <li>Lower case character converts to Upper case</li>
6789     * </ul>
6790     *
6791     * <p>For a word based algorithm, see {@link org.apache.commons.lang3.text.WordUtils#swapCase(String)}.
6792     * A {@code null} input String returns {@code null}.</p>
6793     *
6794     * <pre>
6795     * StringUtils.swapCase(null)                 = null
6796     * StringUtils.swapCase("")                   = ""
6797     * StringUtils.swapCase("The dog has a BONE") = "tHE DOG HAS A bone"
6798     * </pre>
6799     *
6800     * <p>NOTE: This method changed in Lang version 2.0.
6801     * It no longer performs a word based algorithm.
6802     * If you only use ASCII, you will notice no change.
6803     * That functionality is available in org.apache.commons.lang3.text.WordUtils.</p>
6804     *
6805     * @param str  the String to swap case, may be null
6806     * @return the changed String, {@code null} if null String input
6807     */
6808    public static String swapCase(final String str) {
6809        if (StringUtils.isEmpty(str)) {
6810            return str;
6811        }
6812
6813        final int strLen = str.length();
6814        final int newCodePoints[] = new int[strLen]; // cannot be longer than the char array
6815        int outOffset = 0;
6816        for (int i = 0; i < strLen; ) {
6817            final int oldCodepoint = str.codePointAt(i);
6818            final int newCodePoint;
6819            if (Character.isUpperCase(oldCodepoint)) {
6820                newCodePoint = Character.toLowerCase(oldCodepoint);
6821            } else if (Character.isTitleCase(oldCodepoint)) {
6822                newCodePoint = Character.toLowerCase(oldCodepoint);
6823            } else if (Character.isLowerCase(oldCodepoint)) {
6824                newCodePoint = Character.toUpperCase(oldCodepoint);
6825            } else {
6826                newCodePoint = oldCodepoint;
6827            }
6828            newCodePoints[outOffset++] = newCodePoint;
6829            i += Character.charCount(newCodePoint);
6830         }
6831        return new String(newCodePoints, 0, outOffset);
6832    }
6833
6834    // Count matches
6835    //-----------------------------------------------------------------------
6836    /**
6837     * <p>Counts how many times the substring appears in the larger string.</p>
6838     *
6839     * <p>A {@code null} or empty ("") String input returns {@code 0}.</p>
6840     *
6841     * <pre>
6842     * StringUtils.countMatches(null, *)       = 0
6843     * StringUtils.countMatches("", *)         = 0
6844     * StringUtils.countMatches("abba", null)  = 0
6845     * StringUtils.countMatches("abba", "")    = 0
6846     * StringUtils.countMatches("abba", "a")   = 2
6847     * StringUtils.countMatches("abba", "ab")  = 1
6848     * StringUtils.countMatches("abba", "xxx") = 0
6849     * </pre>
6850     *
6851     * @param str  the CharSequence to check, may be null
6852     * @param sub  the substring to count, may be null
6853     * @return the number of occurrences, 0 if either CharSequence is {@code null}
6854     * @since 3.0 Changed signature from countMatches(String, String) to countMatches(CharSequence, CharSequence)
6855     */
6856    public static int countMatches(final CharSequence str, final CharSequence sub) {
6857        if (isEmpty(str) || isEmpty(sub)) {
6858            return 0;
6859        }
6860        int count = 0;
6861        int idx = 0;
6862        while ((idx = CharSequenceUtils.indexOf(str, sub, idx)) != INDEX_NOT_FOUND) {
6863            count++;
6864            idx += sub.length();
6865        }
6866        return count;
6867    }
6868
6869    /**
6870     * <p>Counts how many times the char appears in the given string.</p>
6871     *
6872     * <p>A {@code null} or empty ("") String input returns {@code 0}.</p>
6873     *
6874     * <pre>
6875     * StringUtils.countMatches(null, *)       = 0
6876     * StringUtils.countMatches("", *)         = 0
6877     * StringUtils.countMatches("abba", 0)  = 0
6878     * StringUtils.countMatches("abba", 'a')   = 2
6879     * StringUtils.countMatches("abba", 'b')  = 2
6880     * StringUtils.countMatches("abba", 'x') = 0
6881     * </pre>
6882     *
6883     * @param str  the CharSequence to check, may be null
6884     * @param ch  the char to count
6885     * @return the number of occurrences, 0 if the CharSequence is {@code null}
6886     * @since 3.4
6887     */
6888    public static int countMatches(final CharSequence str, final char ch) {
6889        if (isEmpty(str)) {
6890            return 0;
6891        }
6892        int count = 0;
6893        // We could also call str.toCharArray() for faster look ups but that would generate more garbage.
6894        for (int i = 0; i < str.length(); i++) {
6895            if (ch == str.charAt(i)) {
6896                count++;
6897            }
6898        }
6899        return count;
6900    }
6901
6902    // Character Tests
6903    //-----------------------------------------------------------------------
6904    /**
6905     * <p>Checks if the CharSequence contains only Unicode letters.</p>
6906     *
6907     * <p>{@code null} will return {@code false}.
6908     * An empty CharSequence (length()=0) will return {@code false}.</p>
6909     *
6910     * <pre>
6911     * StringUtils.isAlpha(null)   = false
6912     * StringUtils.isAlpha("")     = false
6913     * StringUtils.isAlpha("  ")   = false
6914     * StringUtils.isAlpha("abc")  = true
6915     * StringUtils.isAlpha("ab2c") = false
6916     * StringUtils.isAlpha("ab-c") = false
6917     * </pre>
6918     *
6919     * @param cs  the CharSequence to check, may be null
6920     * @return {@code true} if only contains letters, and is non-null
6921     * @since 3.0 Changed signature from isAlpha(String) to isAlpha(CharSequence)
6922     * @since 3.0 Changed "" to return false and not true
6923     */
6924    public static boolean isAlpha(final CharSequence cs) {
6925        if (isEmpty(cs)) {
6926            return false;
6927        }
6928        final int sz = cs.length();
6929        for (int i = 0; i < sz; i++) {
6930            if (Character.isLetter(cs.charAt(i)) == false) {
6931                return false;
6932            }
6933        }
6934        return true;
6935    }
6936
6937    /**
6938     * <p>Checks if the CharSequence contains only Unicode letters and
6939     * space (' ').</p>
6940     *
6941     * <p>{@code null} will return {@code false}
6942     * An empty CharSequence (length()=0) will return {@code true}.</p>
6943     *
6944     * <pre>
6945     * StringUtils.isAlphaSpace(null)   = false
6946     * StringUtils.isAlphaSpace("")     = true
6947     * StringUtils.isAlphaSpace("  ")   = true
6948     * StringUtils.isAlphaSpace("abc")  = true
6949     * StringUtils.isAlphaSpace("ab c") = true
6950     * StringUtils.isAlphaSpace("ab2c") = false
6951     * StringUtils.isAlphaSpace("ab-c") = false
6952     * </pre>
6953     *
6954     * @param cs  the CharSequence to check, may be null
6955     * @return {@code true} if only contains letters and space,
6956     *  and is non-null
6957     * @since 3.0 Changed signature from isAlphaSpace(String) to isAlphaSpace(CharSequence)
6958     */
6959    public static boolean isAlphaSpace(final CharSequence cs) {
6960        if (cs == null) {
6961            return false;
6962        }
6963        final int sz = cs.length();
6964        for (int i = 0; i < sz; i++) {
6965            if (Character.isLetter(cs.charAt(i)) == false && cs.charAt(i) != ' ') {
6966                return false;
6967            }
6968        }
6969        return true;
6970    }
6971
6972    /**
6973     * <p>Checks if the CharSequence contains only Unicode letters or digits.</p>
6974     *
6975     * <p>{@code null} will return {@code false}.
6976     * An empty CharSequence (length()=0) will return {@code false}.</p>
6977     *
6978     * <pre>
6979     * StringUtils.isAlphanumeric(null)   = false
6980     * StringUtils.isAlphanumeric("")     = false
6981     * StringUtils.isAlphanumeric("  ")   = false
6982     * StringUtils.isAlphanumeric("abc")  = true
6983     * StringUtils.isAlphanumeric("ab c") = false
6984     * StringUtils.isAlphanumeric("ab2c") = true
6985     * StringUtils.isAlphanumeric("ab-c") = false
6986     * </pre>
6987     *
6988     * @param cs  the CharSequence to check, may be null
6989     * @return {@code true} if only contains letters or digits,
6990     *  and is non-null
6991     * @since 3.0 Changed signature from isAlphanumeric(String) to isAlphanumeric(CharSequence)
6992     * @since 3.0 Changed "" to return false and not true
6993     */
6994    public static boolean isAlphanumeric(final CharSequence cs) {
6995        if (isEmpty(cs)) {
6996            return false;
6997        }
6998        final int sz = cs.length();
6999        for (int i = 0; i < sz; i++) {
7000            if (Character.isLetterOrDigit(cs.charAt(i)) == false) {
7001                return false;
7002            }
7003        }
7004        return true;
7005    }
7006
7007    /**
7008     * <p>Checks if the CharSequence contains only Unicode letters, digits
7009     * or space ({@code ' '}).</p>
7010     *
7011     * <p>{@code null} will return {@code false}.
7012     * An empty CharSequence (length()=0) will return {@code true}.</p>
7013     *
7014     * <pre>
7015     * StringUtils.isAlphanumericSpace(null)   = false
7016     * StringUtils.isAlphanumericSpace("")     = true
7017     * StringUtils.isAlphanumericSpace("  ")   = true
7018     * StringUtils.isAlphanumericSpace("abc")  = true
7019     * StringUtils.isAlphanumericSpace("ab c") = true
7020     * StringUtils.isAlphanumericSpace("ab2c") = true
7021     * StringUtils.isAlphanumericSpace("ab-c") = false
7022     * </pre>
7023     *
7024     * @param cs  the CharSequence to check, may be null
7025     * @return {@code true} if only contains letters, digits or space,
7026     *  and is non-null
7027     * @since 3.0 Changed signature from isAlphanumericSpace(String) to isAlphanumericSpace(CharSequence)
7028     */
7029    public static boolean isAlphanumericSpace(final CharSequence cs) {
7030        if (cs == null) {
7031            return false;
7032        }
7033        final int sz = cs.length();
7034        for (int i = 0; i < sz; i++) {
7035            if (Character.isLetterOrDigit(cs.charAt(i)) == false && cs.charAt(i) != ' ') {
7036                return false;
7037            }
7038        }
7039        return true;
7040    }
7041
7042    /**
7043     * <p>Checks if the CharSequence contains only ASCII printable characters.</p>
7044     *
7045     * <p>{@code null} will return {@code false}.
7046     * An empty CharSequence (length()=0) will return {@code true}.</p>
7047     *
7048     * <pre>
7049     * StringUtils.isAsciiPrintable(null)     = false
7050     * StringUtils.isAsciiPrintable("")       = true
7051     * StringUtils.isAsciiPrintable(" ")      = true
7052     * StringUtils.isAsciiPrintable("Ceki")   = true
7053     * StringUtils.isAsciiPrintable("ab2c")   = true
7054     * StringUtils.isAsciiPrintable("!ab-c~") = true
7055     * StringUtils.isAsciiPrintable("\u0020") = true
7056     * StringUtils.isAsciiPrintable("\u0021") = true
7057     * StringUtils.isAsciiPrintable("\u007e") = true
7058     * StringUtils.isAsciiPrintable("\u007f") = false
7059     * StringUtils.isAsciiPrintable("Ceki G\u00fclc\u00fc") = false
7060     * </pre>
7061     *
7062     * @param cs the CharSequence to check, may be null
7063     * @return {@code true} if every character is in the range
7064     *  32 thru 126
7065     * @since 2.1
7066     * @since 3.0 Changed signature from isAsciiPrintable(String) to isAsciiPrintable(CharSequence)
7067     */
7068    public static boolean isAsciiPrintable(final CharSequence cs) {
7069        if (cs == null) {
7070            return false;
7071        }
7072        final int sz = cs.length();
7073        for (int i = 0; i < sz; i++) {
7074            if (CharUtils.isAsciiPrintable(cs.charAt(i)) == false) {
7075                return false;
7076            }
7077        }
7078        return true;
7079    }
7080
7081    /**
7082     * <p>Checks if the CharSequence contains only Unicode digits.
7083     * A decimal point is not a Unicode digit and returns false.</p>
7084     *
7085     * <p>{@code null} will return {@code false}.
7086     * An empty CharSequence (length()=0) will return {@code false}.</p>
7087     *
7088     * <p>Note that the method does not allow for a leading sign, either positive or negative.
7089     * Also, if a String passes the numeric test, it may still generate a NumberFormatException
7090     * when parsed by Integer.parseInt or Long.parseLong, e.g. if the value is outside the range
7091     * for int or long respectively.</p>
7092     *
7093     * <pre>
7094     * StringUtils.isNumeric(null)   = false
7095     * StringUtils.isNumeric("")     = false
7096     * StringUtils.isNumeric("  ")   = false
7097     * StringUtils.isNumeric("123")  = true
7098     * StringUtils.isNumeric("\u0967\u0968\u0969")  = true
7099     * StringUtils.isNumeric("12 3") = false
7100     * StringUtils.isNumeric("ab2c") = false
7101     * StringUtils.isNumeric("12-3") = false
7102     * StringUtils.isNumeric("12.3") = false
7103     * StringUtils.isNumeric("-123") = false
7104     * StringUtils.isNumeric("+123") = false
7105     * </pre>
7106     *
7107     * @param cs  the CharSequence to check, may be null
7108     * @return {@code true} if only contains digits, and is non-null
7109     * @since 3.0 Changed signature from isNumeric(String) to isNumeric(CharSequence)
7110     * @since 3.0 Changed "" to return false and not true
7111     */
7112    public static boolean isNumeric(final CharSequence cs) {
7113        if (isEmpty(cs)) {
7114            return false;
7115        }
7116        final int sz = cs.length();
7117        for (int i = 0; i < sz; i++) {
7118            if (!Character.isDigit(cs.charAt(i))) {
7119                return false;
7120            }
7121        }
7122        return true;
7123    }
7124
7125    /**
7126     * <p>Checks if the CharSequence contains only Unicode digits or space
7127     * ({@code ' '}).
7128     * A decimal point is not a Unicode digit and returns false.</p>
7129     *
7130     * <p>{@code null} will return {@code false}.
7131     * An empty CharSequence (length()=0) will return {@code true}.</p>
7132     *
7133     * <pre>
7134     * StringUtils.isNumericSpace(null)   = false
7135     * StringUtils.isNumericSpace("")     = true
7136     * StringUtils.isNumericSpace("  ")   = true
7137     * StringUtils.isNumericSpace("123")  = true
7138     * StringUtils.isNumericSpace("12 3") = true
7139     * StringUtils.isNumeric("\u0967\u0968\u0969")  = true
7140     * StringUtils.isNumeric("\u0967\u0968 \u0969")  = true
7141     * StringUtils.isNumericSpace("ab2c") = false
7142     * StringUtils.isNumericSpace("12-3") = false
7143     * StringUtils.isNumericSpace("12.3") = false
7144     * </pre>
7145     *
7146     * @param cs  the CharSequence to check, may be null
7147     * @return {@code true} if only contains digits or space,
7148     *  and is non-null
7149     * @since 3.0 Changed signature from isNumericSpace(String) to isNumericSpace(CharSequence)
7150     */
7151    public static boolean isNumericSpace(final CharSequence cs) {
7152        if (cs == null) {
7153            return false;
7154        }
7155        final int sz = cs.length();
7156        for (int i = 0; i < sz; i++) {
7157            if (Character.isDigit(cs.charAt(i)) == false && cs.charAt(i) != ' ') {
7158                return false;
7159            }
7160        }
7161        return true;
7162    }
7163
7164    /**
7165     * <p>Checks if a String {@code str} contains Unicode digits,
7166     * if yes then concatenate all the digits in {@code str} and return it as a String.</p>
7167     *
7168     * <p>An empty ("") String will be returned if no digits found in {@code str}.</p>
7169     *
7170     * <pre>
7171     * StringUtils.getDigits(null)  = null
7172     * StringUtils.getDigits("")    = ""
7173     * StringUtils.getDigits("abc") = ""
7174     * StringUtils.getDigits("1000$") = "1000"
7175     * StringUtils.getDigits("1123~45") = "12345"
7176     * StringUtils.getDigits("(541) 754-3010") = "5417543010"
7177     * StringUtils.getDigits("\u0967\u0968\u0969") = "\u0967\u0968\u0969"
7178     * </pre>
7179     *
7180     * @param str the String to extract digits from, may be null
7181     * @return String with only digits,
7182     *           or an empty ("") String if no digits found,
7183     *           or {@code null} String if {@code str} is null
7184     * @since 3.6
7185     */
7186    public static String getDigits(final String str) {
7187        if (isEmpty(str)) {
7188            return str;
7189        }
7190        final int sz = str.length();
7191        final StringBuilder strDigits = new StringBuilder(sz);
7192        for (int i = 0; i < sz; i++) {
7193            final char tempChar = str.charAt(i);
7194            if (Character.isDigit(tempChar)) {
7195                strDigits.append(tempChar);
7196            }
7197        }
7198        return strDigits.toString();
7199    }
7200
7201    /**
7202     * <p>Checks if the CharSequence contains only whitespace.</p>
7203     *
7204     * <p>Whitespace is defined by {@link Character#isWhitespace(char)}.</p>
7205     *
7206     * <p>{@code null} will return {@code false}.
7207     * An empty CharSequence (length()=0) will return {@code true}.</p>
7208     *
7209     * <pre>
7210     * StringUtils.isWhitespace(null)   = false
7211     * StringUtils.isWhitespace("")     = true
7212     * StringUtils.isWhitespace("  ")   = true
7213     * StringUtils.isWhitespace("abc")  = false
7214     * StringUtils.isWhitespace("ab2c") = false
7215     * StringUtils.isWhitespace("ab-c") = false
7216     * </pre>
7217     *
7218     * @param cs  the CharSequence to check, may be null
7219     * @return {@code true} if only contains whitespace, and is non-null
7220     * @since 2.0
7221     * @since 3.0 Changed signature from isWhitespace(String) to isWhitespace(CharSequence)
7222     */
7223    public static boolean isWhitespace(final CharSequence cs) {
7224        if (cs == null) {
7225            return false;
7226        }
7227        final int sz = cs.length();
7228        for (int i = 0; i < sz; i++) {
7229            if (Character.isWhitespace(cs.charAt(i)) == false) {
7230                return false;
7231            }
7232        }
7233        return true;
7234    }
7235
7236    /**
7237     * <p>Checks if the CharSequence contains only lowercase characters.</p>
7238     *
7239     * <p>{@code null} will return {@code false}.
7240     * An empty CharSequence (length()=0) will return {@code false}.</p>
7241     *
7242     * <pre>
7243     * StringUtils.isAllLowerCase(null)   = false
7244     * StringUtils.isAllLowerCase("")     = false
7245     * StringUtils.isAllLowerCase("  ")   = false
7246     * StringUtils.isAllLowerCase("abc")  = true
7247     * StringUtils.isAllLowerCase("abC")  = false
7248     * StringUtils.isAllLowerCase("ab c") = false
7249     * StringUtils.isAllLowerCase("ab1c") = false
7250     * StringUtils.isAllLowerCase("ab/c") = false
7251     * </pre>
7252     *
7253     * @param cs  the CharSequence to check, may be null
7254     * @return {@code true} if only contains lowercase characters, and is non-null
7255     * @since 2.5
7256     * @since 3.0 Changed signature from isAllLowerCase(String) to isAllLowerCase(CharSequence)
7257     */
7258    public static boolean isAllLowerCase(final CharSequence cs) {
7259        if (cs == null || isEmpty(cs)) {
7260            return false;
7261        }
7262        final int sz = cs.length();
7263        for (int i = 0; i < sz; i++) {
7264            if (Character.isLowerCase(cs.charAt(i)) == false) {
7265                return false;
7266            }
7267        }
7268        return true;
7269    }
7270
7271    /**
7272     * <p>Checks if the CharSequence contains only uppercase characters.</p>
7273     *
7274     * <p>{@code null} will return {@code false}.
7275     * An empty String (length()=0) will return {@code false}.</p>
7276     *
7277     * <pre>
7278     * StringUtils.isAllUpperCase(null)   = false
7279     * StringUtils.isAllUpperCase("")     = false
7280     * StringUtils.isAllUpperCase("  ")   = false
7281     * StringUtils.isAllUpperCase("ABC")  = true
7282     * StringUtils.isAllUpperCase("aBC")  = false
7283     * StringUtils.isAllUpperCase("A C")  = false
7284     * StringUtils.isAllUpperCase("A1C")  = false
7285     * StringUtils.isAllUpperCase("A/C")  = false
7286     * </pre>
7287     *
7288     * @param cs the CharSequence to check, may be null
7289     * @return {@code true} if only contains uppercase characters, and is non-null
7290     * @since 2.5
7291     * @since 3.0 Changed signature from isAllUpperCase(String) to isAllUpperCase(CharSequence)
7292     */
7293    public static boolean isAllUpperCase(final CharSequence cs) {
7294        if (cs == null || isEmpty(cs)) {
7295            return false;
7296        }
7297        final int sz = cs.length();
7298        for (int i = 0; i < sz; i++) {
7299            if (Character.isUpperCase(cs.charAt(i)) == false) {
7300                return false;
7301            }
7302        }
7303        return true;
7304    }
7305
7306    /**
7307     * <p>Checks if the CharSequence contains mixed casing of both uppercase and lowercase characters.</p>
7308     *
7309     * <p>{@code null} will return {@code false}. An empty CharSequence ({@code length()=0}) will return
7310     * {@code false}.</p>
7311     *
7312     * <pre>
7313     * StringUtils.isMixedCase(null)    = false
7314     * StringUtils.isMixedCase("")      = false
7315     * StringUtils.isMixedCase("ABC")   = false
7316     * StringUtils.isMixedCase("abc")   = false
7317     * StringUtils.isMixedCase("aBc")   = true
7318     * StringUtils.isMixedCase("A c")   = true
7319     * StringUtils.isMixedCase("A1c")   = true
7320     * StringUtils.isMixedCase("a/C")   = true
7321     * StringUtils.isMixedCase("aC\t")  = true
7322     * </pre>
7323     *
7324     * @param cs the CharSequence to check, may be null
7325     * @return {@code true} if the CharSequence contains both uppercase and lowercase characters
7326     * @since 3.5
7327     */
7328    public static boolean isMixedCase(final CharSequence cs) {
7329        if (isEmpty(cs) || cs.length() == 1) {
7330            return false;
7331        }
7332        boolean containsUppercase = false;
7333        boolean containsLowercase = false;
7334        final int sz = cs.length();
7335        for (int i = 0; i < sz; i++) {
7336            if (containsUppercase && containsLowercase) {
7337                return true;
7338            } else if (Character.isUpperCase(cs.charAt(i))) {
7339                containsUppercase = true;
7340            } else if (Character.isLowerCase(cs.charAt(i))) {
7341                containsLowercase = true;
7342            }
7343        }
7344        return containsUppercase && containsLowercase;
7345    }
7346
7347    // Defaults
7348    //-----------------------------------------------------------------------
7349    /**
7350     * <p>Returns either the passed in String,
7351     * or if the String is {@code null}, an empty String ("").</p>
7352     *
7353     * <pre>
7354     * StringUtils.defaultString(null)  = ""
7355     * StringUtils.defaultString("")    = ""
7356     * StringUtils.defaultString("bat") = "bat"
7357     * </pre>
7358     *
7359     * @see ObjectUtils#toString(Object)
7360     * @see String#valueOf(Object)
7361     * @param str  the String to check, may be null
7362     * @return the passed in String, or the empty String if it
7363     *  was {@code null}
7364     */
7365    public static String defaultString(final String str) {
7366        return str == null ? EMPTY : str;
7367    }
7368
7369    /**
7370     * <p>Returns either the passed in String, or if the String is
7371     * {@code null}, the value of {@code defaultStr}.</p>
7372     *
7373     * <pre>
7374     * StringUtils.defaultString(null, "NULL")  = "NULL"
7375     * StringUtils.defaultString("", "NULL")    = ""
7376     * StringUtils.defaultString("bat", "NULL") = "bat"
7377     * </pre>
7378     *
7379     * @see ObjectUtils#toString(Object,String)
7380     * @see String#valueOf(Object)
7381     * @param str  the String to check, may be null
7382     * @param defaultStr  the default String to return
7383     *  if the input is {@code null}, may be null
7384     * @return the passed in String, or the default if it was {@code null}
7385     */
7386    public static String defaultString(final String str, final String defaultStr) {
7387        return str == null ? defaultStr : str;
7388    }
7389
7390    /**
7391     * <p>Returns either the passed in CharSequence, or if the CharSequence is
7392     * whitespace, empty ("") or {@code null}, the value of {@code defaultStr}.</p>
7393     *
7394     * <p>Whitespace is defined by {@link Character#isWhitespace(char)}.</p>
7395     *
7396     * <pre>
7397     * StringUtils.defaultIfBlank(null, "NULL")  = "NULL"
7398     * StringUtils.defaultIfBlank("", "NULL")    = "NULL"
7399     * StringUtils.defaultIfBlank(" ", "NULL")   = "NULL"
7400     * StringUtils.defaultIfBlank("bat", "NULL") = "bat"
7401     * StringUtils.defaultIfBlank("", null)      = null
7402     * </pre>
7403     * @param <T> the specific kind of CharSequence
7404     * @param str the CharSequence to check, may be null
7405     * @param defaultStr  the default CharSequence to return
7406     *  if the input is whitespace, empty ("") or {@code null}, may be null
7407     * @return the passed in CharSequence, or the default
7408     * @see StringUtils#defaultString(String, String)
7409     */
7410    public static <T extends CharSequence> T defaultIfBlank(final T str, final T defaultStr) {
7411        return isBlank(str) ? defaultStr : str;
7412    }
7413
7414    /**
7415     * <p>Returns either the passed in CharSequence, or if the CharSequence is
7416     * empty or {@code null}, the value of {@code defaultStr}.</p>
7417     *
7418     * <pre>
7419     * StringUtils.defaultIfEmpty(null, "NULL")  = "NULL"
7420     * StringUtils.defaultIfEmpty("", "NULL")    = "NULL"
7421     * StringUtils.defaultIfEmpty(" ", "NULL")   = " "
7422     * StringUtils.defaultIfEmpty("bat", "NULL") = "bat"
7423     * StringUtils.defaultIfEmpty("", null)      = null
7424     * </pre>
7425     * @param <T> the specific kind of CharSequence
7426     * @param str  the CharSequence to check, may be null
7427     * @param defaultStr  the default CharSequence to return
7428     *  if the input is empty ("") or {@code null}, may be null
7429     * @return the passed in CharSequence, or the default
7430     * @see StringUtils#defaultString(String, String)
7431     */
7432    public static <T extends CharSequence> T defaultIfEmpty(final T str, final T defaultStr) {
7433        return isEmpty(str) ? defaultStr : str;
7434    }
7435
7436    // Rotating (circular shift)
7437    //-----------------------------------------------------------------------
7438    /**
7439     * <p>Rotate (circular shift) a String of {@code shift} characters.</p>
7440     * <ul>
7441     *  <li>If {@code shift > 0}, right circular shift (ex : ABCDEF =&gt; FABCDE)</li>
7442     *  <li>If {@code shift < 0}, left circular shift (ex : ABCDEF =&gt; BCDEFA)</li>
7443     * </ul>
7444     *
7445     * <pre>
7446     * StringUtils.rotate(null, *)        = null
7447     * StringUtils.rotate("", *)          = ""
7448     * StringUtils.rotate("abcdefg", 0)   = "abcdefg"
7449     * StringUtils.rotate("abcdefg", 2)   = "fgabcde"
7450     * StringUtils.rotate("abcdefg", -2)  = "cdefgab"
7451     * StringUtils.rotate("abcdefg", 7)   = "abcdefg"
7452     * StringUtils.rotate("abcdefg", -7)  = "abcdefg"
7453     * StringUtils.rotate("abcdefg", 9)   = "fgabcde"
7454     * StringUtils.rotate("abcdefg", -9)  = "cdefgab"
7455     * </pre>
7456     *
7457     * @param str  the String to rotate, may be null
7458     * @param shift  number of time to shift (positive : right shift, negative : left shift)
7459     * @return the rotated String,
7460     *          or the original String if {@code shift == 0},
7461     *          or {@code null} if null String input
7462     * @since 3.5
7463     */
7464    public static String rotate(final String str, final int shift) {
7465        if (str == null) {
7466            return null;
7467        }
7468
7469        final int strLen = str.length();
7470        if (shift == 0 || strLen == 0 || shift % strLen == 0) {
7471            return str;
7472        }
7473
7474        final StringBuilder builder = new StringBuilder(strLen);
7475        final int offset = - (shift % strLen);
7476        builder.append(substring(str, offset));
7477        builder.append(substring(str, 0, offset));
7478        return builder.toString();
7479    }
7480
7481    // Reversing
7482    //-----------------------------------------------------------------------
7483    /**
7484     * <p>Reverses a String as per {@link StringBuilder#reverse()}.</p>
7485     *
7486     * <p>A {@code null} String returns {@code null}.</p>
7487     *
7488     * <pre>
7489     * StringUtils.reverse(null)  = null
7490     * StringUtils.reverse("")    = ""
7491     * StringUtils.reverse("bat") = "tab"
7492     * </pre>
7493     *
7494     * @param str  the String to reverse, may be null
7495     * @return the reversed String, {@code null} if null String input
7496     */
7497    public static String reverse(final String str) {
7498        if (str == null) {
7499            return null;
7500        }
7501        return new StringBuilder(str).reverse().toString();
7502    }
7503
7504    /**
7505     * <p>Reverses a String that is delimited by a specific character.</p>
7506     *
7507     * <p>The Strings between the delimiters are not reversed.
7508     * Thus java.lang.String becomes String.lang.java (if the delimiter
7509     * is {@code '.'}).</p>
7510     *
7511     * <pre>
7512     * StringUtils.reverseDelimited(null, *)      = null
7513     * StringUtils.reverseDelimited("", *)        = ""
7514     * StringUtils.reverseDelimited("a.b.c", 'x') = "a.b.c"
7515     * StringUtils.reverseDelimited("a.b.c", ".") = "c.b.a"
7516     * </pre>
7517     *
7518     * @param str  the String to reverse, may be null
7519     * @param separatorChar  the separator character to use
7520     * @return the reversed String, {@code null} if null String input
7521     * @since 2.0
7522     */
7523    public static String reverseDelimited(final String str, final char separatorChar) {
7524        if (str == null) {
7525            return null;
7526        }
7527        // could implement manually, but simple way is to reuse other,
7528        // probably slower, methods.
7529        final String[] strs = split(str, separatorChar);
7530        ArrayUtils.reverse(strs);
7531        return join(strs, separatorChar);
7532    }
7533
7534    // Abbreviating
7535    //-----------------------------------------------------------------------
7536    /**
7537     * <p>Abbreviates a String using ellipses. This will turn
7538     * "Now is the time for all good men" into "Now is the time for..."</p>
7539     *
7540     * <p>Specifically:</p>
7541     * <ul>
7542     *   <li>If the number of characters in {@code str} is less than or equal to
7543     *       {@code maxWidth}, return {@code str}.</li>
7544     *   <li>Else abbreviate it to {@code (substring(str, 0, max-3) + "...")}.</li>
7545     *   <li>If {@code maxWidth} is less than {@code 4}, throw an
7546     *       {@code IllegalArgumentException}.</li>
7547     *   <li>In no case will it return a String of length greater than
7548     *       {@code maxWidth}.</li>
7549     * </ul>
7550     *
7551     * <pre>
7552     * StringUtils.abbreviate(null, *)      = null
7553     * StringUtils.abbreviate("", 4)        = ""
7554     * StringUtils.abbreviate("abcdefg", 6) = "abc..."
7555     * StringUtils.abbreviate("abcdefg", 7) = "abcdefg"
7556     * StringUtils.abbreviate("abcdefg", 8) = "abcdefg"
7557     * StringUtils.abbreviate("abcdefg", 4) = "a..."
7558     * StringUtils.abbreviate("abcdefg", 3) = IllegalArgumentException
7559     * </pre>
7560     *
7561     * @param str  the String to check, may be null
7562     * @param maxWidth  maximum length of result String, must be at least 4
7563     * @return abbreviated String, {@code null} if null String input
7564     * @throws IllegalArgumentException if the width is too small
7565     * @since 2.0
7566     */
7567    public static String abbreviate(final String str, final int maxWidth) {
7568        final String defaultAbbrevMarker = "...";
7569        return abbreviate(str, defaultAbbrevMarker, 0, maxWidth);
7570    }
7571
7572    /**
7573     * <p>Abbreviates a String using ellipses. This will turn
7574     * "Now is the time for all good men" into "...is the time for..."</p>
7575     *
7576     * <p>Works like {@code abbreviate(String, int)}, but allows you to specify
7577     * a "left edge" offset.  Note that this left edge is not necessarily going to
7578     * be the leftmost character in the result, or the first character following the
7579     * ellipses, but it will appear somewhere in the result.
7580     *
7581     * <p>In no case will it return a String of length greater than
7582     * {@code maxWidth}.</p>
7583     *
7584     * <pre>
7585     * StringUtils.abbreviate(null, *, *)                = null
7586     * StringUtils.abbreviate("", 0, 4)                  = ""
7587     * StringUtils.abbreviate("abcdefghijklmno", -1, 10) = "abcdefg..."
7588     * StringUtils.abbreviate("abcdefghijklmno", 0, 10)  = "abcdefg..."
7589     * StringUtils.abbreviate("abcdefghijklmno", 1, 10)  = "abcdefg..."
7590     * StringUtils.abbreviate("abcdefghijklmno", 4, 10)  = "abcdefg..."
7591     * StringUtils.abbreviate("abcdefghijklmno", 5, 10)  = "...fghi..."
7592     * StringUtils.abbreviate("abcdefghijklmno", 6, 10)  = "...ghij..."
7593     * StringUtils.abbreviate("abcdefghijklmno", 8, 10)  = "...ijklmno"
7594     * StringUtils.abbreviate("abcdefghijklmno", 10, 10) = "...ijklmno"
7595     * StringUtils.abbreviate("abcdefghijklmno", 12, 10) = "...ijklmno"
7596     * StringUtils.abbreviate("abcdefghij", 0, 3)        = IllegalArgumentException
7597     * StringUtils.abbreviate("abcdefghij", 5, 6)        = IllegalArgumentException
7598     * </pre>
7599     *
7600     * @param str  the String to check, may be null
7601     * @param offset  left edge of source String
7602     * @param maxWidth  maximum length of result String, must be at least 4
7603     * @return abbreviated String, {@code null} if null String input
7604     * @throws IllegalArgumentException if the width is too small
7605     * @since 2.0
7606     */
7607    public static String abbreviate(final String str, final int offset, final int maxWidth) {
7608        final String defaultAbbrevMarker = "...";
7609        return abbreviate(str, defaultAbbrevMarker, offset, maxWidth);
7610    }
7611
7612    /**
7613     * <p>Abbreviates a String using another given String as replacement marker. This will turn
7614     * "Now is the time for all good men" into "Now is the time for..." if "..." was defined
7615     * as the replacement marker.</p>
7616     *
7617     * <p>Specifically:</p>
7618     * <ul>
7619     *   <li>If the number of characters in {@code str} is less than or equal to
7620     *       {@code maxWidth}, return {@code str}.</li>
7621     *   <li>Else abbreviate it to {@code (substring(str, 0, max-abbrevMarker.length) + abbrevMarker)}.</li>
7622     *   <li>If {@code maxWidth} is less than {@code abbrevMarker.length + 1}, throw an
7623     *       {@code IllegalArgumentException}.</li>
7624     *   <li>In no case will it return a String of length greater than
7625     *       {@code maxWidth}.</li>
7626     * </ul>
7627     *
7628     * <pre>
7629     * StringUtils.abbreviate(null, "...", *)      = null
7630     * StringUtils.abbreviate("abcdefg", null, *)  = "abcdefg"
7631     * StringUtils.abbreviate("", "...", 4)        = ""
7632     * StringUtils.abbreviate("abcdefg", ".", 5)   = "abcd."
7633     * StringUtils.abbreviate("abcdefg", ".", 7)   = "abcdefg"
7634     * StringUtils.abbreviate("abcdefg", ".", 8)   = "abcdefg"
7635     * StringUtils.abbreviate("abcdefg", "..", 4)  = "ab.."
7636     * StringUtils.abbreviate("abcdefg", "..", 3)  = "a.."
7637     * StringUtils.abbreviate("abcdefg", "..", 2)  = IllegalArgumentException
7638     * StringUtils.abbreviate("abcdefg", "...", 3) = IllegalArgumentException
7639     * </pre>
7640     *
7641     * @param str  the String to check, may be null
7642     * @param abbrevMarker  the String used as replacement marker
7643     * @param maxWidth  maximum length of result String, must be at least {@code abbrevMarker.length + 1}
7644     * @return abbreviated String, {@code null} if null String input
7645     * @throws IllegalArgumentException if the width is too small
7646     * @since 3.6
7647     */
7648    public static String abbreviate(final String str, final String abbrevMarker, final int maxWidth) {
7649        return abbreviate(str, abbrevMarker, 0, maxWidth);
7650    }
7651
7652    /**
7653     * <p>Abbreviates a String using a given replacement marker. This will turn
7654     * "Now is the time for all good men" into "...is the time for..." if "..." was defined
7655     * as the replacement marker.</p>
7656     *
7657     * <p>Works like {@code abbreviate(String, String, int)}, but allows you to specify
7658     * a "left edge" offset.  Note that this left edge is not necessarily going to
7659     * be the leftmost character in the result, or the first character following the
7660     * replacement marker, but it will appear somewhere in the result.
7661     *
7662     * <p>In no case will it return a String of length greater than {@code maxWidth}.</p>
7663     *
7664     * <pre>
7665     * StringUtils.abbreviate(null, null, *, *)                 = null
7666     * StringUtils.abbreviate("abcdefghijklmno", null, *, *)    = "abcdefghijklmno"
7667     * StringUtils.abbreviate("", "...", 0, 4)                  = ""
7668     * StringUtils.abbreviate("abcdefghijklmno", "---", -1, 10) = "abcdefg---"
7669     * StringUtils.abbreviate("abcdefghijklmno", ",", 0, 10)    = "abcdefghi,"
7670     * StringUtils.abbreviate("abcdefghijklmno", ",", 1, 10)    = "abcdefghi,"
7671     * StringUtils.abbreviate("abcdefghijklmno", ",", 2, 10)    = "abcdefghi,"
7672     * StringUtils.abbreviate("abcdefghijklmno", "::", 4, 10)   = "::efghij::"
7673     * StringUtils.abbreviate("abcdefghijklmno", "...", 6, 10)  = "...ghij..."
7674     * StringUtils.abbreviate("abcdefghijklmno", "*", 9, 10)    = "*ghijklmno"
7675     * StringUtils.abbreviate("abcdefghijklmno", "'", 10, 10)   = "'ghijklmno"
7676     * StringUtils.abbreviate("abcdefghijklmno", "!", 12, 10)   = "!ghijklmno"
7677     * StringUtils.abbreviate("abcdefghij", "abra", 0, 4)       = IllegalArgumentException
7678     * StringUtils.abbreviate("abcdefghij", "...", 5, 6)        = IllegalArgumentException
7679     * </pre>
7680     *
7681     * @param str  the String to check, may be null
7682     * @param abbrevMarker  the String used as replacement marker
7683     * @param offset  left edge of source String
7684     * @param maxWidth  maximum length of result String, must be at least 4
7685     * @return abbreviated String, {@code null} if null String input
7686     * @throws IllegalArgumentException if the width is too small
7687     * @since 3.6
7688     */
7689    public static String abbreviate(final String str, final String abbrevMarker, int offset, final int maxWidth) {
7690        if (isEmpty(str) || isEmpty(abbrevMarker)) {
7691            return str;
7692        }
7693
7694        final int abbrevMarkerLength = abbrevMarker.length();
7695        final int minAbbrevWidth = abbrevMarkerLength + 1;
7696        final int minAbbrevWidthOffset = abbrevMarkerLength + abbrevMarkerLength + 1;
7697
7698        if (maxWidth < minAbbrevWidth) {
7699            throw new IllegalArgumentException(String.format("Minimum abbreviation width is %d", minAbbrevWidth));
7700        }
7701        if (str.length() <= maxWidth) {
7702            return str;
7703        }
7704        if (offset > str.length()) {
7705            offset = str.length();
7706        }
7707        if (str.length() - offset < maxWidth - abbrevMarkerLength) {
7708            offset = str.length() - (maxWidth - abbrevMarkerLength);
7709        }
7710        if (offset <= abbrevMarkerLength+1) {
7711            return str.substring(0, maxWidth - abbrevMarkerLength) + abbrevMarker;
7712        }
7713        if (maxWidth < minAbbrevWidthOffset) {
7714            throw new IllegalArgumentException(String.format("Minimum abbreviation width with offset is %d", minAbbrevWidthOffset));
7715        }
7716        if (offset + maxWidth - abbrevMarkerLength < str.length()) {
7717            return abbrevMarker + abbreviate(str.substring(offset), abbrevMarker, maxWidth - abbrevMarkerLength);
7718        }
7719        return abbrevMarker + str.substring(str.length() - (maxWidth - abbrevMarkerLength));
7720    }
7721
7722    /**
7723     * <p>Abbreviates a String to the length passed, replacing the middle characters with the supplied
7724     * replacement String.</p>
7725     *
7726     * <p>This abbreviation only occurs if the following criteria is met:</p>
7727     * <ul>
7728     * <li>Neither the String for abbreviation nor the replacement String are null or empty </li>
7729     * <li>The length to truncate to is less than the length of the supplied String</li>
7730     * <li>The length to truncate to is greater than 0</li>
7731     * <li>The abbreviated String will have enough room for the length supplied replacement String
7732     * and the first and last characters of the supplied String for abbreviation</li>
7733     * </ul>
7734     * <p>Otherwise, the returned String will be the same as the supplied String for abbreviation.
7735     * </p>
7736     *
7737     * <pre>
7738     * StringUtils.abbreviateMiddle(null, null, 0)      = null
7739     * StringUtils.abbreviateMiddle("abc", null, 0)      = "abc"
7740     * StringUtils.abbreviateMiddle("abc", ".", 0)      = "abc"
7741     * StringUtils.abbreviateMiddle("abc", ".", 3)      = "abc"
7742     * StringUtils.abbreviateMiddle("abcdef", ".", 4)     = "ab.f"
7743     * </pre>
7744     *
7745     * @param str  the String to abbreviate, may be null
7746     * @param middle the String to replace the middle characters with, may be null
7747     * @param length the length to abbreviate {@code str} to.
7748     * @return the abbreviated String if the above criteria is met, or the original String supplied for abbreviation.
7749     * @since 2.5
7750     */
7751    public static String abbreviateMiddle(final String str, final String middle, final int length) {
7752        if (isEmpty(str) || isEmpty(middle)) {
7753            return str;
7754        }
7755
7756        if (length >= str.length() || length < middle.length()+2) {
7757            return str;
7758        }
7759
7760        final int targetSting = length-middle.length();
7761        final int startOffset = targetSting/2+targetSting%2;
7762        final int endOffset = str.length()-targetSting/2;
7763
7764        final StringBuilder builder = new StringBuilder(length);
7765        builder.append(str.substring(0,startOffset));
7766        builder.append(middle);
7767        builder.append(str.substring(endOffset));
7768
7769        return builder.toString();
7770    }
7771
7772    // Difference
7773    //-----------------------------------------------------------------------
7774    /**
7775     * <p>Compares two Strings, and returns the portion where they differ.
7776     * More precisely, return the remainder of the second String,
7777     * starting from where it's different from the first. This means that
7778     * the difference between "abc" and "ab" is the empty String and not "c". </p>
7779     *
7780     * <p>For example,
7781     * {@code difference("i am a machine", "i am a robot") -> "robot"}.</p>
7782     *
7783     * <pre>
7784     * StringUtils.difference(null, null) = null
7785     * StringUtils.difference("", "") = ""
7786     * StringUtils.difference("", "abc") = "abc"
7787     * StringUtils.difference("abc", "") = ""
7788     * StringUtils.difference("abc", "abc") = ""
7789     * StringUtils.difference("abc", "ab") = ""
7790     * StringUtils.difference("ab", "abxyz") = "xyz"
7791     * StringUtils.difference("abcde", "abxyz") = "xyz"
7792     * StringUtils.difference("abcde", "xyz") = "xyz"
7793     * </pre>
7794     *
7795     * @param str1  the first String, may be null
7796     * @param str2  the second String, may be null
7797     * @return the portion of str2 where it differs from str1; returns the
7798     * empty String if they are equal
7799     * @see #indexOfDifference(CharSequence,CharSequence)
7800     * @since 2.0
7801     */
7802    public static String difference(final String str1, final String str2) {
7803        if (str1 == null) {
7804            return str2;
7805        }
7806        if (str2 == null) {
7807            return str1;
7808        }
7809        final int at = indexOfDifference(str1, str2);
7810        if (at == INDEX_NOT_FOUND) {
7811            return EMPTY;
7812        }
7813        return str2.substring(at);
7814    }
7815
7816    /**
7817     * <p>Compares two CharSequences, and returns the index at which the
7818     * CharSequences begin to differ.</p>
7819     *
7820     * <p>For example,
7821     * {@code indexOfDifference("i am a machine", "i am a robot") -> 7}</p>
7822     *
7823     * <pre>
7824     * StringUtils.indexOfDifference(null, null) = -1
7825     * StringUtils.indexOfDifference("", "") = -1
7826     * StringUtils.indexOfDifference("", "abc") = 0
7827     * StringUtils.indexOfDifference("abc", "") = 0
7828     * StringUtils.indexOfDifference("abc", "abc") = -1
7829     * StringUtils.indexOfDifference("ab", "abxyz") = 2
7830     * StringUtils.indexOfDifference("abcde", "abxyz") = 2
7831     * StringUtils.indexOfDifference("abcde", "xyz") = 0
7832     * </pre>
7833     *
7834     * @param cs1  the first CharSequence, may be null
7835     * @param cs2  the second CharSequence, may be null
7836     * @return the index where cs1 and cs2 begin to differ; -1 if they are equal
7837     * @since 2.0
7838     * @since 3.0 Changed signature from indexOfDifference(String, String) to
7839     * indexOfDifference(CharSequence, CharSequence)
7840     */
7841    public static int indexOfDifference(final CharSequence cs1, final CharSequence cs2) {
7842        if (cs1 == cs2) {
7843            return INDEX_NOT_FOUND;
7844        }
7845        if (cs1 == null || cs2 == null) {
7846            return 0;
7847        }
7848        int i;
7849        for (i = 0; i < cs1.length() && i < cs2.length(); ++i) {
7850            if (cs1.charAt(i) != cs2.charAt(i)) {
7851                break;
7852            }
7853        }
7854        if (i < cs2.length() || i < cs1.length()) {
7855            return i;
7856        }
7857        return INDEX_NOT_FOUND;
7858    }
7859
7860    /**
7861     * <p>Compares all CharSequences in an array and returns the index at which the
7862     * CharSequences begin to differ.</p>
7863     *
7864     * <p>For example,
7865     * <code>indexOfDifference(new String[] {"i am a machine", "i am a robot"}) -&gt; 7</code></p>
7866     *
7867     * <pre>
7868     * StringUtils.indexOfDifference(null) = -1
7869     * StringUtils.indexOfDifference(new String[] {}) = -1
7870     * StringUtils.indexOfDifference(new String[] {"abc"}) = -1
7871     * StringUtils.indexOfDifference(new String[] {null, null}) = -1
7872     * StringUtils.indexOfDifference(new String[] {"", ""}) = -1
7873     * StringUtils.indexOfDifference(new String[] {"", null}) = 0
7874     * StringUtils.indexOfDifference(new String[] {"abc", null, null}) = 0
7875     * StringUtils.indexOfDifference(new String[] {null, null, "abc"}) = 0
7876     * StringUtils.indexOfDifference(new String[] {"", "abc"}) = 0
7877     * StringUtils.indexOfDifference(new String[] {"abc", ""}) = 0
7878     * StringUtils.indexOfDifference(new String[] {"abc", "abc"}) = -1
7879     * StringUtils.indexOfDifference(new String[] {"abc", "a"}) = 1
7880     * StringUtils.indexOfDifference(new String[] {"ab", "abxyz"}) = 2
7881     * StringUtils.indexOfDifference(new String[] {"abcde", "abxyz"}) = 2
7882     * StringUtils.indexOfDifference(new String[] {"abcde", "xyz"}) = 0
7883     * StringUtils.indexOfDifference(new String[] {"xyz", "abcde"}) = 0
7884     * StringUtils.indexOfDifference(new String[] {"i am a machine", "i am a robot"}) = 7
7885     * </pre>
7886     *
7887     * @param css  array of CharSequences, entries may be null
7888     * @return the index where the strings begin to differ; -1 if they are all equal
7889     * @since 2.4
7890     * @since 3.0 Changed signature from indexOfDifference(String...) to indexOfDifference(CharSequence...)
7891     */
7892    public static int indexOfDifference(final CharSequence... css) {
7893        if (css == null || css.length <= 1) {
7894            return INDEX_NOT_FOUND;
7895        }
7896        boolean anyStringNull = false;
7897        boolean allStringsNull = true;
7898        final int arrayLen = css.length;
7899        int shortestStrLen = Integer.MAX_VALUE;
7900        int longestStrLen = 0;
7901
7902        // find the min and max string lengths; this avoids checking to make
7903        // sure we are not exceeding the length of the string each time through
7904        // the bottom loop.
7905        for (CharSequence cs : css) {
7906            if (cs == null) {
7907                anyStringNull = true;
7908                shortestStrLen = 0;
7909            } else {
7910                allStringsNull = false;
7911                shortestStrLen = Math.min(cs.length(), shortestStrLen);
7912                longestStrLen = Math.max(cs.length(), longestStrLen);
7913            }
7914        }
7915
7916        // handle lists containing all nulls or all empty strings
7917        if (allStringsNull || longestStrLen == 0 && !anyStringNull) {
7918            return INDEX_NOT_FOUND;
7919        }
7920
7921        // handle lists containing some nulls or some empty strings
7922        if (shortestStrLen == 0) {
7923            return 0;
7924        }
7925
7926        // find the position with the first difference across all strings
7927        int firstDiff = -1;
7928        for (int stringPos = 0; stringPos < shortestStrLen; stringPos++) {
7929            final char comparisonChar = css[0].charAt(stringPos);
7930            for (int arrayPos = 1; arrayPos < arrayLen; arrayPos++) {
7931                if (css[arrayPos].charAt(stringPos) != comparisonChar) {
7932                    firstDiff = stringPos;
7933                    break;
7934                }
7935            }
7936            if (firstDiff != -1) {
7937                break;
7938            }
7939        }
7940
7941        if (firstDiff == -1 && shortestStrLen != longestStrLen) {
7942            // we compared all of the characters up to the length of the
7943            // shortest string and didn't find a match, but the string lengths
7944            // vary, so return the length of the shortest string.
7945            return shortestStrLen;
7946        }
7947        return firstDiff;
7948    }
7949
7950    /**
7951     * <p>Compares all Strings in an array and returns the initial sequence of
7952     * characters that is common to all of them.</p>
7953     *
7954     * <p>For example,
7955     * <code>getCommonPrefix(new String[] {"i am a machine", "i am a robot"}) -&gt; "i am a "</code></p>
7956     *
7957     * <pre>
7958     * StringUtils.getCommonPrefix(null) = ""
7959     * StringUtils.getCommonPrefix(new String[] {}) = ""
7960     * StringUtils.getCommonPrefix(new String[] {"abc"}) = "abc"
7961     * StringUtils.getCommonPrefix(new String[] {null, null}) = ""
7962     * StringUtils.getCommonPrefix(new String[] {"", ""}) = ""
7963     * StringUtils.getCommonPrefix(new String[] {"", null}) = ""
7964     * StringUtils.getCommonPrefix(new String[] {"abc", null, null}) = ""
7965     * StringUtils.getCommonPrefix(new String[] {null, null, "abc"}) = ""
7966     * StringUtils.getCommonPrefix(new String[] {"", "abc"}) = ""
7967     * StringUtils.getCommonPrefix(new String[] {"abc", ""}) = ""
7968     * StringUtils.getCommonPrefix(new String[] {"abc", "abc"}) = "abc"
7969     * StringUtils.getCommonPrefix(new String[] {"abc", "a"}) = "a"
7970     * StringUtils.getCommonPrefix(new String[] {"ab", "abxyz"}) = "ab"
7971     * StringUtils.getCommonPrefix(new String[] {"abcde", "abxyz"}) = "ab"
7972     * StringUtils.getCommonPrefix(new String[] {"abcde", "xyz"}) = ""
7973     * StringUtils.getCommonPrefix(new String[] {"xyz", "abcde"}) = ""
7974     * StringUtils.getCommonPrefix(new String[] {"i am a machine", "i am a robot"}) = "i am a "
7975     * </pre>
7976     *
7977     * @param strs  array of String objects, entries may be null
7978     * @return the initial sequence of characters that are common to all Strings
7979     * in the array; empty String if the array is null, the elements are all null
7980     * or if there is no common prefix.
7981     * @since 2.4
7982     */
7983    public static String getCommonPrefix(final String... strs) {
7984        if (strs == null || strs.length == 0) {
7985            return EMPTY;
7986        }
7987        final int smallestIndexOfDiff = indexOfDifference(strs);
7988        if (smallestIndexOfDiff == INDEX_NOT_FOUND) {
7989            // all strings were identical
7990            if (strs[0] == null) {
7991                return EMPTY;
7992            }
7993            return strs[0];
7994        } else if (smallestIndexOfDiff == 0) {
7995            // there were no common initial characters
7996            return EMPTY;
7997        } else {
7998            // we found a common initial character sequence
7999            return strs[0].substring(0, smallestIndexOfDiff);
8000        }
8001    }
8002
8003    // Misc
8004    //-----------------------------------------------------------------------
8005    /**
8006     * <p>Find the Levenshtein distance between two Strings.</p>
8007     *
8008     * <p>This is the number of changes needed to change one String into
8009     * another, where each change is a single character modification (deletion,
8010     * insertion or substitution).</p>
8011     *
8012     * <p>The implementation uses a single-dimensional array of length s.length() + 1. See
8013     * <a href="http://blog.softwx.net/2014/12/optimizing-levenshtein-algorithm-in-c.html">
8014     * http://blog.softwx.net/2014/12/optimizing-levenshtein-algorithm-in-c.html</a> for details.</p>
8015     *
8016     * <pre>
8017     * StringUtils.getLevenshteinDistance(null, *)             = IllegalArgumentException
8018     * StringUtils.getLevenshteinDistance(*, null)             = IllegalArgumentException
8019     * StringUtils.getLevenshteinDistance("","")               = 0
8020     * StringUtils.getLevenshteinDistance("","a")              = 1
8021     * StringUtils.getLevenshteinDistance("aaapppp", "")       = 7
8022     * StringUtils.getLevenshteinDistance("frog", "fog")       = 1
8023     * StringUtils.getLevenshteinDistance("fly", "ant")        = 3
8024     * StringUtils.getLevenshteinDistance("elephant", "hippo") = 7
8025     * StringUtils.getLevenshteinDistance("hippo", "elephant") = 7
8026     * StringUtils.getLevenshteinDistance("hippo", "zzzzzzzz") = 8
8027     * StringUtils.getLevenshteinDistance("hello", "hallo")    = 1
8028     * </pre>
8029     *
8030     * @param s  the first String, must not be null
8031     * @param t  the second String, must not be null
8032     * @return result distance
8033     * @throws IllegalArgumentException if either String input {@code null}
8034     * @since 3.0 Changed signature from getLevenshteinDistance(String, String) to
8035     * getLevenshteinDistance(CharSequence, CharSequence)
8036     * @deprecated as of 3.6, use commons-text
8037     * <a href="https://commons.apache.org/proper/commons-text/javadocs/api-release/org/apache/commons/text/similarity/LevenshteinDistance.html">
8038     * LevenshteinDistance</a> instead
8039     */
8040    @Deprecated
8041    public static int getLevenshteinDistance(CharSequence s, CharSequence t) {
8042        if (s == null || t == null) {
8043            throw new IllegalArgumentException("Strings must not be null");
8044        }
8045
8046        int n = s.length();
8047        int m = t.length();
8048
8049        if (n == 0) {
8050            return m;
8051        } else if (m == 0) {
8052            return n;
8053        }
8054
8055        if (n > m) {
8056            // swap the input strings to consume less memory
8057            final CharSequence tmp = s;
8058            s = t;
8059            t = tmp;
8060            n = m;
8061            m = t.length();
8062        }
8063
8064        final int p[] = new int[n + 1];
8065        // indexes into strings s and t
8066        int i; // iterates through s
8067        int j; // iterates through t
8068        int upper_left;
8069        int upper;
8070
8071        char t_j; // jth character of t
8072        int cost;
8073
8074        for (i = 0; i <= n; i++) {
8075            p[i] = i;
8076        }
8077
8078        for (j = 1; j <= m; j++) {
8079            upper_left = p[0];
8080            t_j = t.charAt(j - 1);
8081            p[0] = j;
8082
8083            for (i = 1; i <= n; i++) {
8084                upper = p[i];
8085                cost = s.charAt(i - 1) == t_j ? 0 : 1;
8086                // minimum of cell to the left+1, to the top+1, diagonally left and up +cost
8087                p[i] = Math.min(Math.min(p[i - 1] + 1, p[i] + 1), upper_left + cost);
8088                upper_left = upper;
8089            }
8090        }
8091
8092        return p[n];
8093    }
8094
8095    /**
8096     * <p>Find the Levenshtein distance between two Strings if it's less than or equal to a given
8097     * threshold.</p>
8098     *
8099     * <p>This is the number of changes needed to change one String into
8100     * another, where each change is a single character modification (deletion,
8101     * insertion or substitution).</p>
8102     *
8103     * <p>This implementation follows from Algorithms on Strings, Trees and Sequences by Dan Gusfield
8104     * and Chas Emerick's implementation of the Levenshtein distance algorithm from
8105     * <a href="http://www.merriampark.com/ld.htm">http://www.merriampark.com/ld.htm</a></p>
8106     *
8107     * <pre>
8108     * StringUtils.getLevenshteinDistance(null, *, *)             = IllegalArgumentException
8109     * StringUtils.getLevenshteinDistance(*, null, *)             = IllegalArgumentException
8110     * StringUtils.getLevenshteinDistance(*, *, -1)               = IllegalArgumentException
8111     * StringUtils.getLevenshteinDistance("","", 0)               = 0
8112     * StringUtils.getLevenshteinDistance("aaapppp", "", 8)       = 7
8113     * StringUtils.getLevenshteinDistance("aaapppp", "", 7)       = 7
8114     * StringUtils.getLevenshteinDistance("aaapppp", "", 6))      = -1
8115     * StringUtils.getLevenshteinDistance("elephant", "hippo", 7) = 7
8116     * StringUtils.getLevenshteinDistance("elephant", "hippo", 6) = -1
8117     * StringUtils.getLevenshteinDistance("hippo", "elephant", 7) = 7
8118     * StringUtils.getLevenshteinDistance("hippo", "elephant", 6) = -1
8119     * </pre>
8120     *
8121     * @param s  the first String, must not be null
8122     * @param t  the second String, must not be null
8123     * @param threshold the target threshold, must not be negative
8124     * @return result distance, or {@code -1} if the distance would be greater than the threshold
8125     * @throws IllegalArgumentException if either String input {@code null} or negative threshold
8126     * @deprecated as of 3.6, use commons-text
8127     * <a href="https://commons.apache.org/proper/commons-text/javadocs/api-release/org/apache/commons/text/similarity/LevenshteinDistance.html">
8128     * LevenshteinDistance</a> instead
8129     */
8130    @Deprecated
8131    public static int getLevenshteinDistance(CharSequence s, CharSequence t, final int threshold) {
8132        if (s == null || t == null) {
8133            throw new IllegalArgumentException("Strings must not be null");
8134        }
8135        if (threshold < 0) {
8136            throw new IllegalArgumentException("Threshold must not be negative");
8137        }
8138
8139        /*
8140        This implementation only computes the distance if it's less than or equal to the
8141        threshold value, returning -1 if it's greater.  The advantage is performance: unbounded
8142        distance is O(nm), but a bound of k allows us to reduce it to O(km) time by only
8143        computing a diagonal stripe of width 2k + 1 of the cost table.
8144        It is also possible to use this to compute the unbounded Levenshtein distance by starting
8145        the threshold at 1 and doubling each time until the distance is found; this is O(dm), where
8146        d is the distance.
8147
8148        One subtlety comes from needing to ignore entries on the border of our stripe
8149        eg.
8150        p[] = |#|#|#|*
8151        d[] =  *|#|#|#|
8152        We must ignore the entry to the left of the leftmost member
8153        We must ignore the entry above the rightmost member
8154
8155        Another subtlety comes from our stripe running off the matrix if the strings aren't
8156        of the same size.  Since string s is always swapped to be the shorter of the two,
8157        the stripe will always run off to the upper right instead of the lower left of the matrix.
8158
8159        As a concrete example, suppose s is of length 5, t is of length 7, and our threshold is 1.
8160        In this case we're going to walk a stripe of length 3.  The matrix would look like so:
8161
8162           1 2 3 4 5
8163        1 |#|#| | | |
8164        2 |#|#|#| | |
8165        3 | |#|#|#| |
8166        4 | | |#|#|#|
8167        5 | | | |#|#|
8168        6 | | | | |#|
8169        7 | | | | | |
8170
8171        Note how the stripe leads off the table as there is no possible way to turn a string of length 5
8172        into one of length 7 in edit distance of 1.
8173
8174        Additionally, this implementation decreases memory usage by using two
8175        single-dimensional arrays and swapping them back and forth instead of allocating
8176        an entire n by m matrix.  This requires a few minor changes, such as immediately returning
8177        when it's detected that the stripe has run off the matrix and initially filling the arrays with
8178        large values so that entries we don't compute are ignored.
8179
8180        See Algorithms on Strings, Trees and Sequences by Dan Gusfield for some discussion.
8181         */
8182
8183        int n = s.length(); // length of s
8184        int m = t.length(); // length of t
8185
8186        // if one string is empty, the edit distance is necessarily the length of the other
8187        if (n == 0) {
8188            return m <= threshold ? m : -1;
8189        } else if (m == 0) {
8190            return n <= threshold ? n : -1;
8191        } else if (Math.abs(n - m) > threshold) {
8192            // no need to calculate the distance if the length difference is greater than the threshold
8193            return -1;
8194        }
8195
8196        if (n > m) {
8197            // swap the two strings to consume less memory
8198            final CharSequence tmp = s;
8199            s = t;
8200            t = tmp;
8201            n = m;
8202            m = t.length();
8203        }
8204
8205        int p[] = new int[n + 1]; // 'previous' cost array, horizontally
8206        int d[] = new int[n + 1]; // cost array, horizontally
8207        int _d[]; // placeholder to assist in swapping p and d
8208
8209        // fill in starting table values
8210        final int boundary = Math.min(n, threshold) + 1;
8211        for (int i = 0; i < boundary; i++) {
8212            p[i] = i;
8213        }
8214        // these fills ensure that the value above the rightmost entry of our
8215        // stripe will be ignored in following loop iterations
8216        Arrays.fill(p, boundary, p.length, Integer.MAX_VALUE);
8217        Arrays.fill(d, Integer.MAX_VALUE);
8218
8219        // iterates through t
8220        for (int j = 1; j <= m; j++) {
8221            final char t_j = t.charAt(j - 1); // jth character of t
8222            d[0] = j;
8223
8224            // compute stripe indices, constrain to array size
8225            final int min = Math.max(1, j - threshold);
8226            final int max = j > Integer.MAX_VALUE - threshold ? n : Math.min(n, j + threshold);
8227
8228            // the stripe may lead off of the table if s and t are of different sizes
8229            if (min > max) {
8230                return -1;
8231            }
8232
8233            // ignore entry left of leftmost
8234            if (min > 1) {
8235                d[min - 1] = Integer.MAX_VALUE;
8236            }
8237
8238            // iterates through [min, max] in s
8239            for (int i = min; i <= max; i++) {
8240                if (s.charAt(i - 1) == t_j) {
8241                    // diagonally left and up
8242                    d[i] = p[i - 1];
8243                } else {
8244                    // 1 + minimum of cell to the left, to the top, diagonally left and up
8245                    d[i] = 1 + Math.min(Math.min(d[i - 1], p[i]), p[i - 1]);
8246                }
8247            }
8248
8249            // copy current distance counts to 'previous row' distance counts
8250            _d = p;
8251            p = d;
8252            d = _d;
8253        }
8254
8255        // if p[n] is greater than the threshold, there's no guarantee on it being the correct
8256        // distance
8257        if (p[n] <= threshold) {
8258            return p[n];
8259        }
8260        return -1;
8261    }
8262
8263    /**
8264     * <p>Find the Jaro Winkler Distance which indicates the similarity score between two Strings.</p>
8265     *
8266     * <p>The Jaro measure is the weighted sum of percentage of matched characters from each file and transposed characters.
8267     * Winkler increased this measure for matching initial characters.</p>
8268     *
8269     * <p>This implementation is based on the Jaro Winkler similarity algorithm
8270     * 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>
8271     *
8272     * <pre>
8273     * StringUtils.getJaroWinklerDistance(null, null)          = IllegalArgumentException
8274     * StringUtils.getJaroWinklerDistance("","")               = 0.0
8275     * StringUtils.getJaroWinklerDistance("","a")              = 0.0
8276     * StringUtils.getJaroWinklerDistance("aaapppp", "")       = 0.0
8277     * StringUtils.getJaroWinklerDistance("frog", "fog")       = 0.93
8278     * StringUtils.getJaroWinklerDistance("fly", "ant")        = 0.0
8279     * StringUtils.getJaroWinklerDistance("elephant", "hippo") = 0.44
8280     * StringUtils.getJaroWinklerDistance("hippo", "elephant") = 0.44
8281     * StringUtils.getJaroWinklerDistance("hippo", "zzzzzzzz") = 0.0
8282     * StringUtils.getJaroWinklerDistance("hello", "hallo")    = 0.88
8283     * StringUtils.getJaroWinklerDistance("ABC Corporation", "ABC Corp") = 0.93
8284     * StringUtils.getJaroWinklerDistance("D N H Enterprises Inc", "D &amp; H Enterprises, Inc.") = 0.95
8285     * StringUtils.getJaroWinklerDistance("My Gym Children's Fitness Center", "My Gym. Childrens Fitness") = 0.92
8286     * StringUtils.getJaroWinklerDistance("PENNSYLVANIA", "PENNCISYLVNIA") = 0.88
8287     * </pre>
8288     *
8289     * @param first the first String, must not be null
8290     * @param second the second String, must not be null
8291     * @return result distance
8292     * @throws IllegalArgumentException if either String input {@code null}
8293     * @since 3.3
8294     * @deprecated as of 3.6, use commons-text
8295     * <a href="https://commons.apache.org/proper/commons-text/javadocs/api-release/org/apache/commons/text/similarity/JaroWinklerDistance.html">
8296     * JaroWinklerDistance</a> instead
8297     */
8298    @Deprecated
8299    public static double getJaroWinklerDistance(final CharSequence first, final CharSequence second) {
8300        final double DEFAULT_SCALING_FACTOR = 0.1;
8301
8302        if (first == null || second == null) {
8303            throw new IllegalArgumentException("Strings must not be null");
8304        }
8305
8306        final int[] mtp = matches(first, second);
8307        final double m = mtp[0];
8308        if (m == 0) {
8309            return 0D;
8310        }
8311        final double j = ((m / first.length() + m / second.length() + (m - mtp[1]) / m)) / 3;
8312        final double jw = j < 0.7D ? j : j + Math.min(DEFAULT_SCALING_FACTOR, 1D / mtp[3]) * mtp[2] * (1D - j);
8313        return Math.round(jw * 100.0D) / 100.0D;
8314    }
8315
8316    private static int[] matches(final CharSequence first, final CharSequence second) {
8317        CharSequence max, min;
8318        if (first.length() > second.length()) {
8319            max = first;
8320            min = second;
8321        } else {
8322            max = second;
8323            min = first;
8324        }
8325        final int range = Math.max(max.length() / 2 - 1, 0);
8326        final int[] matchIndexes = new int[min.length()];
8327        Arrays.fill(matchIndexes, -1);
8328        final boolean[] matchFlags = new boolean[max.length()];
8329        int matches = 0;
8330        for (int mi = 0; mi < min.length(); mi++) {
8331            final char c1 = min.charAt(mi);
8332            for (int xi = Math.max(mi - range, 0), xn = Math.min(mi + range + 1, max.length()); xi < xn; xi++) {
8333                if (!matchFlags[xi] && c1 == max.charAt(xi)) {
8334                    matchIndexes[mi] = xi;
8335                    matchFlags[xi] = true;
8336                    matches++;
8337                    break;
8338                }
8339            }
8340        }
8341        final char[] ms1 = new char[matches];
8342        final char[] ms2 = new char[matches];
8343        for (int i = 0, si = 0; i < min.length(); i++) {
8344            if (matchIndexes[i] != -1) {
8345                ms1[si] = min.charAt(i);
8346                si++;
8347            }
8348        }
8349        for (int i = 0, si = 0; i < max.length(); i++) {
8350            if (matchFlags[i]) {
8351                ms2[si] = max.charAt(i);
8352                si++;
8353            }
8354        }
8355        int transpositions = 0;
8356        for (int mi = 0; mi < ms1.length; mi++) {
8357            if (ms1[mi] != ms2[mi]) {
8358                transpositions++;
8359            }
8360        }
8361        int prefix = 0;
8362        for (int mi = 0; mi < min.length(); mi++) {
8363            if (first.charAt(mi) == second.charAt(mi)) {
8364                prefix++;
8365            } else {
8366                break;
8367            }
8368        }
8369        return new int[] { matches, transpositions / 2, prefix, max.length() };
8370    }
8371
8372    /**
8373     * <p>Find the Fuzzy Distance which indicates the similarity score between two Strings.</p>
8374     *
8375     * <p>This string matching algorithm is similar to the algorithms of editors such as Sublime Text,
8376     * TextMate, Atom and others. One point is given for every matched character. Subsequent
8377     * matches yield two bonus points. A higher score indicates a higher similarity.</p>
8378     *
8379     * <pre>
8380     * StringUtils.getFuzzyDistance(null, null, null)                                    = IllegalArgumentException
8381     * StringUtils.getFuzzyDistance("", "", Locale.ENGLISH)                              = 0
8382     * StringUtils.getFuzzyDistance("Workshop", "b", Locale.ENGLISH)                     = 0
8383     * StringUtils.getFuzzyDistance("Room", "o", Locale.ENGLISH)                         = 1
8384     * StringUtils.getFuzzyDistance("Workshop", "w", Locale.ENGLISH)                     = 1
8385     * StringUtils.getFuzzyDistance("Workshop", "ws", Locale.ENGLISH)                    = 2
8386     * StringUtils.getFuzzyDistance("Workshop", "wo", Locale.ENGLISH)                    = 4
8387     * StringUtils.getFuzzyDistance("Apache Software Foundation", "asf", Locale.ENGLISH) = 3
8388     * </pre>
8389     *
8390     * @param term a full term that should be matched against, must not be null
8391     * @param query the query that will be matched against a term, must not be null
8392     * @param locale This string matching logic is case insensitive. A locale is necessary to normalize
8393     *  both Strings to lower case.
8394     * @return result score
8395     * @throws IllegalArgumentException if either String input {@code null} or Locale input {@code null}
8396     * @since 3.4
8397     * @deprecated as of 3.6, use commons-text
8398     * <a href="https://commons.apache.org/proper/commons-text/javadocs/api-release/org/apache/commons/text/similarity/FuzzyScore.html">
8399     * FuzzyScore</a> instead
8400     */
8401    @Deprecated
8402    public static int getFuzzyDistance(final CharSequence term, final CharSequence query, final Locale locale) {
8403        if (term == null || query == null) {
8404            throw new IllegalArgumentException("Strings must not be null");
8405        } else if (locale == null) {
8406            throw new IllegalArgumentException("Locale must not be null");
8407        }
8408
8409        // fuzzy logic is case insensitive. We normalize the Strings to lower
8410        // case right from the start. Turning characters to lower case
8411        // via Character.toLowerCase(char) is unfortunately insufficient
8412        // as it does not accept a locale.
8413        final String termLowerCase = term.toString().toLowerCase(locale);
8414        final String queryLowerCase = query.toString().toLowerCase(locale);
8415
8416        // the resulting score
8417        int score = 0;
8418
8419        // the position in the term which will be scanned next for potential
8420        // query character matches
8421        int termIndex = 0;
8422
8423        // index of the previously matched character in the term
8424        int previousMatchingCharacterIndex = Integer.MIN_VALUE;
8425
8426        for (int queryIndex = 0; queryIndex < queryLowerCase.length(); queryIndex++) {
8427            final char queryChar = queryLowerCase.charAt(queryIndex);
8428
8429            boolean termCharacterMatchFound = false;
8430            for (; termIndex < termLowerCase.length() && !termCharacterMatchFound; termIndex++) {
8431                final char termChar = termLowerCase.charAt(termIndex);
8432
8433                if (queryChar == termChar) {
8434                    // simple character matches result in one point
8435                    score++;
8436
8437                    // subsequent character matches further improve
8438                    // the score.
8439                    if (previousMatchingCharacterIndex + 1 == termIndex) {
8440                        score += 2;
8441                    }
8442
8443                    previousMatchingCharacterIndex = termIndex;
8444
8445                    // we can leave the nested loop. Every character in the
8446                    // query can match at most one character in the term.
8447                    termCharacterMatchFound = true;
8448                }
8449            }
8450        }
8451
8452        return score;
8453    }
8454
8455    // startsWith
8456    //-----------------------------------------------------------------------
8457
8458    /**
8459     * <p>Check if a CharSequence starts with a specified prefix.</p>
8460     *
8461     * <p>{@code null}s are handled without exceptions. Two {@code null}
8462     * references are considered to be equal. The comparison is case sensitive.</p>
8463     *
8464     * <pre>
8465     * StringUtils.startsWith(null, null)      = true
8466     * StringUtils.startsWith(null, "abc")     = false
8467     * StringUtils.startsWith("abcdef", null)  = false
8468     * StringUtils.startsWith("abcdef", "abc") = true
8469     * StringUtils.startsWith("ABCDEF", "abc") = false
8470     * </pre>
8471     *
8472     * @see java.lang.String#startsWith(String)
8473     * @param str  the CharSequence to check, may be null
8474     * @param prefix the prefix to find, may be null
8475     * @return {@code true} if the CharSequence starts with the prefix, case sensitive, or
8476     *  both {@code null}
8477     * @since 2.4
8478     * @since 3.0 Changed signature from startsWith(String, String) to startsWith(CharSequence, CharSequence)
8479     */
8480    public static boolean startsWith(final CharSequence str, final CharSequence prefix) {
8481        return startsWith(str, prefix, false);
8482    }
8483
8484    /**
8485     * <p>Case insensitive check if a CharSequence starts with a specified prefix.</p>
8486     *
8487     * <p>{@code null}s are handled without exceptions. Two {@code null}
8488     * references are considered to be equal. The comparison is case insensitive.</p>
8489     *
8490     * <pre>
8491     * StringUtils.startsWithIgnoreCase(null, null)      = true
8492     * StringUtils.startsWithIgnoreCase(null, "abc")     = false
8493     * StringUtils.startsWithIgnoreCase("abcdef", null)  = false
8494     * StringUtils.startsWithIgnoreCase("abcdef", "abc") = true
8495     * StringUtils.startsWithIgnoreCase("ABCDEF", "abc") = true
8496     * </pre>
8497     *
8498     * @see java.lang.String#startsWith(String)
8499     * @param str  the CharSequence to check, may be null
8500     * @param prefix the prefix to find, may be null
8501     * @return {@code true} if the CharSequence starts with the prefix, case insensitive, or
8502     *  both {@code null}
8503     * @since 2.4
8504     * @since 3.0 Changed signature from startsWithIgnoreCase(String, String) to startsWithIgnoreCase(CharSequence, CharSequence)
8505     */
8506    public static boolean startsWithIgnoreCase(final CharSequence str, final CharSequence prefix) {
8507        return startsWith(str, prefix, true);
8508    }
8509
8510    /**
8511     * <p>Check if a CharSequence starts with a specified prefix (optionally case insensitive).</p>
8512     *
8513     * @see java.lang.String#startsWith(String)
8514     * @param str  the CharSequence to check, may be null
8515     * @param prefix the prefix to find, may be null
8516     * @param ignoreCase indicates whether the compare should ignore case
8517     *  (case insensitive) or not.
8518     * @return {@code true} if the CharSequence starts with the prefix or
8519     *  both {@code null}
8520     */
8521    private static boolean startsWith(final CharSequence str, final CharSequence prefix, final boolean ignoreCase) {
8522        if (str == null || prefix == null) {
8523            return str == null && prefix == null;
8524        }
8525        if (prefix.length() > str.length()) {
8526            return false;
8527        }
8528        return CharSequenceUtils.regionMatches(str, ignoreCase, 0, prefix, 0, prefix.length());
8529    }
8530
8531    /**
8532     * <p>Check if a CharSequence starts with any of the provided case-sensitive prefixes.</p>
8533     *
8534     * <pre>
8535     * StringUtils.startsWithAny(null, null)      = false
8536     * StringUtils.startsWithAny(null, new String[] {"abc"})  = false
8537     * StringUtils.startsWithAny("abcxyz", null)     = false
8538     * StringUtils.startsWithAny("abcxyz", new String[] {""}) = true
8539     * StringUtils.startsWithAny("abcxyz", new String[] {"abc"}) = true
8540     * StringUtils.startsWithAny("abcxyz", new String[] {null, "xyz", "abc"}) = true
8541     * StringUtils.startsWithAny("abcxyz", null, "xyz", "ABCX") = false
8542     * StringUtils.startsWithAny("ABCXYZ", null, "xyz", "abc") = false
8543     * </pre>
8544     *
8545     * @param sequence the CharSequence to check, may be null
8546     * @param searchStrings the case-sensitive CharSequence prefixes, may be empty or contain {@code null}
8547     * @see StringUtils#startsWith(CharSequence, CharSequence)
8548     * @return {@code true} if the input {@code sequence} is {@code null} AND no {@code searchStrings} are provided, or
8549     *   the input {@code sequence} begins with any of the provided case-sensitive {@code searchStrings}.
8550     * @since 2.5
8551     * @since 3.0 Changed signature from startsWithAny(String, String[]) to startsWithAny(CharSequence, CharSequence...)
8552     */
8553    public static boolean startsWithAny(final CharSequence sequence, final CharSequence... searchStrings) {
8554        if (isEmpty(sequence) || ArrayUtils.isEmpty(searchStrings)) {
8555            return false;
8556        }
8557        for (final CharSequence searchString : searchStrings) {
8558            if (startsWith(sequence, searchString)) {
8559                return true;
8560            }
8561        }
8562        return false;
8563    }
8564
8565    // endsWith
8566    //-----------------------------------------------------------------------
8567
8568    /**
8569     * <p>Check if a CharSequence ends with a specified suffix.</p>
8570     *
8571     * <p>{@code null}s are handled without exceptions. Two {@code null}
8572     * references are considered to be equal. The comparison is case sensitive.</p>
8573     *
8574     * <pre>
8575     * StringUtils.endsWith(null, null)      = true
8576     * StringUtils.endsWith(null, "def")     = false
8577     * StringUtils.endsWith("abcdef", null)  = false
8578     * StringUtils.endsWith("abcdef", "def") = true
8579     * StringUtils.endsWith("ABCDEF", "def") = false
8580     * StringUtils.endsWith("ABCDEF", "cde") = false
8581     * StringUtils.endsWith("ABCDEF", "")    = true
8582     * </pre>
8583     *
8584     * @see java.lang.String#endsWith(String)
8585     * @param str  the CharSequence to check, may be null
8586     * @param suffix the suffix to find, may be null
8587     * @return {@code true} if the CharSequence ends with the suffix, case sensitive, or
8588     *  both {@code null}
8589     * @since 2.4
8590     * @since 3.0 Changed signature from endsWith(String, String) to endsWith(CharSequence, CharSequence)
8591     */
8592    public static boolean endsWith(final CharSequence str, final CharSequence suffix) {
8593        return endsWith(str, suffix, false);
8594    }
8595
8596    /**
8597     * <p>Case insensitive check if a CharSequence ends with a specified suffix.</p>
8598     *
8599     * <p>{@code null}s are handled without exceptions. Two {@code null}
8600     * references are considered to be equal. The comparison is case insensitive.</p>
8601     *
8602     * <pre>
8603     * StringUtils.endsWithIgnoreCase(null, null)      = true
8604     * StringUtils.endsWithIgnoreCase(null, "def")     = false
8605     * StringUtils.endsWithIgnoreCase("abcdef", null)  = false
8606     * StringUtils.endsWithIgnoreCase("abcdef", "def") = true
8607     * StringUtils.endsWithIgnoreCase("ABCDEF", "def") = true
8608     * StringUtils.endsWithIgnoreCase("ABCDEF", "cde") = false
8609     * </pre>
8610     *
8611     * @see java.lang.String#endsWith(String)
8612     * @param str  the CharSequence to check, may be null
8613     * @param suffix the suffix to find, may be null
8614     * @return {@code true} if the CharSequence ends with the suffix, case insensitive, or
8615     *  both {@code null}
8616     * @since 2.4
8617     * @since 3.0 Changed signature from endsWithIgnoreCase(String, String) to endsWithIgnoreCase(CharSequence, CharSequence)
8618     */
8619    public static boolean endsWithIgnoreCase(final CharSequence str, final CharSequence suffix) {
8620        return endsWith(str, suffix, true);
8621    }
8622
8623    /**
8624     * <p>Check if a CharSequence ends with a specified suffix (optionally case insensitive).</p>
8625     *
8626     * @see java.lang.String#endsWith(String)
8627     * @param str  the CharSequence to check, may be null
8628     * @param suffix the suffix to find, may be null
8629     * @param ignoreCase indicates whether the compare should ignore case
8630     *  (case insensitive) or not.
8631     * @return {@code true} if the CharSequence starts with the prefix or
8632     *  both {@code null}
8633     */
8634    private static boolean endsWith(final CharSequence str, final CharSequence suffix, final boolean ignoreCase) {
8635        if (str == null || suffix == null) {
8636            return str == null && suffix == null;
8637        }
8638        if (suffix.length() > str.length()) {
8639            return false;
8640        }
8641        final int strOffset = str.length() - suffix.length();
8642        return CharSequenceUtils.regionMatches(str, ignoreCase, strOffset, suffix, 0, suffix.length());
8643    }
8644
8645    /**
8646     * <p>
8647     * Similar to <a
8648     * href="http://www.w3.org/TR/xpath/#function-normalize-space">http://www.w3.org/TR/xpath/#function-normalize
8649     * -space</a>
8650     * </p>
8651     * <p>
8652     * The function returns the argument string with whitespace normalized by using
8653     * <code>{@link #trim(String)}</code> to remove leading and trailing whitespace
8654     * and then replacing sequences of whitespace characters by a single space.
8655     * </p>
8656     * In XML Whitespace characters are the same as those allowed by the <a
8657     * href="http://www.w3.org/TR/REC-xml/#NT-S">S</a> production, which is S ::= (#x20 | #x9 | #xD | #xA)+
8658     * <p>
8659     * Java's regexp pattern \s defines whitespace as [ \t\n\x0B\f\r]
8660     *
8661     * <p>For reference:</p>
8662     * <ul>
8663     * <li>\x0B = vertical tab</li>
8664     * <li>\f = #xC = form feed</li>
8665     * <li>#x20 = space</li>
8666     * <li>#x9 = \t</li>
8667     * <li>#xA = \n</li>
8668     * <li>#xD = \r</li>
8669     * </ul>
8670     *
8671     * <p>
8672     * The difference is that Java's whitespace includes vertical tab and form feed, which this functional will also
8673     * normalize. Additionally <code>{@link #trim(String)}</code> removes control characters (char &lt;= 32) from both
8674     * ends of this String.
8675     * </p>
8676     *
8677     * @see Pattern
8678     * @see #trim(String)
8679     * @see <a
8680     *      href="http://www.w3.org/TR/xpath/#function-normalize-space">http://www.w3.org/TR/xpath/#function-normalize-space</a>
8681     * @param str the source String to normalize whitespaces from, may be null
8682     * @return the modified string with whitespace normalized, {@code null} if null String input
8683     *
8684     * @since 3.0
8685     */
8686    public static String normalizeSpace(final String str) {
8687        // LANG-1020: Improved performance significantly by normalizing manually instead of using regex
8688        // See https://github.com/librucha/commons-lang-normalizespaces-benchmark for performance test
8689        if (isEmpty(str)) {
8690            return str;
8691        }
8692        final int size = str.length();
8693        final char[] newChars = new char[size];
8694        int count = 0;
8695        int whitespacesCount = 0;
8696        boolean startWhitespaces = true;
8697        for (int i = 0; i < size; i++) {
8698            final char actualChar = str.charAt(i);
8699            final boolean isWhitespace = Character.isWhitespace(actualChar);
8700            if (!isWhitespace) {
8701                startWhitespaces = false;
8702                newChars[count++] = (actualChar == 160 ? 32 : actualChar);
8703                whitespacesCount = 0;
8704            } else {
8705                if (whitespacesCount == 0 && !startWhitespaces) {
8706                    newChars[count++] = SPACE.charAt(0);
8707                }
8708                whitespacesCount++;
8709            }
8710        }
8711        if (startWhitespaces) {
8712            return EMPTY;
8713        }
8714        return new String(newChars, 0, count - (whitespacesCount > 0 ? 1 : 0)).trim();
8715    }
8716
8717    /**
8718     * <p>Check if a CharSequence ends with any of the provided case-sensitive suffixes.</p>
8719     *
8720     * <pre>
8721     * StringUtils.endsWithAny(null, null)      = false
8722     * StringUtils.endsWithAny(null, new String[] {"abc"})  = false
8723     * StringUtils.endsWithAny("abcxyz", null)     = false
8724     * StringUtils.endsWithAny("abcxyz", new String[] {""}) = true
8725     * StringUtils.endsWithAny("abcxyz", new String[] {"xyz"}) = true
8726     * StringUtils.endsWithAny("abcxyz", new String[] {null, "xyz", "abc"}) = true
8727     * StringUtils.endsWithAny("abcXYZ", "def", "XYZ") = true
8728     * StringUtils.endsWithAny("abcXYZ", "def", "xyz") = false
8729     * </pre>
8730     *
8731     * @param sequence  the CharSequence to check, may be null
8732     * @param searchStrings the case-sensitive CharSequences to find, may be empty or contain {@code null}
8733     * @see StringUtils#endsWith(CharSequence, CharSequence)
8734     * @return {@code true} if the input {@code sequence} is {@code null} AND no {@code searchStrings} are provided, or
8735     *   the input {@code sequence} ends in any of the provided case-sensitive {@code searchStrings}.
8736     * @since 3.0
8737     */
8738    public static boolean endsWithAny(final CharSequence sequence, final CharSequence... searchStrings) {
8739        if (isEmpty(sequence) || ArrayUtils.isEmpty(searchStrings)) {
8740            return false;
8741        }
8742        for (final CharSequence searchString : searchStrings) {
8743            if (endsWith(sequence, searchString)) {
8744                return true;
8745            }
8746        }
8747        return false;
8748    }
8749
8750    /**
8751     * Appends the suffix to the end of the string if the string does not
8752     * already end with the suffix.
8753     *
8754     * @param str The string.
8755     * @param suffix The suffix to append to the end of the string.
8756     * @param ignoreCase Indicates whether the compare should ignore case.
8757     * @param suffixes Additional suffixes that are valid terminators (optional).
8758     *
8759     * @return A new String if suffix was appended, the same string otherwise.
8760     */
8761    private static String appendIfMissing(final String str, final CharSequence suffix, final boolean ignoreCase, final CharSequence... suffixes) {
8762        if (str == null || isEmpty(suffix) || endsWith(str, suffix, ignoreCase)) {
8763            return str;
8764        }
8765        if (suffixes != null && suffixes.length > 0) {
8766            for (final CharSequence s : suffixes) {
8767                if (endsWith(str, s, ignoreCase)) {
8768                    return str;
8769                }
8770            }
8771        }
8772        return str + suffix.toString();
8773    }
8774
8775    /**
8776     * Appends the suffix to the end of the string if the string does not
8777     * already end with any of the suffixes.
8778     *
8779     * <pre>
8780     * StringUtils.appendIfMissing(null, null) = null
8781     * StringUtils.appendIfMissing("abc", null) = "abc"
8782     * StringUtils.appendIfMissing("", "xyz") = "xyz"
8783     * StringUtils.appendIfMissing("abc", "xyz") = "abcxyz"
8784     * StringUtils.appendIfMissing("abcxyz", "xyz") = "abcxyz"
8785     * StringUtils.appendIfMissing("abcXYZ", "xyz") = "abcXYZxyz"
8786     * </pre>
8787     * <p>With additional suffixes,</p>
8788     * <pre>
8789     * StringUtils.appendIfMissing(null, null, null) = null
8790     * StringUtils.appendIfMissing("abc", null, null) = "abc"
8791     * StringUtils.appendIfMissing("", "xyz", null) = "xyz"
8792     * StringUtils.appendIfMissing("abc", "xyz", new CharSequence[]{null}) = "abcxyz"
8793     * StringUtils.appendIfMissing("abc", "xyz", "") = "abc"
8794     * StringUtils.appendIfMissing("abc", "xyz", "mno") = "abcxyz"
8795     * StringUtils.appendIfMissing("abcxyz", "xyz", "mno") = "abcxyz"
8796     * StringUtils.appendIfMissing("abcmno", "xyz", "mno") = "abcmno"
8797     * StringUtils.appendIfMissing("abcXYZ", "xyz", "mno") = "abcXYZxyz"
8798     * StringUtils.appendIfMissing("abcMNO", "xyz", "mno") = "abcMNOxyz"
8799     * </pre>
8800     *
8801     * @param str The string.
8802     * @param suffix The suffix to append to the end of the string.
8803     * @param suffixes Additional suffixes that are valid terminators.
8804     *
8805     * @return A new String if suffix was appended, the same string otherwise.
8806     *
8807     * @since 3.2
8808     */
8809    public static String appendIfMissing(final String str, final CharSequence suffix, final CharSequence... suffixes) {
8810        return appendIfMissing(str, suffix, false, suffixes);
8811    }
8812
8813    /**
8814     * Appends the suffix to the end of the string if the string does not
8815     * already end, case insensitive, with any of the suffixes.
8816     *
8817     * <pre>
8818     * StringUtils.appendIfMissingIgnoreCase(null, null) = null
8819     * StringUtils.appendIfMissingIgnoreCase("abc", null) = "abc"
8820     * StringUtils.appendIfMissingIgnoreCase("", "xyz") = "xyz"
8821     * StringUtils.appendIfMissingIgnoreCase("abc", "xyz") = "abcxyz"
8822     * StringUtils.appendIfMissingIgnoreCase("abcxyz", "xyz") = "abcxyz"
8823     * StringUtils.appendIfMissingIgnoreCase("abcXYZ", "xyz") = "abcXYZ"
8824     * </pre>
8825     * <p>With additional suffixes,</p>
8826     * <pre>
8827     * StringUtils.appendIfMissingIgnoreCase(null, null, null) = null
8828     * StringUtils.appendIfMissingIgnoreCase("abc", null, null) = "abc"
8829     * StringUtils.appendIfMissingIgnoreCase("", "xyz", null) = "xyz"
8830     * StringUtils.appendIfMissingIgnoreCase("abc", "xyz", new CharSequence[]{null}) = "abcxyz"
8831     * StringUtils.appendIfMissingIgnoreCase("abc", "xyz", "") = "abc"
8832     * StringUtils.appendIfMissingIgnoreCase("abc", "xyz", "mno") = "axyz"
8833     * StringUtils.appendIfMissingIgnoreCase("abcxyz", "xyz", "mno") = "abcxyz"
8834     * StringUtils.appendIfMissingIgnoreCase("abcmno", "xyz", "mno") = "abcmno"
8835     * StringUtils.appendIfMissingIgnoreCase("abcXYZ", "xyz", "mno") = "abcXYZ"
8836     * StringUtils.appendIfMissingIgnoreCase("abcMNO", "xyz", "mno") = "abcMNO"
8837     * </pre>
8838     *
8839     * @param str The string.
8840     * @param suffix The suffix to append to the end of the string.
8841     * @param suffixes Additional suffixes that are valid terminators.
8842     *
8843     * @return A new String if suffix was appended, the same string otherwise.
8844     *
8845     * @since 3.2
8846     */
8847    public static String appendIfMissingIgnoreCase(final String str, final CharSequence suffix, final CharSequence... suffixes) {
8848        return appendIfMissing(str, suffix, true, suffixes);
8849    }
8850
8851    /**
8852     * Prepends the prefix to the start of the string if the string does not
8853     * already start with any of the prefixes.
8854     *
8855     * @param str The string.
8856     * @param prefix The prefix to prepend to the start of the string.
8857     * @param ignoreCase Indicates whether the compare should ignore case.
8858     * @param prefixes Additional prefixes that are valid (optional).
8859     *
8860     * @return A new String if prefix was prepended, the same string otherwise.
8861     */
8862    private static String prependIfMissing(final String str, final CharSequence prefix, final boolean ignoreCase, final CharSequence... prefixes) {
8863        if (str == null || isEmpty(prefix) || startsWith(str, prefix, ignoreCase)) {
8864            return str;
8865        }
8866        if (prefixes != null && prefixes.length > 0) {
8867            for (final CharSequence p : prefixes) {
8868                if (startsWith(str, p, ignoreCase)) {
8869                    return str;
8870                }
8871            }
8872        }
8873        return prefix.toString() + str;
8874    }
8875
8876    /**
8877     * Prepends the prefix to the start of the string if the string does not
8878     * already start with any of the prefixes.
8879     *
8880     * <pre>
8881     * StringUtils.prependIfMissing(null, null) = null
8882     * StringUtils.prependIfMissing("abc", null) = "abc"
8883     * StringUtils.prependIfMissing("", "xyz") = "xyz"
8884     * StringUtils.prependIfMissing("abc", "xyz") = "xyzabc"
8885     * StringUtils.prependIfMissing("xyzabc", "xyz") = "xyzabc"
8886     * StringUtils.prependIfMissing("XYZabc", "xyz") = "xyzXYZabc"
8887     * </pre>
8888     * <p>With additional prefixes,</p>
8889     * <pre>
8890     * StringUtils.prependIfMissing(null, null, null) = null
8891     * StringUtils.prependIfMissing("abc", null, null) = "abc"
8892     * StringUtils.prependIfMissing("", "xyz", null) = "xyz"
8893     * StringUtils.prependIfMissing("abc", "xyz", new CharSequence[]{null}) = "xyzabc"
8894     * StringUtils.prependIfMissing("abc", "xyz", "") = "abc"
8895     * StringUtils.prependIfMissing("abc", "xyz", "mno") = "xyzabc"
8896     * StringUtils.prependIfMissing("xyzabc", "xyz", "mno") = "xyzabc"
8897     * StringUtils.prependIfMissing("mnoabc", "xyz", "mno") = "mnoabc"
8898     * StringUtils.prependIfMissing("XYZabc", "xyz", "mno") = "xyzXYZabc"
8899     * StringUtils.prependIfMissing("MNOabc", "xyz", "mno") = "xyzMNOabc"
8900     * </pre>
8901     *
8902     * @param str The string.
8903     * @param prefix The prefix to prepend to the start of the string.
8904     * @param prefixes Additional prefixes that are valid.
8905     *
8906     * @return A new String if prefix was prepended, the same string otherwise.
8907     *
8908     * @since 3.2
8909     */
8910    public static String prependIfMissing(final String str, final CharSequence prefix, final CharSequence... prefixes) {
8911        return prependIfMissing(str, prefix, false, prefixes);
8912    }
8913
8914    /**
8915     * Prepends the prefix to the start of the string if the string does not
8916     * already start, case insensitive, with any of the prefixes.
8917     *
8918     * <pre>
8919     * StringUtils.prependIfMissingIgnoreCase(null, null) = null
8920     * StringUtils.prependIfMissingIgnoreCase("abc", null) = "abc"
8921     * StringUtils.prependIfMissingIgnoreCase("", "xyz") = "xyz"
8922     * StringUtils.prependIfMissingIgnoreCase("abc", "xyz") = "xyzabc"
8923     * StringUtils.prependIfMissingIgnoreCase("xyzabc", "xyz") = "xyzabc"
8924     * StringUtils.prependIfMissingIgnoreCase("XYZabc", "xyz") = "XYZabc"
8925     * </pre>
8926     * <p>With additional prefixes,</p>
8927     * <pre>
8928     * StringUtils.prependIfMissingIgnoreCase(null, null, null) = null
8929     * StringUtils.prependIfMissingIgnoreCase("abc", null, null) = "abc"
8930     * StringUtils.prependIfMissingIgnoreCase("", "xyz", null) = "xyz"
8931     * StringUtils.prependIfMissingIgnoreCase("abc", "xyz", new CharSequence[]{null}) = "xyzabc"
8932     * StringUtils.prependIfMissingIgnoreCase("abc", "xyz", "") = "abc"
8933     * StringUtils.prependIfMissingIgnoreCase("abc", "xyz", "mno") = "xyzabc"
8934     * StringUtils.prependIfMissingIgnoreCase("xyzabc", "xyz", "mno") = "xyzabc"
8935     * StringUtils.prependIfMissingIgnoreCase("mnoabc", "xyz", "mno") = "mnoabc"
8936     * StringUtils.prependIfMissingIgnoreCase("XYZabc", "xyz", "mno") = "XYZabc"
8937     * StringUtils.prependIfMissingIgnoreCase("MNOabc", "xyz", "mno") = "MNOabc"
8938     * </pre>
8939     *
8940     * @param str The string.
8941     * @param prefix The prefix to prepend to the start of the string.
8942     * @param prefixes Additional prefixes that are valid (optional).
8943     *
8944     * @return A new String if prefix was prepended, the same string otherwise.
8945     *
8946     * @since 3.2
8947     */
8948    public static String prependIfMissingIgnoreCase(final String str, final CharSequence prefix, final CharSequence... prefixes) {
8949        return prependIfMissing(str, prefix, true, prefixes);
8950    }
8951
8952    /**
8953     * Converts a <code>byte[]</code> to a String using the specified character encoding.
8954     *
8955     * @param bytes
8956     *            the byte array to read from
8957     * @param charsetName
8958     *            the encoding to use, if null then use the platform default
8959     * @return a new String
8960     * @throws UnsupportedEncodingException
8961     *             If the named charset is not supported
8962     * @throws NullPointerException
8963     *             if the input is null
8964     * @deprecated use {@link StringUtils#toEncodedString(byte[], Charset)} instead of String constants in your code
8965     * @since 3.1
8966     */
8967    @Deprecated
8968    public static String toString(final byte[] bytes, final String charsetName) throws UnsupportedEncodingException {
8969        return charsetName != null ? new String(bytes, charsetName) : new String(bytes, Charset.defaultCharset());
8970    }
8971
8972    /**
8973     * Converts a <code>byte[]</code> to a String using the specified character encoding.
8974     *
8975     * @param bytes
8976     *            the byte array to read from
8977     * @param charset
8978     *            the encoding to use, if null then use the platform default
8979     * @return a new String
8980     * @throws NullPointerException
8981     *             if {@code bytes} is null
8982     * @since 3.2
8983     * @since 3.3 No longer throws {@link UnsupportedEncodingException}.
8984     */
8985    public static String toEncodedString(final byte[] bytes, final Charset charset) {
8986        return new String(bytes, charset != null ? charset : Charset.defaultCharset());
8987    }
8988
8989    /**
8990     * <p>
8991     * Wraps a string with a char.
8992     * </p>
8993     *
8994     * <pre>
8995     * StringUtils.wrap(null, *)        = null
8996     * StringUtils.wrap("", *)          = ""
8997     * StringUtils.wrap("ab", '\0')     = "ab"
8998     * StringUtils.wrap("ab", 'x')      = "xabx"
8999     * StringUtils.wrap("ab", '\'')     = "'ab'"
9000     * StringUtils.wrap("\"ab\"", '\"') = "\"\"ab\"\""
9001     * </pre>
9002     *
9003     * @param str
9004     *            the string to be wrapped, may be {@code null}
9005     * @param wrapWith
9006     *            the char that will wrap {@code str}
9007     * @return the wrapped string, or {@code null} if {@code str==null}
9008     * @since 3.4
9009     */
9010    public static String wrap(final String str, final char wrapWith) {
9011
9012        if (isEmpty(str) || wrapWith == CharUtils.NUL) {
9013            return str;
9014        }
9015
9016        return wrapWith + str + wrapWith;
9017    }
9018
9019    /**
9020     * <p>
9021     * Wraps a String with another String.
9022     * </p>
9023     *
9024     * <p>
9025     * A {@code null} input String returns {@code null}.
9026     * </p>
9027     *
9028     * <pre>
9029     * StringUtils.wrap(null, *)         = null
9030     * StringUtils.wrap("", *)           = ""
9031     * StringUtils.wrap("ab", null)      = "ab"
9032     * StringUtils.wrap("ab", "x")       = "xabx"
9033     * StringUtils.wrap("ab", "\"")      = "\"ab\""
9034     * StringUtils.wrap("\"ab\"", "\"")  = "\"\"ab\"\""
9035     * StringUtils.wrap("ab", "'")       = "'ab'"
9036     * StringUtils.wrap("'abcd'", "'")   = "''abcd''"
9037     * StringUtils.wrap("\"abcd\"", "'") = "'\"abcd\"'"
9038     * StringUtils.wrap("'abcd'", "\"")  = "\"'abcd'\""
9039     * </pre>
9040     *
9041     * @param str
9042     *            the String to be wrapper, may be null
9043     * @param wrapWith
9044     *            the String that will wrap str
9045     * @return wrapped String, {@code null} if null String input
9046     * @since 3.4
9047     */
9048    public static String wrap(final String str, final String wrapWith) {
9049
9050        if (isEmpty(str) || isEmpty(wrapWith)) {
9051            return str;
9052        }
9053
9054        return wrapWith.concat(str).concat(wrapWith);
9055    }
9056
9057    /**
9058     * <p>
9059     * Wraps a string with a char if that char is missing from the start or end of the given string.
9060     * </p>
9061     *
9062     * <pre>
9063     * StringUtils.wrap(null, *)        = null
9064     * StringUtils.wrap("", *)          = ""
9065     * StringUtils.wrap("ab", '\0')     = "ab"
9066     * StringUtils.wrap("ab", 'x')      = "xabx"
9067     * StringUtils.wrap("ab", '\'')     = "'ab'"
9068     * StringUtils.wrap("\"ab\"", '\"') = "\"ab\""
9069     * StringUtils.wrap("/", '/')  = "/"
9070     * StringUtils.wrap("a/b/c", '/')  = "/a/b/c/"
9071     * StringUtils.wrap("/a/b/c", '/')  = "/a/b/c/"
9072     * StringUtils.wrap("a/b/c/", '/')  = "/a/b/c/"
9073     * </pre>
9074     *
9075     * @param str
9076     *            the string to be wrapped, may be {@code null}
9077     * @param wrapWith
9078     *            the char that will wrap {@code str}
9079     * @return the wrapped string, or {@code null} if {@code str==null}
9080     * @since 3.5
9081     */
9082    public static String wrapIfMissing(final String str, final char wrapWith) {
9083        if (isEmpty(str) || wrapWith == CharUtils.NUL) {
9084            return str;
9085        }
9086        final StringBuilder builder = new StringBuilder(str.length() + 2);
9087        if (str.charAt(0) != wrapWith) {
9088            builder.append(wrapWith);
9089        }
9090        builder.append(str);
9091        if (str.charAt(str.length() - 1) != wrapWith) {
9092            builder.append(wrapWith);
9093        }
9094        return builder.toString();
9095    }
9096
9097    /**
9098     * <p>
9099     * Wraps a string with a string if that string is missing from the start or end of the given string.
9100     * </p>
9101     *
9102     * <pre>
9103     * StringUtils.wrap(null, *)         = null
9104     * StringUtils.wrap("", *)           = ""
9105     * StringUtils.wrap("ab", null)      = "ab"
9106     * StringUtils.wrap("ab", "x")       = "xabx"
9107     * StringUtils.wrap("ab", "\"")      = "\"ab\""
9108     * StringUtils.wrap("\"ab\"", "\"")  = "\"ab\""
9109     * StringUtils.wrap("ab", "'")       = "'ab'"
9110     * StringUtils.wrap("'abcd'", "'")   = "'abcd'"
9111     * StringUtils.wrap("\"abcd\"", "'") = "'\"abcd\"'"
9112     * StringUtils.wrap("'abcd'", "\"")  = "\"'abcd'\""
9113     * StringUtils.wrap("/", "/")  = "/"
9114     * StringUtils.wrap("a/b/c", "/")  = "/a/b/c/"
9115     * StringUtils.wrap("/a/b/c", "/")  = "/a/b/c/"
9116     * StringUtils.wrap("a/b/c/", "/")  = "/a/b/c/"
9117     * </pre>
9118     *
9119     * @param str
9120     *            the string to be wrapped, may be {@code null}
9121     * @param wrapWith
9122     *            the char that will wrap {@code str}
9123     * @return the wrapped string, or {@code null} if {@code str==null}
9124     * @since 3.5
9125     */
9126    public static String wrapIfMissing(final String str, final String wrapWith) {
9127        if (isEmpty(str) || isEmpty(wrapWith)) {
9128            return str;
9129        }
9130        final StringBuilder builder = new StringBuilder(str.length() + wrapWith.length() + wrapWith.length());
9131        if (!str.startsWith(wrapWith)) {
9132            builder.append(wrapWith);
9133        }
9134        builder.append(str);
9135        if (!str.endsWith(wrapWith)) {
9136            builder.append(wrapWith);
9137        }
9138        return builder.toString();
9139    }
9140
9141    /**
9142     * <p>
9143     * Unwraps a given string from anther string.
9144     * </p>
9145     *
9146     * <pre>
9147     * StringUtils.unwrap(null, null)         = null
9148     * StringUtils.unwrap(null, "")           = null
9149     * StringUtils.unwrap(null, "1")          = null
9150     * StringUtils.unwrap("\'abc\'", "\'")    = "abc"
9151     * StringUtils.unwrap("\"abc\"", "\"")    = "abc"
9152     * StringUtils.unwrap("AABabcBAA", "AA")  = "BabcB"
9153     * StringUtils.unwrap("A", "#")           = "A"
9154     * StringUtils.unwrap("#A", "#")          = "#A"
9155     * StringUtils.unwrap("A#", "#")          = "A#"
9156     * </pre>
9157     *
9158     * @param str
9159     *          the String to be unwrapped, can be null
9160     * @param wrapToken
9161     *          the String used to unwrap
9162     * @return unwrapped String or the original string
9163     *          if it is not quoted properly with the wrapToken
9164     * @since 3.6
9165     */
9166    public static String unwrap(final String str, final String wrapToken) {
9167        if (isEmpty(str) || isEmpty(wrapToken)) {
9168            return str;
9169        }
9170
9171        if (startsWith(str, wrapToken) && endsWith(str, wrapToken)) {
9172            final int startIndex = str.indexOf(wrapToken);
9173            final int endIndex = str.lastIndexOf(wrapToken);
9174            final int wrapLength = wrapToken.length();
9175            if (startIndex != -1 && endIndex != -1) {
9176                return str.substring(startIndex + wrapLength, endIndex);
9177            }
9178        }
9179
9180        return str;
9181    }
9182
9183    /**
9184     * <p>
9185     * Unwraps a given string from a character.
9186     * </p>
9187     *
9188     * <pre>
9189     * StringUtils.unwrap(null, null)         = null
9190     * StringUtils.unwrap(null, '\0')         = null
9191     * StringUtils.unwrap(null, '1')          = null
9192     * StringUtils.unwrap("\'abc\'", '\'')    = "abc"
9193     * StringUtils.unwrap("AABabcBAA", 'A')  = "ABabcBA"
9194     * StringUtils.unwrap("A", '#')           = "A"
9195     * StringUtils.unwrap("#A", '#')          = "#A"
9196     * StringUtils.unwrap("A#", '#')          = "A#"
9197     * </pre>
9198     *
9199     * @param str
9200     *          the String to be unwrapped, can be null
9201     * @param wrapChar
9202     *          the character used to unwrap
9203     * @return unwrapped String or the original string
9204     *          if it is not quoted properly with the wrapChar
9205     * @since 3.6
9206     */
9207    public static String unwrap(final String str, final char wrapChar) {
9208        if (isEmpty(str) || wrapChar == CharUtils.NUL) {
9209            return str;
9210        }
9211
9212        if (str.charAt(0) == wrapChar && str.charAt(str.length() - 1) == wrapChar) {
9213            final int startIndex = 0;
9214            final int endIndex = str.length() - 1;
9215            if (startIndex != -1 && endIndex != -1) {
9216                return str.substring(startIndex + 1, endIndex);
9217            }
9218        }
9219
9220        return str;
9221    }
9222
9223    /**
9224     * <p>Converts a {@code CharSequence} into an array of code points.</p>
9225     *
9226     * <p>Valid pairs of surrogate code units will be converted into a single supplementary
9227     * code point. Isolated surrogate code units (i.e. a high surrogate not followed by a low surrogate or
9228     * a low surrogate not preceeded by a high surrogate) will be returned as-is.</p>
9229     *
9230     * <pre>
9231     * StringUtils.toCodePoints(null)   =  null
9232     * StringUtils.toCodePoints("")     =  []  // empty array
9233     * </pre>
9234     *
9235     * @param str the character sequence to convert
9236     * @return an array of code points
9237     * @since 3.6
9238     */
9239    public static int[] toCodePoints(CharSequence str) {
9240        if (str == null) {
9241            return null;
9242        }
9243        if (str.length() == 0) {
9244            return ArrayUtils.EMPTY_INT_ARRAY;
9245        }
9246
9247        String s = str.toString();
9248        int[] result = new int[s.codePointCount(0, s.length())];
9249        int index = 0;
9250        for (int i = 0; i < result.length; i++) {
9251            result[i] = s.codePointAt(index);
9252            index += Character.charCount(result[i]);
9253        }
9254        return result;
9255    }
9256}