Coverage Report - org.apache.commons.lang3.StringUtils
 
Classes in this File Line Coverage Branch Coverage Complexity
StringUtils
99%
1682/1685
98%
1493/1521
5,686
 
 1  
 /*
 2  
  * Licensed to the Apache Software Foundation (ASF) under one or more
 3  
  * contributor license agreements.  See the NOTICE file distributed with
 4  
  * this work for additional information regarding copyright ownership.
 5  
  * The ASF licenses this file to You under the Apache License, Version 2.0
 6  
  * (the "License"); you may not use this file except in compliance with
 7  
  * the License.  You may obtain a copy of the License at
 8  
  *
 9  
  *      http://www.apache.org/licenses/LICENSE-2.0
 10  
  *
 11  
  * Unless required by applicable law or agreed to in writing, software
 12  
  * distributed under the License is distributed on an "AS IS" BASIS,
 13  
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 14  
  * See the License for the specific language governing permissions and
 15  
  * limitations under the License.
 16  
  */
 17  
 package org.apache.commons.lang3;
 18  
 
 19  
 import java.io.UnsupportedEncodingException;
 20  
 import java.nio.charset.Charset;
 21  
 import java.text.Normalizer;
 22  
 import java.util.ArrayList;
 23  
 import java.util.Arrays;
 24  
 import java.util.Iterator;
 25  
 import java.util.List;
 26  
 import java.util.Locale;
 27  
 import java.util.Objects;
 28  
 import java.util.regex.Pattern;
 29  
 
 30  
 /**
 31  
  * <p>Operations on {@link java.lang.String} that are
 32  
  * {@code null} safe.</p>
 33  
  *
 34  
  * <ul>
 35  
  *  <li><b>IsEmpty/IsBlank</b>
 36  
  *      - checks if a String contains text</li>
 37  
  *  <li><b>Trim/Strip</b>
 38  
  *      - removes leading and trailing whitespace</li>
 39  
  *  <li><b>Equals/Compare</b>
 40  
  *      - compares two strings null-safe</li>
 41  
  *  <li><b>startsWith</b>
 42  
  *      - check if a String starts with a prefix null-safe</li>
 43  
  *  <li><b>endsWith</b>
 44  
  *      - check if a String ends with a suffix null-safe</li>
 45  
  *  <li><b>IndexOf/LastIndexOf/Contains</b>
 46  
  *      - null-safe index-of checks
 47  
  *  <li><b>IndexOfAny/LastIndexOfAny/IndexOfAnyBut/LastIndexOfAnyBut</b>
 48  
  *      - index-of any of a set of Strings</li>
 49  
  *  <li><b>ContainsOnly/ContainsNone/ContainsAny</b>
 50  
  *      - does String contains only/none/any of these characters</li>
 51  
  *  <li><b>Substring/Left/Right/Mid</b>
 52  
  *      - null-safe substring extractions</li>
 53  
  *  <li><b>SubstringBefore/SubstringAfter/SubstringBetween</b>
 54  
  *      - substring extraction relative to other strings</li>
 55  
  *  <li><b>Split/Join</b>
 56  
  *      - splits a String into an array of substrings and vice versa</li>
 57  
  *  <li><b>Remove/Delete</b>
 58  
  *      - removes part of a String</li>
 59  
  *  <li><b>Replace/Overlay</b>
 60  
  *      - Searches a String and replaces one String with another</li>
 61  
  *  <li><b>Chomp/Chop</b>
 62  
  *      - removes the last part of a String</li>
 63  
  *  <li><b>AppendIfMissing</b>
 64  
  *      - appends a suffix to the end of the String if not present</li>
 65  
  *  <li><b>PrependIfMissing</b>
 66  
  *      - prepends a prefix to the start of the String if not present</li>
 67  
  *  <li><b>LeftPad/RightPad/Center/Repeat</b>
 68  
  *      - pads a String</li>
 69  
  *  <li><b>UpperCase/LowerCase/SwapCase/Capitalize/Uncapitalize</b>
 70  
  *      - changes the case of a String</li>
 71  
  *  <li><b>CountMatches</b>
 72  
  *      - counts the number of occurrences of one String in another</li>
 73  
  *  <li><b>IsAlpha/IsNumeric/IsWhitespace/IsAsciiPrintable</b>
 74  
  *      - checks the characters in a String</li>
 75  
  *  <li><b>DefaultString</b>
 76  
  *      - protects against a null input String</li>
 77  
  *  <li><b>Rotate</b>
 78  
  *      - rotate (circular shift) a String</li>
 79  
  *  <li><b>Reverse/ReverseDelimited</b>
 80  
  *      - reverses a String</li>
 81  
  *  <li><b>Abbreviate</b>
 82  
  *      - abbreviates a string using ellipsis or another given String</li>
 83  
  *  <li><b>Difference</b>
 84  
  *      - compares Strings and reports on their differences</li>
 85  
  *  <li><b>LevenshteinDistance</b>
 86  
  *      - the number of changes needed to change one String into another</li>
 87  
  * </ul>
 88  
  *
 89  
  * <p>The {@code StringUtils} class defines certain words related to
 90  
  * String handling.</p>
 91  
  *
 92  
  * <ul>
 93  
  *  <li>null - {@code null}</li>
 94  
  *  <li>empty - a zero-length string ({@code ""})</li>
 95  
  *  <li>space - the space character ({@code ' '}, char 32)</li>
 96  
  *  <li>whitespace - the characters defined by {@link Character#isWhitespace(char)}</li>
 97  
  *  <li>trim - the characters &lt;= 32 as in {@link String#trim()}</li>
 98  
  * </ul>
 99  
  *
 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
 117  
 public 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  1
         super();
 186  1
     }
 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  3783
         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  82
         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  16
       if (ArrayUtils.isEmpty(css)) {
 253  2
         return false;
 254  
       }
 255  26
       for (final CharSequence cs : css){
 256  22
         if (isEmpty(cs)) {
 257  10
           return true;
 258  
         }
 259  
       }
 260  4
       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  8
       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  11
         if (ArrayUtils.isEmpty(css)) {
 307  3
             return true;
 308  
         }
 309  13
         for (final CharSequence cs : css) {
 310  11
             if (isNotEmpty(cs)) {
 311  6
                 return false;
 312  
             }
 313  
         }
 314  2
         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  671
         if (cs == null || (strLen = cs.length()) == 0) {
 338  62
             return true;
 339  
         }
 340  770
         for (int i = 0; i < strLen; i++) {
 341  709
             if (Character.isWhitespace(cs.charAt(i)) == false) {
 342  548
                 return false;
 343  
             }
 344  
         }
 345  61
         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  305
         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  18
       if (ArrayUtils.isEmpty(css)) {
 395  2
         return false;
 396  
       }
 397  24
       for (final CharSequence cs : css){
 398  22
         if (isBlank(cs)) {
 399  14
           return true;
 400  
         }
 401  
       }
 402  2
       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  9
       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  10
         if (ArrayUtils.isEmpty(css)) {
 454  1
             return true;
 455  
         }
 456  17
         for (final CharSequence cs : css) {
 457  14
             if (isNotBlank(cs)) {
 458  6
                return false;
 459  
             }
 460  
         }
 461  3
         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  18
         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  9
         final String ts = trim(str);
 517  9
         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  9
         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  16
         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  58
         if (offset < 0) {
 641  11
             throw new IllegalArgumentException("offset cannot be negative");
 642  
         }
 643  47
         if (maxWidth < 0) {
 644  11
             throw new IllegalArgumentException("maxWith cannot be negative");
 645  
         }
 646  36
         if (str == null) {
 647  3
             return null;
 648  
         }
 649  33
         if (offset > str.length()) {
 650  2
             return EMPTY;
 651  
         }
 652  31
         if (str.length() > maxWidth) {
 653  21
             final int ix = offset + maxWidth > str.length() ? str.length() : offset + maxWidth;
 654  21
             return str.substring(offset, ix);
 655  
         }
 656  10
         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  5
         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  6
         if (str == null) {
 712  1
             return null;
 713  
         }
 714  5
         str = strip(str, null);
 715  5
         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  6
         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  45
         if (isEmpty(str)) {
 772  13
             return str;
 773  
         }
 774  32
         str = stripStart(str, stripChars);
 775  32
         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  52
         if (str == null || (strLen = str.length()) == 0) {
 805  8
             return str;
 806  
         }
 807  44
         int start = 0;
 808  44
         if (stripChars == null) {
 809  263
             while (start != strLen && Character.isWhitespace(str.charAt(start))) {
 810  240
                 start++;
 811  
             }
 812  21
         } else if (stripChars.isEmpty()) {
 813  8
             return str;
 814  
         } else {
 815  41
             while (start != strLen && stripChars.indexOf(str.charAt(start)) != INDEX_NOT_FOUND) {
 816  28
                 start++;
 817  
             }
 818  
         }
 819  36
         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  54
         if (str == null || (end = str.length()) == 0) {
 850  15
             return str;
 851  
         }
 852  
 
 853  39
         if (stripChars == null) {
 854  173
             while (end != 0 && Character.isWhitespace(str.charAt(end - 1))) {
 855  156
                 end--;
 856  
             }
 857  22
         } else if (stripChars.isEmpty()) {
 858  8
             return str;
 859  
         } else {
 860  45
             while (end != 0 && stripChars.indexOf(str.charAt(end - 1)) != INDEX_NOT_FOUND) {
 861  31
                 end--;
 862  
             }
 863  
         }
 864  31
         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  5
         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  8
         if (strs == null || (strsLen = strs.length) == 0) {
 920  4
             return strs;
 921  
         }
 922  4
         final String[] newArr = new String[strsLen];
 923  14
         for (int i = 0; i < strsLen; i++) {
 924  10
             newArr[i] = strip(strs[i], stripChars);
 925  
         }
 926  4
         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  7
         if(input == null) {
 949  1
             return null;
 950  
         }
 951  6
         final Pattern pattern = Pattern.compile("\\p{InCombiningDiacriticalMarks}+");//$NON-NLS-1$
 952  6
         final StringBuilder decomposed = new StringBuilder(Normalizer.normalize(input, Normalizer.Form.NFD));
 953  6
         convertRemainingAccentCharacters(decomposed);
 954  
         // Note that this doesn't correctly remove ligatures...
 955  6
         return pattern.matcher(decomposed).replaceAll(StringUtils.EMPTY);
 956  
     }
 957  
 
 958  
     private static void convertRemainingAccentCharacters(final StringBuilder decomposed) {
 959  109
         for (int i = 0; i < decomposed.length(); i++) {
 960  103
             if (decomposed.charAt(i) == '\u0141') {
 961  1
                 decomposed.deleteCharAt(i);
 962  1
                 decomposed.insert(i, 'L');
 963  102
             } else if (decomposed.charAt(i) == '\u0142') {
 964  1
                 decomposed.deleteCharAt(i);
 965  1
                 decomposed.insert(i, 'l');
 966  
             }
 967  
         }
 968  6
     }
 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  296
         if (cs1 == cs2) {
 995  61
             return true;
 996  
         }
 997  235
         if (cs1 == null || cs2 == null) {
 998  11
             return false;
 999  
         }
 1000  224
         if (cs1.length() != cs2.length()) {
 1001  160
             return false;
 1002  
         }
 1003  64
         if (cs1 instanceof String && cs2 instanceof String) {
 1004  54
             return cs1.equals(cs2);
 1005  
         }
 1006  10
         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  33
         if (str1 == null || str2 == null) {
 1032  11
             return str1 == str2;
 1033  22
         } else if (str1 == str2) {
 1034  4
             return true;
 1035  18
         } else if (str1.length() != str2.length()) {
 1036  4
             return false;
 1037  
         } else {
 1038  14
             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  11
         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  24
         if (str1 == str2) {
 1116  4
             return 0;
 1117  
         }
 1118  20
         if (str1 == null) {
 1119  3
             return nullIsLess ? -1 : 1;
 1120  
         }
 1121  17
         if (str2 == null) {
 1122  3
             return nullIsLess ? 1 : - 1;
 1123  
         }
 1124  14
         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  13
         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  28
         if (str1 == str2) {
 1209  4
             return 0;
 1210  
         }
 1211  24
         if (str1 == null) {
 1212  3
             return nullIsLess ? -1 : 1;
 1213  
         }
 1214  21
         if (str2 == null) {
 1215  3
             return nullIsLess ? 1 : - 1;
 1216  
         }
 1217  18
         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  20
         if (ArrayUtils.isNotEmpty(searchStrings)) {
 1241  37
             for (final CharSequence next : searchStrings) {
 1242  26
                 if (equals(string, next)) {
 1243  6
                     return true;
 1244  
                 }
 1245  
             }
 1246  
         }
 1247  14
         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  19
         if (ArrayUtils.isNotEmpty(searchStrings)) {
 1272  31
             for (final CharSequence next : searchStrings) {
 1273  24
                 if (equalsIgnoreCase(string, next)) {
 1274  9
                     return true;
 1275  
                 }
 1276  
             }
 1277  
         }
 1278  10
         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  5
         if (isEmpty(seq)) {
 1322  2
             return INDEX_NOT_FOUND;
 1323  
         }
 1324  3
         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  20
         if (isEmpty(seq)) {
 1382  4
             return INDEX_NOT_FOUND;
 1383  
         }
 1384  16
         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  8
         if (seq == null || searchSeq == null) {
 1413  2
             return INDEX_NOT_FOUND;
 1414  
         }
 1415  6
         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  25
         if (seq == null || searchSeq == null) {
 1453  6
             return INDEX_NOT_FOUND;
 1454  
         }
 1455  19
         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  76
         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  87
         if (str == null || searchStr == null || ordinal <= 0) {
 1529  30
             return INDEX_NOT_FOUND;
 1530  
         }
 1531  57
         if (searchStr.length() == 0) {
 1532  9
             return lastIndex ? str.length() : 0;
 1533  
         }
 1534  48
         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  48
         int index = lastIndex ? str.length() : INDEX_NOT_FOUND;
 1538  
         do {
 1539  142
             if (lastIndex) {
 1540  9
                 index = CharSequenceUtils.lastIndexOf(str, searchStr, index - 1); // step backwards thru string
 1541  
             } else {
 1542  133
                 index = CharSequenceUtils.indexOf(str, searchStr, index + 1); // step forwards through string
 1543  
             }
 1544  142
             if (index < 0) {
 1545  7
                 return index;
 1546  
             }
 1547  135
             found++;
 1548  135
         } while (found < ordinal);
 1549  41
         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  11
         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  26
         if (str == null || searchStr == null) {
 1615  3
             return INDEX_NOT_FOUND;
 1616  
         }
 1617  23
         if (startPos < 0) {
 1618  1
             startPos = 0;
 1619  
         }
 1620  23
         final int endLimit = str.length() - searchStr.length() + 1;
 1621  23
         if (startPos > endLimit) {
 1622  2
             return INDEX_NOT_FOUND;
 1623  
         }
 1624  21
         if (searchStr.length() == 0) {
 1625  3
             return startPos;
 1626  
         }
 1627  32
         for (int i = startPos; i < endLimit; i++) {
 1628  27
             if (CharSequenceUtils.regionMatches(str, true, i, searchStr, 0, searchStr.length())) {
 1629  13
                 return i;
 1630  
             }
 1631  
         }
 1632  5
         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  5
         if (isEmpty(seq)) {
 1673  2
             return INDEX_NOT_FOUND;
 1674  
         }
 1675  3
         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  21
         if (isEmpty(seq)) {
 1724  4
             return INDEX_NOT_FOUND;
 1725  
         }
 1726  17
         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  9
         if (seq == null || searchSeq == null) {
 1754  2
             return INDEX_NOT_FOUND;
 1755  
         }
 1756  7
         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  11
         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  30
         if (seq == null || searchSeq == null) {
 1835  6
             return INDEX_NOT_FOUND;
 1836  
         }
 1837  24
         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  14
         if (str == null || searchStr == null) {
 1865  3
             return INDEX_NOT_FOUND;
 1866  
         }
 1867  11
         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  32
         if (str == null || searchStr == null) {
 1904  6
             return INDEX_NOT_FOUND;
 1905  
         }
 1906  26
         if (startPos > str.length() - searchStr.length()) {
 1907  15
             startPos = str.length() - searchStr.length();
 1908  
         }
 1909  26
         if (startPos < 0) {
 1910  5
             return INDEX_NOT_FOUND;
 1911  
         }
 1912  21
         if (searchStr.length() == 0) {
 1913  6
             return startPos;
 1914  
         }
 1915  
 
 1916  31
         for (int i = startPos; i >= 0; i--) {
 1917  30
             if (CharSequenceUtils.regionMatches(str, true, i, searchStr, 0, searchStr.length())) {
 1918  14
                 return i;
 1919  
             }
 1920  
         }
 1921  1
         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  6
         if (isEmpty(seq)) {
 1948  2
             return false;
 1949  
         }
 1950  4
         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  35
         if (seq == null || searchSeq == null) {
 1977  8
             return false;
 1978  
         }
 1979  27
         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  40
         if (str == null || searchStr == null) {
 2008  7
             return false;
 2009  
         }
 2010  33
         final int len = searchStr.length();
 2011  33
         final int max = str.length() - len;
 2012  35
         for (int i = 0; i <= max; i++) {
 2013  26
             if (CharSequenceUtils.regionMatches(str, true, i, searchStr, 0, len)) {
 2014  24
                 return true;
 2015  
             }
 2016  
         }
 2017  9
         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  7
         if (isEmpty(seq)) {
 2033  1
             return false;
 2034  
         }
 2035  6
         final int strLen = seq.length();
 2036  9
         for (int i = 0; i < strLen; i++) {
 2037  8
             if (Character.isWhitespace(seq.charAt(i))) {
 2038  5
                 return true;
 2039  
             }
 2040  
         }
 2041  1
         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  22
         if (isEmpty(cs) || ArrayUtils.isEmpty(searchChars)) {
 2071  8
             return INDEX_NOT_FOUND;
 2072  
         }
 2073  14
         final int csLen = cs.length();
 2074  14
         final int csLast = csLen - 1;
 2075  14
         final int searchLen = searchChars.length;
 2076  14
         final int searchLast = searchLen - 1;
 2077  32
         for (int i = 0; i < csLen; i++) {
 2078  28
             final char ch = cs.charAt(i);
 2079  60
             for (int j = 0; j < searchLen; j++) {
 2080  42
                 if (searchChars[j] == ch) {
 2081  14
                     if (i < csLast && j < searchLast && Character.isHighSurrogate(ch)) {
 2082  
                         // ch is a supplementary character
 2083  10
                         if (searchChars[j + 1] == cs.charAt(i + 1)) {
 2084  6
                             return i;
 2085  
                         }
 2086  
                     } else {
 2087  4
                         return i;
 2088  
                     }
 2089  
                 }
 2090  
             }
 2091  
         }
 2092  4
         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  15
         if (isEmpty(cs) || isEmpty(searchChars)) {
 2120  8
             return INDEX_NOT_FOUND;
 2121  
         }
 2122  7
         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  53
         if (isEmpty(cs) || ArrayUtils.isEmpty(searchChars)) {
 2154  13
             return false;
 2155  
         }
 2156  40
         final int csLength = cs.length();
 2157  40
         final int searchLength = searchChars.length;
 2158  40
         final int csLast = csLength - 1;
 2159  40
         final int searchLast = searchLength - 1;
 2160  121
         for (int i = 0; i < csLength; i++) {
 2161  106
             final char ch = cs.charAt(i);
 2162  342
             for (int j = 0; j < searchLength; j++) {
 2163  261
                 if (searchChars[j] == ch) {
 2164  33
                     if (Character.isHighSurrogate(ch)) {
 2165  16
                         if (j == searchLast) {
 2166  
                             // missing low surrogate, fine, like String.indexOf(String)
 2167  2
                             return true;
 2168  
                         }
 2169  14
                         if (i < csLast && searchChars[j + 1] == cs.charAt(i + 1)) {
 2170  6
                             return true;
 2171  
                         }
 2172  
                     } else {
 2173  
                         // ch is in the Basic Multilingual Plane
 2174  17
                         return true;
 2175  
                     }
 2176  
                 }
 2177  
             }
 2178  
         }
 2179  15
         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  21
         if (searchChars == null) {
 2215  3
             return false;
 2216  
         }
 2217  18
         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  16
         if (isEmpty(cs) || ArrayUtils.isEmpty(searchCharSequences)) {
 2247  8
             return false;
 2248  
         }
 2249  15
         for (final CharSequence searchCharSequence : searchCharSequences) {
 2250  12
             if (contains(cs, searchCharSequence)) {
 2251  5
                 return true;
 2252  
             }
 2253  
         }
 2254  3
         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  37
         if (isEmpty(cs) || ArrayUtils.isEmpty(searchChars)) {
 2285  8
             return INDEX_NOT_FOUND;
 2286  
         }
 2287  29
         final int csLen = cs.length();
 2288  29
         final int csLast = csLen - 1;
 2289  29
         final int searchLen = searchChars.length;
 2290  29
         final int searchLast = searchLen - 1;
 2291  
         outer:
 2292  30053
         for (int i = 0; i < csLen; i++) {
 2293  30038
             final char ch = cs.charAt(i);
 2294  30065
             for (int j = 0; j < searchLen; j++) {
 2295  30051
                 if (searchChars[j] == ch) {
 2296  30027
                     if (i < csLast && j < searchLast && Character.isHighSurrogate(ch)) {
 2297  5
                         if (searchChars[j + 1] == cs.charAt(i + 1)) {
 2298  2
                             continue outer;
 2299  
                         }
 2300  
                     } else {
 2301  
                         continue outer;
 2302  
                     }
 2303  
                 }
 2304  
             }
 2305  14
             return i;
 2306  
         }
 2307  15
         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  15
         if (isEmpty(seq) || isEmpty(searchChars)) {
 2335  8
             return INDEX_NOT_FOUND;
 2336  
         }
 2337  7
         final int strLen = seq.length();
 2338  14
         for (int i = 0; i < strLen; i++) {
 2339  13
             final char ch = seq.charAt(i);
 2340  13
             final boolean chFound = CharSequenceUtils.indexOf(searchChars, ch, 0) >= 0;
 2341  13
             if (i + 1 < strLen && Character.isHighSurrogate(ch)) {
 2342  5
                 final char ch2 = seq.charAt(i + 1);
 2343  5
                 if (chFound && CharSequenceUtils.indexOf(searchChars, ch2, 0) < 0) {
 2344  3
                     return i;
 2345  
                 }
 2346  2
             } else {
 2347  8
                 if (!chFound) {
 2348  3
                     return i;
 2349  
                 }
 2350  
             }
 2351  
         }
 2352  1
         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  30
         if (valid == null || cs == null) {
 2382  3
             return false;
 2383  
         }
 2384  27
         if (cs.length() == 0) {
 2385  4
             return true;
 2386  
         }
 2387  23
         if (valid.length == 0) {
 2388  2
             return false;
 2389  
         }
 2390  21
         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  15
         if (cs == null || validChars == null) {
 2418  3
             return false;
 2419  
         }
 2420  12
         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  61
         if (cs == null || searchChars == null) {
 2450  3
             return true;
 2451  
         }
 2452  58
         final int csLen = cs.length();
 2453  58
         final int csLast = csLen - 1;
 2454  58
         final int searchLen = searchChars.length;
 2455  58
         final int searchLast = searchLen - 1;
 2456  164
         for (int i = 0; i < csLen; i++) {
 2457  128
             final char ch = cs.charAt(i);
 2458  456
             for (int j = 0; j < searchLen; j++) {
 2459  350
                 if (searchChars[j] == ch) {
 2460  30
                     if (Character.isHighSurrogate(ch)) {
 2461  16
                         if (j == searchLast) {
 2462  
                             // missing low surrogate, fine, like String.indexOf(String)
 2463  2
                             return false;
 2464  
                         }
 2465  14
                         if (i < csLast && searchChars[j + 1] == cs.charAt(i + 1)) {
 2466  6
                             return false;
 2467  
                         }
 2468  
                     } else {
 2469  
                         // ch is in the Basic Multilingual Plane
 2470  14
                         return false;
 2471  
                     }
 2472  
                 }
 2473  
             }
 2474  
         }
 2475  36
         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  24
         if (cs == null || invalidChars == null) {
 2503  3
             return true;
 2504  
         }
 2505  21
         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  14
         if (str == null || searchStrs == null) {
 2539  5
             return INDEX_NOT_FOUND;
 2540  
         }
 2541  
 
 2542  
         // String's can't have a MAX_VALUEth index.
 2543  9
         int ret = Integer.MAX_VALUE;
 2544  
 
 2545  9
         int tmp = 0;
 2546  17
         for (final CharSequence search : searchStrs) {
 2547  8
             if (search == null) {
 2548  2
                 continue;
 2549  
             }
 2550  6
             tmp = CharSequenceUtils.indexOf(str, search, 0);
 2551  6
             if (tmp == INDEX_NOT_FOUND) {
 2552  2
                 continue;
 2553  
             }
 2554  
 
 2555  4
             if (tmp < ret) {
 2556  3
                 ret = tmp;
 2557  
             }
 2558  
         }
 2559  
 
 2560  9
         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  18
         if (str == null || searchStrs == null) {
 2591  7
             return INDEX_NOT_FOUND;
 2592  
         }
 2593  11
         int ret = INDEX_NOT_FOUND;
 2594  11
         int tmp = 0;
 2595  20
         for (final CharSequence search : searchStrs) {
 2596  9
             if (search == null) {
 2597  3
                 continue;
 2598  
             }
 2599  6
             tmp = CharSequenceUtils.lastIndexOf(str, search, str.length());
 2600  6
             if (tmp > ret) {
 2601  4
                 ret = tmp;
 2602  
             }
 2603  
         }
 2604  11
         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  22
         if (str == null) {
 2635  1
             return null;
 2636  
         }
 2637  
 
 2638  
         // handle negatives, which means last n characters
 2639  21
         if (start < 0) {
 2640  8
             start = str.length() + start; // remember start is negative
 2641  
         }
 2642  
 
 2643  21
         if (start < 0) {
 2644  1
             start = 0;
 2645  
         }
 2646  21
         if (start > str.length()) {
 2647  3
             return EMPTY;
 2648  
         }
 2649  
 
 2650  18
         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  19
         if (str == null) {
 2690  2
             return null;
 2691  
         }
 2692  
 
 2693  
         // handle negatives
 2694  17
         if (end < 0) {
 2695  7
             end = str.length() + end; // remember end is negative
 2696  
         }
 2697  17
         if (start < 0) {
 2698  4
             start = str.length() + start; // remember start is negative
 2699  
         }
 2700  
 
 2701  
         // check length next
 2702  17
         if (end > str.length()) {
 2703  2
             end = str.length();
 2704  
         }
 2705  
 
 2706  
         // if start is greater than end, return ""
 2707  17
         if (start > end) {
 2708  2
             return EMPTY;
 2709  
         }
 2710  
 
 2711  15
         if (start < 0) {
 2712  1
             start = 0;
 2713  
         }
 2714  15
         if (end < 0) {
 2715  1
             end = 0;
 2716  
         }
 2717  
 
 2718  15
         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  10
         if (str == null) {
 2745  3
             return null;
 2746  
         }
 2747  7
         if (len < 0) {
 2748  2
             return EMPTY;
 2749  
         }
 2750  5
         if (str.length() <= len) {
 2751  3
             return str;
 2752  
         }
 2753  2
         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  10
         if (str == null) {
 2778  3
             return null;
 2779  
         }
 2780  7
         if (len < 0) {
 2781  2
             return EMPTY;
 2782  
         }
 2783  5
         if (str.length() <= len) {
 2784  3
             return str;
 2785  
         }
 2786  2
         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  16
         if (str == null) {
 2816  4
             return null;
 2817  
         }
 2818  12
         if (len < 0 || pos > str.length()) {
 2819  3
             return EMPTY;
 2820  
         }
 2821  9
         if (pos < 0) {
 2822  1
             pos = 0;
 2823  
         }
 2824  9
         if (str.length() <= pos + len) {
 2825  5
             return str.substring(pos);
 2826  
         }
 2827  4
         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  14
         if (isEmpty(str) || separator == null) {
 2861  7
             return str;
 2862  
         }
 2863  7
         if (separator.isEmpty()) {
 2864  1
             return EMPTY;
 2865  
         }
 2866  6
         final int pos = str.indexOf(separator);
 2867  6
         if (pos == INDEX_NOT_FOUND) {
 2868  1
             return str;
 2869  
         }
 2870  5
         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  14
         if (isEmpty(str)) {
 2903  6
             return str;
 2904  
         }
 2905  8
         if (separator == null) {
 2906  1
             return EMPTY;
 2907  
         }
 2908  7
         final int pos = str.indexOf(separator);
 2909  7
         if (pos == INDEX_NOT_FOUND) {
 2910  1
             return EMPTY;
 2911  
         }
 2912  6
         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  18
         if (isEmpty(str) || isEmpty(separator)) {
 2944  9
             return str;
 2945  
         }
 2946  9
         final int pos = str.lastIndexOf(separator);
 2947  9
         if (pos == INDEX_NOT_FOUND) {
 2948  2
             return str;
 2949  
         }
 2950  7
         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  15
         if (isEmpty(str)) {
 2984  7
             return str;
 2985  
         }
 2986  8
         if (isEmpty(separator)) {
 2987  2
             return EMPTY;
 2988  
         }
 2989  6
         final int pos = str.lastIndexOf(separator);
 2990  6
         if (pos == INDEX_NOT_FOUND || pos == str.length() - separator.length()) {
 2991  2
             return EMPTY;
 2992  
         }
 2993  4
         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  10
         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  19
         if (str == null || open == null || close == null) {
 3052  5
             return null;
 3053  
         }
 3054  14
         final int start = str.indexOf(open);
 3055  14
         if (start != INDEX_NOT_FOUND) {
 3056  12
             final int end = str.indexOf(close, start + open.length());
 3057  12
             if (end != INDEX_NOT_FOUND) {
 3058  10
                 return str.substring(start + open.length(), end);
 3059  
             }
 3060  
         }
 3061  4
         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  14
         if (str == null || isEmpty(open) || isEmpty(close)) {
 3088  4
             return null;
 3089  
         }
 3090  10
         final int strLen = str.length();
 3091  10
         if (strLen == 0) {
 3092  1
             return ArrayUtils.EMPTY_STRING_ARRAY;
 3093  
         }
 3094  9
         final int closeLen = close.length();
 3095  9
         final int openLen = open.length();
 3096  9
         final List<String> list = new ArrayList<>();
 3097  9
         int pos = 0;
 3098  19
         while (pos < strLen - closeLen) {
 3099  17
             int start = str.indexOf(open, pos);
 3100  17
             if (start < 0) {
 3101  6
                 break;
 3102  
             }
 3103  11
             start += openLen;
 3104  11
             final int end = str.indexOf(close, start);
 3105  11
             if (end < 0) {
 3106  1
                 break;
 3107  
             }
 3108  10
             list.add(str.substring(start, end));
 3109  10
             pos = end + closeLen;
 3110  10
         }
 3111  9
         if (list.isEmpty()) {
 3112  3
             return null;
 3113  
         }
 3114  6
         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  5
         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  9
         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  3128
         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  6261
         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  5
         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  4
         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  5
         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  6
         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  20
         if (str == null) {
 3376  4
             return null;
 3377  
         }
 3378  
 
 3379  16
         final int len = str.length();
 3380  
 
 3381  16
         if (len == 0) {
 3382  4
             return ArrayUtils.EMPTY_STRING_ARRAY;
 3383  
         }
 3384  
 
 3385  12
         if (separator == null || EMPTY.equals(separator)) {
 3386  
             // Split on whitespace.
 3387  4
             return splitWorker(str, null, max, preserveAllTokens);
 3388  
         }
 3389  
 
 3390  8
         final int separatorLength = separator.length();
 3391  
 
 3392  8
         final ArrayList<String> substrings = new ArrayList<>();
 3393  8
         int numberOfSubstrings = 0;
 3394  8
         int beg = 0;
 3395  8
         int end = 0;
 3396  50
         while (end < len) {
 3397  42
             end = str.indexOf(separator, beg);
 3398  
 
 3399  42
             if (end > -1) {
 3400  36
                 if (end > beg) {
 3401  19
                     numberOfSubstrings += 1;
 3402  
 
 3403  19
                     if (numberOfSubstrings == max) {
 3404  1
                         end = len;
 3405  1
                         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  18
                         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  18
                         beg = end + separatorLength;
 3415  
                     }
 3416  
                 } else {
 3417  
                     // We found a consecutive occurrence of the separator, so skip it.
 3418  17
                     if (preserveAllTokens) {
 3419  16
                         numberOfSubstrings += 1;
 3420  16
                         if (numberOfSubstrings == max) {
 3421  1
                             end = len;
 3422  1
                             substrings.add(str.substring(beg));
 3423  
                         } else {
 3424  15
                             substrings.add(EMPTY);
 3425  
                         }
 3426  
                     }
 3427  17
                     beg = end + separatorLength;
 3428  
                 }
 3429  
             } else {
 3430  
                 // String.substring( beg ) goes from 'beg' to the end of the String.
 3431  6
                 substrings.add(str.substring(beg));
 3432  6
                 end = len;
 3433  
             }
 3434  
         }
 3435  
 
 3436  8
         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  11
         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  15
         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  24
         if (str == null) {
 3520  2
             return null;
 3521  
         }
 3522  22
         final int len = str.length();
 3523  22
         if (len == 0) {
 3524  4
             return ArrayUtils.EMPTY_STRING_ARRAY;
 3525  
         }
 3526  18
         final List<String> list = new ArrayList<>();
 3527  18
         int i = 0, start = 0;
 3528  18
         boolean match = false;
 3529  18
         boolean lastMatch = false;
 3530  114
         while (i < len) {
 3531  96
             if (str.charAt(i) == separatorChar) {
 3532  47
                 if (match || preserveAllTokens) {
 3533  45
                     list.add(str.substring(start, i));
 3534  45
                     match = false;
 3535  45
                     lastMatch = true;
 3536  
                 }
 3537  47
                 start = ++i;
 3538  47
                 continue;
 3539  
             }
 3540  49
             lastMatch = false;
 3541  49
             match = true;
 3542  49
             i++;
 3543  
         }
 3544  18
         if (match || preserveAllTokens && lastMatch) {
 3545  17
             list.add(str.substring(start, i));
 3546  
         }
 3547  18
         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  3128
         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  6265
         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  18797
         if (str == null) {
 3647  6
             return null;
 3648  
         }
 3649  18791
         final int len = str.length();
 3650  18791
         if (len == 0) {
 3651  6
             return ArrayUtils.EMPTY_STRING_ARRAY;
 3652  
         }
 3653  18785
         final List<String> list = new ArrayList<>();
 3654  18785
         int sizePlus1 = 1;
 3655  18785
         int i = 0, start = 0;
 3656  18785
         boolean match = false;
 3657  18785
         boolean lastMatch = false;
 3658  18785
         if (separatorChars == null) {
 3659  
             // Null separator means use whitespace
 3660  56428
             while (i < len) {
 3661  47047
                 if (Character.isWhitespace(str.charAt(i))) {
 3662  21948
                     if (match || preserveAllTokens) {
 3663  18795
                         lastMatch = true;
 3664  18795
                         if (sizePlus1++ == max) {
 3665  3126
                             i = len;
 3666  3126
                             lastMatch = false;
 3667  
                         }
 3668  18795
                         list.add(str.substring(start, i));
 3669  18795
                         match = false;
 3670  
                     }
 3671  21948
                     start = ++i;
 3672  21948
                     continue;
 3673  
                 }
 3674  25099
                 lastMatch = false;
 3675  25099
                 match = true;
 3676  25099
                 i++;
 3677  
             }
 3678  9404
         } else if (separatorChars.length() == 1) {
 3679  
             // Optimise 1 character case
 3680  9392
             final char sep = separatorChars.charAt(0);
 3681  56364
             while (i < len) {
 3682  46972
                 if (str.charAt(i) == sep) {
 3683  21922
                     if (match || preserveAllTokens) {
 3684  18794
                         lastMatch = true;
 3685  18794
                         if (sizePlus1++ == max) {
 3686  3136
                             i = len;
 3687  3136
                             lastMatch = false;
 3688  
                         }
 3689  18794
                         list.add(str.substring(start, i));
 3690  18794
                         match = false;
 3691  
                     }
 3692  21922
                     start = ++i;
 3693  21922
                     continue;
 3694  
                 }
 3695  25050
                 lastMatch = false;
 3696  25050
                 match = true;
 3697  25050
                 i++;
 3698  
             }
 3699  9392
         } else {
 3700  
             // standard case
 3701  72
             while (i < len) {
 3702  60
                 if (separatorChars.indexOf(str.charAt(i)) >= 0) {
 3703  28
                     if (match || preserveAllTokens) {
 3704  24
                         lastMatch = true;
 3705  24
                         if (sizePlus1++ == max) {
 3706  4
                             i = len;
 3707  4
                             lastMatch = false;
 3708  
                         }
 3709  24
                         list.add(str.substring(start, i));
 3710  24
                         match = false;
 3711  
                     }
 3712  28
                     start = ++i;
 3713  28
                     continue;
 3714  
                 }
 3715  32
                 lastMatch = false;
 3716  32
                 match = true;
 3717  32
                 i++;
 3718  
             }
 3719  
         }
 3720  18785
         if (match || preserveAllTokens && lastMatch) {
 3721  10955
             list.add(str.substring(start, i));
 3722  
         }
 3723  18785
         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  9
         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  9
         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  18
         if (str == null) {
 3793  2
             return null;
 3794  
         }
 3795  16
         if (str.isEmpty()) {
 3796  2
             return ArrayUtils.EMPTY_STRING_ARRAY;
 3797  
         }
 3798  14
         final char[] c = str.toCharArray();
 3799  14
         final List<String> list = new ArrayList<>();
 3800  14
         int tokenStart = 0;
 3801  14
         int currentType = Character.getType(c[tokenStart]);
 3802  112
         for (int pos = tokenStart + 1; pos < c.length; pos++) {
 3803  98
             final int type = Character.getType(c[pos]);
 3804  98
             if (type == currentType) {
 3805  60
                 continue;
 3806  
             }
 3807  38
             if (camelCase && type == Character.LOWERCASE_LETTER && currentType == Character.UPPERCASE_LETTER) {
 3808  3
                 final int newTokenStart = pos - 1;
 3809  3
                 if (newTokenStart != tokenStart) {
 3810  1
                     list.add(new String(c, tokenStart, newTokenStart - tokenStart));
 3811  1
                     tokenStart = newTokenStart;
 3812  
                 }
 3813  3
             } else {
 3814  35
                 list.add(new String(c, tokenStart, pos - tokenStart));
 3815  35
                 tokenStart = pos;
 3816  
             }
 3817  38
             currentType = type;
 3818  
         }
 3819  14
         list.add(new String(c, tokenStart, c.length - tokenStart));
 3820  14
         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  24
         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  16
         if (array == null) {
 3876  1
             return null;
 3877  
         }
 3878  15
         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  2
         if (array == null) {
 3908  1
             return null;
 3909  
         }
 3910  1
         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  2
         if (array == null) {
 3940  1
             return null;
 3941  
         }
 3942  1
         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  2
         if (array == null) {
 3972  1
             return null;
 3973  
         }
 3974  1
         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  2
         if (array == null) {
 4004  1
             return null;
 4005  
         }
 4006  1
         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  2
         if (array == null) {
 4036  1
             return null;
 4037  
         }
 4038  1
         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  2
         if (array == null) {
 4068  1
             return null;
 4069  
         }
 4070  1
         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  2
         if (array == null) {
 4100  1
             return null;
 4101  
         }
 4102  1
         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  22
         if (array == null) {
 4134  1
             return null;
 4135  
         }
 4136  21
         final int noOfItems = endIndex - startIndex;
 4137  21
         if (noOfItems <= 0) {
 4138  4
             return EMPTY;
 4139  
         }
 4140  17
         final StringBuilder buf = new StringBuilder(noOfItems * 16);
 4141  55
         for (int i = startIndex; i < endIndex; i++) {
 4142  38
             if (i > startIndex) {
 4143  21
                 buf.append(separator);
 4144  
             }
 4145  38
             if (array[i] != null) {
 4146  36
                 buf.append(array[i]);
 4147  
             }
 4148  
         }
 4149  17
         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  5
         if (array == null) {
 4185  1
             return null;
 4186  
         }
 4187  4
         final int noOfItems = endIndex - startIndex;
 4188  4
         if (noOfItems <= 0) {
 4189  2
             return EMPTY;
 4190  
         }
 4191  2
         final StringBuilder buf = new StringBuilder(noOfItems * 16);
 4192  5
         for (int i = startIndex; i < endIndex; i++) {
 4193  3
             if (i > startIndex) {
 4194  1
                 buf.append(separator);
 4195  
             }
 4196  3
             buf.append(array[i]);
 4197  
         }
 4198  2
         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  5
         if (array == null) {
 4234  1
             return null;
 4235  
         }
 4236  4
         final int noOfItems = endIndex - startIndex;
 4237  4
         if (noOfItems <= 0) {
 4238  2
             return EMPTY;
 4239  
         }
 4240  2
         final StringBuilder buf = new StringBuilder(noOfItems * 16);
 4241  5
         for (int i = startIndex; i < endIndex; i++) {
 4242  3
             if (i > startIndex) {
 4243  1
                 buf.append(separator);
 4244  
             }
 4245  3
             buf.append(array[i]);
 4246  
         }
 4247  2
         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  5
         if (array == null) {
 4283  1
             return null;
 4284  
         }
 4285  4
         final int noOfItems = endIndex - startIndex;
 4286  4
         if (noOfItems <= 0) {
 4287  2
             return EMPTY;
 4288  
         }
 4289  2
         final StringBuilder buf = new StringBuilder(noOfItems * 16);
 4290  5
         for (int i = startIndex; i < endIndex; i++) {
 4291  3
             if (i > startIndex) {
 4292  1
                 buf.append(separator);
 4293  
             }
 4294  3
             buf.append(array[i]);
 4295  
         }
 4296  2
         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  5
         if (array == null) {
 4332  1
             return null;
 4333  
         }
 4334  4
         final int noOfItems = endIndex - startIndex;
 4335  4
         if (noOfItems <= 0) {
 4336  2
             return EMPTY;
 4337  
         }
 4338  2
         final StringBuilder buf = new StringBuilder(noOfItems * 16);
 4339  5
         for (int i = startIndex; i < endIndex; i++) {
 4340  3
             if (i > startIndex) {
 4341  1
                 buf.append(separator);
 4342  
             }
 4343  3
             buf.append(array[i]);
 4344  
         }
 4345  2
         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  5
         if (array == null) {
 4381  1
             return null;
 4382  
         }
 4383  4
         final int noOfItems = endIndex - startIndex;
 4384  4
         if (noOfItems <= 0) {
 4385  2
             return EMPTY;
 4386  
         }
 4387  2
         final StringBuilder buf = new StringBuilder(noOfItems * 16);
 4388  5
         for (int i = startIndex; i < endIndex; i++) {
 4389  3
             if (i > startIndex) {
 4390  1
                 buf.append(separator);
 4391  
             }
 4392  3
             buf.append(array[i]);
 4393  
         }
 4394  2
         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  5
         if (array == null) {
 4430  1
             return null;
 4431  
         }
 4432  4
         final int noOfItems = endIndex - startIndex;
 4433  4
         if (noOfItems <= 0) {
 4434  2
             return EMPTY;
 4435  
         }
 4436  2
         final StringBuilder buf = new StringBuilder(noOfItems * 16);
 4437  5
         for (int i = startIndex; i < endIndex; i++) {
 4438  3
             if (i > startIndex) {
 4439  1
                 buf.append(separator);
 4440  
             }
 4441  3
             buf.append(array[i]);
 4442  
         }
 4443  2
         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  5
         if (array == null) {
 4479  1
             return null;
 4480  
         }
 4481  4
         final int noOfItems = endIndex - startIndex;
 4482  4
         if (noOfItems <= 0) {
 4483  2
             return EMPTY;
 4484  
         }
 4485  2
         final StringBuilder buf = new StringBuilder(noOfItems * 16);
 4486  5
         for (int i = startIndex; i < endIndex; i++) {
 4487  3
             if (i > startIndex) {
 4488  1
                 buf.append(separator);
 4489  
             }
 4490  3
             buf.append(array[i]);
 4491  
         }
 4492  2
         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  34
         if (array == null) {
 4521  3
             return null;
 4522  
         }
 4523  31
         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  37
         if (array == null) {
 4563  0
             return null;
 4564  
         }
 4565  37
         if (separator == null) {
 4566  25
             separator = EMPTY;
 4567  
         }
 4568  
 
 4569  
         // endIndex - startIndex > 0:   Len = NofStrings *(len(firstString) + len(separator))
 4570  
         //           (Assuming that all Strings are roughly equally long)
 4571  37
         final int noOfItems = endIndex - startIndex;
 4572  37
         if (noOfItems <= 0) {
 4573  10
             return EMPTY;
 4574  
         }
 4575  
 
 4576  27
         final StringBuilder buf = new StringBuilder(noOfItems * 16);
 4577  
 
 4578  102
         for (int i = startIndex; i < endIndex; i++) {
 4579  75
             if (i > startIndex) {
 4580  48
                 buf.append(separator);
 4581  
             }
 4582  75
             if (array[i] != null) {
 4583  66
                 buf.append(array[i]);
 4584  
             }
 4585  
         }
 4586  27
         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  9
         if (iterator == null) {
 4607  1
             return null;
 4608  
         }
 4609  8
         if (!iterator.hasNext()) {
 4610  2
             return EMPTY;
 4611  
         }
 4612  6
         final Object first = iterator.next();
 4613  6
         if (!iterator.hasNext()) {
 4614  4
             final String result = Objects.toString(first, "");
 4615  4
             return result;
 4616  
         }
 4617  
 
 4618  
         // two or more elements
 4619  2
         final StringBuilder buf = new StringBuilder(256); // Java default is 16, probably too small
 4620  2
         if (first != null) {
 4621  2
             buf.append(first);
 4622  
         }
 4623  
 
 4624  6
         while (iterator.hasNext()) {
 4625  4
             buf.append(separator);
 4626  4
             final Object obj = iterator.next();
 4627  4
             if (obj != null) {
 4628  4
                 buf.append(obj);
 4629  
             }
 4630  4
         }
 4631  
 
 4632  2
         return buf.toString();
 4633  
     }
 4634  
 
 4635  
     /**
 4636  
      * <p>Joins the elements of the provided {@code Iterator} into
 4637  
      * a single String containing the provided elements.</p>
 4638  
      *
 4639  
      * <p>No delimiter is added before or after the list.
 4640  
      * A {@code null} separator is the same as an empty String ("").</p>
 4641  
      *
 4642  
      * <p>See the examples here: {@link #join(Object[],String)}. </p>
 4643  
      *
 4644  
      * @param iterator  the {@code Iterator} of values to join together, may be null
 4645  
      * @param separator  the separator character to use, null treated as ""
 4646  
      * @return the joined String, {@code null} if null iterator input
 4647  
      */
 4648  
     public static String join(final Iterator<?> iterator, final String separator) {
 4649  
 
 4650  
         // handle null, zero and one elements before building a buffer
 4651  20
         if (iterator == null) {
 4652  1
             return null;
 4653  
         }
 4654  19
         if (!iterator.hasNext()) {
 4655  6
             return EMPTY;
 4656  
         }
 4657  13
         final Object first = iterator.next();
 4658  13
         if (!iterator.hasNext()) {
 4659  7
             final String result = Objects.toString(first, "");
 4660  7
             return result;
 4661  
         }
 4662  
 
 4663  
         // two or more elements
 4664  6
         final StringBuilder buf = new StringBuilder(256); // Java default is 16, probably too small
 4665  6
         if (first != null) {
 4666  6
             buf.append(first);
 4667  
         }
 4668  
 
 4669  18
         while (iterator.hasNext()) {
 4670  12
             if (separator != null) {
 4671  8
                 buf.append(separator);
 4672  
             }
 4673  12
             final Object obj = iterator.next();
 4674  12
             if (obj != null) {
 4675  12
                 buf.append(obj);
 4676  
             }
 4677  12
         }
 4678  6
         return buf.toString();
 4679  
     }
 4680  
 
 4681  
     /**
 4682  
      * <p>Joins the elements of the provided {@code Iterable} into
 4683  
      * a single String containing the provided elements.</p>
 4684  
      *
 4685  
      * <p>No delimiter is added before or after the list. Null objects or empty
 4686  
      * strings within the iteration are represented by empty strings.</p>
 4687  
      *
 4688  
      * <p>See the examples here: {@link #join(Object[],char)}. </p>
 4689  
      *
 4690  
      * @param iterable  the {@code Iterable} providing the values to join together, may be null
 4691  
      * @param separator  the separator character to use
 4692  
      * @return the joined String, {@code null} if null iterator input
 4693  
      * @since 2.3
 4694  
      */
 4695  
     public static String join(final Iterable<?> iterable, final char separator) {
 4696  5
         if (iterable == null) {
 4697  1
             return null;
 4698  
         }
 4699  4
         return join(iterable.iterator(), separator);
 4700  
     }
 4701  
 
 4702  
     /**
 4703  
      * <p>Joins the elements of the provided {@code Iterable} into
 4704  
      * a single String containing the provided elements.</p>
 4705  
      *
 4706  
      * <p>No delimiter is added before or after the list.
 4707  
      * A {@code null} separator is the same as an empty String ("").</p>
 4708  
      *
 4709  
      * <p>See the examples here: {@link #join(Object[],String)}. </p>
 4710  
      *
 4711  
      * @param iterable  the {@code Iterable} providing the values to join together, may be null
 4712  
      * @param separator  the separator character to use, null treated as ""
 4713  
      * @return the joined String, {@code null} if null iterator input
 4714  
      * @since 2.3
 4715  
      */
 4716  
     public static String join(final Iterable<?> iterable, final String separator) {
 4717  10
         if (iterable == null) {
 4718  1
             return null;
 4719  
         }
 4720  9
         return join(iterable.iterator(), separator);
 4721  
     }
 4722  
 
 4723  
     /**
 4724  
      * <p>Joins the elements of the provided varargs into a
 4725  
      * single String containing the provided elements.</p>
 4726  
      *
 4727  
      * <p>No delimiter is added before or after the list.
 4728  
      * {@code null} elements and separator are treated as empty Strings ("").</p>
 4729  
      *
 4730  
      * <pre>
 4731  
      * StringUtils.joinWith(",", {"a", "b"})        = "a,b"
 4732  
      * StringUtils.joinWith(",", {"a", "b",""})     = "a,b,"
 4733  
      * StringUtils.joinWith(",", {"a", null, "b"})  = "a,,b"
 4734  
      * StringUtils.joinWith(null, {"a", "b"})       = "ab"
 4735  
      * </pre>
 4736  
      *
 4737  
      * @param separator the separator character to use, null treated as ""
 4738  
      * @param objects the varargs providing the values to join together. {@code null} elements are treated as ""
 4739  
      * @return the joined String.
 4740  
      * @throws java.lang.IllegalArgumentException if a null varargs is provided
 4741  
      * @since 3.5
 4742  
      */
 4743  
     public static String joinWith(final String separator, final Object... objects) {
 4744  7
         if (objects == null) {
 4745  1
             throw new IllegalArgumentException("Object varargs must not be null");
 4746  
         }
 4747  
 
 4748  6
         final String sanitizedSeparator = defaultString(separator, StringUtils.EMPTY);
 4749  
 
 4750  6
         final StringBuilder result = new StringBuilder();
 4751  
 
 4752  6
         final Iterator<Object> iterator = Arrays.asList(objects).iterator();
 4753  16
         while (iterator.hasNext()) {
 4754  10
             final String value = Objects.toString(iterator.next(), "");
 4755  10
             result.append(value);
 4756  
 
 4757  10
             if (iterator.hasNext()) {
 4758  5
                 result.append(sanitizedSeparator);
 4759  
             }
 4760  10
         }
 4761  
 
 4762  6
         return result.toString();
 4763  
     }
 4764  
 
 4765  
     // Delete
 4766  
     //-----------------------------------------------------------------------
 4767  
     /**
 4768  
      * <p>Deletes all whitespaces from a String as defined by
 4769  
      * {@link Character#isWhitespace(char)}.</p>
 4770  
      *
 4771  
      * <pre>
 4772  
      * StringUtils.deleteWhitespace(null)         = null
 4773  
      * StringUtils.deleteWhitespace("")           = ""
 4774  
      * StringUtils.deleteWhitespace("abc")        = "abc"
 4775  
      * StringUtils.deleteWhitespace("   ab  c  ") = "abc"
 4776  
      * </pre>
 4777  
      *
 4778  
      * @param str  the String to delete whitespace from, may be null
 4779  
      * @return the String without whitespaces, {@code null} if null String input
 4780  
      */
 4781  
     public static String deleteWhitespace(final String str) {
 4782  134
         if (isEmpty(str)) {
 4783  3
             return str;
 4784  
         }
 4785  131
         final int sz = str.length();
 4786  131
         final char[] chs = new char[sz];
 4787  131
         int count = 0;
 4788  2950
         for (int i = 0; i < sz; i++) {
 4789  2819
             if (!Character.isWhitespace(str.charAt(i))) {
 4790  2721
                 chs[count++] = str.charAt(i);
 4791  
             }
 4792  
         }
 4793  131
         if (count == sz) {
 4794  123
             return str;
 4795  
         }
 4796  8
         return new String(chs, 0, count);
 4797  
     }
 4798  
 
 4799  
     // Remove
 4800  
     //-----------------------------------------------------------------------
 4801  
     /**
 4802  
      * <p>Removes a substring only if it is at the beginning of a source string,
 4803  
      * otherwise returns the source string.</p>
 4804  
      *
 4805  
      * <p>A {@code null} source string will return {@code null}.
 4806  
      * An empty ("") source string will return the empty string.
 4807  
      * A {@code null} search string will return the source string.</p>
 4808  
      *
 4809  
      * <pre>
 4810  
      * StringUtils.removeStart(null, *)      = null
 4811  
      * StringUtils.removeStart("", *)        = ""
 4812  
      * StringUtils.removeStart(*, null)      = *
 4813  
      * StringUtils.removeStart("www.domain.com", "www.")   = "domain.com"
 4814  
      * StringUtils.removeStart("domain.com", "www.")       = "domain.com"
 4815  
      * StringUtils.removeStart("www.domain.com", "domain") = "www.domain.com"
 4816  
      * StringUtils.removeStart("abc", "")    = "abc"
 4817  
      * </pre>
 4818  
      *
 4819  
      * @param str  the source String to search, may be null
 4820  
      * @param remove  the String to search for and remove, may be null
 4821  
      * @return the substring with the string removed if found,
 4822  
      *  {@code null} if null String input
 4823  
      * @since 2.1
 4824  
      */
 4825  
     public static String removeStart(final String str, final String remove) {
 4826  10
         if (isEmpty(str) || isEmpty(remove)) {
 4827  8
             return str;
 4828  
         }
 4829  2
         if (str.startsWith(remove)){
 4830  1
             return str.substring(remove.length());
 4831  
         }
 4832  1
         return str;
 4833  
     }
 4834  
 
 4835  
     /**
 4836  
      * <p>Case insensitive removal of a substring if it is at the beginning of a source string,
 4837  
      * otherwise returns the source string.</p>
 4838  
      *
 4839  
      * <p>A {@code null} source string will return {@code null}.
 4840  
      * An empty ("") source string will return the empty string.
 4841  
      * A {@code null} search string will return the source string.</p>
 4842  
      *
 4843  
      * <pre>
 4844  
      * StringUtils.removeStartIgnoreCase(null, *)      = null
 4845  
      * StringUtils.removeStartIgnoreCase("", *)        = ""
 4846  
      * StringUtils.removeStartIgnoreCase(*, null)      = *
 4847  
      * StringUtils.removeStartIgnoreCase("www.domain.com", "www.")   = "domain.com"
 4848  
      * StringUtils.removeStartIgnoreCase("www.domain.com", "WWW.")   = "domain.com"
 4849  
      * StringUtils.removeStartIgnoreCase("domain.com", "www.")       = "domain.com"
 4850  
      * StringUtils.removeStartIgnoreCase("www.domain.com", "domain") = "www.domain.com"
 4851  
      * StringUtils.removeStartIgnoreCase("abc", "")    = "abc"
 4852  
      * </pre>
 4853  
      *
 4854  
      * @param str  the source String to search, may be null
 4855  
      * @param remove  the String to search for (case insensitive) and remove, may be null
 4856  
      * @return the substring with the string removed if found,
 4857  
      *  {@code null} if null String input
 4858  
      * @since 2.4
 4859  
      */
 4860  
     public static String removeStartIgnoreCase(final String str, final String remove) {
 4861  11
         if (isEmpty(str) || isEmpty(remove)) {
 4862  8
             return str;
 4863  
         }
 4864  3
         if (startsWithIgnoreCase(str, remove)) {
 4865  2
             return str.substring(remove.length());
 4866  
         }
 4867  1
         return str;
 4868  
     }
 4869  
 
 4870  
     /**
 4871  
      * <p>Removes a substring only if it is at the end of a source string,
 4872  
      * otherwise returns the source string.</p>
 4873  
      *
 4874  
      * <p>A {@code null} source string will return {@code null}.
 4875  
      * An empty ("") source string will return the empty string.
 4876  
      * A {@code null} search string will return the source string.</p>
 4877  
      *
 4878  
      * <pre>
 4879  
      * StringUtils.removeEnd(null, *)      = null
 4880  
      * StringUtils.removeEnd("", *)        = ""
 4881  
      * StringUtils.removeEnd(*, null)      = *
 4882  
      * StringUtils.removeEnd("www.domain.com", ".com.")  = "www.domain.com"
 4883  
      * StringUtils.removeEnd("www.domain.com", ".com")   = "www.domain"
 4884