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