001 /* 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017 package org.apache.commons.lang3; 018 019 import java.lang.reflect.InvocationTargetException; 020 import java.lang.reflect.Method; 021 import java.util.ArrayList; 022 import java.util.Arrays; 023 import java.util.Iterator; 024 import java.util.List; 025 import java.util.Locale; 026 import java.util.regex.Pattern; 027 028 /** 029 * <p>Operations on {@link java.lang.String} that are 030 * {@code null} safe.</p> 031 * 032 * <ul> 033 * <li><b>IsEmpty/IsBlank</b> 034 * - checks if a String contains text</li> 035 * <li><b>Trim/Strip</b> 036 * - removes leading and trailing whitespace</li> 037 * <li><b>Equals</b> 038 * - compares two strings null-safe</li> 039 * <li><b>startsWith</b> 040 * - check if a String starts with a prefix null-safe</li> 041 * <li><b>endsWith</b> 042 * - check if a String ends with a suffix null-safe</li> 043 * <li><b>IndexOf/LastIndexOf/Contains</b> 044 * - null-safe index-of checks 045 * <li><b>IndexOfAny/LastIndexOfAny/IndexOfAnyBut/LastIndexOfAnyBut</b> 046 * - index-of any of a set of Strings</li> 047 * <li><b>ContainsOnly/ContainsNone/ContainsAny</b> 048 * - does String contains only/none/any of these characters</li> 049 * <li><b>Substring/Left/Right/Mid</b> 050 * - null-safe substring extractions</li> 051 * <li><b>SubstringBefore/SubstringAfter/SubstringBetween</b> 052 * - substring extraction relative to other strings</li> 053 * <li><b>Split/Join</b> 054 * - splits a String into an array of substrings and vice versa</li> 055 * <li><b>Remove/Delete</b> 056 * - removes part of a String</li> 057 * <li><b>Replace/Overlay</b> 058 * - Searches a String and replaces one String with another</li> 059 * <li><b>Chomp/Chop</b> 060 * - removes the last part of a String</li> 061 * <li><b>LeftPad/RightPad/Center/Repeat</b> 062 * - pads a String</li> 063 * <li><b>UpperCase/LowerCase/SwapCase/Capitalize/Uncapitalize</b> 064 * - changes the case of a String</li> 065 * <li><b>CountMatches</b> 066 * - counts the number of occurrences of one String in another</li> 067 * <li><b>IsAlpha/IsNumeric/IsWhitespace/IsAsciiPrintable</b> 068 * - checks the characters in a String</li> 069 * <li><b>DefaultString</b> 070 * - protects against a null input String</li> 071 * <li><b>Reverse/ReverseDelimited</b> 072 * - reverses a String</li> 073 * <li><b>Abbreviate</b> 074 * - abbreviates a string using ellipsis</li> 075 * <li><b>Difference</b> 076 * - compares Strings and reports on their differences</li> 077 * <li><b>LevenshteinDistance</b> 078 * - the number of changes needed to change one String into another</li> 079 * </ul> 080 * 081 * <p>The {@code StringUtils} class defines certain words related to 082 * String handling.</p> 083 * 084 * <ul> 085 * <li>null - {@code null}</li> 086 * <li>empty - a zero-length string ({@code ""})</li> 087 * <li>space - the space character ({@code ' '}, char 32)</li> 088 * <li>whitespace - the characters defined by {@link Character#isWhitespace(char)}</li> 089 * <li>trim - the characters <= 32 as in {@link String#trim()}</li> 090 * </ul> 091 * 092 * <p>{@code StringUtils} handles {@code null} input Strings quietly. 093 * That is to say that a {@code null} input will return {@code null}. 094 * Where a {@code boolean} or {@code int} is being returned 095 * details vary by method.</p> 096 * 097 * <p>A side effect of the {@code null} handling is that a 098 * {@code NullPointerException} should be considered a bug in 099 * {@code StringUtils}.</p> 100 * 101 * <p>Methods in this class give sample code to explain their operation. 102 * The symbol {@code *} is used to indicate any input including {@code null}.</p> 103 * 104 * <p>#ThreadSafe#</p> 105 * @see java.lang.String 106 * @since 1.0 107 * @version $Id: StringUtils.java 1144929 2011-07-10 18:26:16Z ggregory $ 108 */ 109 //@Immutable 110 public class StringUtils { 111 // Performance testing notes (JDK 1.4, Jul03, scolebourne) 112 // Whitespace: 113 // Character.isWhitespace() is faster than WHITESPACE.indexOf() 114 // where WHITESPACE is a string of all whitespace characters 115 // 116 // Character access: 117 // String.charAt(n) versus toCharArray(), then array[n] 118 // String.charAt(n) is about 15% worse for a 10K string 119 // They are about equal for a length 50 string 120 // String.charAt(n) is about 4 times better for a length 3 string 121 // String.charAt(n) is best bet overall 122 // 123 // Append: 124 // String.concat about twice as fast as StringBuffer.append 125 // (not sure who tested this) 126 127 /** 128 * The empty String {@code ""}. 129 * @since 2.0 130 */ 131 public static final String EMPTY = ""; 132 133 /** 134 * Represents a failed index search. 135 * @since 2.1 136 */ 137 public static final int INDEX_NOT_FOUND = -1; 138 139 /** 140 * <p>The maximum size to which the padding constant(s) can expand.</p> 141 */ 142 private static final int PAD_LIMIT = 8192; 143 144 /** 145 * A regex pattern for recognizing blocks of whitespace characters. 146 */ 147 private static final Pattern WHITESPACE_BLOCK = Pattern.compile("\\s+"); 148 149 /** 150 * <p>{@code StringUtils} instances should NOT be constructed in 151 * standard programming. Instead, the class should be used as 152 * {@code StringUtils.trim(" foo ");}.</p> 153 * 154 * <p>This constructor is public to permit tools that require a JavaBean 155 * instance to operate.</p> 156 */ 157 public StringUtils() { 158 super(); 159 } 160 161 // Empty checks 162 //----------------------------------------------------------------------- 163 /** 164 * <p>Checks if a CharSequence is empty ("") or null.</p> 165 * 166 * <pre> 167 * StringUtils.isEmpty(null) = true 168 * StringUtils.isEmpty("") = true 169 * StringUtils.isEmpty(" ") = false 170 * StringUtils.isEmpty("bob") = false 171 * StringUtils.isEmpty(" bob ") = false 172 * </pre> 173 * 174 * <p>NOTE: This method changed in Lang version 2.0. 175 * It no longer trims the CharSequence. 176 * That functionality is available in isBlank().</p> 177 * 178 * @param cs the CharSequence to check, may be null 179 * @return {@code true} if the CharSequence is empty or null 180 * @since 3.0 Changed signature from isEmpty(String) to isEmpty(CharSequence) 181 */ 182 public static boolean isEmpty(CharSequence cs) { 183 return cs == null || cs.length() == 0; 184 } 185 186 /** 187 * <p>Checks if a CharSequence is not empty ("") and not null.</p> 188 * 189 * <pre> 190 * StringUtils.isNotEmpty(null) = false 191 * StringUtils.isNotEmpty("") = false 192 * StringUtils.isNotEmpty(" ") = true 193 * StringUtils.isNotEmpty("bob") = true 194 * StringUtils.isNotEmpty(" bob ") = true 195 * </pre> 196 * 197 * @param cs the CharSequence to check, may be null 198 * @return {@code true} if the CharSequence is not empty and not null 199 * @since 3.0 Changed signature from isNotEmpty(String) to isNotEmpty(CharSequence) 200 */ 201 public static boolean isNotEmpty(CharSequence cs) { 202 return !StringUtils.isEmpty(cs); 203 } 204 205 /** 206 * <p>Checks if a CharSequence is whitespace, empty ("") or null.</p> 207 * 208 * <pre> 209 * StringUtils.isBlank(null) = true 210 * StringUtils.isBlank("") = true 211 * StringUtils.isBlank(" ") = true 212 * StringUtils.isBlank("bob") = false 213 * StringUtils.isBlank(" bob ") = false 214 * </pre> 215 * 216 * @param cs the CharSequence to check, may be null 217 * @return {@code true} if the CharSequence is null, empty or whitespace 218 * @since 2.0 219 * @since 3.0 Changed signature from isBlank(String) to isBlank(CharSequence) 220 */ 221 public static boolean isBlank(CharSequence cs) { 222 int strLen; 223 if (cs == null || (strLen = cs.length()) == 0) { 224 return true; 225 } 226 for (int i = 0; i < strLen; i++) { 227 if ((Character.isWhitespace(cs.charAt(i)) == false)) { 228 return false; 229 } 230 } 231 return true; 232 } 233 234 /** 235 * <p>Checks if a CharSequence is not empty (""), not null and not whitespace only.</p> 236 * 237 * <pre> 238 * StringUtils.isNotBlank(null) = false 239 * StringUtils.isNotBlank("") = false 240 * StringUtils.isNotBlank(" ") = false 241 * StringUtils.isNotBlank("bob") = true 242 * StringUtils.isNotBlank(" bob ") = true 243 * </pre> 244 * 245 * @param cs the CharSequence to check, may be null 246 * @return {@code true} if the CharSequence is 247 * not empty and not null and not whitespace 248 * @since 2.0 249 * @since 3.0 Changed signature from isNotBlank(String) to isNotBlank(CharSequence) 250 */ 251 public static boolean isNotBlank(CharSequence cs) { 252 return !StringUtils.isBlank(cs); 253 } 254 255 // Trim 256 //----------------------------------------------------------------------- 257 /** 258 * <p>Removes control characters (char <= 32) from both 259 * ends of this String, handling {@code null} by returning 260 * {@code null}.</p> 261 * 262 * <p>The String is trimmed using {@link String#trim()}. 263 * Trim removes start and end characters <= 32. 264 * To strip whitespace use {@link #strip(String)}.</p> 265 * 266 * <p>To trim your choice of characters, use the 267 * {@link #strip(String, String)} methods.</p> 268 * 269 * <pre> 270 * StringUtils.trim(null) = null 271 * StringUtils.trim("") = "" 272 * StringUtils.trim(" ") = "" 273 * StringUtils.trim("abc") = "abc" 274 * StringUtils.trim(" abc ") = "abc" 275 * </pre> 276 * 277 * @param str the String to be trimmed, may be null 278 * @return the trimmed string, {@code null} if null String input 279 */ 280 public static String trim(String str) { 281 return str == null ? null : str.trim(); 282 } 283 284 /** 285 * <p>Removes control characters (char <= 32) from both 286 * ends of this String returning {@code null} if the String is 287 * empty ("") after the trim or if it is {@code null}. 288 * 289 * <p>The String is trimmed using {@link String#trim()}. 290 * Trim removes start and end characters <= 32. 291 * To strip whitespace use {@link #stripToNull(String)}.</p> 292 * 293 * <pre> 294 * StringUtils.trimToNull(null) = null 295 * StringUtils.trimToNull("") = null 296 * StringUtils.trimToNull(" ") = null 297 * StringUtils.trimToNull("abc") = "abc" 298 * StringUtils.trimToNull(" abc ") = "abc" 299 * </pre> 300 * 301 * @param str the String to be trimmed, may be null 302 * @return the trimmed String, 303 * {@code null} if only chars <= 32, empty or null String input 304 * @since 2.0 305 */ 306 public static String trimToNull(String str) { 307 String ts = trim(str); 308 return isEmpty(ts) ? null : ts; 309 } 310 311 /** 312 * <p>Removes control characters (char <= 32) from both 313 * ends of this String returning an empty String ("") if the String 314 * is empty ("") after the trim or if it is {@code null}. 315 * 316 * <p>The String is trimmed using {@link String#trim()}. 317 * Trim removes start and end characters <= 32. 318 * To strip whitespace use {@link #stripToEmpty(String)}.</p> 319 * 320 * <pre> 321 * StringUtils.trimToEmpty(null) = "" 322 * StringUtils.trimToEmpty("") = "" 323 * StringUtils.trimToEmpty(" ") = "" 324 * StringUtils.trimToEmpty("abc") = "abc" 325 * StringUtils.trimToEmpty(" abc ") = "abc" 326 * </pre> 327 * 328 * @param str the String to be trimmed, may be null 329 * @return the trimmed String, or an empty String if {@code null} input 330 * @since 2.0 331 */ 332 public static String trimToEmpty(String str) { 333 return str == null ? EMPTY : str.trim(); 334 } 335 336 // Stripping 337 //----------------------------------------------------------------------- 338 /** 339 * <p>Strips whitespace from the start and end of a String.</p> 340 * 341 * <p>This is similar to {@link #trim(String)} but removes whitespace. 342 * Whitespace is defined by {@link Character#isWhitespace(char)}.</p> 343 * 344 * <p>A {@code null} input String returns {@code null}.</p> 345 * 346 * <pre> 347 * StringUtils.strip(null) = null 348 * StringUtils.strip("") = "" 349 * StringUtils.strip(" ") = "" 350 * StringUtils.strip("abc") = "abc" 351 * StringUtils.strip(" abc") = "abc" 352 * StringUtils.strip("abc ") = "abc" 353 * StringUtils.strip(" abc ") = "abc" 354 * StringUtils.strip(" ab c ") = "ab c" 355 * </pre> 356 * 357 * @param str the String to remove whitespace from, may be null 358 * @return the stripped String, {@code null} if null String input 359 */ 360 public static String strip(String str) { 361 return strip(str, null); 362 } 363 364 /** 365 * <p>Strips whitespace from the start and end of a String returning 366 * {@code null} if the String is empty ("") after the strip.</p> 367 * 368 * <p>This is similar to {@link #trimToNull(String)} but removes whitespace. 369 * Whitespace is defined by {@link Character#isWhitespace(char)}.</p> 370 * 371 * <pre> 372 * StringUtils.stripToNull(null) = null 373 * StringUtils.stripToNull("") = null 374 * StringUtils.stripToNull(" ") = null 375 * StringUtils.stripToNull("abc") = "abc" 376 * StringUtils.stripToNull(" abc") = "abc" 377 * StringUtils.stripToNull("abc ") = "abc" 378 * StringUtils.stripToNull(" abc ") = "abc" 379 * StringUtils.stripToNull(" ab c ") = "ab c" 380 * </pre> 381 * 382 * @param str the String to be stripped, may be null 383 * @return the stripped String, 384 * {@code null} if whitespace, empty or null String input 385 * @since 2.0 386 */ 387 public static String stripToNull(String str) { 388 if (str == null) { 389 return null; 390 } 391 str = strip(str, null); 392 return str.length() == 0 ? null : str; 393 } 394 395 /** 396 * <p>Strips whitespace from the start and end of a String returning 397 * an empty String if {@code null} input.</p> 398 * 399 * <p>This is similar to {@link #trimToEmpty(String)} but removes whitespace. 400 * Whitespace is defined by {@link Character#isWhitespace(char)}.</p> 401 * 402 * <pre> 403 * StringUtils.stripToEmpty(null) = "" 404 * StringUtils.stripToEmpty("") = "" 405 * StringUtils.stripToEmpty(" ") = "" 406 * StringUtils.stripToEmpty("abc") = "abc" 407 * StringUtils.stripToEmpty(" abc") = "abc" 408 * StringUtils.stripToEmpty("abc ") = "abc" 409 * StringUtils.stripToEmpty(" abc ") = "abc" 410 * StringUtils.stripToEmpty(" ab c ") = "ab c" 411 * </pre> 412 * 413 * @param str the String to be stripped, may be null 414 * @return the trimmed String, or an empty String if {@code null} input 415 * @since 2.0 416 */ 417 public static String stripToEmpty(String str) { 418 return str == null ? EMPTY : strip(str, null); 419 } 420 421 /** 422 * <p>Strips any of a set of characters from the start and end of a String. 423 * This is similar to {@link String#trim()} but allows the characters 424 * to be stripped to be controlled.</p> 425 * 426 * <p>A {@code null} input String returns {@code null}. 427 * An empty string ("") input returns the empty string.</p> 428 * 429 * <p>If the stripChars String is {@code null}, whitespace is 430 * stripped as defined by {@link Character#isWhitespace(char)}. 431 * Alternatively use {@link #strip(String)}.</p> 432 * 433 * <pre> 434 * StringUtils.strip(null, *) = null 435 * StringUtils.strip("", *) = "" 436 * StringUtils.strip("abc", null) = "abc" 437 * StringUtils.strip(" abc", null) = "abc" 438 * StringUtils.strip("abc ", null) = "abc" 439 * StringUtils.strip(" abc ", null) = "abc" 440 * StringUtils.strip(" abcyx", "xyz") = " abc" 441 * </pre> 442 * 443 * @param str the String to remove characters from, may be null 444 * @param stripChars the characters to remove, null treated as whitespace 445 * @return the stripped String, {@code null} if null String input 446 */ 447 public static String strip(String str, String stripChars) { 448 if (isEmpty(str)) { 449 return str; 450 } 451 str = stripStart(str, stripChars); 452 return stripEnd(str, stripChars); 453 } 454 455 /** 456 * <p>Strips any of a set of characters from the start of a String.</p> 457 * 458 * <p>A {@code null} input String returns {@code null}. 459 * An empty string ("") input returns the empty string.</p> 460 * 461 * <p>If the stripChars String is {@code null}, whitespace is 462 * stripped as defined by {@link Character#isWhitespace(char)}.</p> 463 * 464 * <pre> 465 * StringUtils.stripStart(null, *) = null 466 * StringUtils.stripStart("", *) = "" 467 * StringUtils.stripStart("abc", "") = "abc" 468 * StringUtils.stripStart("abc", null) = "abc" 469 * StringUtils.stripStart(" abc", null) = "abc" 470 * StringUtils.stripStart("abc ", null) = "abc " 471 * StringUtils.stripStart(" abc ", null) = "abc " 472 * StringUtils.stripStart("yxabc ", "xyz") = "abc " 473 * </pre> 474 * 475 * @param str the String to remove characters from, may be null 476 * @param stripChars the characters to remove, null treated as whitespace 477 * @return the stripped String, {@code null} if null String input 478 */ 479 public static String stripStart(String str, String stripChars) { 480 int strLen; 481 if (str == null || (strLen = str.length()) == 0) { 482 return str; 483 } 484 int start = 0; 485 if (stripChars == null) { 486 while ((start != strLen) && Character.isWhitespace(str.charAt(start))) { 487 start++; 488 } 489 } else if (stripChars.length() == 0) { 490 return str; 491 } else { 492 while ((start != strLen) && (stripChars.indexOf(str.charAt(start)) != INDEX_NOT_FOUND)) { 493 start++; 494 } 495 } 496 return str.substring(start); 497 } 498 499 /** 500 * <p>Strips any of a set of characters from the end of a String.</p> 501 * 502 * <p>A {@code null} input String returns {@code null}. 503 * An empty string ("") input returns the empty string.</p> 504 * 505 * <p>If the stripChars String is {@code null}, whitespace is 506 * stripped as defined by {@link Character#isWhitespace(char)}.</p> 507 * 508 * <pre> 509 * StringUtils.stripEnd(null, *) = null 510 * StringUtils.stripEnd("", *) = "" 511 * StringUtils.stripEnd("abc", "") = "abc" 512 * StringUtils.stripEnd("abc", null) = "abc" 513 * StringUtils.stripEnd(" abc", null) = " abc" 514 * StringUtils.stripEnd("abc ", null) = "abc" 515 * StringUtils.stripEnd(" abc ", null) = " abc" 516 * StringUtils.stripEnd(" abcyx", "xyz") = " abc" 517 * StringUtils.stripEnd("120.00", ".0") = "12" 518 * </pre> 519 * 520 * @param str the String to remove characters from, may be null 521 * @param stripChars the set of characters to remove, null treated as whitespace 522 * @return the stripped String, {@code null} if null String input 523 */ 524 public static String stripEnd(String str, String stripChars) { 525 int end; 526 if (str == null || (end = str.length()) == 0) { 527 return str; 528 } 529 530 if (stripChars == null) { 531 while ((end != 0) && Character.isWhitespace(str.charAt(end - 1))) { 532 end--; 533 } 534 } else if (stripChars.length() == 0) { 535 return str; 536 } else { 537 while ((end != 0) && (stripChars.indexOf(str.charAt(end - 1)) != INDEX_NOT_FOUND)) { 538 end--; 539 } 540 } 541 return str.substring(0, end); 542 } 543 544 // StripAll 545 //----------------------------------------------------------------------- 546 /** 547 * <p>Strips whitespace from the start and end of every String in an array. 548 * Whitespace is defined by {@link Character#isWhitespace(char)}.</p> 549 * 550 * <p>A new array is returned each time, except for length zero. 551 * A {@code null} array will return {@code null}. 552 * An empty array will return itself. 553 * A {@code null} array entry will be ignored.</p> 554 * 555 * <pre> 556 * StringUtils.stripAll(null) = null 557 * StringUtils.stripAll([]) = [] 558 * StringUtils.stripAll(["abc", " abc"]) = ["abc", "abc"] 559 * StringUtils.stripAll(["abc ", null]) = ["abc", null] 560 * </pre> 561 * 562 * @param strs the array to remove whitespace from, may be null 563 * @return the stripped Strings, {@code null} if null array input 564 */ 565 public static String[] stripAll(String... strs) { 566 return stripAll(strs, null); 567 } 568 569 /** 570 * <p>Strips any of a set of characters from the start and end of every 571 * String in an array.</p> 572 * Whitespace is defined by {@link Character#isWhitespace(char)}.</p> 573 * 574 * <p>A new array is returned each time, except for length zero. 575 * A {@code null} array will return {@code null}. 576 * An empty array will return itself. 577 * A {@code null} array entry will be ignored. 578 * A {@code null} stripChars will strip whitespace as defined by 579 * {@link Character#isWhitespace(char)}.</p> 580 * 581 * <pre> 582 * StringUtils.stripAll(null, *) = null 583 * StringUtils.stripAll([], *) = [] 584 * StringUtils.stripAll(["abc", " abc"], null) = ["abc", "abc"] 585 * StringUtils.stripAll(["abc ", null], null) = ["abc", null] 586 * StringUtils.stripAll(["abc ", null], "yz") = ["abc ", null] 587 * StringUtils.stripAll(["yabcz", null], "yz") = ["abc", null] 588 * </pre> 589 * 590 * @param strs the array to remove characters from, may be null 591 * @param stripChars the characters to remove, null treated as whitespace 592 * @return the stripped Strings, {@code null} if null array input 593 */ 594 public static String[] stripAll(String[] strs, String stripChars) { 595 int strsLen; 596 if (strs == null || (strsLen = strs.length) == 0) { 597 return strs; 598 } 599 String[] newArr = new String[strsLen]; 600 for (int i = 0; i < strsLen; i++) { 601 newArr[i] = strip(strs[i], stripChars); 602 } 603 return newArr; 604 } 605 606 /** 607 * <p>Removes diacritics (~= accents) from a string. The case will not be altered.</p> 608 * <p>For instance, 'à' will be replaced by 'a'.</p> 609 * <p>Note that ligatures will be left as is.</p> 610 * 611 * <p>This method will use the first available implementation of: 612 * Java 6's {@link java.text.Normalizer}, Java 1.3–1.5's {@code sun.text.Normalizer}</p> 613 * 614 * <pre> 615 * StringUtils.stripAccents(null) = null 616 * StringUtils.stripAccents("") = "" 617 * StringUtils.stripAccents("control") = "control" 618 * StringUtils.stripAccents("éclair") = "eclair" 619 * </pre> 620 * 621 * @param input String to be stripped 622 * @return input text with diacritics removed 623 * 624 * @since 3.0 625 */ 626 // 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). 627 public static String stripAccents(String input) { 628 if(input == null) { 629 return null; 630 } 631 try { 632 String result = null; 633 if (java6Available) { 634 result = removeAccentsJava6(input); 635 } else if (sunAvailable) { 636 result = removeAccentsSUN(input); 637 } else { 638 throw new UnsupportedOperationException( 639 "The stripAccents(CharSequence) method requires at least Java 1.6 or a Sun JVM"); 640 } 641 // Note that none of the above methods correctly remove ligatures... 642 return result; 643 } catch(IllegalArgumentException iae) { 644 throw new RuntimeException("IllegalArgumentException occurred", iae); 645 } catch(IllegalAccessException iae) { 646 throw new RuntimeException("IllegalAccessException occurred", iae); 647 } catch(InvocationTargetException ite) { 648 throw new RuntimeException("InvocationTargetException occurred", ite); 649 } catch(SecurityException se) { 650 throw new RuntimeException("SecurityException occurred", se); 651 } 652 } 653 654 /** 655 * Use {@code java.text.Normalizer#normalize(CharSequence, Normalizer.Form)} 656 * (but be careful, this class exists in Java 1.3, with an entirely different meaning!) 657 * 658 * @param text the text to be processed 659 * @return the processed string 660 * @throws IllegalAccessException may be thrown by a reflection call 661 * @throws InvocationTargetException if a reflection call throws an exception 662 * @throws IllegalStateException if the {@code Normalizer} class is not available 663 */ 664 private static String removeAccentsJava6(CharSequence text) 665 throws IllegalAccessException, InvocationTargetException { 666 /* 667 String decomposed = java.text.Normalizer.normalize(CharSequence, Normalizer.Form.NFD); 668 return java6Pattern.matcher(decomposed).replaceAll("");//$NON-NLS-1$ 669 */ 670 if (!java6Available || java6NormalizerFormNFD == null) { 671 throw new IllegalStateException("java.text.Normalizer is not available"); 672 } 673 String result; 674 result = (String) java6NormalizeMethod.invoke(null, new Object[] {text, java6NormalizerFormNFD}); 675 result = java6Pattern.matcher(result).replaceAll("");//$NON-NLS-1$ 676 return result; 677 } 678 679 /** 680 * Use {@code sun.text.Normalizer#decompose(String, boolean, int)} 681 * 682 * @param text the text to be processed 683 * @return the processed string 684 * @throws IllegalAccessException may be thrown by a reflection call 685 * @throws InvocationTargetException if a reflection call throws an exception 686 * @throws IllegalStateException if the {@code Normalizer} class is not available 687 */ 688 private static String removeAccentsSUN(CharSequence text) 689 throws IllegalAccessException, InvocationTargetException { 690 /* 691 String decomposed = sun.text.Normalizer.decompose(text, false, 0); 692 return sunPattern.matcher(decomposed).replaceAll("");//$NON-NLS-1$ 693 */ 694 if (! sunAvailable) { 695 throw new IllegalStateException("sun.text.Normalizer is not available"); 696 } 697 String result; 698 result = (String) sunDecomposeMethod.invoke(null, new Object[] {text, Boolean.FALSE, Integer.valueOf(0)}); 699 result = sunPattern.matcher(result).replaceAll("");//$NON-NLS-1$ 700 return result; 701 } 702 703 // SUN internal, Java 1.3 -> Java 5 704 private static boolean sunAvailable = false; 705 private static Method sunDecomposeMethod = null; 706 private static final Pattern sunPattern = Pattern.compile("\\p{InCombiningDiacriticalMarks}+");//$NON-NLS-1$ 707 // Java 6+ 708 private static boolean java6Available = false; 709 private static Method java6NormalizeMethod = null; 710 private static Object java6NormalizerFormNFD = null; 711 private static final Pattern java6Pattern = sunPattern; 712 713 static { 714 try { 715 // java.text.Normalizer.normalize(CharSequence, Normalizer.Form.NFD); 716 // Be careful not to get Java 1.3 java.text.Normalizer! 717 Class<?> normalizerFormClass = Thread.currentThread().getContextClassLoader() 718 .loadClass("java.text.Normalizer$Form");//$NON-NLS-1$ 719 java6NormalizerFormNFD = normalizerFormClass.getField("NFD").get(null);//$NON-NLS-1$ 720 Class<?> normalizerClass = Thread.currentThread().getContextClassLoader() 721 .loadClass("java.text.Normalizer");//$NON-NLS-1$ 722 java6NormalizeMethod = normalizerClass.getMethod("normalize", 723 new Class[] {CharSequence.class, normalizerFormClass});//$NON-NLS-1$ 724 java6Available = true; 725 } catch (ClassNotFoundException e) { 726 java6Available = false; 727 } catch (NoSuchFieldException e) { 728 java6Available = false; 729 } catch (IllegalAccessException e) { 730 java6Available = false; 731 } catch (NoSuchMethodException e) { 732 java6Available = false; 733 } 734 735 try { 736 // sun.text.Normalizer.decompose(text, false, 0); 737 Class<?> normalizerClass = Thread.currentThread().getContextClassLoader() 738 .loadClass("sun.text.Normalizer");//$NON-NLS-1$ 739 sunDecomposeMethod = normalizerClass.getMethod("decompose", 740 new Class[] {String.class, Boolean.TYPE, Integer.TYPE});//$NON-NLS-1$ 741 sunAvailable = true; 742 } catch (ClassNotFoundException e) { 743 sunAvailable = false; 744 } catch (NoSuchMethodException e) { 745 sunAvailable = false; 746 } 747 } 748 749 // Equals 750 //----------------------------------------------------------------------- 751 /** 752 * <p>Compares two CharSequences, returning {@code true} if they are equal.</p> 753 * 754 * <p>{@code null}s are handled without exceptions. Two {@code null} 755 * references are considered to be equal. The comparison is case sensitive.</p> 756 * 757 * <pre> 758 * StringUtils.equals(null, null) = true 759 * StringUtils.equals(null, "abc") = false 760 * StringUtils.equals("abc", null) = false 761 * StringUtils.equals("abc", "abc") = true 762 * StringUtils.equals("abc", "ABC") = false 763 * </pre> 764 * 765 * @see java.lang.String#equals(Object) 766 * @param cs1 the first CharSequence, may be null 767 * @param cs2 the second CharSequence, may be null 768 * @return {@code true} if the CharSequences are equal, case sensitive, or 769 * both {@code null} 770 * @since 3.0 Changed signature from equals(String, String) to equals(CharSequence, CharSequence) 771 */ 772 public static boolean equals(CharSequence cs1, CharSequence cs2) { 773 return cs1 == null ? cs2 == null : cs1.equals(cs2); 774 } 775 776 /** 777 * <p>Compares two CharSequences, returning {@code true} if they are equal ignoring 778 * the case.</p> 779 * 780 * <p>{@code null}s are handled without exceptions. Two {@code null} 781 * references are considered equal. Comparison is case insensitive.</p> 782 * 783 * <pre> 784 * StringUtils.equalsIgnoreCase(null, null) = true 785 * StringUtils.equalsIgnoreCase(null, "abc") = false 786 * StringUtils.equalsIgnoreCase("abc", null) = false 787 * StringUtils.equalsIgnoreCase("abc", "abc") = true 788 * StringUtils.equalsIgnoreCase("abc", "ABC") = true 789 * </pre> 790 * 791 * @param str1 the first CharSequence, may be null 792 * @param str2 the second CharSequence, may be null 793 * @return {@code true} if the CharSequence are equal, case insensitive, or 794 * both {@code null} 795 * @since 3.0 Changed signature from equalsIgnoreCase(String, String) to equalsIgnoreCase(CharSequence, CharSequence) 796 */ 797 public static boolean equalsIgnoreCase(CharSequence str1, CharSequence str2) { 798 if (str1 == null || str2 == null) { 799 return str1 == str2; 800 } else { 801 return CharSequenceUtils.regionMatches(str1, true, 0, str2, 0, Math.max(str1.length(), str2.length())); 802 } 803 } 804 805 // IndexOf 806 //----------------------------------------------------------------------- 807 /** 808 * <p>Finds the first index within a CharSequence, handling {@code null}. 809 * This method uses {@link String#indexOf(int, int)} if possible.</p> 810 * 811 * <p>A {@code null} or empty ("") CharSequence will return {@code INDEX_NOT_FOUND (-1)}.</p> 812 * 813 * <pre> 814 * StringUtils.indexOf(null, *) = -1 815 * StringUtils.indexOf("", *) = -1 816 * StringUtils.indexOf("aabaabaa", 'a') = 0 817 * StringUtils.indexOf("aabaabaa", 'b') = 2 818 * </pre> 819 * 820 * @param seq the CharSequence to check, may be null 821 * @param searchChar the character to find 822 * @return the first index of the search character, 823 * -1 if no match or {@code null} string input 824 * @since 2.0 825 * @since 3.0 Changed signature from indexOf(String, int) to indexOf(CharSequence, int) 826 */ 827 public static int indexOf(CharSequence seq, int searchChar) { 828 if (isEmpty(seq)) { 829 return INDEX_NOT_FOUND; 830 } 831 return CharSequenceUtils.indexOf(seq, searchChar, 0); 832 } 833 834 /** 835 * <p>Finds the first index within a CharSequence from a start position, 836 * handling {@code null}. 837 * This method uses {@link String#indexOf(int, int)} if possible.</p> 838 * 839 * <p>A {@code null} or empty ("") CharSequence will return {@code (INDEX_NOT_FOUND) -1}. 840 * A negative start position is treated as zero. 841 * A start position greater than the string length returns {@code -1}.</p> 842 * 843 * <pre> 844 * StringUtils.indexOf(null, *, *) = -1 845 * StringUtils.indexOf("", *, *) = -1 846 * StringUtils.indexOf("aabaabaa", 'b', 0) = 2 847 * StringUtils.indexOf("aabaabaa", 'b', 3) = 5 848 * StringUtils.indexOf("aabaabaa", 'b', 9) = -1 849 * StringUtils.indexOf("aabaabaa", 'b', -1) = 2 850 * </pre> 851 * 852 * @param seq the CharSequence to check, may be null 853 * @param searchChar the character to find 854 * @param startPos the start position, negative treated as zero 855 * @return the first index of the search character, 856 * -1 if no match or {@code null} string input 857 * @since 2.0 858 * @since 3.0 Changed signature from indexOf(String, int, int) to indexOf(CharSequence, int, int) 859 */ 860 public static int indexOf(CharSequence seq, int searchChar, int startPos) { 861 if (isEmpty(seq)) { 862 return INDEX_NOT_FOUND; 863 } 864 return CharSequenceUtils.indexOf(seq, searchChar, startPos); 865 } 866 867 /** 868 * <p>Finds the first index within a CharSequence, handling {@code null}. 869 * This method uses {@link String#indexOf(String, int)} if possible.</p> 870 * 871 * <p>A {@code null} CharSequence will return {@code -1}.</p> 872 * 873 * <pre> 874 * StringUtils.indexOf(null, *) = -1 875 * StringUtils.indexOf(*, null) = -1 876 * StringUtils.indexOf("", "") = 0 877 * StringUtils.indexOf("", *) = -1 (except when * = "") 878 * StringUtils.indexOf("aabaabaa", "a") = 0 879 * StringUtils.indexOf("aabaabaa", "b") = 2 880 * StringUtils.indexOf("aabaabaa", "ab") = 1 881 * StringUtils.indexOf("aabaabaa", "") = 0 882 * </pre> 883 * 884 * @param seq the CharSequence to check, may be null 885 * @param searchSeq the CharSequence to find, may be null 886 * @return the first index of the search CharSequence, 887 * -1 if no match or {@code null} string input 888 * @since 2.0 889 * @since 3.0 Changed signature from indexOf(String, String) to indexOf(CharSequence, CharSequence) 890 */ 891 public static int indexOf(CharSequence seq, CharSequence searchSeq) { 892 if (seq == null || searchSeq == null) { 893 return INDEX_NOT_FOUND; 894 } 895 return CharSequenceUtils.indexOf(seq, searchSeq, 0); 896 } 897 898 /** 899 * <p>Finds the first index within a CharSequence, handling {@code null}. 900 * This method uses {@link String#indexOf(String, int)} if possible.</p> 901 * 902 * <p>A {@code null} CharSequence will return {@code -1}. 903 * A negative start position is treated as zero. 904 * An empty ("") search CharSequence always matches. 905 * A start position greater than the string length only matches 906 * an empty search CharSequence.</p> 907 * 908 * <pre> 909 * StringUtils.indexOf(null, *, *) = -1 910 * StringUtils.indexOf(*, null, *) = -1 911 * StringUtils.indexOf("", "", 0) = 0 912 * StringUtils.indexOf("", *, 0) = -1 (except when * = "") 913 * StringUtils.indexOf("aabaabaa", "a", 0) = 0 914 * StringUtils.indexOf("aabaabaa", "b", 0) = 2 915 * StringUtils.indexOf("aabaabaa", "ab", 0) = 1 916 * StringUtils.indexOf("aabaabaa", "b", 3) = 5 917 * StringUtils.indexOf("aabaabaa", "b", 9) = -1 918 * StringUtils.indexOf("aabaabaa", "b", -1) = 2 919 * StringUtils.indexOf("aabaabaa", "", 2) = 2 920 * StringUtils.indexOf("abc", "", 9) = 3 921 * </pre> 922 * 923 * @param seq the CharSequence to check, may be null 924 * @param searchSeq the CharSequence to find, may be null 925 * @param startPos the start position, negative treated as zero 926 * @return the first index of the search CharSequence, 927 * -1 if no match or {@code null} string input 928 * @since 2.0 929 * @since 3.0 Changed signature from indexOf(String, String, int) to indexOf(CharSequence, CharSequence, int) 930 */ 931 public static int indexOf(CharSequence seq, CharSequence searchSeq, int startPos) { 932 if (seq == null || searchSeq == null) { 933 return INDEX_NOT_FOUND; 934 } 935 return CharSequenceUtils.indexOf(seq, searchSeq, startPos); 936 } 937 938 /** 939 * <p>Finds the n-th index within a CharSequence, handling {@code null}. 940 * This method uses {@link String#indexOf(String)} if possible.</p> 941 * 942 * <p>A {@code null} CharSequence will return {@code -1}.</p> 943 * 944 * <pre> 945 * StringUtils.ordinalIndexOf(null, *, *) = -1 946 * StringUtils.ordinalIndexOf(*, null, *) = -1 947 * StringUtils.ordinalIndexOf("", "", *) = 0 948 * StringUtils.ordinalIndexOf("aabaabaa", "a", 1) = 0 949 * StringUtils.ordinalIndexOf("aabaabaa", "a", 2) = 1 950 * StringUtils.ordinalIndexOf("aabaabaa", "b", 1) = 2 951 * StringUtils.ordinalIndexOf("aabaabaa", "b", 2) = 5 952 * StringUtils.ordinalIndexOf("aabaabaa", "ab", 1) = 1 953 * StringUtils.ordinalIndexOf("aabaabaa", "ab", 2) = 4 954 * StringUtils.ordinalIndexOf("aabaabaa", "", 1) = 0 955 * StringUtils.ordinalIndexOf("aabaabaa", "", 2) = 0 956 * </pre> 957 * 958 * <p>Note that 'head(CharSequence str, int n)' may be implemented as: </p> 959 * 960 * <pre> 961 * str.substring(0, lastOrdinalIndexOf(str, "\n", n)) 962 * </pre> 963 * 964 * @param str the CharSequence to check, may be null 965 * @param searchStr the CharSequence to find, may be null 966 * @param ordinal the n-th {@code searchStr} to find 967 * @return the n-th index of the search CharSequence, 968 * {@code -1} ({@code INDEX_NOT_FOUND}) if no match or {@code null} string input 969 * @since 2.1 970 * @since 3.0 Changed signature from ordinalIndexOf(String, String, int) to ordinalIndexOf(CharSequence, CharSequence, int) 971 */ 972 public static int ordinalIndexOf(CharSequence str, CharSequence searchStr, int ordinal) { 973 return ordinalIndexOf(str, searchStr, ordinal, false); 974 } 975 976 /** 977 * <p>Finds the n-th index within a String, handling {@code null}. 978 * This method uses {@link String#indexOf(String)} if possible.</p> 979 * 980 * <p>A {@code null} CharSequence will return {@code -1}.</p> 981 * 982 * @param str the CharSequence to check, may be null 983 * @param searchStr the CharSequence to find, may be null 984 * @param ordinal the n-th {@code searchStr} to find 985 * @param lastIndex true if lastOrdinalIndexOf() otherwise false if ordinalIndexOf() 986 * @return the n-th index of the search CharSequence, 987 * {@code -1} ({@code INDEX_NOT_FOUND}) if no match or {@code null} string input 988 */ 989 // Shared code between ordinalIndexOf(String,String,int) and lastOrdinalIndexOf(String,String,int) 990 private static int ordinalIndexOf(CharSequence str, CharSequence searchStr, int ordinal, boolean lastIndex) { 991 if (str == null || searchStr == null || ordinal <= 0) { 992 return INDEX_NOT_FOUND; 993 } 994 if (searchStr.length() == 0) { 995 return lastIndex ? str.length() : 0; 996 } 997 int found = 0; 998 int index = lastIndex ? str.length() : INDEX_NOT_FOUND; 999 do { 1000 if (lastIndex) { 1001 index = CharSequenceUtils.lastIndexOf(str, searchStr, index - 1); 1002 } else { 1003 index = CharSequenceUtils.indexOf(str, searchStr, index + 1); 1004 } 1005 if (index < 0) { 1006 return index; 1007 } 1008 found++; 1009 } while (found < ordinal); 1010 return index; 1011 } 1012 1013 /** 1014 * <p>Case in-sensitive find of the first index within a CharSequence.</p> 1015 * 1016 * <p>A {@code null} CharSequence will return {@code -1}. 1017 * A negative start position is treated as zero. 1018 * An empty ("") search CharSequence always matches. 1019 * A start position greater than the string length only matches 1020 * an empty search CharSequence.</p> 1021 * 1022 * <pre> 1023 * StringUtils.indexOfIgnoreCase(null, *) = -1 1024 * StringUtils.indexOfIgnoreCase(*, null) = -1 1025 * StringUtils.indexOfIgnoreCase("", "") = 0 1026 * StringUtils.indexOfIgnoreCase("aabaabaa", "a") = 0 1027 * StringUtils.indexOfIgnoreCase("aabaabaa", "b") = 2 1028 * StringUtils.indexOfIgnoreCase("aabaabaa", "ab") = 1 1029 * </pre> 1030 * 1031 * @param str the CharSequence to check, may be null 1032 * @param searchStr the CharSequence to find, may be null 1033 * @return the first index of the search CharSequence, 1034 * -1 if no match or {@code null} string input 1035 * @since 2.5 1036 * @since 3.0 Changed signature from indexOfIgnoreCase(String, String) to indexOfIgnoreCase(CharSequence, CharSequence) 1037 */ 1038 public static int indexOfIgnoreCase(CharSequence str, CharSequence searchStr) { 1039 return indexOfIgnoreCase(str, searchStr, 0); 1040 } 1041 1042 /** 1043 * <p>Case in-sensitive find of the first index within a CharSequence 1044 * from the specified position.</p> 1045 * 1046 * <p>A {@code null} CharSequence will return {@code -1}. 1047 * A negative start position is treated as zero. 1048 * An empty ("") search CharSequence always matches. 1049 * A start position greater than the string length only matches 1050 * an empty search CharSequence.</p> 1051 * 1052 * <pre> 1053 * StringUtils.indexOfIgnoreCase(null, *, *) = -1 1054 * StringUtils.indexOfIgnoreCase(*, null, *) = -1 1055 * StringUtils.indexOfIgnoreCase("", "", 0) = 0 1056 * StringUtils.indexOfIgnoreCase("aabaabaa", "A", 0) = 0 1057 * StringUtils.indexOfIgnoreCase("aabaabaa", "B", 0) = 2 1058 * StringUtils.indexOfIgnoreCase("aabaabaa", "AB", 0) = 1 1059 * StringUtils.indexOfIgnoreCase("aabaabaa", "B", 3) = 5 1060 * StringUtils.indexOfIgnoreCase("aabaabaa", "B", 9) = -1 1061 * StringUtils.indexOfIgnoreCase("aabaabaa", "B", -1) = 2 1062 * StringUtils.indexOfIgnoreCase("aabaabaa", "", 2) = 2 1063 * StringUtils.indexOfIgnoreCase("abc", "", 9) = 3 1064 * </pre> 1065 * 1066 * @param str the CharSequence to check, may be null 1067 * @param searchStr the CharSequence to find, may be null 1068 * @param startPos the start position, negative treated as zero 1069 * @return the first index of the search CharSequence, 1070 * -1 if no match or {@code null} string input 1071 * @since 2.5 1072 * @since 3.0 Changed signature from indexOfIgnoreCase(String, String, int) to indexOfIgnoreCase(CharSequence, CharSequence, int) 1073 */ 1074 public static int indexOfIgnoreCase(CharSequence str, CharSequence searchStr, int startPos) { 1075 if (str == null || searchStr == null) { 1076 return INDEX_NOT_FOUND; 1077 } 1078 if (startPos < 0) { 1079 startPos = 0; 1080 } 1081 int endLimit = (str.length() - searchStr.length()) + 1; 1082 if (startPos > endLimit) { 1083 return INDEX_NOT_FOUND; 1084 } 1085 if (searchStr.length() == 0) { 1086 return startPos; 1087 } 1088 for (int i = startPos; i < endLimit; i++) { 1089 if (CharSequenceUtils.regionMatches(str, true, i, searchStr, 0, searchStr.length())) { 1090 return i; 1091 } 1092 } 1093 return INDEX_NOT_FOUND; 1094 } 1095 1096 // LastIndexOf 1097 //----------------------------------------------------------------------- 1098 /** 1099 * <p>Finds the last index within a CharSequence, handling {@code null}. 1100 * This method uses {@link String#lastIndexOf(int)} if possible.</p> 1101 * 1102 * <p>A {@code null} or empty ("") CharSequence will return {@code -1}.</p> 1103 * 1104 * <pre> 1105 * StringUtils.lastIndexOf(null, *) = -1 1106 * StringUtils.lastIndexOf("", *) = -1 1107 * StringUtils.lastIndexOf("aabaabaa", 'a') = 7 1108 * StringUtils.lastIndexOf("aabaabaa", 'b') = 5 1109 * </pre> 1110 * 1111 * @param seq the CharSequence to check, may be null 1112 * @param searchChar the character to find 1113 * @return the last index of the search character, 1114 * -1 if no match or {@code null} string input 1115 * @since 2.0 1116 * @since 3.0 Changed signature from lastIndexOf(String, int) to lastIndexOf(CharSequence, int) 1117 */ 1118 public static int lastIndexOf(CharSequence seq, int searchChar) { 1119 if (isEmpty(seq)) { 1120 return INDEX_NOT_FOUND; 1121 } 1122 return CharSequenceUtils.lastIndexOf(seq, searchChar, seq.length()); 1123 } 1124 1125 /** 1126 * <p>Finds the last index within a CharSequence from a start position, 1127 * handling {@code null}. 1128 * This method uses {@link String#lastIndexOf(int, int)} if possible.</p> 1129 * 1130 * <p>A {@code null} or empty ("") CharSequence will return {@code -1}. 1131 * A negative start position returns {@code -1}. 1132 * A start position greater than the string length searches the whole string.</p> 1133 * 1134 * <pre> 1135 * StringUtils.lastIndexOf(null, *, *) = -1 1136 * StringUtils.lastIndexOf("", *, *) = -1 1137 * StringUtils.lastIndexOf("aabaabaa", 'b', 8) = 5 1138 * StringUtils.lastIndexOf("aabaabaa", 'b', 4) = 2 1139 * StringUtils.lastIndexOf("aabaabaa", 'b', 0) = -1 1140 * StringUtils.lastIndexOf("aabaabaa", 'b', 9) = 5 1141 * StringUtils.lastIndexOf("aabaabaa", 'b', -1) = -1 1142 * StringUtils.lastIndexOf("aabaabaa", 'a', 0) = 0 1143 * </pre> 1144 * 1145 * @param seq the CharSequence to check, may be null 1146 * @param searchChar the character to find 1147 * @param startPos the start position 1148 * @return the last index of the search character, 1149 * -1 if no match or {@code null} string input 1150 * @since 2.0 1151 * @since 3.0 Changed signature from lastIndexOf(String, int, int) to lastIndexOf(CharSequence, int, int) 1152 */ 1153 public static int lastIndexOf(CharSequence seq, int searchChar, int startPos) { 1154 if (isEmpty(seq)) { 1155 return INDEX_NOT_FOUND; 1156 } 1157 return CharSequenceUtils.lastIndexOf(seq, searchChar, startPos); 1158 } 1159 1160 /** 1161 * <p>Finds the last index within a CharSequence, handling {@code null}. 1162 * This method uses {@link String#lastIndexOf(String)} if possible.</p> 1163 * 1164 * <p>A {@code null} CharSequence will return {@code -1}.</p> 1165 * 1166 * <pre> 1167 * StringUtils.lastIndexOf(null, *) = -1 1168 * StringUtils.lastIndexOf(*, null) = -1 1169 * StringUtils.lastIndexOf("", "") = 0 1170 * StringUtils.lastIndexOf("aabaabaa", "a") = 7 1171 * StringUtils.lastIndexOf("aabaabaa", "b") = 5 1172 * StringUtils.lastIndexOf("aabaabaa", "ab") = 4 1173 * StringUtils.lastIndexOf("aabaabaa", "") = 8 1174 * </pre> 1175 * 1176 * @param seq the CharSequence to check, may be null 1177 * @param searchSeq the CharSequence to find, may be null 1178 * @return the last index of the search String, 1179 * -1 if no match or {@code null} string input 1180 * @since 2.0 1181 * @since 3.0 Changed signature from lastIndexOf(String, String) to lastIndexOf(CharSequence, CharSequence) 1182 */ 1183 public static int lastIndexOf(CharSequence seq, CharSequence searchSeq) { 1184 if (seq == null || searchSeq == null) { 1185 return INDEX_NOT_FOUND; 1186 } 1187 return CharSequenceUtils.lastIndexOf(seq, searchSeq, seq.length()); 1188 } 1189 1190 /** 1191 * <p>Finds the n-th last index within a String, handling {@code null}. 1192 * This method uses {@link String#lastIndexOf(String)}.</p> 1193 * 1194 * <p>A {@code null} String will return {@code -1}.</p> 1195 * 1196 * <pre> 1197 * StringUtils.lastOrdinalIndexOf(null, *, *) = -1 1198 * StringUtils.lastOrdinalIndexOf(*, null, *) = -1 1199 * StringUtils.lastOrdinalIndexOf("", "", *) = 0 1200 * StringUtils.lastOrdinalIndexOf("aabaabaa", "a", 1) = 7 1201 * StringUtils.lastOrdinalIndexOf("aabaabaa", "a", 2) = 6 1202 * StringUtils.lastOrdinalIndexOf("aabaabaa", "b", 1) = 5 1203 * StringUtils.lastOrdinalIndexOf("aabaabaa", "b", 2) = 2 1204 * StringUtils.lastOrdinalIndexOf("aabaabaa", "ab", 1) = 4 1205 * StringUtils.lastOrdinalIndexOf("aabaabaa", "ab", 2) = 1 1206 * StringUtils.lastOrdinalIndexOf("aabaabaa", "", 1) = 8 1207 * StringUtils.lastOrdinalIndexOf("aabaabaa", "", 2) = 8 1208 * </pre> 1209 * 1210 * <p>Note that 'tail(CharSequence str, int n)' may be implemented as: </p> 1211 * 1212 * <pre> 1213 * str.substring(lastOrdinalIndexOf(str, "\n", n) + 1) 1214 * </pre> 1215 * 1216 * @param str the CharSequence to check, may be null 1217 * @param searchStr the CharSequence to find, may be null 1218 * @param ordinal the n-th last {@code searchStr} to find 1219 * @return the n-th last index of the search CharSequence, 1220 * {@code -1} ({@code INDEX_NOT_FOUND}) if no match or {@code null} string input 1221 * @since 2.5 1222 * @since 3.0 Changed signature from lastOrdinalIndexOf(String, String, int) to lastOrdinalIndexOf(CharSequence, CharSequence, int) 1223 */ 1224 public static int lastOrdinalIndexOf(CharSequence str, CharSequence searchStr, int ordinal) { 1225 return ordinalIndexOf(str, searchStr, ordinal, true); 1226 } 1227 1228 /** 1229 * <p>Finds the first index within a CharSequence, handling {@code null}. 1230 * This method uses {@link String#lastIndexOf(String, int)} if possible.</p> 1231 * 1232 * <p>A {@code null} CharSequence will return {@code -1}. 1233 * A negative start position returns {@code -1}. 1234 * An empty ("") search CharSequence always matches unless the start position is negative. 1235 * A start position greater than the string length searches the whole string.</p> 1236 * 1237 * <pre> 1238 * StringUtils.lastIndexOf(null, *, *) = -1 1239 * StringUtils.lastIndexOf(*, null, *) = -1 1240 * StringUtils.lastIndexOf("aabaabaa", "a", 8) = 7 1241 * StringUtils.lastIndexOf("aabaabaa", "b", 8) = 5 1242 * StringUtils.lastIndexOf("aabaabaa", "ab", 8) = 4 1243 * StringUtils.lastIndexOf("aabaabaa", "b", 9) = 5 1244 * StringUtils.lastIndexOf("aabaabaa", "b", -1) = -1 1245 * StringUtils.lastIndexOf("aabaabaa", "a", 0) = 0 1246 * StringUtils.lastIndexOf("aabaabaa", "b", 0) = -1 1247 * </pre> 1248 * 1249 * @param seq the CharSequence to check, may be null 1250 * @param searchSeq the CharSequence to find, may be null 1251 * @param startPos the start position, negative treated as zero 1252 * @return the first index of the search CharSequence, 1253 * -1 if no match or {@code null} string input 1254 * @since 2.0 1255 * @since 3.0 Changed signature from lastIndexOf(String, String, int) to lastIndexOf(CharSequence, CharSequence, int) 1256 */ 1257 public static int lastIndexOf(CharSequence seq, CharSequence searchSeq, int startPos) { 1258 if (seq == null || searchSeq == null) { 1259 return INDEX_NOT_FOUND; 1260 } 1261 return CharSequenceUtils.lastIndexOf(seq, searchSeq, startPos); 1262 } 1263 1264 /** 1265 * <p>Case in-sensitive find of the last index within a CharSequence.</p> 1266 * 1267 * <p>A {@code null} CharSequence will return {@code -1}. 1268 * A negative start position returns {@code -1}. 1269 * An empty ("") search CharSequence always matches unless the start position is negative. 1270 * A start position greater than the string length searches the whole string.</p> 1271 * 1272 * <pre> 1273 * StringUtils.lastIndexOfIgnoreCase(null, *) = -1 1274 * StringUtils.lastIndexOfIgnoreCase(*, null) = -1 1275 * StringUtils.lastIndexOfIgnoreCase("aabaabaa", "A") = 7 1276 * StringUtils.lastIndexOfIgnoreCase("aabaabaa", "B") = 5 1277 * StringUtils.lastIndexOfIgnoreCase("aabaabaa", "AB") = 4 1278 * </pre> 1279 * 1280 * @param str the CharSequence to check, may be null 1281 * @param searchStr the CharSequence to find, may be null 1282 * @return the first index of the search CharSequence, 1283 * -1 if no match or {@code null} string input 1284 * @since 2.5 1285 * @since 3.0 Changed signature from lastIndexOfIgnoreCase(String, String) to lastIndexOfIgnoreCase(CharSequence, CharSequence) 1286 */ 1287 public static int lastIndexOfIgnoreCase(CharSequence str, CharSequence searchStr) { 1288 if (str == null || searchStr == null) { 1289 return INDEX_NOT_FOUND; 1290 } 1291 return lastIndexOfIgnoreCase(str, searchStr, str.length()); 1292 } 1293 1294 /** 1295 * <p>Case in-sensitive find of the last index within a CharSequence 1296 * from the specified position.</p> 1297 * 1298 * <p>A {@code null} CharSequence will return {@code -1}. 1299 * A negative start position returns {@code -1}. 1300 * An empty ("") search CharSequence always matches unless the start position is negative. 1301 * A start position greater than the string length searches the whole string.</p> 1302 * 1303 * <pre> 1304 * StringUtils.lastIndexOfIgnoreCase(null, *, *) = -1 1305 * StringUtils.lastIndexOfIgnoreCase(*, null, *) = -1 1306 * StringUtils.lastIndexOfIgnoreCase("aabaabaa", "A", 8) = 7 1307 * StringUtils.lastIndexOfIgnoreCase("aabaabaa", "B", 8) = 5 1308 * StringUtils.lastIndexOfIgnoreCase("aabaabaa", "AB", 8) = 4 1309 * StringUtils.lastIndexOfIgnoreCase("aabaabaa", "B", 9) = 5 1310 * StringUtils.lastIndexOfIgnoreCase("aabaabaa", "B", -1) = -1 1311 * StringUtils.lastIndexOfIgnoreCase("aabaabaa", "A", 0) = 0 1312 * StringUtils.lastIndexOfIgnoreCase("aabaabaa", "B", 0) = -1 1313 * </pre> 1314 * 1315 * @param str the CharSequence to check, may be null 1316 * @param searchStr the CharSequence to find, may be null 1317 * @param startPos the start position 1318 * @return the first index of the search CharSequence, 1319 * -1 if no match or {@code null} input 1320 * @since 2.5 1321 * @since 3.0 Changed signature from lastIndexOfIgnoreCase(String, String, int) to lastIndexOfIgnoreCase(CharSequence, CharSequence, int) 1322 */ 1323 public static int lastIndexOfIgnoreCase(CharSequence str, CharSequence searchStr, int startPos) { 1324 if (str == null || searchStr == null) { 1325 return INDEX_NOT_FOUND; 1326 } 1327 if (startPos > (str.length() - searchStr.length())) { 1328 startPos = str.length() - searchStr.length(); 1329 } 1330 if (startPos < 0) { 1331 return INDEX_NOT_FOUND; 1332 } 1333 if (searchStr.length() == 0) { 1334 return startPos; 1335 } 1336 1337 for (int i = startPos; i >= 0; i--) { 1338 if (CharSequenceUtils.regionMatches(str, true, i, searchStr, 0, searchStr.length())) { 1339 return i; 1340 } 1341 } 1342 return INDEX_NOT_FOUND; 1343 } 1344 1345 // Contains 1346 //----------------------------------------------------------------------- 1347 /** 1348 * <p>Checks if CharSequence contains a search character, handling {@code null}. 1349 * This method uses {@link String#indexOf(int)} if possible.</p> 1350 * 1351 * <p>A {@code null} or empty ("") CharSequence will return {@code false}.</p> 1352 * 1353 * <pre> 1354 * StringUtils.contains(null, *) = false 1355 * StringUtils.contains("", *) = false 1356 * StringUtils.contains("abc", 'a') = true 1357 * StringUtils.contains("abc", 'z') = false 1358 * </pre> 1359 * 1360 * @param seq the CharSequence to check, may be null 1361 * @param searchChar the character to find 1362 * @return true if the CharSequence contains the search character, 1363 * false if not or {@code null} string input 1364 * @since 2.0 1365 * @since 3.0 Changed signature from contains(String, int) to contains(CharSequence, int) 1366 */ 1367 public static boolean contains(CharSequence seq, int searchChar) { 1368 if (isEmpty(seq)) { 1369 return false; 1370 } 1371 return CharSequenceUtils.indexOf(seq, searchChar, 0) >= 0; 1372 } 1373 1374 /** 1375 * <p>Checks if CharSequence contains a search CharSequence, handling {@code null}. 1376 * This method uses {@link String#indexOf(String)} if possible.</p> 1377 * 1378 * <p>A {@code null} CharSequence will return {@code false}.</p> 1379 * 1380 * <pre> 1381 * StringUtils.contains(null, *) = false 1382 * StringUtils.contains(*, null) = false 1383 * StringUtils.contains("", "") = true 1384 * StringUtils.contains("abc", "") = true 1385 * StringUtils.contains("abc", "a") = true 1386 * StringUtils.contains("abc", "z") = false 1387 * </pre> 1388 * 1389 * @param seq the CharSequence to check, may be null 1390 * @param searchSeq the CharSequence to find, may be null 1391 * @return true if the CharSequence contains the search CharSequence, 1392 * false if not or {@code null} string input 1393 * @since 2.0 1394 * @since 3.0 Changed signature from contains(String, String) to contains(CharSequence, CharSequence) 1395 */ 1396 public static boolean contains(CharSequence seq, CharSequence searchSeq) { 1397 if (seq == null || searchSeq == null) { 1398 return false; 1399 } 1400 return CharSequenceUtils.indexOf(seq, searchSeq, 0) >= 0; 1401 } 1402 1403 /** 1404 * <p>Checks if CharSequence contains a search CharSequence irrespective of case, 1405 * handling {@code null}. Case-insensitivity is defined as by 1406 * {@link String#equalsIgnoreCase(String)}. 1407 * 1408 * <p>A {@code null} CharSequence will return {@code false}.</p> 1409 * 1410 * <pre> 1411 * StringUtils.contains(null, *) = false 1412 * StringUtils.contains(*, null) = false 1413 * StringUtils.contains("", "") = true 1414 * StringUtils.contains("abc", "") = true 1415 * StringUtils.contains("abc", "a") = true 1416 * StringUtils.contains("abc", "z") = false 1417 * StringUtils.contains("abc", "A") = true 1418 * StringUtils.contains("abc", "Z") = false 1419 * </pre> 1420 * 1421 * @param str the CharSequence to check, may be null 1422 * @param searchStr the CharSequence to find, may be null 1423 * @return true if the CharSequence contains the search CharSequence irrespective of 1424 * case or false if not or {@code null} string input 1425 * @since 3.0 Changed signature from containsIgnoreCase(String, String) to containsIgnoreCase(CharSequence, CharSequence) 1426 */ 1427 public static boolean containsIgnoreCase(CharSequence str, CharSequence searchStr) { 1428 if (str == null || searchStr == null) { 1429 return false; 1430 } 1431 int len = searchStr.length(); 1432 int max = str.length() - len; 1433 for (int i = 0; i <= max; i++) { 1434 if (CharSequenceUtils.regionMatches(str, true, i, searchStr, 0, len)) { 1435 return true; 1436 } 1437 } 1438 return false; 1439 } 1440 1441 /** 1442 * Check whether the given CharSequence contains any whitespace characters. 1443 * @param seq the CharSequence to check (may be {@code null}) 1444 * @return {@code true} if the CharSequence is not empty and 1445 * contains at least 1 whitespace character 1446 * @see java.lang.Character#isWhitespace 1447 * @since 3.0 1448 */ 1449 // From org.springframework.util.StringUtils, under Apache License 2.0 1450 public static boolean containsWhitespace(CharSequence seq) { 1451 if (isEmpty(seq)) { 1452 return false; 1453 } 1454 int strLen = seq.length(); 1455 for (int i = 0; i < strLen; i++) { 1456 if (Character.isWhitespace(seq.charAt(i))) { 1457 return true; 1458 } 1459 } 1460 return false; 1461 } 1462 1463 // IndexOfAny chars 1464 //----------------------------------------------------------------------- 1465 /** 1466 * <p>Search a CharSequence to find the first index of any 1467 * character in the given set of characters.</p> 1468 * 1469 * <p>A {@code null} String will return {@code -1}. 1470 * A {@code null} or zero length search array will return {@code -1}.</p> 1471 * 1472 * <pre> 1473 * StringUtils.indexOfAny(null, *) = -1 1474 * StringUtils.indexOfAny("", *) = -1 1475 * StringUtils.indexOfAny(*, null) = -1 1476 * StringUtils.indexOfAny(*, []) = -1 1477 * StringUtils.indexOfAny("zzabyycdxx",['z','a']) = 0 1478 * StringUtils.indexOfAny("zzabyycdxx",['b','y']) = 3 1479 * StringUtils.indexOfAny("aba", ['z']) = -1 1480 * </pre> 1481 * 1482 * @param cs the CharSequence to check, may be null 1483 * @param searchChars the chars to search for, may be null 1484 * @return the index of any of the chars, -1 if no match or null input 1485 * @since 2.0 1486 * @since 3.0 Changed signature from indexOfAny(String, char[]) to indexOfAny(CharSequence, char...) 1487 */ 1488 public static int indexOfAny(CharSequence cs, char... searchChars) { 1489 if (isEmpty(cs) || ArrayUtils.isEmpty(searchChars)) { 1490 return INDEX_NOT_FOUND; 1491 } 1492 int csLen = cs.length(); 1493 int csLast = csLen - 1; 1494 int searchLen = searchChars.length; 1495 int searchLast = searchLen - 1; 1496 for (int i = 0; i < csLen; i++) { 1497 char ch = cs.charAt(i); 1498 for (int j = 0; j < searchLen; j++) { 1499 if (searchChars[j] == ch) { 1500 if (i < csLast && j < searchLast && Character.isHighSurrogate(ch)) { 1501 // ch is a supplementary character 1502 if (searchChars[j + 1] == cs.charAt(i + 1)) { 1503 return i; 1504 } 1505 } else { 1506 return i; 1507 } 1508 } 1509 } 1510 } 1511 return INDEX_NOT_FOUND; 1512 } 1513 1514 /** 1515 * <p>Search a CharSequence to find the first index of any 1516 * character in the given set of characters.</p> 1517 * 1518 * <p>A {@code null} String will return {@code -1}. 1519 * A {@code null} search string will return {@code -1}.</p> 1520 * 1521 * <pre> 1522 * StringUtils.indexOfAny(null, *) = -1 1523 * StringUtils.indexOfAny("", *) = -1 1524 * StringUtils.indexOfAny(*, null) = -1 1525 * StringUtils.indexOfAny(*, "") = -1 1526 * StringUtils.indexOfAny("zzabyycdxx", "za") = 0 1527 * StringUtils.indexOfAny("zzabyycdxx", "by") = 3 1528 * StringUtils.indexOfAny("aba","z") = -1 1529 * </pre> 1530 * 1531 * @param cs the CharSequence to check, may be null 1532 * @param searchChars the chars to search for, may be null 1533 * @return the index of any of the chars, -1 if no match or null input 1534 * @since 2.0 1535 * @since 3.0 Changed signature from indexOfAny(String, String) to indexOfAny(CharSequence, String) 1536 */ 1537 public static int indexOfAny(CharSequence cs, String searchChars) { 1538 if (isEmpty(cs) || isEmpty(searchChars)) { 1539 return INDEX_NOT_FOUND; 1540 } 1541 return indexOfAny(cs, searchChars.toCharArray()); 1542 } 1543 1544 // ContainsAny 1545 //----------------------------------------------------------------------- 1546 /** 1547 * <p>Checks if the CharSequence contains any character in the given 1548 * set of characters.</p> 1549 * 1550 * <p>A {@code null} CharSequence will return {@code false}. 1551 * A {@code null} or zero length search array will return {@code false}.</p> 1552 * 1553 * <pre> 1554 * StringUtils.containsAny(null, *) = false 1555 * StringUtils.containsAny("", *) = false 1556 * StringUtils.containsAny(*, null) = false 1557 * StringUtils.containsAny(*, []) = false 1558 * StringUtils.containsAny("zzabyycdxx",['z','a']) = true 1559 * StringUtils.containsAny("zzabyycdxx",['b','y']) = true 1560 * StringUtils.containsAny("aba", ['z']) = false 1561 * </pre> 1562 * 1563 * @param cs the CharSequence to check, may be null 1564 * @param searchChars the chars to search for, may be null 1565 * @return the {@code true} if any of the chars are found, 1566 * {@code false} if no match or null input 1567 * @since 2.4 1568 * @since 3.0 Changed signature from containsAny(String, char[]) to containsAny(CharSequence, char...) 1569 */ 1570 public static boolean containsAny(CharSequence cs, char... searchChars) { 1571 if (isEmpty(cs) || ArrayUtils.isEmpty(searchChars)) { 1572 return false; 1573 } 1574 int csLength = cs.length(); 1575 int searchLength = searchChars.length; 1576 int csLast = csLength - 1; 1577 int searchLast = searchLength - 1; 1578 for (int i = 0; i < csLength; i++) { 1579 char ch = cs.charAt(i); 1580 for (int j = 0; j < searchLength; j++) { 1581 if (searchChars[j] == ch) { 1582 if (Character.isHighSurrogate(ch)) { 1583 if (j == searchLast) { 1584 // missing low surrogate, fine, like String.indexOf(String) 1585 return true; 1586 } 1587 if (i < csLast && searchChars[j + 1] == cs.charAt(i + 1)) { 1588 return true; 1589 } 1590 } else { 1591 // ch is in the Basic Multilingual Plane 1592 return true; 1593 } 1594 } 1595 } 1596 } 1597 return false; 1598 } 1599 1600 /** 1601 * <p> 1602 * Checks if the CharSequence contains any character in the given set of characters. 1603 * </p> 1604 * 1605 * <p> 1606 * A {@code null} CharSequence will return {@code false}. A {@code null} search CharSequence will return 1607 * {@code false}. 1608 * </p> 1609 * 1610 * <pre> 1611 * StringUtils.containsAny(null, *) = false 1612 * StringUtils.containsAny("", *) = false 1613 * StringUtils.containsAny(*, null) = false 1614 * StringUtils.containsAny(*, "") = false 1615 * StringUtils.containsAny("zzabyycdxx", "za") = true 1616 * StringUtils.containsAny("zzabyycdxx", "by") = true 1617 * StringUtils.containsAny("aba","z") = false 1618 * </pre> 1619 * 1620 * @param cs 1621 * the CharSequence to check, may be null 1622 * @param searchChars 1623 * the chars to search for, may be null 1624 * @return the {@code true} if any of the chars are found, {@code false} if no match or null input 1625 * @since 2.4 1626 * @since 3.0 Changed signature from containsAny(String, String) to containsAny(CharSequence, CharSequence) 1627 */ 1628 public static boolean containsAny(CharSequence cs, CharSequence searchChars) { 1629 if (searchChars == null) { 1630 return false; 1631 } 1632 return containsAny(cs, CharSequenceUtils.toCharArray(searchChars)); 1633 } 1634 1635 // IndexOfAnyBut chars 1636 //----------------------------------------------------------------------- 1637 /** 1638 * <p>Searches a CharSequence to find the first index of any 1639 * character not in the given set of characters.</p> 1640 * 1641 * <p>A {@code null} CharSequence will return {@code -1}. 1642 * A {@code null} or zero length search array will return {@code -1}.</p> 1643 * 1644 * <pre> 1645 * StringUtils.indexOfAnyBut(null, *) = -1 1646 * StringUtils.indexOfAnyBut("", *) = -1 1647 * StringUtils.indexOfAnyBut(*, null) = -1 1648 * StringUtils.indexOfAnyBut(*, []) = -1 1649 * StringUtils.indexOfAnyBut("zzabyycdxx", new char[] {'z', 'a'} ) = 3 1650 * StringUtils.indexOfAnyBut("aba", new char[] {'z'} ) = 0 1651 * StringUtils.indexOfAnyBut("aba", new char[] {'a', 'b'} ) = -1 1652 1653 * </pre> 1654 * 1655 * @param cs the CharSequence to check, may be null 1656 * @param searchChars the chars to search for, may be null 1657 * @return the index of any of the chars, -1 if no match or null input 1658 * @since 2.0 1659 * @since 3.0 Changed signature from indexOfAnyBut(String, char[]) to indexOfAnyBut(CharSequence, char...) 1660 */ 1661 public static int indexOfAnyBut(CharSequence cs, char... searchChars) { 1662 if (isEmpty(cs) || ArrayUtils.isEmpty(searchChars)) { 1663 return INDEX_NOT_FOUND; 1664 } 1665 int csLen = cs.length(); 1666 int csLast = csLen - 1; 1667 int searchLen = searchChars.length; 1668 int searchLast = searchLen - 1; 1669 outer: 1670 for (int i = 0; i < csLen; i++) { 1671 char ch = cs.charAt(i); 1672 for (int j = 0; j < searchLen; j++) { 1673 if (searchChars[j] == ch) { 1674 if (i < csLast && j < searchLast && Character.isHighSurrogate(ch)) { 1675 if (searchChars[j + 1] == cs.charAt(i + 1)) { 1676 continue outer; 1677 } 1678 } else { 1679 continue outer; 1680 } 1681 } 1682 } 1683 return i; 1684 } 1685 return INDEX_NOT_FOUND; 1686 } 1687 1688 /** 1689 * <p>Search a CharSequence to find the first index of any 1690 * character not in the given set of characters.</p> 1691 * 1692 * <p>A {@code null} CharSequence will return {@code -1}. 1693 * A {@code null} or empty search string will return {@code -1}.</p> 1694 * 1695 * <pre> 1696 * StringUtils.indexOfAnyBut(null, *) = -1 1697 * StringUtils.indexOfAnyBut("", *) = -1 1698 * StringUtils.indexOfAnyBut(*, null) = -1 1699 * StringUtils.indexOfAnyBut(*, "") = -1 1700 * StringUtils.indexOfAnyBut("zzabyycdxx", "za") = 3 1701 * StringUtils.indexOfAnyBut("zzabyycdxx", "") = -1 1702 * StringUtils.indexOfAnyBut("aba","ab") = -1 1703 * </pre> 1704 * 1705 * @param seq the CharSequence to check, may be null 1706 * @param searchChars the chars to search for, may be null 1707 * @return the index of any of the chars, -1 if no match or null input 1708 * @since 2.0 1709 * @since 3.0 Changed signature from indexOfAnyBut(String, String) to indexOfAnyBut(CharSequence, CharSequence) 1710 */ 1711 public static int indexOfAnyBut(CharSequence seq, CharSequence searchChars) { 1712 if (isEmpty(seq) || isEmpty(searchChars)) { 1713 return INDEX_NOT_FOUND; 1714 } 1715 int strLen = seq.length(); 1716 for (int i = 0; i < strLen; i++) { 1717 char ch = seq.charAt(i); 1718 boolean chFound = CharSequenceUtils.indexOf(searchChars, ch, 0) >= 0; 1719 if (i + 1 < strLen && Character.isHighSurrogate(ch)) { 1720 char ch2 = seq.charAt(i + 1); 1721 if (chFound && CharSequenceUtils.indexOf(searchChars, ch2, 0) < 0) { 1722 return i; 1723 } 1724 } else { 1725 if (!chFound) { 1726 return i; 1727 } 1728 } 1729 } 1730 return INDEX_NOT_FOUND; 1731 } 1732 1733 // ContainsOnly 1734 //----------------------------------------------------------------------- 1735 /** 1736 * <p>Checks if the CharSequence contains only certain characters.</p> 1737 * 1738 * <p>A {@code null} CharSequence will return {@code false}. 1739 * A {@code null} valid character array will return {@code false}. 1740 * An empty CharSequence (length()=0) always returns {@code true}.</p> 1741 * 1742 * <pre> 1743 * StringUtils.containsOnly(null, *) = false 1744 * StringUtils.containsOnly(*, null) = false 1745 * StringUtils.containsOnly("", *) = true 1746 * StringUtils.containsOnly("ab", '') = false 1747 * StringUtils.containsOnly("abab", 'abc') = true 1748 * StringUtils.containsOnly("ab1", 'abc') = false 1749 * StringUtils.containsOnly("abz", 'abc') = false 1750 * </pre> 1751 * 1752 * @param cs the String to check, may be null 1753 * @param valid an array of valid chars, may be null 1754 * @return true if it only contains valid chars and is non-null 1755 * @since 3.0 Changed signature from containsOnly(String, char[]) to containsOnly(CharSequence, char...) 1756 */ 1757 public static boolean containsOnly(CharSequence cs, char... valid) { 1758 // All these pre-checks are to maintain API with an older version 1759 if (valid == null || cs == null) { 1760 return false; 1761 } 1762 if (cs.length() == 0) { 1763 return true; 1764 } 1765 if (valid.length == 0) { 1766 return false; 1767 } 1768 return indexOfAnyBut(cs, valid) == INDEX_NOT_FOUND; 1769 } 1770 1771 /** 1772 * <p>Checks if the CharSequence contains only certain characters.</p> 1773 * 1774 * <p>A {@code null} CharSequence will return {@code false}. 1775 * A {@code null} valid character String will return {@code false}. 1776 * An empty String (length()=0) always returns {@code true}.</p> 1777 * 1778 * <pre> 1779 * StringUtils.containsOnly(null, *) = false 1780 * StringUtils.containsOnly(*, null) = false 1781 * StringUtils.containsOnly("", *) = true 1782 * StringUtils.containsOnly("ab", "") = false 1783 * StringUtils.containsOnly("abab", "abc") = true 1784 * StringUtils.containsOnly("ab1", "abc") = false 1785 * StringUtils.containsOnly("abz", "abc") = false 1786 * </pre> 1787 * 1788 * @param cs the CharSequence to check, may be null 1789 * @param validChars a String of valid chars, may be null 1790 * @return true if it only contains valid chars and is non-null 1791 * @since 2.0 1792 * @since 3.0 Changed signature from containsOnly(String, String) to containsOnly(CharSequence, String) 1793 */ 1794 public static boolean containsOnly(CharSequence cs, String validChars) { 1795 if (cs == null || validChars == null) { 1796 return false; 1797 } 1798 return containsOnly(cs, validChars.toCharArray()); 1799 } 1800 1801 // ContainsNone 1802 //----------------------------------------------------------------------- 1803 /** 1804 * <p>Checks that the CharSequence does not contain certain characters.</p> 1805 * 1806 * <p>A {@code null} CharSequence will return {@code true}. 1807 * A {@code null} invalid character array will return {@code true}. 1808 * An empty CharSequence (length()=0) always returns true.</p> 1809 * 1810 * <pre> 1811 * StringUtils.containsNone(null, *) = true 1812 * StringUtils.containsNone(*, null) = true 1813 * StringUtils.containsNone("", *) = true 1814 * StringUtils.containsNone("ab", '') = true 1815 * StringUtils.containsNone("abab", 'xyz') = true 1816 * StringUtils.containsNone("ab1", 'xyz') = true 1817 * StringUtils.containsNone("abz", 'xyz') = false 1818 * </pre> 1819 * 1820 * @param cs the CharSequence to check, may be null 1821 * @param searchChars an array of invalid chars, may be null 1822 * @return true if it contains none of the invalid chars, or is null 1823 * @since 2.0 1824 * @since 3.0 Changed signature from containsNone(String, char[]) to containsNone(CharSequence, char...) 1825 */ 1826 public static boolean containsNone(CharSequence cs, char... searchChars) { 1827 if (cs == null || searchChars == null) { 1828 return true; 1829 } 1830 int csLen = cs.length(); 1831 int csLast = csLen - 1; 1832 int searchLen = searchChars.length; 1833 int searchLast = searchLen - 1; 1834 for (int i = 0; i < csLen; i++) { 1835 char ch = cs.charAt(i); 1836 for (int j = 0; j < searchLen; j++) { 1837 if (searchChars[j] == ch) { 1838 if (Character.isHighSurrogate(ch)) { 1839 if (j == searchLast) { 1840 // missing low surrogate, fine, like String.indexOf(String) 1841 return false; 1842 } 1843 if (i < csLast && searchChars[j + 1] == cs.charAt(i + 1)) { 1844 return false; 1845 } 1846 } else { 1847 // ch is in the Basic Multilingual Plane 1848 return false; 1849 } 1850 } 1851 } 1852 } 1853 return true; 1854 } 1855 1856 /** 1857 * <p>Checks that the CharSequence does not contain certain characters.</p> 1858 * 1859 * <p>A {@code null} CharSequence will return {@code true}. 1860 * A {@code null} invalid character array will return {@code true}. 1861 * An empty String ("") always returns true.</p> 1862 * 1863 * <pre> 1864 * StringUtils.containsNone(null, *) = true 1865 * StringUtils.containsNone(*, null) = true 1866 * StringUtils.containsNone("", *) = true 1867 * StringUtils.containsNone("ab", "") = true 1868 * StringUtils.containsNone("abab", "xyz") = true 1869 * StringUtils.containsNone("ab1", "xyz") = true 1870 * StringUtils.containsNone("abz", "xyz") = false 1871 * </pre> 1872 * 1873 * @param cs the CharSequence to check, may be null 1874 * @param invalidChars a String of invalid chars, may be null 1875 * @return true if it contains none of the invalid chars, or is null 1876 * @since 2.0 1877 * @since 3.0 Changed signature from containsNone(String, String) to containsNone(CharSequence, String) 1878 */ 1879 public static boolean containsNone(CharSequence cs, String invalidChars) { 1880 if (cs == null || invalidChars == null) { 1881 return true; 1882 } 1883 return containsNone(cs, invalidChars.toCharArray()); 1884 } 1885 1886 // IndexOfAny strings 1887 //----------------------------------------------------------------------- 1888 /** 1889 * <p>Find the first index of any of a set of potential substrings.</p> 1890 * 1891 * <p>A {@code null} CharSequence will return {@code -1}. 1892 * A {@code null} or zero length search array will return {@code -1}. 1893 * A {@code null} search array entry will be ignored, but a search 1894 * array containing "" will return {@code 0} if {@code str} is not 1895 * null. This method uses {@link String#indexOf(String)} if possible.</p> 1896 * 1897 * <pre> 1898 * StringUtils.indexOfAny(null, *) = -1 1899 * StringUtils.indexOfAny(*, null) = -1 1900 * StringUtils.indexOfAny(*, []) = -1 1901 * StringUtils.indexOfAny("zzabyycdxx", ["ab","cd"]) = 2 1902 * StringUtils.indexOfAny("zzabyycdxx", ["cd","ab"]) = 2 1903 * StringUtils.indexOfAny("zzabyycdxx", ["mn","op"]) = -1 1904 * StringUtils.indexOfAny("zzabyycdxx", ["zab","aby"]) = 1 1905 * StringUtils.indexOfAny("zzabyycdxx", [""]) = 0 1906 * StringUtils.indexOfAny("", [""]) = 0 1907 * StringUtils.indexOfAny("", ["a"]) = -1 1908 * </pre> 1909 * 1910 * @param str the CharSequence to check, may be null 1911 * @param searchStrs the CharSequences to search for, may be null 1912 * @return the first index of any of the searchStrs in str, -1 if no match 1913 * @since 3.0 Changed signature from indexOfAny(String, String[]) to indexOfAny(CharSequence, CharSequence...) 1914 */ 1915 public static int indexOfAny(CharSequence str, CharSequence... searchStrs) { 1916 if (str == null || searchStrs == null) { 1917 return INDEX_NOT_FOUND; 1918 } 1919 int sz = searchStrs.length; 1920 1921 // String's can't have a MAX_VALUEth index. 1922 int ret = Integer.MAX_VALUE; 1923 1924 int tmp = 0; 1925 for (int i = 0; i < sz; i++) { 1926 CharSequence search = searchStrs[i]; 1927 if (search == null) { 1928 continue; 1929 } 1930 tmp = CharSequenceUtils.indexOf(str, search, 0); 1931 if (tmp == INDEX_NOT_FOUND) { 1932 continue; 1933 } 1934 1935 if (tmp < ret) { 1936 ret = tmp; 1937 } 1938 } 1939 1940 return (ret == Integer.MAX_VALUE) ? INDEX_NOT_FOUND : ret; 1941 } 1942 1943 /** 1944 * <p>Find the latest index of any of a set of potential substrings.</p> 1945 * 1946 * <p>A {@code null} CharSequence will return {@code -1}. 1947 * A {@code null} search array will return {@code -1}. 1948 * A {@code null} or zero length search array entry will be ignored, 1949 * but a search array containing "" will return the length of {@code str} 1950 * if {@code str} is not null. This method uses {@link String#indexOf(String)} if possible</p> 1951 * 1952 * <pre> 1953 * StringUtils.lastIndexOfAny(null, *) = -1 1954 * StringUtils.lastIndexOfAny(*, null) = -1 1955 * StringUtils.lastIndexOfAny(*, []) = -1 1956 * StringUtils.lastIndexOfAny(*, [null]) = -1 1957 * StringUtils.lastIndexOfAny("zzabyycdxx", ["ab","cd"]) = 6 1958 * StringUtils.lastIndexOfAny("zzabyycdxx", ["cd","ab"]) = 6 1959 * StringUtils.lastIndexOfAny("zzabyycdxx", ["mn","op"]) = -1 1960 * StringUtils.lastIndexOfAny("zzabyycdxx", ["mn","op"]) = -1 1961 * StringUtils.lastIndexOfAny("zzabyycdxx", ["mn",""]) = 10 1962 * </pre> 1963 * 1964 * @param str the CharSequence to check, may be null 1965 * @param searchStrs the CharSequences to search for, may be null 1966 * @return the last index of any of the CharSequences, -1 if no match 1967 * @since 3.0 Changed signature from lastIndexOfAny(String, String[]) to lastIndexOfAny(CharSequence, CharSequence) 1968 */ 1969 public static int lastIndexOfAny(CharSequence str, CharSequence... searchStrs) { 1970 if (str == null || searchStrs == null) { 1971 return INDEX_NOT_FOUND; 1972 } 1973 int sz = searchStrs.length; 1974 int ret = INDEX_NOT_FOUND; 1975 int tmp = 0; 1976 for (int i = 0; i < sz; i++) { 1977 CharSequence search = searchStrs[i]; 1978 if (search == null) { 1979 continue; 1980 } 1981 tmp = CharSequenceUtils.lastIndexOf(str, search, str.length()); 1982 if (tmp > ret) { 1983 ret = tmp; 1984 } 1985 } 1986 return ret; 1987 } 1988 1989 // Substring 1990 //----------------------------------------------------------------------- 1991 /** 1992 * <p>Gets a substring from the specified String avoiding exceptions.</p> 1993 * 1994 * <p>A negative start position can be used to start {@code n} 1995 * characters from the end of the String.</p> 1996 * 1997 * <p>A {@code null} String will return {@code null}. 1998 * An empty ("") String will return "".</p> 1999 * 2000 * <pre> 2001 * StringUtils.substring(null, *) = null 2002 * StringUtils.substring("", *) = "" 2003 * StringUtils.substring("abc", 0) = "abc" 2004 * StringUtils.substring("abc", 2) = "c" 2005 * StringUtils.substring("abc", 4) = "" 2006 * StringUtils.substring("abc", -2) = "bc" 2007 * StringUtils.substring("abc", -4) = "abc" 2008 * </pre> 2009 * 2010 * @param str the String to get the substring from, may be null 2011 * @param start the position to start from, negative means 2012 * count back from the end of the String by this many characters 2013 * @return substring from start position, {@code null} if null String input 2014 */ 2015 public static String substring(String str, int start) { 2016 if (str == null) { 2017 return null; 2018 } 2019 2020 // handle negatives, which means last n characters 2021 if (start < 0) { 2022 start = str.length() + start; // remember start is negative 2023 } 2024 2025 if (start < 0) { 2026 start = 0; 2027 } 2028 if (start > str.length()) { 2029 return EMPTY; 2030 } 2031 2032 return str.substring(start); 2033 } 2034 2035 /** 2036 * <p>Gets a substring from the specified String avoiding exceptions.</p> 2037 * 2038 * <p>A negative start position can be used to start/end {@code n} 2039 * characters from the end of the String.</p> 2040 * 2041 * <p>The returned substring starts with the character in the {@code start} 2042 * position and ends before the {@code end} position. All position counting is 2043 * zero-based -- i.e., to start at the beginning of the string use 2044 * {@code start = 0}. Negative start and end positions can be used to 2045 * specify offsets relative to the end of the String.</p> 2046 * 2047 * <p>If {@code start} is not strictly to the left of {@code end}, "" 2048 * is returned.</p> 2049 * 2050 * <pre> 2051 * StringUtils.substring(null, *, *) = null 2052 * StringUtils.substring("", * , *) = ""; 2053 * StringUtils.substring("abc", 0, 2) = "ab" 2054 * StringUtils.substring("abc", 2, 0) = "" 2055 * StringUtils.substring("abc", 2, 4) = "c" 2056 * StringUtils.substring("abc", 4, 6) = "" 2057 * StringUtils.substring("abc", 2, 2) = "" 2058 * StringUtils.substring("abc", -2, -1) = "b" 2059 * StringUtils.substring("abc", -4, 2) = "ab" 2060 * </pre> 2061 * 2062 * @param str the String to get the substring from, may be null 2063 * @param start the position to start from, negative means 2064 * count back from the end of the String by this many characters 2065 * @param end the position to end at (exclusive), negative means 2066 * count back from the end of the String by this many characters 2067 * @return substring from start position to end position, 2068 * {@code null} if null String input 2069 */ 2070 public static String substring(String str, int start, int end) { 2071 if (str == null) { 2072 return null; 2073 } 2074 2075 // handle negatives 2076 if (end < 0) { 2077 end = str.length() + end; // remember end is negative 2078 } 2079 if (start < 0) { 2080 start = str.length() + start; // remember start is negative 2081 } 2082 2083 // check length next 2084 if (end > str.length()) { 2085 end = str.length(); 2086 } 2087 2088 // if start is greater than end, return "" 2089 if (start > end) { 2090 return EMPTY; 2091 } 2092 2093 if (start < 0) { 2094 start = 0; 2095 } 2096 if (end < 0) { 2097 end = 0; 2098 } 2099 2100 return str.substring(start, end); 2101 } 2102 2103 // Left/Right/Mid 2104 //----------------------------------------------------------------------- 2105 /** 2106 * <p>Gets the leftmost {@code len} characters of a String.</p> 2107 * 2108 * <p>If {@code len} characters are not available, or the 2109 * String is {@code null}, the String will be returned without 2110 * an exception. An empty String is returned if len is negative.</p> 2111 * 2112 * <pre> 2113 * StringUtils.left(null, *) = null 2114 * StringUtils.left(*, -ve) = "" 2115 * StringUtils.left("", *) = "" 2116 * StringUtils.left("abc", 0) = "" 2117 * StringUtils.left("abc", 2) = "ab" 2118 * StringUtils.left("abc", 4) = "abc" 2119 * </pre> 2120 * 2121 * @param str the String to get the leftmost characters from, may be null 2122 * @param len the length of the required String 2123 * @return the leftmost characters, {@code null} if null String input 2124 */ 2125 public static String left(String str, int len) { 2126 if (str == null) { 2127 return null; 2128 } 2129 if (len < 0) { 2130 return EMPTY; 2131 } 2132 if (str.length() <= len) { 2133 return str; 2134 } 2135 return str.substring(0, len); 2136 } 2137 2138 /** 2139 * <p>Gets the rightmost {@code len} characters of a String.</p> 2140 * 2141 * <p>If {@code len} characters are not available, or the String 2142 * is {@code null}, the String will be returned without an 2143 * an exception. An empty String is returned if len is negative.</p> 2144 * 2145 * <pre> 2146 * StringUtils.right(null, *) = null 2147 * StringUtils.right(*, -ve) = "" 2148 * StringUtils.right("", *) = "" 2149 * StringUtils.right("abc", 0) = "" 2150 * StringUtils.right("abc", 2) = "bc" 2151 * StringUtils.right("abc", 4) = "abc" 2152 * </pre> 2153 * 2154 * @param str the String to get the rightmost characters from, may be null 2155 * @param len the length of the required String 2156 * @return the rightmost characters, {@code null} if null String input 2157 */ 2158 public static String right(String str, int len) { 2159 if (str == null) { 2160 return null; 2161 } 2162 if (len < 0) { 2163 return EMPTY; 2164 } 2165 if (str.length() <= len) { 2166 return str; 2167 } 2168 return str.substring(str.length() - len); 2169 } 2170 2171 /** 2172 * <p>Gets {@code len} characters from the middle of a String.</p> 2173 * 2174 * <p>If {@code len} characters are not available, the remainder 2175 * of the String will be returned without an exception. If the 2176 * String is {@code null}, {@code null} will be returned. 2177 * An empty String is returned if len is negative or exceeds the 2178 * length of {@code str}.</p> 2179 * 2180 * <pre> 2181 * StringUtils.mid(null, *, *) = null 2182 * StringUtils.mid(*, *, -ve) = "" 2183 * StringUtils.mid("", 0, *) = "" 2184 * StringUtils.mid("abc", 0, 2) = "ab" 2185 * StringUtils.mid("abc", 0, 4) = "abc" 2186 * StringUtils.mid("abc", 2, 4) = "c" 2187 * StringUtils.mid("abc", 4, 2) = "" 2188 * StringUtils.mid("abc", -2, 2) = "ab" 2189 * </pre> 2190 * 2191 * @param str the String to get the characters from, may be null 2192 * @param pos the position to start from, negative treated as zero 2193 * @param len the length of the required String 2194 * @return the middle characters, {@code null} if null String input 2195 */ 2196 public static String mid(String str, int pos, int len) { 2197 if (str == null) { 2198 return null; 2199 } 2200 if (len < 0 || pos > str.length()) { 2201 return EMPTY; 2202 } 2203 if (pos < 0) { 2204 pos = 0; 2205 } 2206 if (str.length() <= (pos + len)) { 2207 return str.substring(pos); 2208 } 2209 return str.substring(pos, pos + len); 2210 } 2211 2212 // SubStringAfter/SubStringBefore 2213 //----------------------------------------------------------------------- 2214 /** 2215 * <p>Gets the substring before the first occurrence of a separator. 2216 * The separator is not returned.</p> 2217 * 2218 * <p>A {@code null} string input will return {@code null}. 2219 * An empty ("") string input will return the empty string. 2220 * A {@code null} separator will return the input string.</p> 2221 * 2222 * <p>If nothing is found, the string input is returned.</p> 2223 * 2224 * <pre> 2225 * StringUtils.substringBefore(null, *) = null 2226 * StringUtils.substringBefore("", *) = "" 2227 * StringUtils.substringBefore("abc", "a") = "" 2228 * StringUtils.substringBefore("abcba", "b") = "a" 2229 * StringUtils.substringBefore("abc", "c") = "ab" 2230 * StringUtils.substringBefore("abc", "d") = "abc" 2231 * StringUtils.substringBefore("abc", "") = "" 2232 * StringUtils.substringBefore("abc", null) = "abc" 2233 * </pre> 2234 * 2235 * @param str the String to get a substring from, may be null 2236 * @param separator the String to search for, may be null 2237 * @return the substring before the first occurrence of the separator, 2238 * {@code null} if null String input 2239 * @since 2.0 2240 */ 2241 public static String substringBefore(String str, String separator) { 2242 if (isEmpty(str) || separator == null) { 2243 return str; 2244 } 2245 if (separator.length() == 0) { 2246 return EMPTY; 2247 } 2248 int pos = str.indexOf(separator); 2249 if (pos == INDEX_NOT_FOUND) { 2250 return str; 2251 } 2252 return str.substring(0, pos); 2253 } 2254 2255 /** 2256 * <p>Gets the substring after the first occurrence of a separator. 2257 * The separator is not returned.</p> 2258 * 2259 * <p>A {@code null} string input will return {@code null}. 2260 * An empty ("") string input will return the empty string. 2261 * A {@code null} separator will return the empty string if the 2262 * input string is not {@code null}.</p> 2263 * 2264 * <p>If nothing is found, the empty string is returned.</p> 2265 * 2266 * <pre> 2267 * StringUtils.substringAfter(null, *) = null 2268 * StringUtils.substringAfter("", *) = "" 2269 * StringUtils.substringAfter(*, null) = "" 2270 * StringUtils.substringAfter("abc", "a") = "bc" 2271 * StringUtils.substringAfter("abcba", "b") = "cba" 2272 * StringUtils.substringAfter("abc", "c") = "" 2273 * StringUtils.substringAfter("abc", "d") = "" 2274 * StringUtils.substringAfter("abc", "") = "abc" 2275 * </pre> 2276 * 2277 * @param str the String to get a substring from, may be null 2278 * @param separator the String to search for, may be null 2279 * @return the substring after the first occurrence of the separator, 2280 * {@code null} if null String input 2281 * @since 2.0 2282 */ 2283 public static String substringAfter(String str, String separator) { 2284 if (isEmpty(str)) { 2285 return str; 2286 } 2287 if (separator == null) { 2288 return EMPTY; 2289 } 2290 int pos = str.indexOf(separator); 2291 if (pos == INDEX_NOT_FOUND) { 2292 return EMPTY; 2293 } 2294 return str.substring(pos + separator.length()); 2295 } 2296 2297 /** 2298 * <p>Gets the substring before the last occurrence of a separator. 2299 * The separator is not returned.</p> 2300 * 2301 * <p>A {@code null} string input will return {@code null}. 2302 * An empty ("") string input will return the empty string. 2303 * An empty or {@code null} separator will return the input string.</p> 2304 * 2305 * <p>If nothing is found, the string input is returned.</p> 2306 * 2307 * <pre> 2308 * StringUtils.substringBeforeLast(null, *) = null 2309 * StringUtils.substringBeforeLast("", *) = "" 2310 * StringUtils.substringBeforeLast("abcba", "b") = "abc" 2311 * StringUtils.substringBeforeLast("abc", "c") = "ab" 2312 * StringUtils.substringBeforeLast("a", "a") = "" 2313 * StringUtils.substringBeforeLast("a", "z") = "a" 2314 * StringUtils.substringBeforeLast("a", null) = "a" 2315 * StringUtils.substringBeforeLast("a", "") = "a" 2316 * </pre> 2317 * 2318 * @param str the String to get a substring from, may be null 2319 * @param separator the String to search for, may be null 2320 * @return the substring before the last occurrence of the separator, 2321 * {@code null} if null String input 2322 * @since 2.0 2323 */ 2324 public static String substringBeforeLast(String str, String separator) { 2325 if (isEmpty(str) || isEmpty(separator)) { 2326 return str; 2327 } 2328 int pos = str.lastIndexOf(separator); 2329 if (pos == INDEX_NOT_FOUND) { 2330 return str; 2331 } 2332 return str.substring(0, pos); 2333 } 2334 2335 /** 2336 * <p>Gets the substring after the last occurrence of a separator. 2337 * The separator is not returned.</p> 2338 * 2339 * <p>A {@code null} string input will return {@code null}. 2340 * An empty ("") string input will return the empty string. 2341 * An empty or {@code null} separator will return the empty string if 2342 * the input string is not {@code null}.</p> 2343 * 2344 * <p>If nothing is found, the empty string is returned.</p> 2345 * 2346 * <pre> 2347 * StringUtils.substringAfterLast(null, *) = null 2348 * StringUtils.substringAfterLast("", *) = "" 2349 * StringUtils.substringAfterLast(*, "") = "" 2350 * StringUtils.substringAfterLast(*, null) = "" 2351 * StringUtils.substringAfterLast("abc", "a") = "bc" 2352 * StringUtils.substringAfterLast("abcba", "b") = "a" 2353 * StringUtils.substringAfterLast("abc", "c") = "" 2354 * StringUtils.substringAfterLast("a", "a") = "" 2355 * StringUtils.substringAfterLast("a", "z") = "" 2356 * </pre> 2357 * 2358 * @param str the String to get a substring from, may be null 2359 * @param separator the String to search for, may be null 2360 * @return the substring after the last occurrence of the separator, 2361 * {@code null} if null String input 2362 * @since 2.0 2363 */ 2364 public static String substringAfterLast(String str, String separator) { 2365 if (isEmpty(str)) { 2366 return str; 2367 } 2368 if (isEmpty(separator)) { 2369 return EMPTY; 2370 } 2371 int pos = str.lastIndexOf(separator); 2372 if (pos == INDEX_NOT_FOUND || pos == (str.length() - separator.length())) { 2373 return EMPTY; 2374 } 2375 return str.substring(pos + separator.length()); 2376 } 2377 2378 // Substring between 2379 //----------------------------------------------------------------------- 2380 /** 2381 * <p>Gets the String that is nested in between two instances of the 2382 * same String.</p> 2383 * 2384 * <p>A {@code null} input String returns {@code null}. 2385 * A {@code null} tag returns {@code null}.</p> 2386 * 2387 * <pre> 2388 * StringUtils.substringBetween(null, *) = null 2389 * StringUtils.substringBetween("", "") = "" 2390 * StringUtils.substringBetween("", "tag") = null 2391 * StringUtils.substringBetween("tagabctag", null) = null 2392 * StringUtils.substringBetween("tagabctag", "") = "" 2393 * StringUtils.substringBetween("tagabctag", "tag") = "abc" 2394 * </pre> 2395 * 2396 * @param str the String containing the substring, may be null 2397 * @param tag the String before and after the substring, may be null 2398 * @return the substring, {@code null} if no match 2399 * @since 2.0 2400 */ 2401 public static String substringBetween(String str, String tag) { 2402 return substringBetween(str, tag, tag); 2403 } 2404 2405 /** 2406 * <p>Gets the String that is nested in between two Strings. 2407 * Only the first match is returned.</p> 2408 * 2409 * <p>A {@code null} input String returns {@code null}. 2410 * A {@code null} open/close returns {@code null} (no match). 2411 * An empty ("") open and close returns an empty string.</p> 2412 * 2413 * <pre> 2414 * StringUtils.substringBetween("wx[b]yz", "[", "]") = "b" 2415 * StringUtils.substringBetween(null, *, *) = null 2416 * StringUtils.substringBetween(*, null, *) = null 2417 * StringUtils.substringBetween(*, *, null) = null 2418 * StringUtils.substringBetween("", "", "") = "" 2419 * StringUtils.substringBetween("", "", "]") = null 2420 * StringUtils.substringBetween("", "[", "]") = null 2421 * StringUtils.substringBetween("yabcz", "", "") = "" 2422 * StringUtils.substringBetween("yabcz", "y", "z") = "abc" 2423 * StringUtils.substringBetween("yabczyabcz", "y", "z") = "abc" 2424 * </pre> 2425 * 2426 * @param str the String containing the substring, may be null 2427 * @param open the String before the substring, may be null 2428 * @param close the String after the substring, may be null 2429 * @return the substring, {@code null} if no match 2430 * @since 2.0 2431 */ 2432 public static String substringBetween(String str, String open, String close) { 2433 if (str == null || open == null || close == null) { 2434 return null; 2435 } 2436 int start = str.indexOf(open); 2437 if (start != INDEX_NOT_FOUND) { 2438 int end = str.indexOf(close, start + open.length()); 2439 if (end != INDEX_NOT_FOUND) { 2440 return str.substring(start + open.length(), end); 2441 } 2442 } 2443 return null; 2444 } 2445 2446 /** 2447 * <p>Searches a String for substrings delimited by a start and end tag, 2448 * returning all matching substrings in an array.</p> 2449 * 2450 * <p>A {@code null} input String returns {@code null}. 2451 * A {@code null} open/close returns {@code null} (no match). 2452 * An empty ("") open/close returns {@code null} (no match).</p> 2453 * 2454 * <pre> 2455 * StringUtils.substringsBetween("[a][b][c]", "[", "]") = ["a","b","c"] 2456 * StringUtils.substringsBetween(null, *, *) = null 2457 * StringUtils.substringsBetween(*, null, *) = null 2458 * StringUtils.substringsBetween(*, *, null) = null 2459 * StringUtils.substringsBetween("", "[", "]") = [] 2460 * </pre> 2461 * 2462 * @param str the String containing the substrings, null returns null, empty returns empty 2463 * @param open the String identifying the start of the substring, empty returns null 2464 * @param close the String identifying the end of the substring, empty returns null 2465 * @return a String Array of substrings, or {@code null} if no match 2466 * @since 2.3 2467 */ 2468 public static String[] substringsBetween(String str, String open, String close) { 2469 if (str == null || isEmpty(open) || isEmpty(close)) { 2470 return null; 2471 } 2472 int strLen = str.length(); 2473 if (strLen == 0) { 2474 return ArrayUtils.EMPTY_STRING_ARRAY; 2475 } 2476 int closeLen = close.length(); 2477 int openLen = open.length(); 2478 List<String> list = new ArrayList<String>(); 2479 int pos = 0; 2480 while (pos < (strLen - closeLen)) { 2481 int start = str.indexOf(open, pos); 2482 if (start < 0) { 2483 break; 2484 } 2485 start += openLen; 2486 int end = str.indexOf(close, start); 2487 if (end < 0) { 2488 break; 2489 } 2490 list.add(str.substring(start, end)); 2491 pos = end + closeLen; 2492 } 2493 if (list.isEmpty()) { 2494 return null; 2495 } 2496 return list.toArray(new String [list.size()]); 2497 } 2498 2499 // Nested extraction 2500 //----------------------------------------------------------------------- 2501 2502 // Splitting 2503 //----------------------------------------------------------------------- 2504 /** 2505 * <p>Splits the provided text into an array, using whitespace as the 2506 * separator. 2507 * Whitespace is defined by {@link Character#isWhitespace(char)}.</p> 2508 * 2509 * <p>The separator is not included in the returned String array. 2510 * Adjacent separators are treated as one separator. 2511 * For more control over the split use the StrTokenizer class.</p> 2512 * 2513 * <p>A {@code null} input String returns {@code null}.</p> 2514 * 2515 * <pre> 2516 * StringUtils.split(null) = null 2517 * StringUtils.split("") = [] 2518 * StringUtils.split("abc def") = ["abc", "def"] 2519 * StringUtils.split("abc def") = ["abc", "def"] 2520 * StringUtils.split(" abc ") = ["abc"] 2521 * </pre> 2522 * 2523 * @param str the String to parse, may be null 2524 * @return an array of parsed Strings, {@code null} if null String input 2525 */ 2526 public static String[] split(String str) { 2527 return split(str, null, -1); 2528 } 2529 2530 /** 2531 * <p>Splits the provided text into an array, separator specified. 2532 * This is an alternative to using StringTokenizer.</p> 2533 * 2534 * <p>The separator is not included in the returned String array. 2535 * Adjacent separators are treated as one separator. 2536 * For more control over the split use the StrTokenizer class.</p> 2537 * 2538 * <p>A {@code null} input String returns {@code null}.</p> 2539 * 2540 * <pre> 2541 * StringUtils.split(null, *) = null 2542 * StringUtils.split("", *) = [] 2543 * StringUtils.split("a.b.c", '.') = ["a", "b", "c"] 2544 * StringUtils.split("a..b.c", '.') = ["a", "b", "c"] 2545 * StringUtils.split("a:b:c", '.') = ["a:b:c"] 2546 * StringUtils.split("a b c", ' ') = ["a", "b", "c"] 2547 * </pre> 2548 * 2549 * @param str the String to parse, may be null 2550 * @param separatorChar the character used as the delimiter 2551 * @return an array of parsed Strings, {@code null} if null String input 2552 * @since 2.0 2553 */ 2554 public static String[] split(String str, char separatorChar) { 2555 return splitWorker(str, separatorChar, false); 2556 } 2557 2558 /** 2559 * <p>Splits the provided text into an array, separators specified. 2560 * This is an alternative to using StringTokenizer.</p> 2561 * 2562 * <p>The separator is not included in the returned String array. 2563 * Adjacent separators are treated as one separator. 2564 * For more control over the split use the StrTokenizer class.</p> 2565 * 2566 * <p>A {@code null} input String returns {@code null}. 2567 * A {@code null} separatorChars splits on whitespace.</p> 2568 * 2569 * <pre> 2570 * StringUtils.split(null, *) = null 2571 * StringUtils.split("", *) = [] 2572 * StringUtils.split("abc def", null) = ["abc", "def"] 2573 * StringUtils.split("abc def", " ") = ["abc", "def"] 2574 * StringUtils.split("abc def", " ") = ["abc", "def"] 2575 * StringUtils.split("ab:cd:ef", ":") = ["ab", "cd", "ef"] 2576 * </pre> 2577 * 2578 * @param str the String to parse, may be null 2579 * @param separatorChars the characters used as the delimiters, 2580 * {@code null} splits on whitespace 2581 * @return an array of parsed Strings, {@code null} if null String input 2582 */ 2583 public static String[] split(String str, String separatorChars) { 2584 return splitWorker(str, separatorChars, -1, false); 2585 } 2586 2587 /** 2588 * <p>Splits the provided text into an array with a maximum length, 2589 * separators specified.</p> 2590 * 2591 * <p>The separator is not included in the returned String array. 2592 * Adjacent separators are treated as one separator.</p> 2593 * 2594 * <p>A {@code null} input String returns {@code null}. 2595 * A {@code null} separatorChars splits on whitespace.</p> 2596 * 2597 * <p>If more than {@code max} delimited substrings are found, the last 2598 * returned string includes all characters after the first {@code max - 1} 2599 * returned strings (including separator characters).</p> 2600 * 2601 * <pre> 2602 * StringUtils.split(null, *, *) = null 2603 * StringUtils.split("", *, *) = [] 2604 * StringUtils.split("ab de fg", null, 0) = ["ab", "cd", "ef"] 2605 * StringUtils.split("ab de fg", null, 0) = ["ab", "cd", "ef"] 2606 * StringUtils.split("ab:cd:ef", ":", 0) = ["ab", "cd", "ef"] 2607 * StringUtils.split("ab:cd:ef", ":", 2) = ["ab", "cd:ef"] 2608 * </pre> 2609 * 2610 * @param str the String to parse, may be null 2611 * @param separatorChars the characters used as the delimiters, 2612 * {@code null} splits on whitespace 2613 * @param max the maximum number of elements to include in the 2614 * array. A zero or negative value implies no limit 2615 * @return an array of parsed Strings, {@code null} if null String input 2616 */ 2617 public static String[] split(String str, String separatorChars, int max) { 2618 return splitWorker(str, separatorChars, max, false); 2619 } 2620 2621 /** 2622 * <p>Splits the provided text into an array, separator string specified.</p> 2623 * 2624 * <p>The separator(s) will not be included in the returned String array. 2625 * Adjacent separators are treated as one separator.</p> 2626 * 2627 * <p>A {@code null} input String returns {@code null}. 2628 * A {@code null} separator splits on whitespace.</p> 2629 * 2630 * <pre> 2631 * StringUtils.splitByWholeSeparator(null, *) = null 2632 * StringUtils.splitByWholeSeparator("", *) = [] 2633 * StringUtils.splitByWholeSeparator("ab de fg", null) = ["ab", "de", "fg"] 2634 * StringUtils.splitByWholeSeparator("ab de fg", null) = ["ab", "de", "fg"] 2635 * StringUtils.splitByWholeSeparator("ab:cd:ef", ":") = ["ab", "cd", "ef"] 2636 * StringUtils.splitByWholeSeparator("ab-!-cd-!-ef", "-!-") = ["ab", "cd", "ef"] 2637 * </pre> 2638 * 2639 * @param str the String to parse, may be null 2640 * @param separator String containing the String to be used as a delimiter, 2641 * {@code null} splits on whitespace 2642 * @return an array of parsed Strings, {@code null} if null String was input 2643 */ 2644 public static String[] splitByWholeSeparator(String str, String separator) { 2645 return splitByWholeSeparatorWorker( str, separator, -1, false ) ; 2646 } 2647 2648 /** 2649 * <p>Splits the provided text into an array, separator string specified. 2650 * Returns a maximum of {@code max} substrings.</p> 2651 * 2652 * <p>The separator(s) will not be included in the returned String array. 2653 * Adjacent separators are treated as one separator.</p> 2654 * 2655 * <p>A {@code null} input String returns {@code null}. 2656 * A {@code null} separator splits on whitespace.</p> 2657 * 2658 * <pre> 2659 * StringUtils.splitByWholeSeparator(null, *, *) = null 2660 * StringUtils.splitByWholeSeparator("", *, *) = [] 2661 * StringUtils.splitByWholeSeparator("ab de fg", null, 0) = ["ab", "de", "fg"] 2662 * StringUtils.splitByWholeSeparator("ab de fg", null, 0) = ["ab", "de", "fg"] 2663 * StringUtils.splitByWholeSeparator("ab:cd:ef", ":", 2) = ["ab", "cd:ef"] 2664 * StringUtils.splitByWholeSeparator("ab-!-cd-!-ef", "-!-", 5) = ["ab", "cd", "ef"] 2665 * StringUtils.splitByWholeSeparator("ab-!-cd-!-ef", "-!-", 2) = ["ab", "cd-!-ef"] 2666 * </pre> 2667 * 2668 * @param str the String to parse, may be null 2669 * @param separator String containing the String to be used as a delimiter, 2670 * {@code null} splits on whitespace 2671 * @param max the maximum number of elements to include in the returned 2672 * array. A zero or negative value implies no limit. 2673 * @return an array of parsed Strings, {@code null} if null String was input 2674 */ 2675 public static String[] splitByWholeSeparator( String str, String separator, int max ) { 2676 return splitByWholeSeparatorWorker(str, separator, max, false); 2677 } 2678 2679 /** 2680 * <p>Splits the provided text into an array, separator string specified. </p> 2681 * 2682 * <p>The separator is not included in the returned String array. 2683 * Adjacent separators are treated as separators for empty tokens. 2684 * For more control over the split use the StrTokenizer class.</p> 2685 * 2686 * <p>A {@code null} input String returns {@code null}. 2687 * A {@code null} separator splits on whitespace.</p> 2688 * 2689 * <pre> 2690 * StringUtils.splitByWholeSeparatorPreserveAllTokens(null, *) = null 2691 * StringUtils.splitByWholeSeparatorPreserveAllTokens("", *) = [] 2692 * StringUtils.splitByWholeSeparatorPreserveAllTokens("ab de fg", null) = ["ab", "de", "fg"] 2693 * StringUtils.splitByWholeSeparatorPreserveAllTokens("ab de fg", null) = ["ab", "", "", "de", "fg"] 2694 * StringUtils.splitByWholeSeparatorPreserveAllTokens("ab:cd:ef", ":") = ["ab", "cd", "ef"] 2695 * StringUtils.splitByWholeSeparatorPreserveAllTokens("ab-!-cd-!-ef", "-!-") = ["ab", "cd", "ef"] 2696 * </pre> 2697 * 2698 * @param str the String to parse, may be null 2699 * @param separator String containing the String to be used as a delimiter, 2700 * {@code null} splits on whitespace 2701 * @return an array of parsed Strings, {@code null} if null String was input 2702 * @since 2.4 2703 */ 2704 public static String[] splitByWholeSeparatorPreserveAllTokens(String str, String separator) { 2705 return splitByWholeSeparatorWorker(str, separator, -1, true); 2706 } 2707 2708 /** 2709 * <p>Splits the provided text into an array, separator string specified. 2710 * Returns a maximum of {@code max} substrings.</p> 2711 * 2712 * <p>The separator is not included in the returned String array. 2713 * Adjacent separators are treated as separators for empty tokens. 2714 * For more control over the split use the StrTokenizer class.</p> 2715 * 2716 * <p>A {@code null} input String returns {@code null}. 2717 * A {@code null} separator splits on whitespace.</p> 2718 * 2719 * <pre> 2720 * StringUtils.splitByWholeSeparatorPreserveAllTokens(null, *, *) = null 2721 * StringUtils.splitByWholeSeparatorPreserveAllTokens("", *, *) = [] 2722 * StringUtils.splitByWholeSeparatorPreserveAllTokens("ab de fg", null, 0) = ["ab", "de", "fg"] 2723 * StringUtils.splitByWholeSeparatorPreserveAllTokens("ab de fg", null, 0) = ["ab", "", "", "de", "fg"] 2724 * StringUtils.splitByWholeSeparatorPreserveAllTokens("ab:cd:ef", ":", 2) = ["ab", "cd:ef"] 2725 * StringUtils.splitByWholeSeparatorPreserveAllTokens("ab-!-cd-!-ef", "-!-", 5) = ["ab", "cd", "ef"] 2726 * StringUtils.splitByWholeSeparatorPreserveAllTokens("ab-!-cd-!-ef", "-!-", 2) = ["ab", "cd-!-ef"] 2727 * </pre> 2728 * 2729 * @param str the String to parse, may be null 2730 * @param separator String containing the String to be used as a delimiter, 2731 * {@code null} splits on whitespace 2732 * @param max the maximum number of elements to include in the returned 2733 * array. A zero or negative value implies no limit. 2734 * @return an array of parsed Strings, {@code null} if null String was input 2735 * @since 2.4 2736 */ 2737 public static String[] splitByWholeSeparatorPreserveAllTokens(String str, String separator, int max) { 2738 return splitByWholeSeparatorWorker(str, separator, max, true); 2739 } 2740 2741 /** 2742 * Performs the logic for the {@code splitByWholeSeparatorPreserveAllTokens} methods. 2743 * 2744 * @param str the String to parse, may be {@code null} 2745 * @param separator String containing the String to be used as a delimiter, 2746 * {@code null} splits on whitespace 2747 * @param max the maximum number of elements to include in the returned 2748 * array. A zero or negative value implies no limit. 2749 * @param preserveAllTokens if {@code true}, adjacent separators are 2750 * treated as empty token separators; if {@code false}, adjacent 2751 * separators are treated as one separator. 2752 * @return an array of parsed Strings, {@code null} if null String input 2753 * @since 2.4 2754 */ 2755 private static String[] splitByWholeSeparatorWorker( 2756 String str, String separator, int max, boolean preserveAllTokens) { 2757 if (str == null) { 2758 return null; 2759 } 2760 2761 int len = str.length(); 2762 2763 if (len == 0) { 2764 return ArrayUtils.EMPTY_STRING_ARRAY; 2765 } 2766 2767 if ((separator == null) || (EMPTY.equals(separator))) { 2768 // Split on whitespace. 2769 return splitWorker(str, null, max, preserveAllTokens); 2770 } 2771 2772 int separatorLength = separator.length(); 2773 2774 ArrayList<String> substrings = new ArrayList<String>(); 2775 int numberOfSubstrings = 0; 2776 int beg = 0; 2777 int end = 0; 2778 while (end < len) { 2779 end = str.indexOf(separator, beg); 2780 2781 if (end > -1) { 2782 if (end > beg) { 2783 numberOfSubstrings += 1; 2784 2785 if (numberOfSubstrings == max) { 2786 end = len; 2787 substrings.add(str.substring(beg)); 2788 } else { 2789 // The following is OK, because String.substring( beg, end ) excludes 2790 // the character at the position 'end'. 2791 substrings.add(str.substring(beg, end)); 2792 2793 // Set the starting point for the next search. 2794 // The following is equivalent to beg = end + (separatorLength - 1) + 1, 2795 // which is the right calculation: 2796 beg = end + separatorLength; 2797 } 2798 } else { 2799 // We found a consecutive occurrence of the separator, so skip it. 2800 if (preserveAllTokens) { 2801 numberOfSubstrings += 1; 2802 if (numberOfSubstrings == max) { 2803 end = len; 2804 substrings.add(str.substring(beg)); 2805 } else { 2806 substrings.add(EMPTY); 2807 } 2808 } 2809 beg = end + separatorLength; 2810 } 2811 } else { 2812 // String.substring( beg ) goes from 'beg' to the end of the String. 2813 substrings.add(str.substring(beg)); 2814 end = len; 2815 } 2816 } 2817 2818 return substrings.toArray(new String[substrings.size()]); 2819 } 2820 2821 // ----------------------------------------------------------------------- 2822 /** 2823 * <p>Splits the provided text into an array, using whitespace as the 2824 * separator, preserving all tokens, including empty tokens created by 2825 * adjacent separators. This is an alternative to using StringTokenizer. 2826 * Whitespace is defined by {@link Character#isWhitespace(char)}.</p> 2827 * 2828 * <p>The separator is not included in the returned String array. 2829 * Adjacent separators are treated as separators for empty tokens. 2830 * For more control over the split use the StrTokenizer class.</p> 2831 * 2832 * <p>A {@code null} input String returns {@code null}.</p> 2833 * 2834 * <pre> 2835 * StringUtils.splitPreserveAllTokens(null) = null 2836 * StringUtils.splitPreserveAllTokens("") = [] 2837 * StringUtils.splitPreserveAllTokens("abc def") = ["abc", "def"] 2838 * StringUtils.splitPreserveAllTokens("abc def") = ["abc", "", "def"] 2839 * StringUtils.splitPreserveAllTokens(" abc ") = ["", "abc", ""] 2840 * </pre> 2841 * 2842 * @param str the String to parse, may be {@code null} 2843 * @return an array of parsed Strings, {@code null} if null String input 2844 * @since 2.1 2845 */ 2846 public static String[] splitPreserveAllTokens(String str) { 2847 return splitWorker(str, null, -1, true); 2848 } 2849 2850 /** 2851 * <p>Splits the provided text into an array, separator specified, 2852 * preserving all tokens, including empty tokens created by adjacent 2853 * separators. This is an alternative to using StringTokenizer.</p> 2854 * 2855 * <p>The separator is not included in the returned String array. 2856 * Adjacent separators are treated as separators for empty tokens. 2857 * For more control over the split use the StrTokenizer class.</p> 2858 * 2859 * <p>A {@code null} input String returns {@code null}.</p> 2860 * 2861 * <pre> 2862 * StringUtils.splitPreserveAllTokens(null, *) = null 2863 * StringUtils.splitPreserveAllTokens("", *) = [] 2864 * StringUtils.splitPreserveAllTokens("a.b.c", '.') = ["a", "b", "c"] 2865 * StringUtils.splitPreserveAllTokens("a..b.c", '.') = ["a", "", "b", "c"] 2866 * StringUtils.splitPreserveAllTokens("a:b:c", '.') = ["a:b:c"] 2867 * StringUtils.splitPreserveAllTokens("a\tb\nc", null) = ["a", "b", "c"] 2868 * StringUtils.splitPreserveAllTokens("a b c", ' ') = ["a", "b", "c"] 2869 * StringUtils.splitPreserveAllTokens("a b c ", ' ') = ["a", "b", "c", ""] 2870 * StringUtils.splitPreserveAllTokens("a b c ", ' ') = ["a", "b", "c", "", ""] 2871 * StringUtils.splitPreserveAllTokens(" a b c", ' ') = ["", a", "b", "c"] 2872 * StringUtils.splitPreserveAllTokens(" a b c", ' ') = ["", "", a", "b", "c"] 2873 * StringUtils.splitPreserveAllTokens(" a b c ", ' ') = ["", a", "b", "c", ""] 2874 * </pre> 2875 * 2876 * @param str the String to parse, may be {@code null} 2877 * @param separatorChar the character used as the delimiter, 2878 * {@code null} splits on whitespace 2879 * @return an array of parsed Strings, {@code null} if null String input 2880 * @since 2.1 2881 */ 2882 public static String[] splitPreserveAllTokens(String str, char separatorChar) { 2883 return splitWorker(str, separatorChar, true); 2884 } 2885 2886 /** 2887 * Performs the logic for the {@code split} and 2888 * {@code splitPreserveAllTokens} methods that do not return a 2889 * maximum array length. 2890 * 2891 * @param str the String to parse, may be {@code null} 2892 * @param separatorChar the separate character 2893 * @param preserveAllTokens if {@code true}, adjacent separators are 2894 * treated as empty token separators; if {@code false}, adjacent 2895 * separators are treated as one separator. 2896 * @return an array of parsed Strings, {@code null} if null String input 2897 */ 2898 private static String[] splitWorker(String str, char separatorChar, boolean preserveAllTokens) { 2899 // Performance tuned for 2.0 (JDK1.4) 2900 2901 if (str == null) { 2902 return null; 2903 } 2904 int len = str.length(); 2905 if (len == 0) { 2906 return ArrayUtils.EMPTY_STRING_ARRAY; 2907 } 2908 List<String> list = new ArrayList<String>(); 2909 int i = 0, start = 0; 2910 boolean match = false; 2911 boolean lastMatch = false; 2912 while (i < len) { 2913 if (str.charAt(i) == separatorChar) { 2914 if (match || preserveAllTokens) { 2915 list.add(str.substring(start, i)); 2916 match = false; 2917 lastMatch = true; 2918 } 2919 start = ++i; 2920 continue; 2921 } 2922 lastMatch = false; 2923 match = true; 2924 i++; 2925 } 2926 if (match || (preserveAllTokens && lastMatch)) { 2927 list.add(str.substring(start, i)); 2928 } 2929 return list.toArray(new String[list.size()]); 2930 } 2931 2932 /** 2933 * <p>Splits the provided text into an array, separators specified, 2934 * preserving all tokens, including empty tokens created by adjacent 2935 * separators. This is an alternative to using StringTokenizer.</p> 2936 * 2937 * <p>The separator is not included in the returned String array. 2938 * Adjacent separators are treated as separators for empty tokens. 2939 * For more control over the split use the StrTokenizer class.</p> 2940 * 2941 * <p>A {@code null} input String returns {@code null}. 2942 * A {@code null} separatorChars splits on whitespace.</p> 2943 * 2944 * <pre> 2945 * StringUtils.splitPreserveAllTokens(null, *) = null 2946 * StringUtils.splitPreserveAllTokens("", *) = [] 2947 * StringUtils.splitPreserveAllTokens("abc def", null) = ["abc", "def"] 2948 * StringUtils.splitPreserveAllTokens("abc def", " ") = ["abc", "def"] 2949 * StringUtils.splitPreserveAllTokens("abc def", " ") = ["abc", "", def"] 2950 * StringUtils.splitPreserveAllTokens("ab:cd:ef", ":") = ["ab", "cd", "ef"] 2951 * StringUtils.splitPreserveAllTokens("ab:cd:ef:", ":") = ["ab", "cd", "ef", ""] 2952 * StringUtils.splitPreserveAllTokens("ab:cd:ef::", ":") = ["ab", "cd", "ef", "", ""] 2953 * StringUtils.splitPreserveAllTokens("ab::cd:ef", ":") = ["ab", "", cd", "ef"] 2954 * StringUtils.splitPreserveAllTokens(":cd:ef", ":") = ["", cd", "ef"] 2955 * StringUtils.splitPreserveAllTokens("::cd:ef", ":") = ["", "", cd", "ef"] 2956 * StringUtils.splitPreserveAllTokens(":cd:ef:", ":") = ["", cd", "ef", ""] 2957 * </pre> 2958 * 2959 * @param str the String to parse, may be {@code null} 2960 * @param separatorChars the characters used as the delimiters, 2961 * {@code null} splits on whitespace 2962 * @return an array of parsed Strings, {@code null} if null String input 2963 * @since 2.1 2964 */ 2965 public static String[] splitPreserveAllTokens(String str, String separatorChars) { 2966 return splitWorker(str, separatorChars, -1, true); 2967 } 2968 2969 /** 2970 * <p>Splits the provided text into an array with a maximum length, 2971 * separators specified, preserving all tokens, including empty tokens 2972 * created by adjacent separators.</p> 2973 * 2974 * <p>The separator is not included in the returned String array. 2975 * Adjacent separators are treated as separators for empty tokens. 2976 * Adjacent separators are treated as one separator.</p> 2977 * 2978 * <p>A {@code null} input String returns {@code null}. 2979 * A {@code null} separatorChars splits on whitespace.</p> 2980 * 2981 * <p>If more than {@code max} delimited substrings are found, the last 2982 * returned string includes all characters after the first {@code max - 1} 2983 * returned strings (including separator characters).</p> 2984 * 2985 * <pre> 2986 * StringUtils.splitPreserveAllTokens(null, *, *) = null 2987 * StringUtils.splitPreserveAllTokens("", *, *) = [] 2988 * StringUtils.splitPreserveAllTokens("ab de fg", null, 0) = ["ab", "cd", "ef"] 2989 * StringUtils.splitPreserveAllTokens("ab de fg", null, 0) = ["ab", "cd", "ef"] 2990 * StringUtils.splitPreserveAllTokens("ab:cd:ef", ":", 0) = ["ab", "cd", "ef"] 2991 * StringUtils.splitPreserveAllTokens("ab:cd:ef", ":", 2) = ["ab", "cd:ef"] 2992 * StringUtils.splitPreserveAllTokens("ab de fg", null, 2) = ["ab", " de fg"] 2993 * StringUtils.splitPreserveAllTokens("ab de fg", null, 3) = ["ab", "", " de fg"] 2994 * StringUtils.splitPreserveAllTokens("ab de fg", null, 4) = ["ab", "", "", "de fg"] 2995 * </pre> 2996 * 2997 * @param str the String to parse, may be {@code null} 2998 * @param separatorChars the characters used as the delimiters, 2999 * {@code null} splits on whitespace 3000 * @param max the maximum number of elements to include in the 3001 * array. A zero or negative value implies no limit 3002 * @return an array of parsed Strings, {@code null} if null String input 3003 * @since 2.1 3004 */ 3005 public static String[] splitPreserveAllTokens(String str, String separatorChars, int max) { 3006 return splitWorker(str, separatorChars, max, true); 3007 } 3008 3009 /** 3010 * Performs the logic for the {@code split} and 3011 * {@code splitPreserveAllTokens} methods that return a maximum array 3012 * length. 3013 * 3014 * @param str the String to parse, may be {@code null} 3015 * @param separatorChars the separate character 3016 * @param max the maximum number of elements to include in the 3017 * array. A zero or negative value implies no limit. 3018 * @param preserveAllTokens if {@code true}, adjacent separators are 3019 * treated as empty token separators; if {@code false}, adjacent 3020 * separators are treated as one separator. 3021 * @return an array of parsed Strings, {@code null} if null String input 3022 */ 3023 private static String[] splitWorker(String str, String separatorChars, int max, boolean preserveAllTokens) { 3024 // Performance tuned for 2.0 (JDK1.4) 3025 // Direct code is quicker than StringTokenizer. 3026 // Also, StringTokenizer uses isSpace() not isWhitespace() 3027 3028 if (str == null) { 3029 return null; 3030 } 3031 int len = str.length(); 3032 if (len == 0) { 3033 return ArrayUtils.EMPTY_STRING_ARRAY; 3034 } 3035 List<String> list = new ArrayList<String>(); 3036 int sizePlus1 = 1; 3037 int i = 0, start = 0; 3038 boolean match = false; 3039 boolean lastMatch = false; 3040 if (separatorChars == null) { 3041 // Null separator means use whitespace 3042 while (i < len) { 3043 if (Character.isWhitespace(str.charAt(i))) { 3044 if (match || preserveAllTokens) { 3045 lastMatch = true; 3046 if (sizePlus1++ == max) { 3047 i = len; 3048 lastMatch = false; 3049 } 3050 list.add(str.substring(start, i)); 3051 match = false; 3052 } 3053 start = ++i; 3054 continue; 3055 } 3056 lastMatch = false; 3057 match = true; 3058 i++; 3059 } 3060 } else if (separatorChars.length() == 1) { 3061 // Optimise 1 character case 3062 char sep = separatorChars.charAt(0); 3063 while (i < len) { 3064 if (str.charAt(i) == sep) { 3065 if (match || preserveAllTokens) { 3066 lastMatch = true; 3067 if (sizePlus1++ == max) { 3068 i = len; 3069 lastMatch = false; 3070 } 3071 list.add(str.substring(start, i)); 3072 match = false; 3073 } 3074 start = ++i; 3075 continue; 3076 } 3077 lastMatch = false; 3078 match = true; 3079 i++; 3080 } 3081 } else { 3082 // standard case 3083 while (i < len) { 3084 if (separatorChars.indexOf(str.charAt(i)) >= 0) { 3085 if (match || preserveAllTokens) { 3086 lastMatch = true; 3087 if (sizePlus1++ == max) { 3088 i = len; 3089 lastMatch = false; 3090 } 3091 list.add(str.substring(start, i)); 3092 match = false; 3093 } 3094 start = ++i; 3095 continue; 3096 } 3097 lastMatch = false; 3098 match = true; 3099 i++; 3100 } 3101 } 3102 if (match || (preserveAllTokens && lastMatch)) { 3103 list.add(str.substring(start, i)); 3104 } 3105 return list.toArray(new String[list.size()]); 3106 } 3107 3108 /** 3109 * <p>Splits a String by Character type as returned by 3110 * {@code java.lang.Character.getType(char)}. Groups of contiguous 3111 * characters of the same type are returned as complete tokens. 3112 * <pre> 3113 * StringUtils.splitByCharacterType(null) = null 3114 * StringUtils.splitByCharacterType("") = [] 3115 * StringUtils.splitByCharacterType("ab de fg") = ["ab", " ", "de", " ", "fg"] 3116 * StringUtils.splitByCharacterType("ab de fg") = ["ab", " ", "de", " ", "fg"] 3117 * StringUtils.splitByCharacterType("ab:cd:ef") = ["ab", ":", "cd", ":", "ef"] 3118 * StringUtils.splitByCharacterType("number5") = ["number", "5"] 3119 * StringUtils.splitByCharacterType("fooBar") = ["foo", "B", "ar"] 3120 * StringUtils.splitByCharacterType("foo200Bar") = ["foo", "200", "B", "ar"] 3121 * StringUtils.splitByCharacterType("ASFRules") = ["ASFR", "ules"] 3122 * </pre> 3123 * @param str the String to split, may be {@code null} 3124 * @return an array of parsed Strings, {@code null} if null String input 3125 * @since 2.4 3126 */ 3127 public static String[] splitByCharacterType(String str) { 3128 return splitByCharacterType(str, false); 3129 } 3130 3131 /** 3132 * <p>Splits a String by Character type as returned by 3133 * {@code java.lang.Character.getType(char)}. Groups of contiguous 3134 * characters of the same type are returned as complete tokens, with the 3135 * following exception: the character of type 3136 * {@code Character.UPPERCASE_LETTER}, if any, immediately 3137 * preceding a token of type {@code Character.LOWERCASE_LETTER} 3138 * will belong to the following token rather than to the preceding, if any, 3139 * {@code Character.UPPERCASE_LETTER} token. 3140 * <pre> 3141 * StringUtils.splitByCharacterTypeCamelCase(null) = null 3142 * StringUtils.splitByCharacterTypeCamelCase("") = [] 3143 * StringUtils.splitByCharacterTypeCamelCase("ab de fg") = ["ab", " ", "de", " ", "fg"] 3144 * StringUtils.splitByCharacterTypeCamelCase("ab de fg") = ["ab", " ", "de", " ", "fg"] 3145 * StringUtils.splitByCharacterTypeCamelCase("ab:cd:ef") = ["ab", ":", "cd", ":", "ef"] 3146 * StringUtils.splitByCharacterTypeCamelCase("number5") = ["number", "5"] 3147 * StringUtils.splitByCharacterTypeCamelCase("fooBar") = ["foo", "Bar"] 3148 * StringUtils.splitByCharacterTypeCamelCase("foo200Bar") = ["foo", "200", "Bar"] 3149 * StringUtils.splitByCharacterTypeCamelCase("ASFRules") = ["ASF", "Rules"] 3150 * </pre> 3151 * @param str the String to split, may be {@code null} 3152 * @return an array of parsed Strings, {@code null} if null String input 3153 * @since 2.4 3154 */ 3155 public static String[] splitByCharacterTypeCamelCase(String str) { 3156 return splitByCharacterType(str, true); 3157 } 3158 3159 /** 3160 * <p>Splits a String by Character type as returned by 3161 * {@code java.lang.Character.getType(char)}. Groups of contiguous 3162 * characters of the same type are returned as complete tokens, with the 3163 * following exception: if {@code camelCase} is {@code true}, 3164 * the character of type {@code Character.UPPERCASE_LETTER}, if any, 3165 * immediately preceding a token of type {@code Character.LOWERCASE_LETTER} 3166 * will belong to the following token rather than to the preceding, if any, 3167 * {@code Character.UPPERCASE_LETTER} token. 3168 * @param str the String to split, may be {@code null} 3169 * @param camelCase whether to use so-called "camel-case" for letter types 3170 * @return an array of parsed Strings, {@code null} if null String input 3171 * @since 2.4 3172 */ 3173 private static String[] splitByCharacterType(String str, boolean camelCase) { 3174 if (str == null) { 3175 return null; 3176 } 3177 if (str.length() == 0) { 3178 return ArrayUtils.EMPTY_STRING_ARRAY; 3179 } 3180 char[] c = str.toCharArray(); 3181 List<String> list = new ArrayList<String>(); 3182 int tokenStart = 0; 3183 int currentType = Character.getType(c[tokenStart]); 3184 for (int pos = tokenStart + 1; pos < c.length; pos++) { 3185 int type = Character.getType(c[pos]); 3186 if (type == currentType) { 3187 continue; 3188 } 3189 if (camelCase && type == Character.LOWERCASE_LETTER && currentType == Character.UPPERCASE_LETTER) { 3190 int newTokenStart = pos - 1; 3191 if (newTokenStart != tokenStart) { 3192 list.add(new String(c, tokenStart, newTokenStart - tokenStart)); 3193 tokenStart = newTokenStart; 3194 } 3195 } else { 3196 list.add(new String(c, tokenStart, pos - tokenStart)); 3197 tokenStart = pos; 3198 } 3199 currentType = type; 3200 } 3201 list.add(new String(c, tokenStart, c.length - tokenStart)); 3202 return list.toArray(new String[list.size()]); 3203 } 3204 3205 // Joining 3206 //----------------------------------------------------------------------- 3207 /** 3208 * <p>Joins the elements of the provided array into a single String 3209 * containing the provided list of elements.</p> 3210 * 3211 * <p>No separator is added to the joined String. 3212 * Null objects or empty strings within the array are represented by 3213 * empty strings.</p> 3214 * 3215 * <pre> 3216 * StringUtils.join(null) = null 3217 * StringUtils.join([]) = "" 3218 * StringUtils.join([null]) = "" 3219 * StringUtils.join(["a", "b", "c"]) = "abc" 3220 * StringUtils.join([null, "", "a"]) = "a" 3221 * </pre> 3222 * 3223 * @param <T> the specific type of values to join together 3224 * @param elements the values to join together, may be null 3225 * @return the joined String, {@code null} if null array input 3226 * @since 2.0 3227 * @since 3.0 Changed signature to use varargs 3228 */ 3229 public static <T> String join(T... elements) { 3230 return join(elements, null); 3231 } 3232 3233 /** 3234 * <p>Joins the elements of the provided array into a single String 3235 * containing the provided list of elements.</p> 3236 * 3237 * <p>No delimiter is added before or after the list. 3238 * Null objects or empty strings within the array are represented by 3239 * empty strings.</p> 3240 * 3241 * <pre> 3242 * StringUtils.join(null, *) = null 3243 * StringUtils.join([], *) = "" 3244 * StringUtils.join([null], *) = "" 3245 * StringUtils.join(["a", "b", "c"], ';') = "a;b;c" 3246 * StringUtils.join(["a", "b", "c"], null) = "abc" 3247 * StringUtils.join([null, "", "a"], ';') = ";;a" 3248 * </pre> 3249 * 3250 * @param array the array of values to join together, may be null 3251 * @param separator the separator character to use 3252 * @return the joined String, {@code null} if null array input 3253 * @since 2.0 3254 */ 3255 public static String join(Object[] array, char separator) { 3256 if (array == null) { 3257 return null; 3258 } 3259 3260 return join(array, separator, 0, array.length); 3261 } 3262 3263 /** 3264 * <p>Joins the elements of the provided array into a single String 3265 * containing the provided list of elements.</p> 3266 * 3267 * <p>No delimiter is added before or after the list. 3268 * Null objects or empty strings within the array are represented by 3269 * empty strings.</p> 3270 * 3271 * <pre> 3272 * StringUtils.join(null, *) = null 3273 * StringUtils.join([], *) = "" 3274 * StringUtils.join([null], *) = "" 3275 * StringUtils.join(["a", "b", "c"], ';') = "a;b;c" 3276 * StringUtils.join(["a", "b", "c"], null) = "abc" 3277 * StringUtils.join([null, "", "a"], ';') = ";;a" 3278 * </pre> 3279 * 3280 * @param array the array of values to join together, may be null 3281 * @param separator the separator character to use 3282 * @param startIndex the first index to start joining from. It is 3283 * an error to pass in an end index past the end of the array 3284 * @param endIndex the index to stop joining from (exclusive). It is 3285 * an error to pass in an end index past the end of the array 3286 * @return the joined String, {@code null} if null array input 3287 * @since 2.0 3288 */ 3289 public static String join(Object[] array, char separator, int startIndex, int endIndex) { 3290 if (array == null) { 3291 return null; 3292 } 3293 int noOfItems = (endIndex - startIndex); 3294 if (noOfItems <= 0) { 3295 return EMPTY; 3296 } 3297 3298 StringBuilder buf = new StringBuilder(noOfItems * 16); 3299 3300 for (int i = startIndex; i < endIndex; i++) { 3301 if (i > startIndex) { 3302 buf.append(separator); 3303 } 3304 if (array[i] != null) { 3305 buf.append(array[i]); 3306 } 3307 } 3308 return buf.toString(); 3309 } 3310 3311 /** 3312 * <p>Joins the elements of the provided array into a single String 3313 * containing the provided list of elements.</p> 3314 * 3315 * <p>No delimiter is added before or after the list. 3316 * A {@code null} separator is the same as an empty String (""). 3317 * Null objects or empty strings within the array are represented by 3318 * empty strings.</p> 3319 * 3320 * <pre> 3321 * StringUtils.join(null, *) = null 3322 * StringUtils.join([], *) = "" 3323 * StringUtils.join([null], *) = "" 3324 * StringUtils.join(["a", "b", "c"], "--") = "a--b--c" 3325 * StringUtils.join(["a", "b", "c"], null) = "abc" 3326 * StringUtils.join(["a", "b", "c"], "") = "abc" 3327 * StringUtils.join([null, "", "a"], ',') = ",,a" 3328 * </pre> 3329 * 3330 * @param array the array of values to join together, may be null 3331 * @param separator the separator character to use, null treated as "" 3332 * @return the joined String, {@code null} if null array input 3333 */ 3334 public static String join(Object[] array, String separator) { 3335 if (array == null) { 3336 return null; 3337 } 3338 return join(array, separator, 0, array.length); 3339 } 3340 3341 /** 3342 * <p>Joins the elements of the provided array into a single String 3343 * containing the provided list of elements.</p> 3344 * 3345 * <p>No delimiter is added before or after the list. 3346 * A {@code null} separator is the same as an empty String (""). 3347 * Null objects or empty strings within the array are represented by 3348 * empty strings.</p> 3349 * 3350 * <pre> 3351 * StringUtils.join(null, *) = null 3352 * StringUtils.join([], *) = "" 3353 * StringUtils.join([null], *) = "" 3354 * StringUtils.join(["a", "b", "c"], "--") = "a--b--c" 3355 * StringUtils.join(["a", "b", "c"], null) = "abc" 3356 * StringUtils.join(["a", "b", "c"], "") = "abc" 3357 * StringUtils.join([null, "", "a"], ',') = ",,a" 3358 * </pre> 3359 * 3360 * @param array the array of values to join together, may be null 3361 * @param separator the separator character to use, null treated as "" 3362 * @param startIndex the first index to start joining from. It is 3363 * an error to pass in an end index past the end of the array 3364 * @param endIndex the index to stop joining from (exclusive). It is 3365 * an error to pass in an end index past the end of the array 3366 * @return the joined String, {@code null} if null array input 3367 */ 3368 public static String join(Object[] array, String separator, int startIndex, int endIndex) { 3369 if (array == null) { 3370 return null; 3371 } 3372 if (separator == null) { 3373 separator = EMPTY; 3374 } 3375 3376 // endIndex - startIndex > 0: Len = NofStrings *(len(firstString) + len(separator)) 3377 // (Assuming that all Strings are roughly equally long) 3378 int noOfItems = (endIndex - startIndex); 3379 if (noOfItems <= 0) { 3380 return EMPTY; 3381 } 3382 3383 StringBuilder buf = new StringBuilder(noOfItems * 16); 3384 3385 for (int i = startIndex; i < endIndex; i++) { 3386 if (i > startIndex) { 3387 buf.append(separator); 3388 } 3389 if (array[i] != null) { 3390 buf.append(array[i]); 3391 } 3392 } 3393 return buf.toString(); 3394 } 3395 3396 /** 3397 * <p>Joins the elements of the provided {@code Iterator} into 3398 * a single String containing the provided elements.</p> 3399 * 3400 * <p>No delimiter is added before or after the list. Null objects or empty 3401 * strings within the iteration are represented by empty strings.</p> 3402 * 3403 * <p>See the examples here: {@link #join(Object[],char)}. </p> 3404 * 3405 * @param iterator the {@code Iterator} of values to join together, may be null 3406 * @param separator the separator character to use 3407 * @return the joined String, {@code null} if null iterator input 3408 * @since 2.0 3409 */ 3410 public static String join(Iterator<?> iterator, char separator) { 3411 3412 // handle null, zero and one elements before building a buffer 3413 if (iterator == null) { 3414 return null; 3415 } 3416 if (!iterator.hasNext()) { 3417 return EMPTY; 3418 } 3419 Object first = iterator.next(); 3420 if (!iterator.hasNext()) { 3421 return ObjectUtils.toString(first); 3422 } 3423 3424 // two or more elements 3425 StringBuilder buf = new StringBuilder(256); // Java default is 16, probably too small 3426 if (first != null) { 3427 buf.append(first); 3428 } 3429 3430 while (iterator.hasNext()) { 3431 buf.append(separator); 3432 Object obj = iterator.next(); 3433 if (obj != null) { 3434 buf.append(obj); 3435 } 3436 } 3437 3438 return buf.toString(); 3439 } 3440 3441 /** 3442 * <p>Joins the elements of the provided {@code Iterator} into 3443 * a single String containing the provided elements.</p> 3444 * 3445 * <p>No delimiter is added before or after the list. 3446 * A {@code null} separator is the same as an empty String ("").</p> 3447 * 3448 * <p>See the examples here: {@link #join(Object[],String)}. </p> 3449 * 3450 * @param iterator the {@code Iterator} of values to join together, may be null 3451 * @param separator the separator character to use, null treated as "" 3452 * @return the joined String, {@code null} if null iterator input 3453 */ 3454 public static String join(Iterator<?> iterator, String separator) { 3455 3456 // handle null, zero and one elements before building a buffer 3457 if (iterator == null) { 3458 return null; 3459 } 3460 if (!iterator.hasNext()) { 3461 return EMPTY; 3462 } 3463 Object first = iterator.next(); 3464 if (!iterator.hasNext()) { 3465 return ObjectUtils.toString(first); 3466 } 3467 3468 // two or more elements 3469 StringBuilder buf = new StringBuilder(256); // Java default is 16, probably too small 3470 if (first != null) { 3471 buf.append(first); 3472 } 3473 3474 while (iterator.hasNext()) { 3475 if (separator != null) { 3476 buf.append(separator); 3477 } 3478 Object obj = iterator.next(); 3479 if (obj != null) { 3480 buf.append(obj); 3481 } 3482 } 3483 return buf.toString(); 3484 } 3485 3486 /** 3487 * <p>Joins the elements of the provided {@code Iterable} into 3488 * a single String containing the provided elements.</p> 3489 * 3490 * <p>No delimiter is added before or after the list. Null objects or empty 3491 * strings within the iteration are represented by empty strings.</p> 3492 * 3493 * <p>See the examples here: {@link #join(Object[],char)}. </p> 3494 * 3495 * @param iterable the {@code Iterable} providing the values to join together, may be null 3496 * @param separator the separator character to use 3497 * @return the joined String, {@code null} if null iterator input 3498 * @since 2.3 3499 */ 3500 public static String join(Iterable<?> iterable, char separator) { 3501 if (iterable == null) { 3502 return null; 3503 } 3504 return join(iterable.iterator(), separator); 3505 } 3506 3507 /** 3508 * <p>Joins the elements of the provided {@code Iterable} into 3509 * a single String containing the provided elements.</p> 3510 * 3511 * <p>No delimiter is added before or after the list. 3512 * A {@code null} separator is the same as an empty String ("").</p> 3513 * 3514 * <p>See the examples here: {@link #join(Object[],String)}. </p> 3515 * 3516 * @param iterable the {@code Iterable} providing the values to join together, may be null 3517 * @param separator the separator character to use, null treated as "" 3518 * @return the joined String, {@code null} if null iterator input 3519 * @since 2.3 3520 */ 3521 public static String join(Iterable<?> iterable, String separator) { 3522 if (iterable == null) { 3523 return null; 3524 } 3525 return join(iterable.iterator(), separator); 3526 } 3527 3528 // Delete 3529 //----------------------------------------------------------------------- 3530 /** 3531 * <p>Deletes all whitespaces from a String as defined by 3532 * {@link Character#isWhitespace(char)}.</p> 3533 * 3534 * <pre> 3535 * StringUtils.deleteWhitespace(null) = null 3536 * StringUtils.deleteWhitespace("") = "" 3537 * StringUtils.deleteWhitespace("abc") = "abc" 3538 * StringUtils.deleteWhitespace(" ab c ") = "abc" 3539 * </pre> 3540 * 3541 * @param str the String to delete whitespace from, may be null 3542 * @return the String without whitespaces, {@code null} if null String input 3543 */ 3544 public static String deleteWhitespace(String str) { 3545 if (isEmpty(str)) { 3546 return str; 3547 } 3548 int sz = str.length(); 3549 char[] chs = new char[sz]; 3550 int count = 0; 3551 for (int i = 0; i < sz; i++) { 3552 if (!Character.isWhitespace(str.charAt(i))) { 3553 chs[count++] = str.charAt(i); 3554 } 3555 } 3556 if (count == sz) { 3557 return str; 3558 } 3559 return new String(chs, 0, count); 3560 } 3561 3562 // Remove 3563 //----------------------------------------------------------------------- 3564 /** 3565 * <p>Removes a substring only if it is at the beginning of a source string, 3566 * otherwise returns the source string.</p> 3567 * 3568 * <p>A {@code null} source string will return {@code null}. 3569 * An empty ("") source string will return the empty string. 3570 * A {@code null} search string will return the source string.</p> 3571 * 3572 * <pre> 3573 * StringUtils.removeStart(null, *) = null 3574 * StringUtils.removeStart("", *) = "" 3575 * StringUtils.removeStart(*, null) = * 3576 * StringUtils.removeStart("www.domain.com", "www.") = "domain.com" 3577 * StringUtils.removeStart("domain.com", "www.") = "domain.com" 3578 * StringUtils.removeStart("www.domain.com", "domain") = "www.domain.com" 3579 * StringUtils.removeStart("abc", "") = "abc" 3580 * </pre> 3581 * 3582 * @param str the source String to search, may be null 3583 * @param remove the String to search for and remove, may be null 3584 * @return the substring with the string removed if found, 3585 * {@code null} if null String input 3586 * @since 2.1 3587 */ 3588 public static String removeStart(String str, String remove) { 3589 if (isEmpty(str) || isEmpty(remove)) { 3590 return str; 3591 } 3592 if (str.startsWith(remove)){ 3593 return str.substring(remove.length()); 3594 } 3595 return str; 3596 } 3597 3598 /** 3599 * <p>Case insensitive removal of a substring if it is at the beginning of a source string, 3600 * otherwise returns the source string.</p> 3601 * 3602 * <p>A {@code null} source string will return {@code null}. 3603 * An empty ("") source string will return the empty string. 3604 * A {@code null} search string will return the source string.</p> 3605 * 3606 * <pre> 3607 * StringUtils.removeStartIgnoreCase(null, *) = null 3608 * StringUtils.removeStartIgnoreCase("", *) = "" 3609 * StringUtils.removeStartIgnoreCase(*, null) = * 3610 * StringUtils.removeStartIgnoreCase("www.domain.com", "www.") = "domain.com" 3611 * StringUtils.removeStartIgnoreCase("www.domain.com", "WWW.") = "domain.com" 3612 * StringUtils.removeStartIgnoreCase("domain.com", "www.") = "domain.com" 3613 * StringUtils.removeStartIgnoreCase("www.domain.com", "domain") = "www.domain.com" 3614 * StringUtils.removeStartIgnoreCase("abc", "") = "abc" 3615 * </pre> 3616 * 3617 * @param str the source String to search, may be null 3618 * @param remove the String to search for (case insensitive) and remove, may be null 3619 * @return the substring with the string removed if found, 3620 * {@code null} if null String input 3621 * @since 2.4 3622 */ 3623 public static String removeStartIgnoreCase(String str, String remove) { 3624 if (isEmpty(str) || isEmpty(remove)) { 3625 return str; 3626 } 3627 if (startsWithIgnoreCase(str, remove)) { 3628 return str.substring(remove.length()); 3629 } 3630 return str; 3631 } 3632 3633 /** 3634 * <p>Removes a substring only if it is at the end of a source string, 3635 * otherwise returns the source string.</p> 3636 * 3637 * <p>A {@code null} source string will return {@code null}. 3638 * An empty ("") source string will return the empty string. 3639 * A {@code null} search string will return the source string.</p> 3640 * 3641 * <pre> 3642 * StringUtils.removeEnd(null, *) = null 3643 * StringUtils.removeEnd("", *) = "" 3644 * StringUtils.removeEnd(*, null) = * 3645 * StringUtils.removeEnd("www.domain.com", ".com.") = "www.domain.com" 3646 * StringUtils.removeEnd("www.domain.com", ".com") = "www.domain" 3647 * StringUtils.removeEnd("www.domain.com", "domain") = "www.domain.com" 3648 * StringUtils.removeEnd("abc", "") = "abc" 3649 * </pre> 3650 * 3651 * @param str the source String to search, may be null 3652 * @param remove the String to search for and remove, may be null 3653 * @return the substring with the string removed if found, 3654 * {@code null} if null String input 3655 * @since 2.1 3656 */ 3657 public static String removeEnd(String str, String remove) { 3658 if (isEmpty(str) || isEmpty(remove)) { 3659 return str; 3660 } 3661 if (str.endsWith(remove)) { 3662 return str.substring(0, str.length() - remove.length()); 3663 } 3664 return str; 3665 } 3666 3667 /** 3668 * <p>Case insensitive removal of a substring if it is at the end of a source string, 3669 * otherwise returns the source string.</p> 3670 * 3671 * <p>A {@code null} source string will return {@code null}. 3672 * An empty ("") source string will return the empty string. 3673 * A {@code null} search string will return the source string.</p> 3674 * 3675 * <pre> 3676 * StringUtils.removeEndIgnoreCase(null, *) = null 3677 * StringUtils.removeEndIgnoreCase("", *) = "" 3678 * StringUtils.removeEndIgnoreCase(*, null) = * 3679 * StringUtils.removeEndIgnoreCase("www.domain.com", ".com.") = "www.domain.com" 3680 * StringUtils.removeEndIgnoreCase("www.domain.com", ".com") = "www.domain" 3681 * StringUtils.removeEndIgnoreCase("www.domain.com", "domain") = "www.domain.com" 3682 * StringUtils.removeEndIgnoreCase("abc", "") = "abc" 3683 * StringUtils.removeEndIgnoreCase("www.domain.com", ".COM") = "www.domain") 3684 * StringUtils.removeEndIgnoreCase("www.domain.COM", ".com") = "www.domain") 3685 * </pre> 3686 * 3687 * @param str the source String to search, may be null 3688 * @param remove the String to search for (case insensitive) and remove, may be null 3689 * @return the substring with the string removed if found, 3690 * {@code null} if null String input 3691 * @since 2.4 3692 */ 3693 public static String removeEndIgnoreCase(String str, String remove) { 3694 if (isEmpty(str) || isEmpty(remove)) { 3695 return str; 3696 } 3697 if (endsWithIgnoreCase(str, remove)) { 3698 return str.substring(0, str.length() - remove.length()); 3699 } 3700 return str; 3701 } 3702 3703 /** 3704 * <p>Removes all occurrences of a substring from within the source string.</p> 3705 * 3706 * <p>A {@code null} source string will return {@code null}. 3707 * An empty ("") source string will return the empty string. 3708 * A {@code null} remove string will return the source string. 3709 * An empty ("") remove string will return the source string.</p> 3710 * 3711 * <pre> 3712 * StringUtils.remove(null, *) = null 3713 * StringUtils.remove("", *) = "" 3714 * StringUtils.remove(*, null) = * 3715 * StringUtils.remove(*, "") = * 3716 * StringUtils.remove("queued", "ue") = "qd" 3717 * StringUtils.remove("queued", "zz") = "queued" 3718 * </pre> 3719 * 3720 * @param str the source String to search, may be null 3721 * @param remove the String to search for and remove, may be null 3722 * @return the substring with the string removed if found, 3723 * {@code null} if null String input 3724 * @since 2.1 3725 */ 3726 public static String remove(String str, String remove) { 3727 if (isEmpty(str) || isEmpty(remove)) { 3728 return str; 3729 } 3730 return replace(str, remove, EMPTY, -1); 3731 } 3732 3733 /** 3734 * <p>Removes all occurrences of a character from within the source string.</p> 3735 * 3736 * <p>A {@code null} source string will return {@code null}. 3737 * An empty ("") source string will return the empty string.</p> 3738 * 3739 * <pre> 3740 * StringUtils.remove(null, *) = null 3741 * StringUtils.remove("", *) = "" 3742 * StringUtils.remove("queued", 'u') = "qeed" 3743 * StringUtils.remove("queued", 'z') = "queued" 3744 * </pre> 3745 * 3746 * @param str the source String to search, may be null 3747 * @param remove the char to search for and remove, may be null 3748 * @return the substring with the char removed if found, 3749 * {@code null} if null String input 3750 * @since 2.1 3751 */ 3752 public static String remove(String str, char remove) { 3753 if (isEmpty(str) || str.indexOf(remove) == INDEX_NOT_FOUND) { 3754 return str; 3755 } 3756 char[] chars = str.toCharArray(); 3757 int pos = 0; 3758 for (int i = 0; i < chars.length; i++) { 3759 if (chars[i] != remove) { 3760 chars[pos++] = chars[i]; 3761 } 3762 } 3763 return new String(chars, 0, pos); 3764 } 3765 3766 // Replacing 3767 //----------------------------------------------------------------------- 3768 /** 3769 * <p>Replaces a String with another String inside a larger String, once.</p> 3770 * 3771 * <p>A {@code null} reference passed to this method is a no-op.</p> 3772 * 3773 * <pre> 3774 * StringUtils.replaceOnce(null, *, *) = null 3775 * StringUtils.replaceOnce("", *, *) = "" 3776 * StringUtils.replaceOnce("any", null, *) = "any" 3777 * StringUtils.replaceOnce("any", *, null) = "any" 3778 * StringUtils.replaceOnce("any", "", *) = "any" 3779 * StringUtils.replaceOnce("aba", "a", null) = "aba" 3780 * StringUtils.replaceOnce("aba", "a", "") = "ba" 3781 * StringUtils.replaceOnce("aba", "a", "z") = "zba" 3782 * </pre> 3783 * 3784 * @see #replace(String text, String searchString, String replacement, int max) 3785 * @param text text to search and replace in, may be null 3786 * @param searchString the String to search for, may be null 3787 * @param replacement the String to replace with, may be null 3788 * @return the text with any replacements processed, 3789 * {@code null} if null String input 3790 */ 3791 public static String replaceOnce(String text, String searchString, String replacement) { 3792 return replace(text, searchString, replacement, 1); 3793 } 3794 3795 /** 3796 * <p>Replaces all occurrences of a String within another String.</p> 3797 * 3798 * <p>A {@code null} reference passed to this method is a no-op.</p> 3799 * 3800 * <pre> 3801 * StringUtils.replace(null, *, *) = null 3802 * StringUtils.replace("", *, *) = "" 3803 * StringUtils.replace("any", null, *) = "any" 3804 * StringUtils.replace("any", *, null) = "any" 3805 * StringUtils.replace("any", "", *) = "any" 3806 * StringUtils.replace("aba", "a", null) = "aba" 3807 * StringUtils.replace("aba", "a", "") = "b" 3808 * StringUtils.replace("aba", "a", "z") = "zbz" 3809 * </pre> 3810 * 3811 * @see #replace(String text, String searchString, String replacement, int max) 3812 * @param text text to search and replace in, may be null 3813 * @param searchString the String to search for, may be null 3814 * @param replacement the String to replace it with, may be null 3815 * @return the text with any replacements processed, 3816 * {@code null} if null String input 3817 */ 3818 public static String replace(String text, String searchString, String replacement) { 3819 return replace(text, searchString, replacement, -1); 3820 } 3821 3822 /** 3823 * <p>Replaces a String with another String inside a larger String, 3824 * for the first {@code max} values of the search String.</p> 3825 * 3826 * <p>A {@code null} reference passed to this method is a no-op.</p> 3827 * 3828 * <pre> 3829 * StringUtils.replace(null, *, *, *) = null 3830 * StringUtils.replace("", *, *, *) = "" 3831 * StringUtils.replace("any", null, *, *) = "any" 3832 * StringUtils.replace("any", *, null, *) = "any" 3833 * StringUtils.replace("any", "", *, *) = "any" 3834 * StringUtils.replace("any", *, *, 0) = "any" 3835 * StringUtils.replace("abaa", "a", null, -1) = "abaa" 3836 * StringUtils.replace("abaa", "a", "", -1) = "b" 3837 * StringUtils.replace("abaa", "a", "z", 0) = "abaa" 3838 * StringUtils.replace("abaa", "a", "z", 1) = "zbaa" 3839 * StringUtils.replace("abaa", "a", "z", 2) = "zbza" 3840 * StringUtils.replace("abaa", "a", "z", -1) = "zbzz" 3841 * </pre> 3842 * 3843 * @param text text to search and replace in, may be null 3844 * @param searchString the String to search for, may be null 3845 * @param replacement the String to replace it with, may be null 3846 * @param max maximum number of values to replace, or {@code -1} if no maximum 3847 * @return the text with any replacements processed, 3848 * {@code null} if null String input 3849 */ 3850 public static String replace(String text, String searchString, String replacement, int max) { 3851 if (isEmpty(text) || isEmpty(searchString) || replacement == null || max == 0) { 3852 return text; 3853 } 3854 int start = 0; 3855 int end = text.indexOf(searchString, start); 3856 if (end == INDEX_NOT_FOUND) { 3857 return text; 3858 } 3859 int replLength = searchString.length(); 3860 int increase = replacement.length() - replLength; 3861 increase = (increase < 0 ? 0 : increase); 3862 increase *= (max < 0 ? 16 : (max > 64 ? 64 : max)); 3863 StringBuilder buf = new StringBuilder(text.length() + increase); 3864 while (end != INDEX_NOT_FOUND) { 3865 buf.append(text.substring(start, end)).append(replacement); 3866 start = end + replLength; 3867 if (--max == 0) { 3868 break; 3869 } 3870 end = text.indexOf(searchString, start); 3871 } 3872 buf.append(text.substring(start)); 3873 return buf.toString(); 3874 } 3875 3876 /** 3877 * <p> 3878 * Replaces all occurrences of Strings within another String. 3879 * </p> 3880 * 3881 * <p> 3882 * A {@code null} reference passed to this method is a no-op, or if 3883 * any "search string" or "string to replace" is null, that replace will be 3884 * ignored. This will not repeat. For repeating replaces, call the 3885 * overloaded method. 3886 * </p> 3887 * 3888 * <pre> 3889 * StringUtils.replaceEach(null, *, *) = null 3890 * StringUtils.replaceEach("", *, *) = "" 3891 * StringUtils.replaceEach("aba", null, null) = "aba" 3892 * StringUtils.replaceEach("aba", new String[0], null) = "aba" 3893 * StringUtils.replaceEach("aba", null, new String[0]) = "aba" 3894 * StringUtils.replaceEach("aba", new String[]{"a"}, null) = "aba" 3895 * StringUtils.replaceEach("aba", new String[]{"a"}, new String[]{""}) = "b" 3896 * StringUtils.replaceEach("aba", new String[]{null}, new String[]{"a"}) = "aba" 3897 * StringUtils.replaceEach("abcde", new String[]{"ab", "d"}, new String[]{"w", "t"}) = "wcte" 3898 * (example of how it does not repeat) 3899 * StringUtils.replaceEach("abcde", new String[]{"ab", "d"}, new String[]{"d", "t"}) = "dcte" 3900 * </pre> 3901 * 3902 * @param text 3903 * text to search and replace in, no-op if null 3904 * @param searchList 3905 * the Strings to search for, no-op if null 3906 * @param replacementList 3907 * the Strings to replace them with, no-op if null 3908 * @return the text with any replacements processed, {@code null} if 3909 * null String input 3910 * @throws IndexOutOfBoundsException 3911 * if the lengths of the arrays are not the same (null is ok, 3912 * and/or size 0) 3913 * @since 2.4 3914 */ 3915 public static String replaceEach(String text, String[] searchList, String[] replacementList) { 3916 return replaceEach(text, searchList, replacementList, false, 0); 3917 } 3918 3919 /** 3920 * <p> 3921 * Replaces all occurrences of Strings within another String. 3922 * </p> 3923 * 3924 * <p> 3925 * A {@code null} reference passed to this method is a no-op, or if 3926 * any "search string" or "string to replace" is null, that replace will be 3927 * ignored. This will not repeat. For repeating replaces, call the 3928 * overloaded method. 3929 * </p> 3930 * 3931 * <pre> 3932 * StringUtils.replaceEach(null, *, *, *) = null 3933 * StringUtils.replaceEach("", *, *, *) = "" 3934 * StringUtils.replaceEach("aba", null, null, *) = "aba" 3935 * StringUtils.replaceEach("aba", new String[0], null, *) = "aba" 3936 * StringUtils.replaceEach("aba", null, new String[0], *) = "aba" 3937 * StringUtils.replaceEach("aba", new String[]{"a"}, null, *) = "aba" 3938 * StringUtils.replaceEach("aba", new String[]{"a"}, new String[]{""}, *) = "b" 3939 * StringUtils.replaceEach("aba", new String[]{null}, new String[]{"a"}, *) = "aba" 3940 * StringUtils.replaceEach("abcde", new String[]{"ab", "d"}, new String[]{"w", "t"}, *) = "wcte" 3941 * (example of how it repeats) 3942 * StringUtils.replaceEach("abcde", new String[]{"ab", "d"}, new String[]{"d", "t"}, false) = "dcte" 3943 * StringUtils.replaceEach("abcde", new String[]{"ab", "d"}, new String[]{"d", "t"}, true) = "tcte" 3944 * StringUtils.replaceEach("abcde", new String[]{"ab", "d"}, new String[]{"d", "ab"}, true) = IllegalArgumentException 3945 * StringUtils.replaceEach("abcde", new String[]{"ab", "d"}, new String[]{"d", "ab"}, false) = "dcabe" 3946 * </pre> 3947 * 3948 * @param text 3949 * text to search and replace in, no-op if null 3950 * @param searchList 3951 * the Strings to search for, no-op if null 3952 * @param replacementList 3953 * the Strings to replace them with, no-op if null 3954 * @return the text with any replacements processed, {@code null} if 3955 * null String input 3956 * @throws IllegalArgumentException 3957 * if the search is repeating and there is an endless loop due 3958 * to outputs of one being inputs to another 3959 * @throws IndexOutOfBoundsException 3960 * if the lengths of the arrays are not the same (null is ok, 3961 * and/or size 0) 3962 * @since 2.4 3963 */ 3964 public static String replaceEachRepeatedly(String text, String[] searchList, String[] replacementList) { 3965 // timeToLive should be 0 if not used or nothing to replace, else it's 3966 // the length of the replace array 3967 int timeToLive = searchList == null ? 0 : searchList.length; 3968 return replaceEach(text, searchList, replacementList, true, timeToLive); 3969 } 3970 3971 /** 3972 * <p> 3973 * Replaces all occurrences of Strings within another String. 3974 * </p> 3975 * 3976 * <p> 3977 * A {@code null} reference passed to this method is a no-op, or if 3978 * any "search string" or "string to replace" is null, that replace will be 3979 * ignored. 3980 * </p> 3981 * 3982 * <pre> 3983 * StringUtils.replaceEach(null, *, *, *) = null 3984 * StringUtils.replaceEach("", *, *, *) = "" 3985 * StringUtils.replaceEach("aba", null, null, *) = "aba" 3986 * StringUtils.replaceEach("aba", new String[0], null, *) = "aba" 3987 * StringUtils.replaceEach("aba", null, new String[0], *) = "aba" 3988 * StringUtils.replaceEach("aba", new String[]{"a"}, null, *) = "aba" 3989 * StringUtils.replaceEach("aba", new String[]{"a"}, new String[]{""}, *) = "b" 3990 * StringUtils.replaceEach("aba", new String[]{null}, new String[]{"a"}, *) = "aba" 3991 * StringUtils.replaceEach("abcde", new String[]{"ab", "d"}, new String[]{"w", "t"}, *) = "wcte" 3992 * (example of how it repeats) 3993 * StringUtils.replaceEach("abcde", new String[]{"ab", "d"}, new String[]{"d", "t"}, false) = "dcte" 3994 * StringUtils.replaceEach("abcde", new String[]{"ab", "d"}, new String[]{"d", "t"}, true) = "tcte" 3995 * StringUtils.replaceEach("abcde", new String[]{"ab", "d"}, new String[]{"d", "ab"}, *) = IllegalArgumentException 3996 * </pre> 3997 * 3998 * @param text 3999 * text to search and replace in, no-op if null 4000 * @param searchList 4001 * the Strings to search for, no-op if null 4002 * @param replacementList 4003 * the Strings to replace them with, no-op if null 4004 * @param repeat if true, then replace repeatedly 4005 * until there are no more possible replacements or timeToLive < 0 4006 * @param timeToLive 4007 * if less than 0 then there is a circular reference and endless 4008 * loop 4009 * @return the text with any replacements processed, {@code null} if 4010 * null String input 4011 * @throws IllegalArgumentException 4012 * if the search is repeating and there is an endless loop due 4013 * to outputs of one being inputs to another 4014 * @throws IndexOutOfBoundsException 4015 * if the lengths of the arrays are not the same (null is ok, 4016 * and/or size 0) 4017 * @since 2.4 4018 */ 4019 private static String replaceEach( 4020 String text, String[] searchList, String[] replacementList, boolean repeat, int timeToLive) { 4021 4022 // mchyzer Performance note: This creates very few new objects (one major goal) 4023 // let me know if there are performance requests, we can create a harness to measure 4024 4025 if (text == null || text.length() == 0 || searchList == null || 4026 searchList.length == 0 || replacementList == null || replacementList.length == 0) { 4027 return text; 4028 } 4029 4030 // if recursing, this shouldn't be less than 0 4031 if (timeToLive < 0) { 4032 throw new IllegalStateException("TimeToLive of " + timeToLive + " is less than 0: " + text); 4033 } 4034 4035 int searchLength = searchList.length; 4036 int replacementLength = replacementList.length; 4037 4038 // make sure lengths are ok, these need to be equal 4039 if (searchLength != replacementLength) { 4040 throw new IllegalArgumentException("Search and Replace array lengths don't match: " 4041 + searchLength 4042 + " vs " 4043 + replacementLength); 4044 } 4045 4046 // keep track of which still have matches 4047 boolean[] noMoreMatchesForReplIndex = new boolean[searchLength]; 4048 4049 // index on index that the match was found 4050 int textIndex = -1; 4051 int replaceIndex = -1; 4052 int tempIndex = -1; 4053 4054 // index of replace array that will replace the search string found 4055 // NOTE: logic duplicated below START 4056 for (int i = 0; i < searchLength; i++) { 4057 if (noMoreMatchesForReplIndex[i] || searchList[i] == null || 4058 searchList[i].length() == 0 || replacementList[i] == null) { 4059 continue; 4060 } 4061 tempIndex = text.indexOf(searchList[i]); 4062 4063 // see if we need to keep searching for this 4064 if (tempIndex == -1) { 4065 noMoreMatchesForReplIndex[i] = true; 4066 } else { 4067 if (textIndex == -1 || tempIndex < textIndex) { 4068 textIndex = tempIndex; 4069 replaceIndex = i; 4070 } 4071 } 4072 } 4073 // NOTE: logic mostly below END 4074 4075 // no search strings found, we are done 4076 if (textIndex == -1) { 4077 return text; 4078 } 4079 4080 int start = 0; 4081 4082 // get a good guess on the size of the result buffer so it doesn't have to double if it goes over a bit 4083 int increase = 0; 4084 4085 // count the replacement text elements that are larger than their corresponding text being replaced 4086 for (int i = 0; i < searchList.length; i++) { 4087 if (searchList[i] == null || replacementList[i] == null) { 4088 continue; 4089 } 4090 int greater = replacementList[i].length() - searchList[i].length(); 4091 if (greater > 0) { 4092 increase += 3 * greater; // assume 3 matches 4093 } 4094 } 4095 // have upper-bound at 20% increase, then let Java take over 4096 increase = Math.min(increase, text.length() / 5); 4097 4098 StringBuilder buf = new StringBuilder(text.length() + increase); 4099 4100 while (textIndex != -1) { 4101 4102 for (int i = start; i < textIndex; i++) { 4103 buf.append(text.charAt(i)); 4104 } 4105 buf.append(replacementList[replaceIndex]); 4106 4107 start = textIndex + searchList[replaceIndex].length(); 4108 4109 textIndex = -1; 4110 replaceIndex = -1; 4111 tempIndex = -1; 4112 // find the next earliest match 4113 // NOTE: logic mostly duplicated above START 4114 for (int i = 0; i < searchLength; i++) { 4115 if (noMoreMatchesForReplIndex[i] || searchList[i] == null || 4116 searchList[i].length() == 0 || replacementList[i] == null) { 4117 continue; 4118 } 4119 tempIndex = text.indexOf(searchList[i], start); 4120 4121 // see if we need to keep searching for this 4122 if (tempIndex == -1) { 4123 noMoreMatchesForReplIndex[i] = true; 4124 } else { 4125 if (textIndex == -1 || tempIndex < textIndex) { 4126 textIndex = tempIndex; 4127 replaceIndex = i; 4128 } 4129 } 4130 } 4131 // NOTE: logic duplicated above END 4132 4133 } 4134 int textLength = text.length(); 4135 for (int i = start; i < textLength; i++) { 4136 buf.append(text.charAt(i)); 4137 } 4138 String result = buf.toString(); 4139 if (!repeat) { 4140 return result; 4141 } 4142 4143 return replaceEach(result, searchList, replacementList, repeat, timeToLive - 1); 4144 } 4145 4146 // Replace, character based 4147 //----------------------------------------------------------------------- 4148 /** 4149 * <p>Replaces all occurrences of a character in a String with another. 4150 * This is a null-safe version of {@link String#replace(char, char)}.</p> 4151 * 4152 * <p>A {@code null} string input returns {@code null}. 4153 * An empty ("") string input returns an empty string.</p> 4154 * 4155 * <pre> 4156 * StringUtils.replaceChars(null, *, *) = null 4157 * StringUtils.replaceChars("", *, *) = "" 4158 * StringUtils.replaceChars("abcba", 'b', 'y') = "aycya" 4159 * StringUtils.replaceChars("abcba", 'z', 'y') = "abcba" 4160 * </pre> 4161 * 4162 * @param str String to replace characters in, may be null 4163 * @param searchChar the character to search for, may be null 4164 * @param replaceChar the character to replace, may be null 4165 * @return modified String, {@code null} if null string input 4166 * @since 2.0 4167 */ 4168 public static String replaceChars(String str, char searchChar, char replaceChar) { 4169 if (str == null) { 4170 return null; 4171 } 4172 return str.replace(searchChar, replaceChar); 4173 } 4174 4175 /** 4176 * <p>Replaces multiple characters in a String in one go. 4177 * This method can also be used to delete characters.</p> 4178 * 4179 * <p>For example:<br /> 4180 * <code>replaceChars("hello", "ho", "jy") = jelly</code>.</p> 4181 * 4182 * <p>A {@code null} string input returns {@code null}. 4183 * An empty ("") string input returns an empty string. 4184 * A null or empty set of search characters returns the input string.</p> 4185 * 4186 * <p>The length of the search characters should normally equal the length 4187 * of the replace characters. 4188 * If the search characters is longer, then the extra search characters 4189 * are deleted. 4190 * If the search characters is shorter, then the extra replace characters 4191 * are ignored.</p> 4192 * 4193 * <pre> 4194 * StringUtils.replaceChars(null, *, *) = null 4195 * StringUtils.replaceChars("", *, *) = "" 4196 * StringUtils.replaceChars("abc", null, *) = "abc" 4197 * StringUtils.replaceChars("abc", "", *) = "abc" 4198 * StringUtils.replaceChars("abc", "b", null) = "ac" 4199 * StringUtils.replaceChars("abc", "b", "") = "ac" 4200 * StringUtils.replaceChars("abcba", "bc", "yz") = "ayzya" 4201 * StringUtils.replaceChars("abcba", "bc", "y") = "ayya" 4202 * StringUtils.replaceChars("abcba", "bc", "yzx") = "ayzya" 4203 * </pre> 4204 * 4205 * @param str String to replace characters in, may be null 4206 * @param searchChars a set of characters to search for, may be null 4207 * @param replaceChars a set of characters to replace, may be null 4208 * @return modified String, {@code null} if null string input 4209 * @since 2.0 4210 */ 4211 public static String replaceChars(String str, String searchChars, String replaceChars) { 4212 if (isEmpty(str) || isEmpty(searchChars)) { 4213 return str; 4214 } 4215 if (replaceChars == null) { 4216 replaceChars = EMPTY; 4217 } 4218 boolean modified = false; 4219 int replaceCharsLength = replaceChars.length(); 4220 int strLength = str.length(); 4221 StringBuilder buf = new StringBuilder(strLength); 4222 for (int i = 0; i < strLength; i++) { 4223 char ch = str.charAt(i); 4224 int index = searchChars.indexOf(ch); 4225 if (index >= 0) { 4226 modified = true; 4227 if (index < replaceCharsLength) { 4228 buf.append(replaceChars.charAt(index)); 4229 } 4230 } else { 4231 buf.append(ch); 4232 } 4233 } 4234 if (modified) { 4235 return buf.toString(); 4236 } 4237 return str; 4238 } 4239 4240 // Overlay 4241 //----------------------------------------------------------------------- 4242 /** 4243 * <p>Overlays part of a String with another String.</p> 4244 * 4245 * <p>A {@code null} string input returns {@code null}. 4246 * A negative index is treated as zero. 4247 * An index greater than the string length is treated as the string length. 4248 * The start index is always the smaller of the two indices.</p> 4249 * 4250 * <pre> 4251 * StringUtils.overlay(null, *, *, *) = null 4252 * StringUtils.overlay("", "abc", 0, 0) = "abc" 4253 * StringUtils.overlay("abcdef", null, 2, 4) = "abef" 4254 * StringUtils.overlay("abcdef", "", 2, 4) = "abef" 4255 * StringUtils.overlay("abcdef", "", 4, 2) = "abef" 4256 * StringUtils.overlay("abcdef", "zzzz", 2, 4) = "abzzzzef" 4257 * StringUtils.overlay("abcdef", "zzzz", 4, 2) = "abzzzzef" 4258 * StringUtils.overlay("abcdef", "zzzz", -1, 4) = "zzzzef" 4259 * StringUtils.overlay("abcdef", "zzzz", 2, 8) = "abzzzz" 4260 * StringUtils.overlay("abcdef", "zzzz", -2, -3) = "zzzzabcdef" 4261 * StringUtils.overlay("abcdef", "zzzz", 8, 10) = "abcdefzzzz" 4262 * </pre> 4263 * 4264 * @param str the String to do overlaying in, may be null 4265 * @param overlay the String to overlay, may be null 4266 * @param start the position to start overlaying at 4267 * @param end the position to stop overlaying before 4268 * @return overlayed String, {@code null} if null String input 4269 * @since 2.0 4270 */ 4271 public static String overlay(String str, String overlay, int start, int end) { 4272 if (str == null) { 4273 return null; 4274 } 4275 if (overlay == null) { 4276 overlay = EMPTY; 4277 } 4278 int len = str.length(); 4279 if (start < 0) { 4280 start = 0; 4281 } 4282 if (start > len) { 4283 start = len; 4284 } 4285 if (end < 0) { 4286 end = 0; 4287 } 4288 if (end > len) { 4289 end = len; 4290 } 4291 if (start > end) { 4292 int temp = start; 4293 start = end; 4294 end = temp; 4295 } 4296 return new StringBuilder(len + start - end + overlay.length() + 1) 4297 .append(str.substring(0, start)) 4298 .append(overlay) 4299 .append(str.substring(end)) 4300 .toString(); 4301 } 4302 4303 // Chomping 4304 //----------------------------------------------------------------------- 4305 /** 4306 * <p>Removes one newline from end of a String if it's there, 4307 * otherwise leave it alone. A newline is "{@code \n}", 4308 * "{@code \r}", or "{@code \r\n}".</p> 4309 * 4310 * <p>NOTE: This method changed in 2.0. 4311 * It now more closely matches Perl chomp.</p> 4312 * 4313 * <pre> 4314 * StringUtils.chomp(null) = null 4315 * StringUtils.chomp("") = "" 4316 * StringUtils.chomp("abc \r") = "abc " 4317 * StringUtils.chomp("abc\n") = "abc" 4318 * StringUtils.chomp("abc\r\n") = "abc" 4319 * StringUtils.chomp("abc\r\n\r\n") = "abc\r\n" 4320 * StringUtils.chomp("abc\n\r") = "abc\n" 4321 * StringUtils.chomp("abc\n\rabc") = "abc\n\rabc" 4322 * StringUtils.chomp("\r") = "" 4323 * StringUtils.chomp("\n") = "" 4324 * StringUtils.chomp("\r\n") = "" 4325 * </pre> 4326 * 4327 * @param str the String to chomp a newline from, may be null 4328 * @return String without newline, {@code null} if null String input 4329 */ 4330 public static String chomp(String str) { 4331 if (isEmpty(str)) { 4332 return str; 4333 } 4334 4335 if (str.length() == 1) { 4336 char ch = str.charAt(0); 4337 if (ch == CharUtils.CR || ch == CharUtils.LF) { 4338 return EMPTY; 4339 } 4340 return str; 4341 } 4342 4343 int lastIdx = str.length() - 1; 4344 char last = str.charAt(lastIdx); 4345 4346 if (last == CharUtils.LF) { 4347 if (str.charAt(lastIdx - 1) == CharUtils.CR) { 4348 lastIdx--; 4349 } 4350 } else if (last != CharUtils.CR) { 4351 lastIdx++; 4352 } 4353 return str.substring(0, lastIdx); 4354 } 4355 4356 /** 4357 * <p>Removes {@code separator} from the end of 4358 * {@code str} if it's there, otherwise leave it alone.</p> 4359 * 4360 * <p>NOTE: This method changed in version 2.0. 4361 * It now more closely matches Perl chomp. 4362 * For the previous behavior, use {@link #substringBeforeLast(String, String)}. 4363 * This method uses {@link String#endsWith(String)}.</p> 4364 * 4365 * <pre> 4366 * StringUtils.chomp(null, *) = null 4367 * StringUtils.chomp("", *) = "" 4368 * StringUtils.chomp("foobar", "bar") = "foo" 4369 * StringUtils.chomp("foobar", "baz") = "foobar" 4370 * StringUtils.chomp("foo", "foo") = "" 4371 * StringUtils.chomp("foo ", "foo") = "foo " 4372 * StringUtils.chomp(" foo", "foo") = " " 4373 * StringUtils.chomp("foo", "foooo") = "foo" 4374 * StringUtils.chomp("foo", "") = "foo" 4375 * StringUtils.chomp("foo", null) = "foo" 4376 * </pre> 4377 * 4378 * @param str the String to chomp from, may be null 4379 * @param separator separator String, may be null 4380 * @return String without trailing separator, {@code null} if null String input 4381 */ 4382 public static String chomp(String str, String separator) { 4383 if (isEmpty(str) || separator == null) { 4384 return str; 4385 } 4386 if (str.endsWith(separator)) { 4387 return str.substring(0, str.length() - separator.length()); 4388 } 4389 return str; 4390 } 4391 4392 // Chopping 4393 //----------------------------------------------------------------------- 4394 /** 4395 * <p>Remove the last character from a String.</p> 4396 * 4397 * <p>If the String ends in {@code \r\n}, then remove both 4398 * of them.</p> 4399 * 4400 * <pre> 4401 * StringUtils.chop(null) = null 4402 * StringUtils.chop("") = "" 4403 * StringUtils.chop("abc \r") = "abc " 4404 * StringUtils.chop("abc\n") = "abc" 4405 * StringUtils.chop("abc\r\n") = "abc" 4406 * StringUtils.chop("abc") = "ab" 4407 * StringUtils.chop("abc\nabc") = "abc\nab" 4408 * StringUtils.chop("a") = "" 4409 * StringUtils.chop("\r") = "" 4410 * StringUtils.chop("\n") = "" 4411 * StringUtils.chop("\r\n") = "" 4412 * </pre> 4413 * 4414 * @param str the String to chop last character from, may be null 4415 * @return String without last character, {@code null} if null String input 4416 */ 4417 public static String chop(String str) { 4418 if (str == null) { 4419 return null; 4420 } 4421 int strLen = str.length(); 4422 if (strLen < 2) { 4423 return EMPTY; 4424 } 4425 int lastIdx = strLen - 1; 4426 String ret = str.substring(0, lastIdx); 4427 char last = str.charAt(lastIdx); 4428 if (last == CharUtils.LF) { 4429 if (ret.charAt(lastIdx - 1) == CharUtils.CR) { 4430 return ret.substring(0, lastIdx - 1); 4431 } 4432 } 4433 return ret; 4434 } 4435 4436 // Conversion 4437 //----------------------------------------------------------------------- 4438 4439 // Padding 4440 //----------------------------------------------------------------------- 4441 /** 4442 * <p>Repeat a String {@code repeat} times to form a 4443 * new String.</p> 4444 * 4445 * <pre> 4446 * StringUtils.repeat(null, 2) = null 4447 * StringUtils.repeat("", 0) = "" 4448 * StringUtils.repeat("", 2) = "" 4449 * StringUtils.repeat("a", 3) = "aaa" 4450 * StringUtils.repeat("ab", 2) = "abab" 4451 * StringUtils.repeat("a", -2) = "" 4452 * </pre> 4453 * 4454 * @param str the String to repeat, may be null 4455 * @param repeat number of times to repeat str, negative treated as zero 4456 * @return a new String consisting of the original String repeated, 4457 * {@code null} if null String input 4458 */ 4459 public static String repeat(String str, int repeat) { 4460 // Performance tuned for 2.0 (JDK1.4) 4461 4462 if (str == null) { 4463 return null; 4464 } 4465 if (repeat <= 0) { 4466 return EMPTY; 4467 } 4468 int inputLength = str.length(); 4469 if (repeat == 1 || inputLength == 0) { 4470 return str; 4471 } 4472 if (inputLength == 1 && repeat <= PAD_LIMIT) { 4473 return repeat(str.charAt(0), repeat); 4474 } 4475 4476 int outputLength = inputLength * repeat; 4477 switch (inputLength) { 4478 case 1 : 4479 return repeat(str.charAt(0), repeat); 4480 case 2 : 4481 char ch0 = str.charAt(0); 4482 char ch1 = str.charAt(1); 4483 char[] output2 = new char[outputLength]; 4484 for (int i = repeat * 2 - 2; i >= 0; i--, i--) { 4485 output2[i] = ch0; 4486 output2[i + 1] = ch1; 4487 } 4488 return new String(output2); 4489 default : 4490 StringBuilder buf = new StringBuilder(outputLength); 4491 for (int i = 0; i < repeat; i++) { 4492 buf.append(str); 4493 } 4494 return buf.toString(); 4495 } 4496 } 4497 4498 /** 4499 * <p>Repeat a String {@code repeat} times to form a 4500 * new String, with a String separator injected each time. </p> 4501 * 4502 * <pre> 4503 * StringUtils.repeat(null, null, 2) = null 4504 * StringUtils.repeat(null, "x", 2) = null 4505 * StringUtils.repeat("", null, 0) = "" 4506 * StringUtils.repeat("", "", 2) = "" 4507 * StringUtils.repeat("", "x", 3) = "xxx" 4508 * StringUtils.repeat("?", ", ", 3) = "?, ?, ?" 4509 * </pre> 4510 * 4511 * @param str the String to repeat, may be null 4512 * @param separator the String to inject, may be null 4513 * @param repeat number of times to repeat str, negative treated as zero 4514 * @return a new String consisting of the original String repeated, 4515 * {@code null} if null String input 4516 * @since 2.5 4517 */ 4518 public static String repeat(String str, String separator, int repeat) { 4519 if(str == null || separator == null) { 4520 return repeat(str, repeat); 4521 } else { 4522 // given that repeat(String, int) is quite optimized, better to rely on it than try and splice this into it 4523 String result = repeat(str + separator, repeat); 4524 return removeEnd(result, separator); 4525 } 4526 } 4527 4528 /** 4529 * <p>Returns padding using the specified delimiter repeated 4530 * to a given length.</p> 4531 * 4532 * <pre> 4533 * StringUtils.repeat(0, 'e') = "" 4534 * StringUtils.repeat(3, 'e') = "eee" 4535 * StringUtils.repeat(-2, 'e') = "" 4536 * </pre> 4537 * 4538 * <p>Note: this method doesn't not support padding with 4539 * <a href="http://www.unicode.org/glossary/#supplementary_character">Unicode Supplementary Characters</a> 4540 * as they require a pair of {@code char}s to be represented. 4541 * If you are needing to support full I18N of your applications 4542 * consider using {@link #repeat(String, int)} instead. 4543 * </p> 4544 * 4545 * @param ch character to repeat 4546 * @param repeat number of times to repeat char, negative treated as zero 4547 * @return String with repeated character 4548 * @see #repeat(String, int) 4549 */ 4550 public static String repeat(char ch, int repeat) { 4551 char[] buf = new char[repeat]; 4552 for (int i = repeat - 1; i >= 0; i--) { 4553 buf[i] = ch; 4554 } 4555 return new String(buf); 4556 } 4557 4558 /** 4559 * <p>Right pad a String with spaces (' ').</p> 4560 * 4561 * <p>The String is padded to the size of {@code size}.</p> 4562 * 4563 * <pre> 4564 * StringUtils.rightPad(null, *) = null 4565 * StringUtils.rightPad("", 3) = " " 4566 * StringUtils.rightPad("bat", 3) = "bat" 4567 * StringUtils.rightPad("bat", 5) = "bat " 4568 * StringUtils.rightPad("bat", 1) = "bat" 4569 * StringUtils.rightPad("bat", -1) = "bat" 4570 * </pre> 4571 * 4572 * @param str the String to pad out, may be null 4573 * @param size the size to pad to 4574 * @return right padded String or original String if no padding is necessary, 4575 * {@code null} if null String input 4576 */ 4577 public static String rightPad(String str, int size) { 4578 return rightPad(str, size, ' '); 4579 } 4580 4581 /** 4582 * <p>Right pad a String with a specified character.</p> 4583 * 4584 * <p>The String is padded to the size of {@code size}.</p> 4585 * 4586 * <pre> 4587 * StringUtils.rightPad(null, *, *) = null 4588 * StringUtils.rightPad("", 3, 'z') = "zzz" 4589 * StringUtils.rightPad("bat", 3, 'z') = "bat" 4590 * StringUtils.rightPad("bat", 5, 'z') = "batzz" 4591 * StringUtils.rightPad("bat", 1, 'z') = "bat" 4592 * StringUtils.rightPad("bat", -1, 'z') = "bat" 4593 * </pre> 4594 * 4595 * @param str the String to pad out, may be null 4596 * @param size the size to pad to 4597 * @param padChar the character to pad with 4598 * @return right padded String or original String if no padding is necessary, 4599 * {@code null} if null String input 4600 * @since 2.0 4601 */ 4602 public static String rightPad(String str, int size, char padChar) { 4603 if (str == null) { 4604 return null; 4605 } 4606 int pads = size - str.length(); 4607 if (pads <= 0) { 4608 return str; // returns original String when possible 4609 } 4610 if (pads > PAD_LIMIT) { 4611 return rightPad(str, size, String.valueOf(padChar)); 4612 } 4613 return str.concat(repeat(padChar, pads)); 4614 } 4615 4616 /** 4617 * <p>Right pad a String with a specified String.</p> 4618 * 4619 * <p>The String is padded to the size of {@code size}.</p> 4620 * 4621 * <pre> 4622 * StringUtils.rightPad(null, *, *) = null 4623 * StringUtils.rightPad("", 3, "z") = "zzz" 4624 * StringUtils.rightPad("bat", 3, "yz") = "bat" 4625 * StringUtils.rightPad("bat", 5, "yz") = "batyz" 4626 * StringUtils.rightPad("bat", 8, "yz") = "batyzyzy" 4627 * StringUtils.rightPad("bat", 1, "yz") = "bat" 4628 * StringUtils.rightPad("bat", -1, "yz") = "bat" 4629 * StringUtils.rightPad("bat", 5, null) = "bat " 4630 * StringUtils.rightPad("bat", 5, "") = "bat " 4631 * </pre> 4632 * 4633 * @param str the String to pad out, may be null 4634 * @param size the size to pad to 4635 * @param padStr the String to pad with, null or empty treated as single space 4636 * @return right padded String or original String if no padding is necessary, 4637 * {@code null} if null String input 4638 */ 4639 public static String rightPad(String str, int size, String padStr) { 4640 if (str == null) { 4641 return null; 4642 } 4643 if (isEmpty(padStr)) { 4644 padStr = " "; 4645 } 4646 int padLen = padStr.length(); 4647 int strLen = str.length(); 4648 int pads = size - strLen; 4649 if (pads <= 0) { 4650 return str; // returns original String when possible 4651 } 4652 if (padLen == 1 && pads <= PAD_LIMIT) { 4653 return rightPad(str, size, padStr.charAt(0)); 4654 } 4655 4656 if (pads == padLen) { 4657 return str.concat(padStr); 4658 } else if (pads < padLen) { 4659 return str.concat(padStr.substring(0, pads)); 4660 } else { 4661 char[] padding = new char[pads]; 4662 char[] padChars = padStr.toCharArray(); 4663 for (int i = 0; i < pads; i++) { 4664 padding[i] = padChars[i % padLen]; 4665 } 4666 return str.concat(new String(padding)); 4667 } 4668 } 4669 4670 /** 4671 * <p>Left pad a String with spaces (' ').</p> 4672 * 4673 * <p>The String is padded to the size of {@code size}.</p> 4674 * 4675 * <pre> 4676 * StringUtils.leftPad(null, *) = null 4677 * StringUtils.leftPad("", 3) = " " 4678 * StringUtils.leftPad("bat", 3) = "bat" 4679 * StringUtils.leftPad("bat", 5) = " bat" 4680 * StringUtils.leftPad("bat", 1) = "bat" 4681 * StringUtils.leftPad("bat", -1) = "bat" 4682 * </pre> 4683 * 4684 * @param str the String to pad out, may be null 4685 * @param size the size to pad to 4686 * @return left padded String or original String if no padding is necessary, 4687 * {@code null} if null String input 4688 */ 4689 public static String leftPad(String str, int size) { 4690 return leftPad(str, size, ' '); 4691 } 4692 4693 /** 4694 * <p>Left pad a String with a specified character.</p> 4695 * 4696 * <p>Pad to a size of {@code size}.</p> 4697 * 4698 * <pre> 4699 * StringUtils.leftPad(null, *, *) = null 4700 * StringUtils.leftPad("", 3, 'z') = "zzz" 4701 * StringUtils.leftPad("bat", 3, 'z') = "bat" 4702 * StringUtils.leftPad("bat", 5, 'z') = "zzbat" 4703 * StringUtils.leftPad("bat", 1, 'z') = "bat" 4704 * StringUtils.leftPad("bat", -1, 'z') = "bat" 4705 * </pre> 4706 * 4707 * @param str the String to pad out, may be null 4708 * @param size the size to pad to 4709 * @param padChar the character to pad with 4710 * @return left padded String or original String if no padding is necessary, 4711 * {@code null} if null String input 4712 * @since 2.0 4713 */ 4714 public static String leftPad(String str, int size, char padChar) { 4715 if (str == null) { 4716 return null; 4717 } 4718 int pads = size - str.length(); 4719 if (pads <= 0) { 4720 return str; // returns original String when possible 4721 } 4722 if (pads > PAD_LIMIT) { 4723 return leftPad(str, size, String.valueOf(padChar)); 4724 } 4725 return repeat(padChar, pads).concat(str); 4726 } 4727 4728 /** 4729 * <p>Left pad a String with a specified String.</p> 4730 * 4731 * <p>Pad to a size of {@code size}.</p> 4732 * 4733 * <pre> 4734 * StringUtils.leftPad(null, *, *) = null 4735 * StringUtils.leftPad("", 3, "z") = "zzz" 4736 * StringUtils.leftPad("bat", 3, "yz") = "bat" 4737 * StringUtils.leftPad("bat", 5, "yz") = "yzbat" 4738 * StringUtils.leftPad("bat", 8, "yz") = "yzyzybat" 4739 * StringUtils.leftPad("bat", 1, "yz") = "bat" 4740 * StringUtils.leftPad("bat", -1, "yz") = "bat" 4741 * StringUtils.leftPad("bat", 5, null) = " bat" 4742 * StringUtils.leftPad("bat", 5, "") = " bat" 4743 * </pre> 4744 * 4745 * @param str the String to pad out, may be null 4746 * @param size the size to pad to 4747 * @param padStr the String to pad with, null or empty treated as single space 4748 * @return left padded String or original String if no padding is necessary, 4749 * {@code null} if null String input 4750 */ 4751 public static String leftPad(String str, int size, String padStr) { 4752 if (str == null) { 4753 return null; 4754 } 4755 if (isEmpty(padStr)) { 4756 padStr = " "; 4757 } 4758 int padLen = padStr.length(); 4759 int strLen = str.length(); 4760 int pads = size - strLen; 4761 if (pads <= 0) { 4762 return str; // returns original String when possible 4763 } 4764 if (padLen == 1 && pads <= PAD_LIMIT) { 4765 return leftPad(str, size, padStr.charAt(0)); 4766 } 4767 4768 if (pads == padLen) { 4769 return padStr.concat(str); 4770 } else if (pads < padLen) { 4771 return padStr.substring(0, pads).concat(str); 4772 } else { 4773 char[] padding = new char[pads]; 4774 char[] padChars = padStr.toCharArray(); 4775 for (int i = 0; i < pads; i++) { 4776 padding[i] = padChars[i % padLen]; 4777 } 4778 return new String(padding).concat(str); 4779 } 4780 } 4781 4782 /** 4783 * Gets a CharSequence length or {@code 0} if the CharSequence is 4784 * {@code null}. 4785 * 4786 * @param cs 4787 * a CharSequence or {@code null} 4788 * @return CharSequence length or {@code 0} if the CharSequence is 4789 * {@code null}. 4790 * @since 2.4 4791 * @since 3.0 Changed signature from length(String) to length(CharSequence) 4792 */ 4793 public static int length(CharSequence cs) { 4794 return cs == null ? 0 : cs.length(); 4795 } 4796 4797 // Centering 4798 //----------------------------------------------------------------------- 4799 /** 4800 * <p>Centers a String in a larger String of size {@code size} 4801 * using the space character (' ').<p> 4802 * 4803 * <p>If the size is less than the String length, the String is returned. 4804 * A {@code null} String returns {@code null}. 4805 * A negative size is treated as zero.</p> 4806 * 4807 * <p>Equivalent to {@code center(str, size, " ")}.</p> 4808 * 4809 * <pre> 4810 * StringUtils.center(null, *) = null 4811 * StringUtils.center("", 4) = " " 4812 * StringUtils.center("ab", -1) = "ab" 4813 * StringUtils.center("ab", 4) = " ab " 4814 * StringUtils.center("abcd", 2) = "abcd" 4815 * StringUtils.center("a", 4) = " a " 4816 * </pre> 4817 * 4818 * @param str the String to center, may be null 4819 * @param size the int size of new String, negative treated as zero 4820 * @return centered String, {@code null} if null String input 4821 */ 4822 public static String center(String str, int size) { 4823 return center(str, size, ' '); 4824 } 4825 4826 /** 4827 * <p>Centers a String in a larger String of size {@code size}. 4828 * Uses a supplied character as the value to pad the String with.</p> 4829 * 4830 * <p>If the size is less than the String length, the String is returned. 4831 * A {@code null} String returns {@code null}. 4832 * A negative size is treated as zero.</p> 4833 * 4834 * <pre> 4835 * StringUtils.center(null, *, *) = null 4836 * StringUtils.center("", 4, ' ') = " " 4837 * StringUtils.center("ab", -1, ' ') = "ab" 4838 * StringUtils.center("ab", 4, ' ') = " ab" 4839 * StringUtils.center("abcd", 2, ' ') = "abcd" 4840 * StringUtils.center("a", 4, ' ') = " a " 4841 * StringUtils.center("a", 4, 'y') = "yayy" 4842 * </pre> 4843 * 4844 * @param str the String to center, may be null 4845 * @param size the int size of new String, negative treated as zero 4846 * @param padChar the character to pad the new String with 4847 * @return centered String, {@code null} if null String input 4848 * @since 2.0 4849 */ 4850 public static String center(String str, int size, char padChar) { 4851 if (str == null || size <= 0) { 4852 return str; 4853 } 4854 int strLen = str.length(); 4855 int pads = size - strLen; 4856 if (pads <= 0) { 4857 return str; 4858 } 4859 str = leftPad(str, strLen + pads / 2, padChar); 4860 str = rightPad(str, size, padChar); 4861 return str; 4862 } 4863 4864 /** 4865 * <p>Centers a String in a larger String of size {@code size}. 4866 * Uses a supplied String as the value to pad the String with.</p> 4867 * 4868 * <p>If the size is less than the String length, the String is returned. 4869 * A {@code null} String returns {@code null}. 4870 * A negative size is treated as zero.</p> 4871 * 4872 * <pre> 4873 * StringUtils.center(null, *, *) = null 4874 * StringUtils.center("", 4, " ") = " " 4875 * StringUtils.center("ab", -1, " ") = "ab" 4876 * StringUtils.center("ab", 4, " ") = " ab" 4877 * StringUtils.center("abcd", 2, " ") = "abcd" 4878 * StringUtils.center("a", 4, " ") = " a " 4879 * StringUtils.center("a", 4, "yz") = "yayz" 4880 * StringUtils.center("abc", 7, null) = " abc " 4881 * StringUtils.center("abc", 7, "") = " abc " 4882 * </pre> 4883 * 4884 * @param str the String to center, may be null 4885 * @param size the int size of new String, negative treated as zero 4886 * @param padStr the String to pad the new String with, must not be null or empty 4887 * @return centered String, {@code null} if null String input 4888 * @throws IllegalArgumentException if padStr is {@code null} or empty 4889 */ 4890 public static String center(String str, int size, String padStr) { 4891 if (str == null || size <= 0) { 4892 return str; 4893 } 4894 if (isEmpty(padStr)) { 4895 padStr = " "; 4896 } 4897 int strLen = str.length(); 4898 int pads = size - strLen; 4899 if (pads <= 0) { 4900 return str; 4901 } 4902 str = leftPad(str, strLen + pads / 2, padStr); 4903 str = rightPad(str, size, padStr); 4904 return str; 4905 } 4906 4907 // Case conversion 4908 //----------------------------------------------------------------------- 4909 /** 4910 * <p>Converts a String to upper case as per {@link String#toUpperCase()}.</p> 4911 * 4912 * <p>A {@code null} input String returns {@code null}.</p> 4913 * 4914 * <pre> 4915 * StringUtils.upperCase(null) = null 4916 * StringUtils.upperCase("") = "" 4917 * StringUtils.upperCase("aBc") = "ABC" 4918 * </pre> 4919 * 4920 * <p><strong>Note:</strong> As described in the documentation for {@link String#toUpperCase()}, 4921 * the result of this method is affected by the current locale. 4922 * For platform-independent case transformations, the method {@link #lowerCase(String, Locale)} 4923 * should be used with a specific locale (e.g. {@link Locale#ENGLISH}).</p> 4924 * 4925 * @param str the String to upper case, may be null 4926 * @return the upper cased String, {@code null} if null String input 4927 */ 4928 public static String upperCase(String str) { 4929 if (str == null) { 4930 return null; 4931 } 4932 return str.toUpperCase(); 4933 } 4934 4935 /** 4936 * <p>Converts a String to upper case as per {@link String#toUpperCase(Locale)}.</p> 4937 * 4938 * <p>A {@code null} input String returns {@code null}.</p> 4939 * 4940 * <pre> 4941 * StringUtils.upperCase(null, Locale.ENGLISH) = null 4942 * StringUtils.upperCase("", Locale.ENGLISH) = "" 4943 * StringUtils.upperCase("aBc", Locale.ENGLISH) = "ABC" 4944 * </pre> 4945 * 4946 * @param str the String to upper case, may be null 4947 * @param locale the locale that defines the case transformation rules, must not be null 4948 * @return the upper cased String, {@code null} if null String input 4949 * @since 2.5 4950 */ 4951 public static String upperCase(String str, Locale locale) { 4952 if (str == null) { 4953 return null; 4954 } 4955 return str.toUpperCase(locale); 4956 } 4957 4958 /** 4959 * <p>Converts a String to lower case as per {@link String#toLowerCase()}.</p> 4960 * 4961 * <p>A {@code null} input String returns {@code null}.</p> 4962 * 4963 * <pre> 4964 * StringUtils.lowerCase(null) = null 4965 * StringUtils.lowerCase("") = "" 4966 * StringUtils.lowerCase("aBc") = "abc" 4967 * </pre> 4968 * 4969 * <p><strong>Note:</strong> As described in the documentation for {@link String#toLowerCase()}, 4970 * the result of this method is affected by the current locale. 4971 * For platform-independent case transformations, the method {@link #lowerCase(String, Locale)} 4972 * should be used with a specific locale (e.g. {@link Locale#ENGLISH}).</p> 4973 * 4974 * @param str the String to lower case, may be null 4975 * @return the lower cased String, {@code null} if null String input 4976 */ 4977 public static String lowerCase(String str) { 4978 if (str == null) { 4979 return null; 4980 } 4981 return str.toLowerCase(); 4982 } 4983 4984 /** 4985 * <p>Converts a String to lower case as per {@link String#toLowerCase(Locale)}.</p> 4986 * 4987 * <p>A {@code null} input String returns {@code null}.</p> 4988 * 4989 * <pre> 4990 * StringUtils.lowerCase(null, Locale.ENGLISH) = null 4991 * StringUtils.lowerCase("", Locale.ENGLISH) = "" 4992 * StringUtils.lowerCase("aBc", Locale.ENGLISH) = "abc" 4993 * </pre> 4994 * 4995 * @param str the String to lower case, may be null 4996 * @param locale the locale that defines the case transformation rules, must not be null 4997 * @return the lower cased String, {@code null} if null String input 4998 * @since 2.5 4999 */ 5000 public static String lowerCase(String str, Locale locale) { 5001 if (str == null) { 5002 return null; 5003 } 5004 return str.toLowerCase(locale); 5005 } 5006 5007 /** 5008 * <p>Capitalizes a String changing the first letter to title case as 5009 * per {@link Character#toTitleCase(char)}. No other letters are changed.</p> 5010 * 5011 * <p>For a word based algorithm, see {@link org.apache.commons.lang3.text.WordUtils#capitalize(String)}. 5012 * A {@code null} input String returns {@code null}.</p> 5013 * 5014 * <pre> 5015 * StringUtils.capitalize(null) = null 5016 * StringUtils.capitalize("") = "" 5017 * StringUtils.capitalize("cat") = "Cat" 5018 * StringUtils.capitalize("cAt") = "CAt" 5019 * </pre> 5020 * 5021 * @param str the String to capitalize, may be null 5022 * @return the capitalized String, {@code null} if null String input 5023 * @see org.apache.commons.lang3.text.WordUtils#capitalize(String) 5024 * @see #uncapitalize(String) 5025 * @since 2.0 5026 */ 5027 public static String capitalize(String str) { 5028 int strLen; 5029 if (str == null || (strLen = str.length()) == 0) { 5030 return str; 5031 } 5032 return new StringBuilder(strLen) 5033 .append(Character.toTitleCase(str.charAt(0))) 5034 .append(str.substring(1)) 5035 .toString(); 5036 } 5037 5038 /** 5039 * <p>Uncapitalizes a String changing the first letter to title case as 5040 * per {@link Character#toLowerCase(char)}. No other letters are changed.</p> 5041 * 5042 * <p>For a word based algorithm, see {@link org.apache.commons.lang3.text.WordUtils#uncapitalize(String)}. 5043 * A {@code null} input String returns {@code null}.</p> 5044 * 5045 * <pre> 5046 * StringUtils.uncapitalize(null) = null 5047 * StringUtils.uncapitalize("") = "" 5048 * StringUtils.uncapitalize("Cat") = "cat" 5049 * StringUtils.uncapitalize("CAT") = "cAT" 5050 * </pre> 5051 * 5052 * @param str the String to uncapitalize, may be null 5053 * @return the uncapitalized String, {@code null} if null String input 5054 * @see org.apache.commons.lang3.text.WordUtils#uncapitalize(String) 5055 * @see #capitalize(String) 5056 * @since 2.0 5057 */ 5058 public static String uncapitalize(String str) { 5059 int strLen; 5060 if (str == null || (strLen = str.length()) == 0) { 5061 return str; 5062 } 5063 return new StringBuilder(strLen) 5064 .append(Character.toLowerCase(str.charAt(0))) 5065 .append(str.substring(1)) 5066 .toString(); 5067 } 5068 5069 /** 5070 * <p>Swaps the case of a String changing upper and title case to 5071 * lower case, and lower case to upper case.</p> 5072 * 5073 * <ul> 5074 * <li>Upper case character converts to Lower case</li> 5075 * <li>Title case character converts to Lower case</li> 5076 * <li>Lower case character converts to Upper case</li> 5077 * </ul> 5078 * 5079 * <p>For a word based algorithm, see {@link org.apache.commons.lang3.text.WordUtils#swapCase(String)}. 5080 * A {@code null} input String returns {@code null}.</p> 5081 * 5082 * <pre> 5083 * StringUtils.swapCase(null) = null 5084 * StringUtils.swapCase("") = "" 5085 * StringUtils.swapCase("The dog has a BONE") = "tHE DOG HAS A bone" 5086 * </pre> 5087 * 5088 * <p>NOTE: This method changed in Lang version 2.0. 5089 * It no longer performs a word based algorithm. 5090 * If you only use ASCII, you will notice no change. 5091 * That functionality is available in org.apache.commons.lang3.text.WordUtils.</p> 5092 * 5093 * @param str the String to swap case, may be null 5094 * @return the changed String, {@code null} if null String input 5095 */ 5096 public static String swapCase(String str) { 5097 if (StringUtils.isEmpty(str)) { 5098 return str; 5099 } 5100 5101 char[] buffer = str.toCharArray(); 5102 5103 for (int i = 0; i < buffer.length; i++) { 5104 char ch = buffer[i]; 5105 if (Character.isUpperCase(ch)) { 5106 buffer[i] = Character.toLowerCase(ch); 5107 } else if (Character.isTitleCase(ch)) { 5108 buffer[i] = Character.toLowerCase(ch); 5109 } else if (Character.isLowerCase(ch)) { 5110 buffer[i] = Character.toUpperCase(ch); 5111 } 5112 } 5113 return new String(buffer); 5114 } 5115 5116 // Count matches 5117 //----------------------------------------------------------------------- 5118 /** 5119 * <p>Counts how many times the substring appears in the larger string.</p> 5120 * 5121 * <p>A {@code null} or empty ("") String input returns {@code 0}.</p> 5122 * 5123 * <pre> 5124 * StringUtils.countMatches(null, *) = 0 5125 * StringUtils.countMatches("", *) = 0 5126 * StringUtils.countMatches("abba", null) = 0 5127 * StringUtils.countMatches("abba", "") = 0 5128 * StringUtils.countMatches("abba", "a") = 2 5129 * StringUtils.countMatches("abba", "ab") = 1 5130 * StringUtils.countMatches("abba", "xxx") = 0 5131 * </pre> 5132 * 5133 * @param str the CharSequence to check, may be null 5134 * @param sub the substring to count, may be null 5135 * @return the number of occurrences, 0 if either CharSequence is {@code null} 5136 * @since 3.0 Changed signature from countMatches(String, String) to countMatches(CharSequence, CharSequence) 5137 */ 5138 public static int countMatches(CharSequence str, CharSequence sub) { 5139 if (isEmpty(str) || isEmpty(sub)) { 5140 return 0; 5141 } 5142 int count = 0; 5143 int idx = 0; 5144 while ((idx = CharSequenceUtils.indexOf(str, sub, idx)) != INDEX_NOT_FOUND) { 5145 count++; 5146 idx += sub.length(); 5147 } 5148 return count; 5149 } 5150 5151 // Character Tests 5152 //----------------------------------------------------------------------- 5153 /** 5154 * <p>Checks if the CharSequence contains only Unicode letters.</p> 5155 * 5156 * <p>{@code null} will return {@code false}. 5157 * An empty CharSequence (length()=0) will return {@code false}.</p> 5158 * 5159 * <pre> 5160 * StringUtils.isAlpha(null) = false 5161 * StringUtils.isAlpha("") = false 5162 * StringUtils.isAlpha(" ") = false 5163 * StringUtils.isAlpha("abc") = true 5164 * StringUtils.isAlpha("ab2c") = false 5165 * StringUtils.isAlpha("ab-c") = false 5166 * </pre> 5167 * 5168 * @param cs the CharSequence to check, may be null 5169 * @return {@code true} if only contains letters, and is non-null 5170 * @since 3.0 Changed signature from isAlpha(String) to isAlpha(CharSequence) 5171 * @since 3.0 Changed "" to return false and not true 5172 */ 5173 public static boolean isAlpha(CharSequence cs) { 5174 if (cs == null || cs.length() == 0) { 5175 return false; 5176 } 5177 int sz = cs.length(); 5178 for (int i = 0; i < sz; i++) { 5179 if (Character.isLetter(cs.charAt(i)) == false) { 5180 return false; 5181 } 5182 } 5183 return true; 5184 } 5185 5186 /** 5187 * <p>Checks if the CharSequence contains only Unicode letters and 5188 * space (' ').</p> 5189 * 5190 * <p>{@code null} will return {@code false} 5191 * An empty CharSequence (length()=0) will return {@code true}.</p> 5192 * 5193 * <pre> 5194 * StringUtils.isAlphaSpace(null) = false 5195 * StringUtils.isAlphaSpace("") = true 5196 * StringUtils.isAlphaSpace(" ") = true 5197 * StringUtils.isAlphaSpace("abc") = true 5198 * StringUtils.isAlphaSpace("ab c") = true 5199 * StringUtils.isAlphaSpace("ab2c") = false 5200 * StringUtils.isAlphaSpace("ab-c") = false 5201 * </pre> 5202 * 5203 * @param cs the CharSequence to check, may be null 5204 * @return {@code true} if only contains letters and space, 5205 * and is non-null 5206 * @since 3.0 Changed signature from isAlphaSpace(String) to isAlphaSpace(CharSequence) 5207 */ 5208 public static boolean isAlphaSpace(CharSequence cs) { 5209 if (cs == null) { 5210 return false; 5211 } 5212 int sz = cs.length(); 5213 for (int i = 0; i < sz; i++) { 5214 if ((Character.isLetter(cs.charAt(i)) == false) && (cs.charAt(i) != ' ')) { 5215 return false; 5216 } 5217 } 5218 return true; 5219 } 5220 5221 /** 5222 * <p>Checks if the CharSequence contains only Unicode letters or digits.</p> 5223 * 5224 * <p>{@code null} will return {@code false}. 5225 * An empty CharSequence (length()=0) will return {@code false}.</p> 5226 * 5227 * <pre> 5228 * StringUtils.isAlphanumeric(null) = false 5229 * StringUtils.isAlphanumeric("") = false 5230 * StringUtils.isAlphanumeric(" ") = false 5231 * StringUtils.isAlphanumeric("abc") = true 5232 * StringUtils.isAlphanumeric("ab c") = false 5233 * StringUtils.isAlphanumeric("ab2c") = true 5234 * StringUtils.isAlphanumeric("ab-c") = false 5235 * </pre> 5236 * 5237 * @param cs the CharSequence to check, may be null 5238 * @return {@code true} if only contains letters or digits, 5239 * and is non-null 5240 * @since 3.0 Changed signature from isAlphanumeric(String) to isAlphanumeric(CharSequence) 5241 * @since 3.0 Changed "" to return false and not true 5242 */ 5243 public static boolean isAlphanumeric(CharSequence cs) { 5244 if (cs == null || cs.length() == 0) { 5245 return false; 5246 } 5247 int sz = cs.length(); 5248 for (int i = 0; i < sz; i++) { 5249 if (Character.isLetterOrDigit(cs.charAt(i)) == false) { 5250 return false; 5251 } 5252 } 5253 return true; 5254 } 5255 5256 /** 5257 * <p>Checks if the CharSequence contains only Unicode letters, digits 5258 * or space ({@code ' '}).</p> 5259 * 5260 * <p>{@code null} will return {@code false}. 5261 * An empty CharSequence (length()=0) will return {@code true}.</p> 5262 * 5263 * <pre> 5264 * StringUtils.isAlphanumericSpace(null) = false 5265 * StringUtils.isAlphanumericSpace("") = true 5266 * StringUtils.isAlphanumericSpace(" ") = true 5267 * StringUtils.isAlphanumericSpace("abc") = true 5268 * StringUtils.isAlphanumericSpace("ab c") = true 5269 * StringUtils.isAlphanumericSpace("ab2c") = true 5270 * StringUtils.isAlphanumericSpace("ab-c") = false 5271 * </pre> 5272 * 5273 * @param cs the CharSequence to check, may be null 5274 * @return {@code true} if only contains letters, digits or space, 5275 * and is non-null 5276 * @since 3.0 Changed signature from isAlphanumericSpace(String) to isAlphanumericSpace(CharSequence) 5277 */ 5278 public static boolean isAlphanumericSpace(CharSequence cs) { 5279 if (cs == null) { 5280 return false; 5281 } 5282 int sz = cs.length(); 5283 for (int i = 0; i < sz; i++) { 5284 if ((Character.isLetterOrDigit(cs.charAt(i)) == false) && (cs.charAt(i) != ' ')) { 5285 return false; 5286 } 5287 } 5288 return true; 5289 } 5290 5291 /** 5292 * <p>Checks if the CharSequence contains only ASCII printable characters.</p> 5293 * 5294 * <p>{@code null} will return {@code false}. 5295 * An empty CharSequence (length()=0) will return {@code true}.</p> 5296 * 5297 * <pre> 5298 * StringUtils.isAsciiPrintable(null) = false 5299 * StringUtils.isAsciiPrintable("") = true 5300 * StringUtils.isAsciiPrintable(" ") = true 5301 * StringUtils.isAsciiPrintable("Ceki") = true 5302 * StringUtils.isAsciiPrintable("ab2c") = true 5303 * StringUtils.isAsciiPrintable("!ab-c~") = true 5304 * StringUtils.isAsciiPrintable("\u0020") = true 5305 * StringUtils.isAsciiPrintable("\u0021") = true 5306 * StringUtils.isAsciiPrintable("\u007e") = true 5307 * StringUtils.isAsciiPrintable("\u007f") = false 5308 * StringUtils.isAsciiPrintable("Ceki G\u00fclc\u00fc") = false 5309 * </pre> 5310 * 5311 * @param cs the CharSequence to check, may be null 5312 * @return {@code true} if every character is in the range 5313 * 32 thru 126 5314 * @since 2.1 5315 * @since 3.0 Changed signature from isAsciiPrintable(String) to isAsciiPrintable(CharSequence) 5316 */ 5317 public static boolean isAsciiPrintable(CharSequence cs) { 5318 if (cs == null) { 5319 return false; 5320 } 5321 int sz = cs.length(); 5322 for (int i = 0; i < sz; i++) { 5323 if (CharUtils.isAsciiPrintable(cs.charAt(i)) == false) { 5324 return false; 5325 } 5326 } 5327 return true; 5328 } 5329 5330 /** 5331 * <p>Checks if the CharSequence contains only Unicode digits. 5332 * A decimal point is not a Unicode digit and returns false.</p> 5333 * 5334 * <p>{@code null} will return {@code false}. 5335 * An empty CharSequence (length()=0) will return {@code false}.</p> 5336 * 5337 * <pre> 5338 * StringUtils.isNumeric(null) = false 5339 * StringUtils.isNumeric("") = false 5340 * StringUtils.isNumeric(" ") = false 5341 * StringUtils.isNumeric("123") = true 5342 * StringUtils.isNumeric("12 3") = false 5343 * StringUtils.isNumeric("ab2c") = false 5344 * StringUtils.isNumeric("12-3") = false 5345 * StringUtils.isNumeric("12.3") = false 5346 * </pre> 5347 * 5348 * @param cs the CharSequence to check, may be null 5349 * @return {@code true} if only contains digits, and is non-null 5350 * @since 3.0 Changed signature from isNumeric(String) to isNumeric(CharSequence) 5351 * @since 3.0 Changed "" to return false and not true 5352 */ 5353 public static boolean isNumeric(CharSequence cs) { 5354 if (cs == null || cs.length() == 0) { 5355 return false; 5356 } 5357 int sz = cs.length(); 5358 for (int i = 0; i < sz; i++) { 5359 if (Character.isDigit(cs.charAt(i)) == false) { 5360 return false; 5361 } 5362 } 5363 return true; 5364 } 5365 5366 /** 5367 * <p>Checks if the CharSequence contains only Unicode digits or space 5368 * ({@code ' '}). 5369 * A decimal point is not a Unicode digit and returns false.</p> 5370 * 5371 * <p>{@code null} will return {@code false}. 5372 * An empty CharSequence (length()=0) will return {@code true}.</p> 5373 * 5374 * <pre> 5375 * StringUtils.isNumericSpace(null) = false 5376 * StringUtils.isNumericSpace("") = true 5377 * StringUtils.isNumericSpace(" ") = true 5378 * StringUtils.isNumericSpace("123") = true 5379 * StringUtils.isNumericSpace("12 3") = true 5380 * StringUtils.isNumericSpace("ab2c") = false 5381 * StringUtils.isNumericSpace("12-3") = false 5382 * StringUtils.isNumericSpace("12.3") = false 5383 * </pre> 5384 * 5385 * @param cs the CharSequence to check, may be null 5386 * @return {@code true} if only contains digits or space, 5387 * and is non-null 5388 * @since 3.0 Changed signature from isNumericSpace(String) to isNumericSpace(CharSequence) 5389 */ 5390 public static boolean isNumericSpace(CharSequence cs) { 5391 if (cs == null) { 5392 return false; 5393 } 5394 int sz = cs.length(); 5395 for (int i = 0; i < sz; i++) { 5396 if ((Character.isDigit(cs.charAt(i)) == false) && (cs.charAt(i) != ' ')) { 5397 return false; 5398 } 5399 } 5400 return true; 5401 } 5402 5403 /** 5404 * <p>Checks if the CharSequence contains only whitespace.</p> 5405 * 5406 * <p>{@code null} will return {@code false}. 5407 * An empty CharSequence (length()=0) will return {@code true}.</p> 5408 * 5409 * <pre> 5410 * StringUtils.isWhitespace(null) = false 5411 * StringUtils.isWhitespace("") = true 5412 * StringUtils.isWhitespace(" ") = true 5413 * StringUtils.isWhitespace("abc") = false 5414 * StringUtils.isWhitespace("ab2c") = false 5415 * StringUtils.isWhitespace("ab-c") = false 5416 * </pre> 5417 * 5418 * @param cs the CharSequence to check, may be null 5419 * @return {@code true} if only contains whitespace, and is non-null 5420 * @since 2.0 5421 * @since 3.0 Changed signature from isWhitespace(String) to isWhitespace(CharSequence) 5422 */ 5423 public static boolean isWhitespace(CharSequence cs) { 5424 if (cs == null) { 5425 return false; 5426 } 5427 int sz = cs.length(); 5428 for (int i = 0; i < sz; i++) { 5429 if ((Character.isWhitespace(cs.charAt(i)) == false)) { 5430 return false; 5431 } 5432 } 5433 return true; 5434 } 5435 5436 /** 5437 * <p>Checks if the CharSequence contains only lowercase characters.</p> 5438 * 5439 * <p>{@code null} will return {@code false}. 5440 * An empty CharSequence (length()=0) will return {@code false}.</p> 5441 * 5442 * <pre> 5443 * StringUtils.isAllLowerCase(null) = false 5444 * StringUtils.isAllLowerCase("") = false 5445 * StringUtils.isAllLowerCase(" ") = false 5446 * StringUtils.isAllLowerCase("abc") = true 5447 * StringUtils.isAllLowerCase("abC") = false 5448 * </pre> 5449 * 5450 * @param cs the CharSequence to check, may be null 5451 * @return {@code true} if only contains lowercase characters, and is non-null 5452 * @since 2.5 5453 * @since 3.0 Changed signature from isAllLowerCase(String) to isAllLowerCase(CharSequence) 5454 */ 5455 public static boolean isAllLowerCase(CharSequence cs) { 5456 if (cs == null || isEmpty(cs)) { 5457 return false; 5458 } 5459 int sz = cs.length(); 5460 for (int i = 0; i < sz; i++) { 5461 if (Character.isLowerCase(cs.charAt(i)) == false) { 5462 return false; 5463 } 5464 } 5465 return true; 5466 } 5467 5468 /** 5469 * <p>Checks if the CharSequence contains only uppercase characters.</p> 5470 * 5471 * <p>{@code null} will return {@code false}. 5472 * An empty String (length()=0) will return {@code false}.</p> 5473 * 5474 * <pre> 5475 * StringUtils.isAllUpperCase(null) = false 5476 * StringUtils.isAllUpperCase("") = false 5477 * StringUtils.isAllUpperCase(" ") = false 5478 * StringUtils.isAllUpperCase("ABC") = true 5479 * StringUtils.isAllUpperCase("aBC") = false 5480 * </pre> 5481 * 5482 * @param cs the CharSequence to check, may be null 5483 * @return {@code true} if only contains uppercase characters, and is non-null 5484 * @since 2.5 5485 * @since 3.0 Changed signature from isAllUpperCase(String) to isAllUpperCase(CharSequence) 5486 */ 5487 public static boolean isAllUpperCase(CharSequence cs) { 5488 if (cs == null || isEmpty(cs)) { 5489 return false; 5490 } 5491 int sz = cs.length(); 5492 for (int i = 0; i < sz; i++) { 5493 if (Character.isUpperCase(cs.charAt(i)) == false) { 5494 return false; 5495 } 5496 } 5497 return true; 5498 } 5499 5500 // Defaults 5501 //----------------------------------------------------------------------- 5502 /** 5503 * <p>Returns either the passed in String, 5504 * or if the String is {@code null}, an empty String ("").</p> 5505 * 5506 * <pre> 5507 * StringUtils.defaultString(null) = "" 5508 * StringUtils.defaultString("") = "" 5509 * StringUtils.defaultString("bat") = "bat" 5510 * </pre> 5511 * 5512 * @see ObjectUtils#toString(Object) 5513 * @see String#valueOf(Object) 5514 * @param str the String to check, may be null 5515 * @return the passed in String, or the empty String if it 5516 * was {@code null} 5517 */ 5518 public static String defaultString(String str) { 5519 return str == null ? EMPTY : str; 5520 } 5521 5522 /** 5523 * <p>Returns either the passed in String, or if the String is 5524 * {@code null}, the value of {@code defaultStr}.</p> 5525 * 5526 * <pre> 5527 * StringUtils.defaultString(null, "NULL") = "NULL" 5528 * StringUtils.defaultString("", "NULL") = "" 5529 * StringUtils.defaultString("bat", "NULL") = "bat" 5530 * </pre> 5531 * 5532 * @see ObjectUtils#toString(Object,String) 5533 * @see String#valueOf(Object) 5534 * @param str the String to check, may be null 5535 * @param defaultStr the default String to return 5536 * if the input is {@code null}, may be null 5537 * @return the passed in String, or the default if it was {@code null} 5538 */ 5539 public static String defaultString(String str, String defaultStr) { 5540 return str == null ? defaultStr : str; 5541 } 5542 5543 /** 5544 * <p>Returns either the passed in CharSequence, or if the CharSequence is 5545 * whitespace, empty ("") or {@code null}, the value of {@code defaultStr}.</p> 5546 * 5547 * <pre> 5548 * StringUtils.defaultIfBlank(null, "NULL") = "NULL" 5549 * StringUtils.defaultIfBlank("", "NULL") = "NULL" 5550 * StringUtils.defaultIfBlank(" ", "NULL") = "NULL" 5551 * StringUtils.defaultIfBlank("bat", "NULL") = "bat" 5552 * StringUtils.defaultIfBlank("", null) = null 5553 * </pre> 5554 * @param <T> the specific kind of CharSequence 5555 * @param str the CharSequence to check, may be null 5556 * @param defaultStr the default CharSequence to return 5557 * if the input is whitespace, empty ("") or {@code null}, may be null 5558 * @return the passed in CharSequence, or the default 5559 * @see StringUtils#defaultString(String, String) 5560 */ 5561 public static <T extends CharSequence> T defaultIfBlank(T str, T defaultStr) { 5562 return StringUtils.isBlank(str) ? defaultStr : str; 5563 } 5564 5565 /** 5566 * <p>Returns either the passed in CharSequence, or if the CharSequence is 5567 * empty or {@code null}, the value of {@code defaultStr}.</p> 5568 * 5569 * <pre> 5570 * StringUtils.defaultIfEmpty(null, "NULL") = "NULL" 5571 * StringUtils.defaultIfEmpty("", "NULL") = "NULL" 5572 * StringUtils.defaultIfEmpty("bat", "NULL") = "bat" 5573 * StringUtils.defaultIfEmpty("", null) = null 5574 * </pre> 5575 * @param <T> the specific kind of CharSequence 5576 * @param str the CharSequence to check, may be null 5577 * @param defaultStr the default CharSequence to return 5578 * if the input is empty ("") or {@code null}, may be null 5579 * @return the passed in CharSequence, or the default 5580 * @see StringUtils#defaultString(String, String) 5581 */ 5582 public static <T extends CharSequence> T defaultIfEmpty(T str, T defaultStr) { 5583 return StringUtils.isEmpty(str) ? defaultStr : str; 5584 } 5585 5586 // Reversing 5587 //----------------------------------------------------------------------- 5588 /** 5589 * <p>Reverses a String as per {@link StringBuilder#reverse()}.</p> 5590 * 5591 * <p>A {@code null} String returns {@code null}.</p> 5592 * 5593 * <pre> 5594 * StringUtils.reverse(null) = null 5595 * StringUtils.reverse("") = "" 5596 * StringUtils.reverse("bat") = "tab" 5597 * </pre> 5598 * 5599 * @param str the String to reverse, may be null 5600 * @return the reversed String, {@code null} if null String input 5601 */ 5602 public static String reverse(String str) { 5603 if (str == null) { 5604 return null; 5605 } 5606 return new StringBuilder(str).reverse().toString(); 5607 } 5608 5609 /** 5610 * <p>Reverses a String that is delimited by a specific character.</p> 5611 * 5612 * <p>The Strings between the delimiters are not reversed. 5613 * Thus java.lang.String becomes String.lang.java (if the delimiter 5614 * is {@code '.'}).</p> 5615 * 5616 * <pre> 5617 * StringUtils.reverseDelimited(null, *) = null 5618 * StringUtils.reverseDelimited("", *) = "" 5619 * StringUtils.reverseDelimited("a.b.c", 'x') = "a.b.c" 5620 * StringUtils.reverseDelimited("a.b.c", ".") = "c.b.a" 5621 * </pre> 5622 * 5623 * @param str the String to reverse, may be null 5624 * @param separatorChar the separator character to use 5625 * @return the reversed String, {@code null} if null String input 5626 * @since 2.0 5627 */ 5628 public static String reverseDelimited(String str, char separatorChar) { 5629 if (str == null) { 5630 return null; 5631 } 5632 // could implement manually, but simple way is to reuse other, 5633 // probably slower, methods. 5634 String[] strs = split(str, separatorChar); 5635 ArrayUtils.reverse(strs); 5636 return join(strs, separatorChar); 5637 } 5638 5639 // Abbreviating 5640 //----------------------------------------------------------------------- 5641 /** 5642 * <p>Abbreviates a String using ellipses. This will turn 5643 * "Now is the time for all good men" into "Now is the time for..."</p> 5644 * 5645 * <p>Specifically: 5646 * <ul> 5647 * <li>If {@code str} is less than {@code maxWidth} characters 5648 * long, return it.</li> 5649 * <li>Else abbreviate it to {@code (substring(str, 0, max-3) + "...")}.</li> 5650 * <li>If {@code maxWidth} is less than {@code 4}, throw an 5651 * {@code IllegalArgumentException}.</li> 5652 * <li>In no case will it return a String of length greater than 5653 * {@code maxWidth}.</li> 5654 * </ul> 5655 * </p> 5656 * 5657 * <pre> 5658 * StringUtils.abbreviate(null, *) = null 5659 * StringUtils.abbreviate("", 4) = "" 5660 * StringUtils.abbreviate("abcdefg", 6) = "abc..." 5661 * StringUtils.abbreviate("abcdefg", 7) = "abcdefg" 5662 * StringUtils.abbreviate("abcdefg", 8) = "abcdefg" 5663 * StringUtils.abbreviate("abcdefg", 4) = "a..." 5664 * StringUtils.abbreviate("abcdefg", 3) = IllegalArgumentException 5665 * </pre> 5666 * 5667 * @param str the String to check, may be null 5668 * @param maxWidth maximum length of result String, must be at least 4 5669 * @return abbreviated String, {@code null} if null String input 5670 * @throws IllegalArgumentException if the width is too small 5671 * @since 2.0 5672 */ 5673 public static String abbreviate(String str, int maxWidth) { 5674 return abbreviate(str, 0, maxWidth); 5675 } 5676 5677 /** 5678 * <p>Abbreviates a String using ellipses. This will turn 5679 * "Now is the time for all good men" into "...is the time for..."</p> 5680 * 5681 * <p>Works like {@code abbreviate(String, int)}, but allows you to specify 5682 * a "left edge" offset. Note that this left edge is not necessarily going to 5683 * be the leftmost character in the result, or the first character following the 5684 * ellipses, but it will appear somewhere in the result. 5685 * 5686 * <p>In no case will it return a String of length greater than 5687 * {@code maxWidth}.</p> 5688 * 5689 * <pre> 5690 * StringUtils.abbreviate(null, *, *) = null 5691 * StringUtils.abbreviate("", 0, 4) = "" 5692 * StringUtils.abbreviate("abcdefghijklmno", -1, 10) = "abcdefg..." 5693 * StringUtils.abbreviate("abcdefghijklmno", 0, 10) = "abcdefg..." 5694 * StringUtils.abbreviate("abcdefghijklmno", 1, 10) = "abcdefg..." 5695 * StringUtils.abbreviate("abcdefghijklmno", 4, 10) = "abcdefg..." 5696 * StringUtils.abbreviate("abcdefghijklmno", 5, 10) = "...fghi..." 5697 * StringUtils.abbreviate("abcdefghijklmno", 6, 10) = "...ghij..." 5698 * StringUtils.abbreviate("abcdefghijklmno", 8, 10) = "...ijklmno" 5699 * StringUtils.abbreviate("abcdefghijklmno", 10, 10) = "...ijklmno" 5700 * StringUtils.abbreviate("abcdefghijklmno", 12, 10) = "...ijklmno" 5701 * StringUtils.abbreviate("abcdefghij", 0, 3) = IllegalArgumentException 5702 * StringUtils.abbreviate("abcdefghij", 5, 6) = IllegalArgumentException 5703 * </pre> 5704 * 5705 * @param str the String to check, may be null 5706 * @param offset left edge of source String 5707 * @param maxWidth maximum length of result String, must be at least 4 5708 * @return abbreviated String, {@code null} if null String input 5709 * @throws IllegalArgumentException if the width is too small 5710 * @since 2.0 5711 */ 5712 public static String abbreviate(String str, int offset, int maxWidth) { 5713 if (str == null) { 5714 return null; 5715 } 5716 if (maxWidth < 4) { 5717 throw new IllegalArgumentException("Minimum abbreviation width is 4"); 5718 } 5719 if (str.length() <= maxWidth) { 5720 return str; 5721 } 5722 if (offset > str.length()) { 5723 offset = str.length(); 5724 } 5725 if ((str.length() - offset) < (maxWidth - 3)) { 5726 offset = str.length() - (maxWidth - 3); 5727 } 5728 final String abrevMarker = "..."; 5729 if (offset <= 4) { 5730 return str.substring(0, maxWidth - 3) + abrevMarker; 5731 } 5732 if (maxWidth < 7) { 5733 throw new IllegalArgumentException("Minimum abbreviation width with offset is 7"); 5734 } 5735 if ((offset + (maxWidth - 3)) < str.length()) { 5736 return abrevMarker + abbreviate(str.substring(offset), maxWidth - 3); 5737 } 5738 return abrevMarker + str.substring(str.length() - (maxWidth - 3)); 5739 } 5740 5741 /** 5742 * <p>Abbreviates a String to the length passed, replacing the middle characters with the supplied 5743 * replacement String.</p> 5744 * 5745 * <p>This abbreviation only occurs if the following criteria is met: 5746 * <ul> 5747 * <li>Neither the String for abbreviation nor the replacement String are null or empty </li> 5748 * <li>The length to truncate to is less than the length of the supplied String</li> 5749 * <li>The length to truncate to is greater than 0</li> 5750 * <li>The abbreviated String will have enough room for the length supplied replacement String 5751 * and the first and last characters of the supplied String for abbreviation</li> 5752 * </ul> 5753 * Otherwise, the returned String will be the same as the supplied String for abbreviation. 5754 * </p> 5755 * 5756 * <pre> 5757 * StringUtils.abbreviateMiddle(null, null, 0) = null 5758 * StringUtils.abbreviateMiddle("abc", null, 0) = "abc" 5759 * StringUtils.abbreviateMiddle("abc", ".", 0) = "abc" 5760 * StringUtils.abbreviateMiddle("abc", ".", 3) = "abc" 5761 * StringUtils.abbreviateMiddle("abcdef", ".", 4) = "ab.f" 5762 * </pre> 5763 * 5764 * @param str the String to abbreviate, may be null 5765 * @param middle the String to replace the middle characters with, may be null 5766 * @param length the length to abbreviate {@code str} to. 5767 * @return the abbreviated String if the above criteria is met, or the original String supplied for abbreviation. 5768 * @since 2.5 5769 */ 5770 public static String abbreviateMiddle(String str, String middle, int length) { 5771 if (isEmpty(str) || isEmpty(middle)) { 5772 return str; 5773 } 5774 5775 if (length >= str.length() || length < (middle.length()+2)) { 5776 return str; 5777 } 5778 5779 int targetSting = length-middle.length(); 5780 int startOffset = targetSting/2+targetSting%2; 5781 int endOffset = str.length()-targetSting/2; 5782 5783 StringBuilder builder = new StringBuilder(length); 5784 builder.append(str.substring(0,startOffset)); 5785 builder.append(middle); 5786 builder.append(str.substring(endOffset)); 5787 5788 return builder.toString(); 5789 } 5790 5791 // Difference 5792 //----------------------------------------------------------------------- 5793 /** 5794 * <p>Compares two Strings, and returns the portion where they differ. 5795 * (More precisely, return the remainder of the second String, 5796 * starting from where it's different from the first.)</p> 5797 * 5798 * <p>For example, 5799 * {@code difference("i am a machine", "i am a robot") -> "robot"}.</p> 5800 * 5801 * <pre> 5802 * StringUtils.difference(null, null) = null 5803 * StringUtils.difference("", "") = "" 5804 * StringUtils.difference("", "abc") = "abc" 5805 * StringUtils.difference("abc", "") = "" 5806 * StringUtils.difference("abc", "abc") = "" 5807 * StringUtils.difference("ab", "abxyz") = "xyz" 5808 * StringUtils.difference("abcde", "abxyz") = "xyz" 5809 * StringUtils.difference("abcde", "xyz") = "xyz" 5810 * </pre> 5811 * 5812 * @param str1 the first String, may be null 5813 * @param str2 the second String, may be null 5814 * @return the portion of str2 where it differs from str1; returns the 5815 * empty String if they are equal 5816 * @since 2.0 5817 */ 5818 public static String difference(String str1, String str2) { 5819 if (str1 == null) { 5820 return str2; 5821 } 5822 if (str2 == null) { 5823 return str1; 5824 } 5825 int at = indexOfDifference(str1, str2); 5826 if (at == INDEX_NOT_FOUND) { 5827 return EMPTY; 5828 } 5829 return str2.substring(at); 5830 } 5831 5832 /** 5833 * <p>Compares two CharSequences, and returns the index at which the 5834 * CharSequences begin to differ.</p> 5835 * 5836 * <p>For example, 5837 * {@code indexOfDifference("i am a machine", "i am a robot") -> 7}</p> 5838 * 5839 * <pre> 5840 * StringUtils.indexOfDifference(null, null) = -1 5841 * StringUtils.indexOfDifference("", "") = -1 5842 * StringUtils.indexOfDifference("", "abc") = 0 5843 * StringUtils.indexOfDifference("abc", "") = 0 5844 * StringUtils.indexOfDifference("abc", "abc") = -1 5845 * StringUtils.indexOfDifference("ab", "abxyz") = 2 5846 * StringUtils.indexOfDifference("abcde", "abxyz") = 2 5847 * StringUtils.indexOfDifference("abcde", "xyz") = 0 5848 * </pre> 5849 * 5850 * @param cs1 the first CharSequence, may be null 5851 * @param cs2 the second CharSequence, may be null 5852 * @return the index where cs1 and cs2 begin to differ; -1 if they are equal 5853 * @since 2.0 5854 * @since 3.0 Changed signature from indexOfDifference(String, String) to 5855 * indexOfDifference(CharSequence, CharSequence) 5856 */ 5857 public static int indexOfDifference(CharSequence cs1, CharSequence cs2) { 5858 if (cs1 == cs2) { 5859 return INDEX_NOT_FOUND; 5860 } 5861 if (cs1 == null || cs2 == null) { 5862 return 0; 5863 } 5864 int i; 5865 for (i = 0; i < cs1.length() && i < cs2.length(); ++i) { 5866 if (cs1.charAt(i) != cs2.charAt(i)) { 5867 break; 5868 } 5869 } 5870 if (i < cs2.length() || i < cs1.length()) { 5871 return i; 5872 } 5873 return INDEX_NOT_FOUND; 5874 } 5875 5876 /** 5877 * <p>Compares all CharSequences in an array and returns the index at which the 5878 * CharSequences begin to differ.</p> 5879 * 5880 * <p>For example, 5881 * <code>indexOfDifference(new String[] {"i am a machine", "i am a robot"}) -> 7</code></p> 5882 * 5883 * <pre> 5884 * StringUtils.indexOfDifference(null) = -1 5885 * StringUtils.indexOfDifference(new String[] {}) = -1 5886 * StringUtils.indexOfDifference(new String[] {"abc"}) = -1 5887 * StringUtils.indexOfDifference(new String[] {null, null}) = -1 5888 * StringUtils.indexOfDifference(new String[] {"", ""}) = -1 5889 * StringUtils.indexOfDifference(new String[] {"", null}) = 0 5890 * StringUtils.indexOfDifference(new String[] {"abc", null, null}) = 0 5891 * StringUtils.indexOfDifference(new String[] {null, null, "abc"}) = 0 5892 * StringUtils.indexOfDifference(new String[] {"", "abc"}) = 0 5893 * StringUtils.indexOfDifference(new String[] {"abc", ""}) = 0 5894 * StringUtils.indexOfDifference(new String[] {"abc", "abc"}) = -1 5895 * StringUtils.indexOfDifference(new String[] {"abc", "a"}) = 1 5896 * StringUtils.indexOfDifference(new String[] {"ab", "abxyz"}) = 2 5897 * StringUtils.indexOfDifference(new String[] {"abcde", "abxyz"}) = 2 5898 * StringUtils.indexOfDifference(new String[] {"abcde", "xyz"}) = 0 5899 * StringUtils.indexOfDifference(new String[] {"xyz", "abcde"}) = 0 5900 * StringUtils.indexOfDifference(new String[] {"i am a machine", "i am a robot"}) = 7 5901 * </pre> 5902 * 5903 * @param css array of CharSequences, entries may be null 5904 * @return the index where the strings begin to differ; -1 if they are all equal 5905 * @since 2.4 5906 * @since 3.0 Changed signature from indexOfDifference(String...) to indexOfDifference(CharSequence...) 5907 */ 5908 public static int indexOfDifference(CharSequence... css) { 5909 if (css == null || css.length <= 1) { 5910 return INDEX_NOT_FOUND; 5911 } 5912 boolean anyStringNull = false; 5913 boolean allStringsNull = true; 5914 int arrayLen = css.length; 5915 int shortestStrLen = Integer.MAX_VALUE; 5916 int longestStrLen = 0; 5917 5918 // find the min and max string lengths; this avoids checking to make 5919 // sure we are not exceeding the length of the string each time through 5920 // the bottom loop. 5921 for (int i = 0; i < arrayLen; i++) { 5922 if (css[i] == null) { 5923 anyStringNull = true; 5924 shortestStrLen = 0; 5925 } else { 5926 allStringsNull = false; 5927 shortestStrLen = Math.min(css[i].length(), shortestStrLen); 5928 longestStrLen = Math.max(css[i].length(), longestStrLen); 5929 } 5930 } 5931 5932 // handle lists containing all nulls or all empty strings 5933 if (allStringsNull || (longestStrLen == 0 && !anyStringNull)) { 5934 return INDEX_NOT_FOUND; 5935 } 5936 5937 // handle lists containing some nulls or some empty strings 5938 if (shortestStrLen == 0) { 5939 return 0; 5940 } 5941 5942 // find the position with the first difference across all strings 5943 int firstDiff = -1; 5944 for (int stringPos = 0; stringPos < shortestStrLen; stringPos++) { 5945 char comparisonChar = css[0].charAt(stringPos); 5946 for (int arrayPos = 1; arrayPos < arrayLen; arrayPos++) { 5947 if (css[arrayPos].charAt(stringPos) != comparisonChar) { 5948 firstDiff = stringPos; 5949 break; 5950 } 5951 } 5952 if (firstDiff != -1) { 5953 break; 5954 } 5955 } 5956 5957 if (firstDiff == -1 && shortestStrLen != longestStrLen) { 5958 // we compared all of the characters up to the length of the 5959 // shortest string and didn't find a match, but the string lengths 5960 // vary, so return the length of the shortest string. 5961 return shortestStrLen; 5962 } 5963 return firstDiff; 5964 } 5965 5966 /** 5967 * <p>Compares all Strings in an array and returns the initial sequence of 5968 * characters that is common to all of them.</p> 5969 * 5970 * <p>For example, 5971 * <code>getCommonPrefix(new String[] {"i am a machine", "i am a robot"}) -> "i am a "</code></p> 5972 * 5973 * <pre> 5974 * StringUtils.getCommonPrefix(null) = "" 5975 * StringUtils.getCommonPrefix(new String[] {}) = "" 5976 * StringUtils.getCommonPrefix(new String[] {"abc"}) = "abc" 5977 * StringUtils.getCommonPrefix(new String[] {null, null}) = "" 5978 * StringUtils.getCommonPrefix(new String[] {"", ""}) = "" 5979 * StringUtils.getCommonPrefix(new String[] {"", null}) = "" 5980 * StringUtils.getCommonPrefix(new String[] {"abc", null, null}) = "" 5981 * StringUtils.getCommonPrefix(new String[] {null, null, "abc"}) = "" 5982 * StringUtils.getCommonPrefix(new String[] {"", "abc"}) = "" 5983 * StringUtils.getCommonPrefix(new String[] {"abc", ""}) = "" 5984 * StringUtils.getCommonPrefix(new String[] {"abc", "abc"}) = "abc" 5985 * StringUtils.getCommonPrefix(new String[] {"abc", "a"}) = "a" 5986 * StringUtils.getCommonPrefix(new String[] {"ab", "abxyz"}) = "ab" 5987 * StringUtils.getCommonPrefix(new String[] {"abcde", "abxyz"}) = "ab" 5988 * StringUtils.getCommonPrefix(new String[] {"abcde", "xyz"}) = "" 5989 * StringUtils.getCommonPrefix(new String[] {"xyz", "abcde"}) = "" 5990 * StringUtils.getCommonPrefix(new String[] {"i am a machine", "i am a robot"}) = "i am a " 5991 * </pre> 5992 * 5993 * @param strs array of String objects, entries may be null 5994 * @return the initial sequence of characters that are common to all Strings 5995 * in the array; empty String if the array is null, the elements are all null 5996 * or if there is no common prefix. 5997 * @since 2.4 5998 */ 5999 public static String getCommonPrefix(String... strs) { 6000 if (strs == null || strs.length == 0) { 6001 return EMPTY; 6002 } 6003 int smallestIndexOfDiff = indexOfDifference(strs); 6004 if (smallestIndexOfDiff == INDEX_NOT_FOUND) { 6005 // all strings were identical 6006 if (strs[0] == null) { 6007 return EMPTY; 6008 } 6009 return strs[0]; 6010 } else if (smallestIndexOfDiff == 0) { 6011 // there were no common initial characters 6012 return EMPTY; 6013 } else { 6014 // we found a common initial character sequence 6015 return strs[0].substring(0, smallestIndexOfDiff); 6016 } 6017 } 6018 6019 // Misc 6020 //----------------------------------------------------------------------- 6021 /** 6022 * <p>Find the Levenshtein distance between two Strings.</p> 6023 * 6024 * <p>This is the number of changes needed to change one String into 6025 * another, where each change is a single character modification (deletion, 6026 * insertion or substitution).</p> 6027 * 6028 * <p>The previous implementation of the Levenshtein distance algorithm 6029 * was from <a href="http://www.merriampark.com/ld.htm">http://www.merriampark.com/ld.htm</a></p> 6030 * 6031 * <p>Chas Emerick has written an implementation in Java, which avoids an OutOfMemoryError 6032 * which can occur when my Java implementation is used with very large strings.<br> 6033 * This implementation of the Levenshtein distance algorithm 6034 * is from <a href="http://www.merriampark.com/ldjava.htm">http://www.merriampark.com/ldjava.htm</a></p> 6035 * 6036 * <pre> 6037 * StringUtils.getLevenshteinDistance(null, *) = IllegalArgumentException 6038 * StringUtils.getLevenshteinDistance(*, null) = IllegalArgumentException 6039 * StringUtils.getLevenshteinDistance("","") = 0 6040 * StringUtils.getLevenshteinDistance("","a") = 1 6041 * StringUtils.getLevenshteinDistance("aaapppp", "") = 7 6042 * StringUtils.getLevenshteinDistance("frog", "fog") = 1 6043 * StringUtils.getLevenshteinDistance("fly", "ant") = 3 6044 * StringUtils.getLevenshteinDistance("elephant", "hippo") = 7 6045 * StringUtils.getLevenshteinDistance("hippo", "elephant") = 7 6046 * StringUtils.getLevenshteinDistance("hippo", "zzzzzzzz") = 8 6047 * StringUtils.getLevenshteinDistance("hello", "hallo") = 1 6048 * </pre> 6049 * 6050 * @param s the first String, must not be null 6051 * @param t the second String, must not be null 6052 * @return result distance 6053 * @throws IllegalArgumentException if either String input {@code null} 6054 * @since 3.0 Changed signature from getLevenshteinDistance(String, String) to 6055 * getLevenshteinDistance(CharSequence, CharSequence) 6056 */ 6057 public static int getLevenshteinDistance(CharSequence s, CharSequence t) { 6058 if (s == null || t == null) { 6059 throw new IllegalArgumentException("Strings must not be null"); 6060 } 6061 6062 /* 6063 The difference between this impl. and the previous is that, rather 6064 than creating and retaining a matrix of size s.length() + 1 by t.length() + 1, 6065 we maintain two single-dimensional arrays of length s.length() + 1. The first, d, 6066 is the 'current working' distance array that maintains the newest distance cost 6067 counts as we iterate through the characters of String s. Each time we increment 6068 the index of String t we are comparing, d is copied to p, the second int[]. Doing so 6069 allows us to retain the previous cost counts as required by the algorithm (taking 6070 the minimum of the cost count to the left, up one, and diagonally up and to the left 6071 of the current cost count being calculated). (Note that the arrays aren't really 6072 copied anymore, just switched...this is clearly much better than cloning an array 6073 or doing a System.arraycopy() each time through the outer loop.) 6074 6075 Effectively, the difference between the two implementations is this one does not 6076 cause an out of memory condition when calculating the LD over two very large strings. 6077 */ 6078 6079 int n = s.length(); // length of s 6080 int m = t.length(); // length of t 6081 6082 if (n == 0) { 6083 return m; 6084 } else if (m == 0) { 6085 return n; 6086 } 6087 6088 if (n > m) { 6089 // swap the input strings to consume less memory 6090 CharSequence tmp = s; 6091 s = t; 6092 t = tmp; 6093 n = m; 6094 m = t.length(); 6095 } 6096 6097 int p[] = new int[n + 1]; //'previous' cost array, horizontally 6098 int d[] = new int[n + 1]; // cost array, horizontally 6099 int _d[]; //placeholder to assist in swapping p and d 6100 6101 // indexes into strings s and t 6102 int i; // iterates through s 6103 int j; // iterates through t 6104 6105 char t_j; // jth character of t 6106 6107 int cost; // cost 6108 6109 for (i = 0; i <= n; i++) { 6110 p[i] = i; 6111 } 6112 6113 for (j = 1; j <= m; j++) { 6114 t_j = t.charAt(j - 1); 6115 d[0] = j; 6116 6117 for (i = 1; i <= n; i++) { 6118 cost = s.charAt(i - 1) == t_j ? 0 : 1; 6119 // minimum of cell to the left+1, to the top+1, diagonally left and up +cost 6120 d[i] = Math.min(Math.min(d[i - 1] + 1, p[i] + 1), p[i - 1] + cost); 6121 } 6122 6123 // copy current distance counts to 'previous row' distance counts 6124 _d = p; 6125 p = d; 6126 d = _d; 6127 } 6128 6129 // our last action in the above loop was to switch d and p, so p now 6130 // actually has the most recent cost counts 6131 return p[n]; 6132 } 6133 6134 /** 6135 * <p>Find the Levenshtein distance between two Strings if it's less than or equal to a given 6136 * threshold.</p> 6137 * 6138 * <p>This is the number of changes needed to change one String into 6139 * another, where each change is a single character modification (deletion, 6140 * insertion or substitution).</p> 6141 * 6142 * <p>This implementation follows from Algorithms on Strings, Trees and Sequences by Dan Gusfield 6143 * and Chas Emerick's implementation of the Levenshtein distance algorithm from 6144 * <a href="http://www.merriampark.com/ld.htm">http://www.merriampark.com/ld.htm</a></p> 6145 * 6146 * <pre> 6147 * StringUtils.getLevenshteinDistance(null, *, *) = IllegalArgumentException 6148 * StringUtils.getLevenshteinDistance(*, null, *) = IllegalArgumentException 6149 * StringUtils.getLevenshteinDistance(*, *, -1) = IllegalArgumentException 6150 * StringUtils.getLevenshteinDistance("","", 0) = 0 6151 * StringUtils.getLevenshteinDistance("aaapppp", "", 8) = 7 6152 * StringUtils.getLevenshteinDistance("aaapppp", "", 7) = 7 6153 * StringUtils.getLevenshteinDistance("aaapppp", "", 6)) = -1 6154 * StringUtils.getLevenshteinDistance("elephant", "hippo", 7) = 7 6155 * StringUtils.getLevenshteinDistance("elephant", "hippo", 6) = -1 6156 * StringUtils.getLevenshteinDistance("hippo", "elephant", 7) = 7 6157 * StringUtils.getLevenshteinDistance("hippo", "elephant", 6) = -1 6158 * </pre> 6159 * 6160 * @param s the first String, must not be null 6161 * @param t the second String, must not be null 6162 * @param threshold the target threshold, must not be negative 6163 * @return result distance, or {@code -1} if the distance would be greater than the threshold 6164 * @throws IllegalArgumentException if either String input {@code null} or negative threshold 6165 */ 6166 public static int getLevenshteinDistance(CharSequence s, CharSequence t, int threshold) { 6167 if (s == null || t == null) { 6168 throw new IllegalArgumentException("Strings must not be null"); 6169 } 6170 if (threshold < 0) { 6171 throw new IllegalArgumentException("Threshold must not be negative"); 6172 } 6173 6174 /* 6175 This implementation only computes the distance if it's less than or equal to the 6176 threshold value, returning -1 if it's greater. The advantage is performance: unbounded 6177 distance is O(nm), but a bound of k allows us to reduce it to O(km) time by only 6178 computing a diagonal stripe of width 2k + 1 of the cost table. 6179 It is also possible to use this to compute the unbounded Levenshtein distance by starting 6180 the threshold at 1 and doubling each time until the distance is found; this is O(dm), where 6181 d is the distance. 6182 6183 One subtlety comes from needing to ignore entries on the border of our stripe 6184 eg. 6185 p[] = |#|#|#|* 6186 d[] = *|#|#|#| 6187 We must ignore the entry to the left of the leftmost member 6188 We must ignore the entry above the rightmost member 6189 6190 Another subtlety comes from our stripe running off the matrix if the strings aren't 6191 of the same size. Since string s is always swapped to be the shorter of the two, 6192 the stripe will always run off to the upper right instead of the lower left of the matrix. 6193 6194 As a concrete example, suppose s is of length 5, t is of length 7, and our threshold is 1. 6195 In this case we're going to walk a stripe of length 3. The matrix would look like so: 6196 6197 1 2 3 4 5 6198 1 |#|#| | | | 6199 2 |#|#|#| | | 6200 3 | |#|#|#| | 6201 4 | | |#|#|#| 6202 5 | | | |#|#| 6203 6 | | | | |#| 6204 7 | | | | | | 6205 6206 Note how the stripe leads off the table as there is no possible way to turn a string of length 5 6207 into one of length 7 in edit distance of 1. 6208 6209 Additionally, this implementation decreases memory usage by using two 6210 single-dimensional arrays and swapping them back and forth instead of allocating 6211 an entire n by m matrix. This requires a few minor changes, such as immediately returning 6212 when it's detected that the stripe has run off the matrix and initially filling the arrays with 6213 large values so that entries we don't compute are ignored. 6214 6215 See Algorithms on Strings, Trees and Sequences by Dan Gusfield for some discussion. 6216 */ 6217 6218 int n = s.length(); // length of s 6219 int m = t.length(); // length of t 6220 6221 // if one string is empty, the edit distance is necessarily the length of the other 6222 if (n == 0) { 6223 return m <= threshold ? m : -1; 6224 } else if (m == 0) { 6225 return n <= threshold ? n : -1; 6226 } 6227 6228 if (n > m) { 6229 // swap the two strings to consume less memory 6230 CharSequence tmp = s; 6231 s = t; 6232 t = tmp; 6233 n = m; 6234 m = t.length(); 6235 } 6236 6237 int p[] = new int[n + 1]; // 'previous' cost array, horizontally 6238 int d[] = new int[n + 1]; // cost array, horizontally 6239 int _d[]; // placeholder to assist in swapping p and d 6240 6241 // fill in starting table values 6242 int boundary = Math.min(n, threshold) + 1; 6243 for (int i = 0; i < boundary; i++) { 6244 p[i] = i; 6245 } 6246 // these fills ensure that the value above the rightmost entry of our 6247 // stripe will be ignored in following loop iterations 6248 Arrays.fill(p, boundary, p.length, Integer.MAX_VALUE); 6249 Arrays.fill(d, Integer.MAX_VALUE); 6250 6251 // iterates through t 6252 for (int j = 1; j <= m; j++) { 6253 char t_j = t.charAt(j - 1); // jth character of t 6254 d[0] = j; 6255 6256 // compute stripe indices, constrain to array size 6257 int min = Math.max(1, j - threshold); 6258 int max = Math.min(n, j + threshold); 6259 6260 // the stripe may lead off of the table if s and t are of different sizes 6261 if (min > max) { 6262 return -1; 6263 } 6264 6265 // ignore entry left of leftmost 6266 if (min > 1) { 6267 d[min - 1] = Integer.MAX_VALUE; 6268 } 6269 6270 // iterates through [min, max] in s 6271 for (int i = min; i <= max; i++) { 6272 if (s.charAt(i - 1) == t_j) { 6273 // diagonally left and up 6274 d[i] = p[i - 1]; 6275 } else { 6276 // 1 + minimum of cell to the left, to the top, diagonally left and up 6277 d[i] = 1 + Math.min(Math.min(d[i - 1], p[i]), p[i - 1]); 6278 } 6279 } 6280 6281 // copy current distance counts to 'previous row' distance counts 6282 _d = p; 6283 p = d; 6284 d = _d; 6285 } 6286 6287 // if p[n] is greater than the threshold, there's no guarantee on it being the correct 6288 // distance 6289 if (p[n] <= threshold) { 6290 return p[n]; 6291 } else { 6292 return -1; 6293 } 6294 } 6295 6296 // startsWith 6297 //----------------------------------------------------------------------- 6298 6299 /** 6300 * <p>Check if a CharSequence starts with a specified prefix.</p> 6301 * 6302 * <p>{@code null}s are handled without exceptions. Two {@code null} 6303 * references are considered to be equal. The comparison is case sensitive.</p> 6304 * 6305 * <pre> 6306 * StringUtils.startsWith(null, null) = true 6307 * StringUtils.startsWith(null, "abc") = false 6308 * StringUtils.startsWith("abcdef", null) = false 6309 * StringUtils.startsWith("abcdef", "abc") = true 6310 * StringUtils.startsWith("ABCDEF", "abc") = false 6311 * </pre> 6312 * 6313 * @see java.lang.String#startsWith(String) 6314 * @param str the CharSequence to check, may be null 6315 * @param prefix the prefix to find, may be null 6316 * @return {@code true} if the CharSequence starts with the prefix, case sensitive, or 6317 * both {@code null} 6318 * @since 2.4 6319 * @since 3.0 Changed signature from startsWith(String, String) to startsWith(CharSequence, CharSequence) 6320 */ 6321 public static boolean startsWith(CharSequence str, CharSequence prefix) { 6322 return startsWith(str, prefix, false); 6323 } 6324 6325 /** 6326 * <p>Case insensitive check if a CharSequence starts with a specified prefix.</p> 6327 * 6328 * <p>{@code null}s are handled without exceptions. Two {@code null} 6329 * references are considered to be equal. The comparison is case insensitive.</p> 6330 * 6331 * <pre> 6332 * StringUtils.startsWithIgnoreCase(null, null) = true 6333 * StringUtils.startsWithIgnoreCase(null, "abc") = false 6334 * StringUtils.startsWithIgnoreCase("abcdef", null) = false 6335 * StringUtils.startsWithIgnoreCase("abcdef", "abc") = true 6336 * StringUtils.startsWithIgnoreCase("ABCDEF", "abc") = true 6337 * </pre> 6338 * 6339 * @see java.lang.String#startsWith(String) 6340 * @param str the CharSequence to check, may be null 6341 * @param prefix the prefix to find, may be null 6342 * @return {@code true} if the CharSequence starts with the prefix, case insensitive, or 6343 * both {@code null} 6344 * @since 2.4 6345 * @since 3.0 Changed signature from startsWithIgnoreCase(String, String) to startsWithIgnoreCase(CharSequence, CharSequence) 6346 */ 6347 public static boolean startsWithIgnoreCase(CharSequence str, CharSequence prefix) { 6348 return startsWith(str, prefix, true); 6349 } 6350 6351 /** 6352 * <p>Check if a CharSequence starts with a specified prefix (optionally case insensitive).</p> 6353 * 6354 * @see java.lang.String#startsWith(String) 6355 * @param str the CharSequence to check, may be null 6356 * @param prefix the prefix to find, may be null 6357 * @param ignoreCase indicates whether the compare should ignore case 6358 * (case insensitive) or not. 6359 * @return {@code true} if the CharSequence starts with the prefix or 6360 * both {@code null} 6361 */ 6362 private static boolean startsWith(CharSequence str, CharSequence prefix, boolean ignoreCase) { 6363 if (str == null || prefix == null) { 6364 return (str == null && prefix == null); 6365 } 6366 if (prefix.length() > str.length()) { 6367 return false; 6368 } 6369 return CharSequenceUtils.regionMatches(str, ignoreCase, 0, prefix, 0, prefix.length()); 6370 } 6371 6372 /** 6373 * <p>Check if a CharSequence starts with any of an array of specified strings.</p> 6374 * 6375 * <pre> 6376 * StringUtils.startsWithAny(null, null) = false 6377 * StringUtils.startsWithAny(null, new String[] {"abc"}) = false 6378 * StringUtils.startsWithAny("abcxyz", null) = false 6379 * StringUtils.startsWithAny("abcxyz", new String[] {""}) = false 6380 * StringUtils.startsWithAny("abcxyz", new String[] {"abc"}) = true 6381 * StringUtils.startsWithAny("abcxyz", new String[] {null, "xyz", "abc"}) = true 6382 * </pre> 6383 * 6384 * @param string the CharSequence to check, may be null 6385 * @param searchStrings the CharSequences to find, may be null or empty 6386 * @return {@code true} if the CharSequence starts with any of the the prefixes, case insensitive, or 6387 * both {@code null} 6388 * @since 2.5 6389 * @since 3.0 Changed signature from startsWithAny(String, String[]) to startsWithAny(CharSequence, CharSequence...) 6390 */ 6391 public static boolean startsWithAny(CharSequence string, CharSequence... searchStrings) { 6392 if (isEmpty(string) || ArrayUtils.isEmpty(searchStrings)) { 6393 return false; 6394 } 6395 for (CharSequence searchString : searchStrings) { 6396 if (StringUtils.startsWith(string, searchString)) { 6397 return true; 6398 } 6399 } 6400 return false; 6401 } 6402 6403 // endsWith 6404 //----------------------------------------------------------------------- 6405 6406 /** 6407 * <p>Check if a CharSequence ends with a specified suffix.</p> 6408 * 6409 * <p>{@code null}s are handled without exceptions. Two {@code null} 6410 * references are considered to be equal. The comparison is case sensitive.</p> 6411 * 6412 * <pre> 6413 * StringUtils.endsWith(null, null) = true 6414 * StringUtils.endsWith(null, "def") = false 6415 * StringUtils.endsWith("abcdef", null) = false 6416 * StringUtils.endsWith("abcdef", "def") = true 6417 * StringUtils.endsWith("ABCDEF", "def") = false 6418 * StringUtils.endsWith("ABCDEF", "cde") = false 6419 * </pre> 6420 * 6421 * @see java.lang.String#endsWith(String) 6422 * @param str the CharSequence to check, may be null 6423 * @param suffix the suffix to find, may be null 6424 * @return {@code true} if the CharSequence ends with the suffix, case sensitive, or 6425 * both {@code null} 6426 * @since 2.4 6427 * @since 3.0 Changed signature from endsWith(String, String) to endsWith(CharSequence, CharSequence) 6428 */ 6429 public static boolean endsWith(CharSequence str, CharSequence suffix) { 6430 return endsWith(str, suffix, false); 6431 } 6432 6433 /** 6434 * <p>Case insensitive check if a CharSequence ends with a specified suffix.</p> 6435 * 6436 * <p>{@code null}s are handled without exceptions. Two {@code null} 6437 * references are considered to be equal. The comparison is case insensitive.</p> 6438 * 6439 * <pre> 6440 * StringUtils.endsWithIgnoreCase(null, null) = true 6441 * StringUtils.endsWithIgnoreCase(null, "def") = false 6442 * StringUtils.endsWithIgnoreCase("abcdef", null) = false 6443 * StringUtils.endsWithIgnoreCase("abcdef", "def") = true 6444 * StringUtils.endsWithIgnoreCase("ABCDEF", "def") = true 6445 * StringUtils.endsWithIgnoreCase("ABCDEF", "cde") = false 6446 * </pre> 6447 * 6448 * @see java.lang.String#endsWith(String) 6449 * @param str the CharSequence to check, may be null 6450 * @param suffix the suffix to find, may be null 6451 * @return {@code true} if the CharSequence ends with the suffix, case insensitive, or 6452 * both {@code null} 6453 * @since 2.4 6454 * @since 3.0 Changed signature from endsWithIgnoreCase(String, String) to endsWithIgnoreCase(CharSequence, CharSequence) 6455 */ 6456 public static boolean endsWithIgnoreCase(CharSequence str, CharSequence suffix) { 6457 return endsWith(str, suffix, true); 6458 } 6459 6460 /** 6461 * <p>Check if a CharSequence ends with a specified suffix (optionally case insensitive).</p> 6462 * 6463 * @see java.lang.String#endsWith(String) 6464 * @param str the CharSequence to check, may be null 6465 * @param suffix the suffix to find, may be null 6466 * @param ignoreCase indicates whether the compare should ignore case 6467 * (case insensitive) or not. 6468 * @return {@code true} if the CharSequence starts with the prefix or 6469 * both {@code null} 6470 */ 6471 private static boolean endsWith(CharSequence str, CharSequence suffix, boolean ignoreCase) { 6472 if (str == null || suffix == null) { 6473 return str == null && suffix == null; 6474 } 6475 if (suffix.length() > str.length()) { 6476 return false; 6477 } 6478 int strOffset = str.length() - suffix.length(); 6479 return CharSequenceUtils.regionMatches(str, ignoreCase, strOffset, suffix, 0, suffix.length()); 6480 } 6481 6482 /** 6483 * <p> 6484 * Similar to <a 6485 * href="http://www.w3.org/TR/xpath/#function-normalize-space">http://www.w3.org/TR/xpath/#function-normalize 6486 * -space</a> 6487 * </p> 6488 * <p> 6489 * The function returns the argument string with whitespace normalized by using 6490 * <code>{@link #trim(String)}</code> to remove leading and trailing whitespace 6491 * and then replacing sequences of whitespace characters by a single space. 6492 * </p> 6493 * In XML Whitespace characters are the same as those allowed by the <a 6494 * href="http://www.w3.org/TR/REC-xml/#NT-S">S</a> production, which is S ::= (#x20 | #x9 | #xD | #xA)+ 6495 * <p> 6496 * Java's regexp pattern \s defines whitespace as [ \t\n\x0B\f\r] 6497 * <p> 6498 * For reference: 6499 * <ul> 6500 * <li>\x0B = vertical tab</li> 6501 * <li>\f = #xC = form feed</li> 6502 * <li>#x20 = space</li> 6503 * <li>#x9 = \t</li> 6504 * <li>#xA = \n</li> 6505 * <li>#xD = \r</li> 6506 * </ul> 6507 * </p> 6508 * <p> 6509 * The difference is that Java's whitespace includes vertical tab and form feed, which this functional will also 6510 * normalize. Additionally <code>{@link #trim(String)}</code> removes control characters (char <= 32) from both 6511 * ends of this String. 6512 * </p> 6513 * 6514 * @see Pattern 6515 * @see #trim(String) 6516 * @see <a 6517 * href="http://www.w3.org/TR/xpath/#function-normalize-space">http://www.w3.org/TR/xpath/#function-normalize-space</a> 6518 * @param str the source String to normalize whitespaces from, may be null 6519 * @return the modified string with whitespace normalized, {@code null} if null String input 6520 * 6521 * @since 3.0 6522 */ 6523 public static String normalizeSpace(String str) { 6524 if (str == null) { 6525 return null; 6526 } 6527 return WHITESPACE_BLOCK.matcher(trim(str)).replaceAll(" "); 6528 } 6529 6530 /** 6531 * <p>Check if a CharSequence ends with any of an array of specified strings.</p> 6532 * 6533 * <pre> 6534 * StringUtils.endsWithAny(null, null) = false 6535 * StringUtils.endsWithAny(null, new String[] {"abc"}) = false 6536 * StringUtils.endsWithAny("abcxyz", null) = false 6537 * StringUtils.endsWithAny("abcxyz", new String[] {""}) = true 6538 * StringUtils.endsWithAny("abcxyz", new String[] {"xyz"}) = true 6539 * StringUtils.endsWithAny("abcxyz", new String[] {null, "xyz", "abc"}) = true 6540 * </pre> 6541 * 6542 * @param string the CharSequence to check, may be null 6543 * @param searchStrings the CharSequences to find, may be null or empty 6544 * @return {@code true} if the CharSequence ends with any of the the prefixes, case insensitive, or 6545 * both {@code null} 6546 * @since 3.0 6547 */ 6548 public static boolean endsWithAny(CharSequence string, CharSequence... searchStrings) { 6549 if (isEmpty(string) || ArrayUtils.isEmpty(searchStrings)) { 6550 return false; 6551 } 6552 for (CharSequence searchString : searchStrings) { 6553 if (StringUtils.endsWith(string, searchString)) { 6554 return true; 6555 } 6556 } 6557 return false; 6558 } 6559 6560 }