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