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