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