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.Objects; 028import java.util.regex.Pattern; 029 030/** 031 * <p>Operations on {@link java.lang.String} that are 032 * {@code null} safe.</p> 033 * 034 * <ul> 035 * <li><b>IsEmpty/IsBlank</b> 036 * - checks if a String contains text</li> 037 * <li><b>Trim/Strip</b> 038 * - removes leading and trailing whitespace</li> 039 * <li><b>Equals/Compare</b> 040 * - compares two strings null-safe</li> 041 * <li><b>startsWith</b> 042 * - check if a String starts with a prefix null-safe</li> 043 * <li><b>endsWith</b> 044 * - check if a String ends with a suffix null-safe</li> 045 * <li><b>IndexOf/LastIndexOf/Contains</b> 046 * - null-safe index-of checks 047 * <li><b>IndexOfAny/LastIndexOfAny/IndexOfAnyBut/LastIndexOfAnyBut</b> 048 * - index-of any of a set of Strings</li> 049 * <li><b>ContainsOnly/ContainsNone/ContainsAny</b> 050 * - does String contains only/none/any of these characters</li> 051 * <li><b>Substring/Left/Right/Mid</b> 052 * - null-safe substring extractions</li> 053 * <li><b>SubstringBefore/SubstringAfter/SubstringBetween</b> 054 * - substring extraction relative to other strings</li> 055 * <li><b>Split/Join</b> 056 * - splits a String into an array of substrings and vice versa</li> 057 * <li><b>Remove/Delete</b> 058 * - removes part of a String</li> 059 * <li><b>Replace/Overlay</b> 060 * - Searches a String and replaces one String with another</li> 061 * <li><b>Chomp/Chop</b> 062 * - removes the last part of a String</li> 063 * <li><b>AppendIfMissing</b> 064 * - appends a suffix to the end of the String if not present</li> 065 * <li><b>PrependIfMissing</b> 066 * - prepends a prefix to the start of the String if not present</li> 067 * <li><b>LeftPad/RightPad/Center/Repeat</b> 068 * - pads a String</li> 069 * <li><b>UpperCase/LowerCase/SwapCase/Capitalize/Uncapitalize</b> 070 * - changes the case of a String</li> 071 * <li><b>CountMatches</b> 072 * - counts the number of occurrences of one String in another</li> 073 * <li><b>IsAlpha/IsNumeric/IsWhitespace/IsAsciiPrintable</b> 074 * - checks the characters in a String</li> 075 * <li><b>DefaultString</b> 076 * - protects against a null input String</li> 077 * <li><b>Rotate</b> 078 * - rotate (circular shift) a String</li> 079 * <li><b>Reverse/ReverseDelimited</b> 080 * - reverses a String</li> 081 * <li><b>Abbreviate</b> 082 * - abbreviates a string using ellipsis or another given String</li> 083 * <li><b>Difference</b> 084 * - compares Strings and reports on their differences</li> 085 * <li><b>LevenshteinDistance</b> 086 * - the number of changes needed to change one String into another</li> 087 * </ul> 088 * 089 * <p>The {@code StringUtils} class defines certain words related to 090 * String handling.</p> 091 * 092 * <ul> 093 * <li>null - {@code null}</li> 094 * <li>empty - a zero-length string ({@code ""})</li> 095 * <li>space - the space character ({@code ' '}, char 32)</li> 096 * <li>whitespace - the characters defined by {@link Character#isWhitespace(char)}</li> 097 * <li>trim - the characters <= 32 as in {@link String#trim()}</li> 098 * </ul> 099 * 100 * <p>{@code StringUtils} handles {@code null} input Strings quietly. 101 * That is to say that a {@code null} input will return {@code null}. 102 * Where a {@code boolean} or {@code int} is being returned 103 * details vary by method.</p> 104 * 105 * <p>A side effect of the {@code null} handling is that a 106 * {@code NullPointerException} should be considered a bug in 107 * {@code StringUtils}.</p> 108 * 109 * <p>Methods in this class give sample code to explain their operation. 110 * The symbol {@code *} is used to indicate any input including {@code null}.</p> 111 * 112 * <p>#ThreadSafe#</p> 113 * @see java.lang.String 114 * @since 1.0 115 */ 116//@Immutable 117public class StringUtils { 118 119 private static final int STRING_BUILDER_SIZE = 256; 120 121 // Performance testing notes (JDK 1.4, Jul03, scolebourne) 122 // Whitespace: 123 // Character.isWhitespace() is faster than WHITESPACE.indexOf() 124 // where WHITESPACE is a string of all whitespace characters 125 // 126 // Character access: 127 // String.charAt(n) versus toCharArray(), then array[n] 128 // String.charAt(n) is about 15% worse for a 10K string 129 // They are about equal for a length 50 string 130 // String.charAt(n) is about 4 times better for a length 3 string 131 // String.charAt(n) is best bet overall 132 // 133 // Append: 134 // String.concat about twice as fast as StringBuffer.append 135 // (not sure who tested this) 136 137 /** 138 * A String for a space character. 139 * 140 * @since 3.2 141 */ 142 public static final String SPACE = " "; 143 144 /** 145 * The empty String {@code ""}. 146 * @since 2.0 147 */ 148 public static final String EMPTY = ""; 149 150 /** 151 * A String for linefeed LF ("\n"). 152 * 153 * @see <a href="http://docs.oracle.com/javase/specs/jls/se7/html/jls-3.html#jls-3.10.6">JLF: Escape Sequences 154 * for Character and String Literals</a> 155 * @since 3.2 156 */ 157 public static final String LF = "\n"; 158 159 /** 160 * A String for carriage return CR ("\r"). 161 * 162 * @see <a href="http://docs.oracle.com/javase/specs/jls/se7/html/jls-3.html#jls-3.10.6">JLF: Escape Sequences 163 * for Character and String Literals</a> 164 * @since 3.2 165 */ 166 public static final String CR = "\r"; 167 168 /** 169 * Represents a failed index search. 170 * @since 2.1 171 */ 172 public static final int INDEX_NOT_FOUND = -1; 173 174 /** 175 * <p>The maximum size to which the padding constant(s) can expand.</p> 176 */ 177 private static final int PAD_LIMIT = 8192; 178 179 /** 180 * <p>{@code StringUtils} instances should NOT be constructed in 181 * standard programming. Instead, the class should be used as 182 * {@code StringUtils.trim(" foo ");}.</p> 183 * 184 * <p>This constructor is public to permit tools that require a JavaBean 185 * instance to operate.</p> 186 */ 187 public StringUtils() { 188 super(); 189 } 190 191 // Empty checks 192 //----------------------------------------------------------------------- 193 /** 194 * <p>Checks if a CharSequence is empty ("") or null.</p> 195 * 196 * <pre> 197 * StringUtils.isEmpty(null) = true 198 * StringUtils.isEmpty("") = true 199 * StringUtils.isEmpty(" ") = false 200 * StringUtils.isEmpty("bob") = false 201 * StringUtils.isEmpty(" bob ") = false 202 * </pre> 203 * 204 * <p>NOTE: This method changed in Lang version 2.0. 205 * It no longer trims the CharSequence. 206 * That functionality is available in isBlank().</p> 207 * 208 * @param cs the CharSequence to check, may be null 209 * @return {@code true} if the CharSequence is empty or null 210 * @since 3.0 Changed signature from isEmpty(String) to isEmpty(CharSequence) 211 */ 212 public static boolean isEmpty(final CharSequence cs) { 213 return cs == null || cs.length() == 0; 214 } 215 216 /** 217 * <p>Checks if a CharSequence is not empty ("") and not null.</p> 218 * 219 * <pre> 220 * StringUtils.isNotEmpty(null) = false 221 * StringUtils.isNotEmpty("") = false 222 * StringUtils.isNotEmpty(" ") = true 223 * StringUtils.isNotEmpty("bob") = true 224 * StringUtils.isNotEmpty(" bob ") = true 225 * </pre> 226 * 227 * @param cs the CharSequence to check, may be null 228 * @return {@code true} if the CharSequence is not empty and not null 229 * @since 3.0 Changed signature from isNotEmpty(String) to isNotEmpty(CharSequence) 230 */ 231 public static boolean isNotEmpty(final CharSequence cs) { 232 return !isEmpty(cs); 233 } 234 235 /** 236 * <p>Checks if any of the CharSequences are empty ("") or null.</p> 237 * 238 * <pre> 239 * StringUtils.isAnyEmpty((String) null) = true 240 * StringUtils.isAnyEmpty((String[]) null) = false 241 * StringUtils.isAnyEmpty(null, "foo") = true 242 * StringUtils.isAnyEmpty("", "bar") = true 243 * StringUtils.isAnyEmpty("bob", "") = true 244 * StringUtils.isAnyEmpty(" bob ", null) = true 245 * StringUtils.isAnyEmpty(" ", "bar") = false 246 * StringUtils.isAnyEmpty("foo", "bar") = false 247 * StringUtils.isAnyEmpty(new String[]{}) = false 248 * StringUtils.isAnyEmpty(new String[]{""}) = true 249 * </pre> 250 * 251 * @param css the CharSequences to check, may be null or empty 252 * @return {@code true} if any of the CharSequences are empty or null 253 * @since 3.2 254 */ 255 public static boolean isAnyEmpty(final CharSequence... css) { 256 if (ArrayUtils.isEmpty(css)) { 257 return false; 258 } 259 for (final CharSequence cs : css){ 260 if (isEmpty(cs)) { 261 return true; 262 } 263 } 264 return false; 265 } 266 267 /** 268 * <p>Checks if none of the CharSequences are empty ("") or null.</p> 269 * 270 * <pre> 271 * StringUtils.isNoneEmpty((String) null) = false 272 * StringUtils.isNoneEmpty((String[]) null) = true 273 * StringUtils.isNoneEmpty(null, "foo") = false 274 * StringUtils.isNoneEmpty("", "bar") = false 275 * StringUtils.isNoneEmpty("bob", "") = false 276 * StringUtils.isNoneEmpty(" bob ", null) = false 277 * StringUtils.isNoneEmpty(new String[] {}) = true 278 * StringUtils.isNoneEmpty(new String[]{""}) = false 279 * StringUtils.isNoneEmpty(" ", "bar") = true 280 * StringUtils.isNoneEmpty("foo", "bar") = true 281 * </pre> 282 * 283 * @param css the CharSequences to check, may be null or empty 284 * @return {@code true} if none of the CharSequences are empty or null 285 * @since 3.2 286 */ 287 public static boolean isNoneEmpty(final CharSequence... css) { 288 return !isAnyEmpty(css); 289 } 290 291 /** 292 * <p>Checks if all of the CharSequences are empty ("") or null.</p> 293 * 294 * <pre> 295 * StringUtils.isAllEmpty(null) = true 296 * StringUtils.isAllEmpty(null, "") = true 297 * StringUtils.isAllEmpty(new String[] {}) = true 298 * StringUtils.isAllEmpty(null, "foo") = false 299 * StringUtils.isAllEmpty("", "bar") = false 300 * StringUtils.isAllEmpty("bob", "") = false 301 * StringUtils.isAllEmpty(" bob ", null) = false 302 * StringUtils.isAllEmpty(" ", "bar") = false 303 * StringUtils.isAllEmpty("foo", "bar") = false 304 * </pre> 305 * 306 * @param css the CharSequences to check, may be null or empty 307 * @return {@code true} if all of the CharSequences are empty or null 308 * @since 3.6 309 */ 310 public static boolean isAllEmpty(final CharSequence... css) { 311 if (ArrayUtils.isEmpty(css)) { 312 return true; 313 } 314 for (final CharSequence cs : css) { 315 if (isNotEmpty(cs)) { 316 return false; 317 } 318 } 319 return true; 320 } 321 322 /** 323 * <p>Checks if a CharSequence is empty (""), null or whitespace only.</p> 324 * 325 * <p>Whitespace is defined by {@link Character#isWhitespace(char)}.</p> 326 * 327 * <pre> 328 * StringUtils.isBlank(null) = true 329 * StringUtils.isBlank("") = true 330 * StringUtils.isBlank(" ") = true 331 * StringUtils.isBlank("bob") = false 332 * StringUtils.isBlank(" bob ") = false 333 * </pre> 334 * 335 * @param cs the CharSequence to check, may be null 336 * @return {@code true} if the CharSequence is null, empty or whitespace only 337 * @since 2.0 338 * @since 3.0 Changed signature from isBlank(String) to isBlank(CharSequence) 339 */ 340 public static boolean isBlank(final CharSequence cs) { 341 int strLen; 342 if (cs == null || (strLen = cs.length()) == 0) { 343 return true; 344 } 345 for (int i = 0; i < strLen; i++) { 346 if (!Character.isWhitespace(cs.charAt(i))) { 347 return false; 348 } 349 } 350 return true; 351 } 352 353 /** 354 * <p>Checks if a CharSequence is not empty (""), not null and not whitespace only.</p> 355 * 356 * <p>Whitespace is defined by {@link Character#isWhitespace(char)}.</p> 357 * 358 * <pre> 359 * StringUtils.isNotBlank(null) = false 360 * StringUtils.isNotBlank("") = false 361 * StringUtils.isNotBlank(" ") = false 362 * StringUtils.isNotBlank("bob") = true 363 * StringUtils.isNotBlank(" bob ") = true 364 * </pre> 365 * 366 * @param cs the CharSequence to check, may be null 367 * @return {@code true} if the CharSequence is 368 * not empty and not null and not whitespace only 369 * @since 2.0 370 * @since 3.0 Changed signature from isNotBlank(String) to isNotBlank(CharSequence) 371 */ 372 public static boolean isNotBlank(final CharSequence cs) { 373 return !isBlank(cs); 374 } 375 376 /** 377 * <p>Checks if any of the CharSequences are empty ("") or null or whitespace only.</p> 378 * 379 * <p>Whitespace is defined by {@link Character#isWhitespace(char)}.</p> 380 * 381 * <pre> 382 * StringUtils.isAnyBlank((String) null) = true 383 * StringUtils.isAnyBlank((String[]) null) = false 384 * StringUtils.isAnyBlank(null, "foo") = true 385 * StringUtils.isAnyBlank(null, null) = true 386 * StringUtils.isAnyBlank("", "bar") = true 387 * StringUtils.isAnyBlank("bob", "") = true 388 * StringUtils.isAnyBlank(" bob ", null) = true 389 * StringUtils.isAnyBlank(" ", "bar") = true 390 * StringUtils.isAnyBlank(new String[] {}) = false 391 * StringUtils.isAnyBlank(new String[]{""}) = true 392 * StringUtils.isAnyBlank("foo", "bar") = false 393 * </pre> 394 * 395 * @param css the CharSequences to check, may be null or empty 396 * @return {@code true} if any of the CharSequences are empty or null or whitespace only 397 * @since 3.2 398 */ 399 public static boolean isAnyBlank(final CharSequence... css) { 400 if (ArrayUtils.isEmpty(css)) { 401 return false; 402 } 403 for (final CharSequence cs : css){ 404 if (isBlank(cs)) { 405 return true; 406 } 407 } 408 return false; 409 } 410 411 /** 412 * <p>Checks if none of the CharSequences are empty (""), null or whitespace only.</p> 413 * 414 * <p>Whitespace is defined by {@link Character#isWhitespace(char)}.</p> 415 * 416 * <pre> 417 * StringUtils.isNoneBlank((String) null) = false 418 * StringUtils.isNoneBlank((String[]) null) = true 419 * StringUtils.isNoneBlank(null, "foo") = false 420 * StringUtils.isNoneBlank(null, null) = false 421 * StringUtils.isNoneBlank("", "bar") = false 422 * StringUtils.isNoneBlank("bob", "") = false 423 * StringUtils.isNoneBlank(" bob ", null) = false 424 * StringUtils.isNoneBlank(" ", "bar") = false 425 * StringUtils.isNoneBlank(new String[] {}) = true 426 * StringUtils.isNoneBlank(new String[]{""}) = false 427 * StringUtils.isNoneBlank("foo", "bar") = true 428 * </pre> 429 * 430 * @param css the CharSequences to check, may be null or empty 431 * @return {@code true} if none of the CharSequences are empty or null or whitespace only 432 * @since 3.2 433 */ 434 public static boolean isNoneBlank(final CharSequence... css) { 435 return !isAnyBlank(css); 436 } 437 438 /** 439 * <p>Checks if all of the CharSequences are empty (""), null or whitespace only.</p> 440 * 441 * <p>Whitespace is defined by {@link Character#isWhitespace(char)}.</p> 442 * 443 * <pre> 444 * StringUtils.isAllBlank(null) = true 445 * StringUtils.isAllBlank(null, "foo") = false 446 * StringUtils.isAllBlank(null, null) = true 447 * StringUtils.isAllBlank("", "bar") = false 448 * StringUtils.isAllBlank("bob", "") = false 449 * StringUtils.isAllBlank(" bob ", null) = false 450 * StringUtils.isAllBlank(" ", "bar") = false 451 * StringUtils.isAllBlank("foo", "bar") = false 452 * StringUtils.isAllBlank(new String[] {}) = true 453 * </pre> 454 * 455 * @param css the CharSequences to check, may be null or empty 456 * @return {@code true} if all of the CharSequences are empty or null or whitespace only 457 * @since 3.6 458 */ 459 public static boolean isAllBlank(final CharSequence... css) { 460 if (ArrayUtils.isEmpty(css)) { 461 return true; 462 } 463 for (final CharSequence cs : css) { 464 if (isNotBlank(cs)) { 465 return false; 466 } 467 } 468 return true; 469 } 470 471 // Trim 472 //----------------------------------------------------------------------- 473 /** 474 * <p>Removes control characters (char <= 32) from both 475 * ends of this String, handling {@code null} by returning 476 * {@code null}.</p> 477 * 478 * <p>The String is trimmed using {@link String#trim()}. 479 * Trim removes start and end characters <= 32. 480 * To strip whitespace use {@link #strip(String)}.</p> 481 * 482 * <p>To trim your choice of characters, use the 483 * {@link #strip(String, String)} methods.</p> 484 * 485 * <pre> 486 * StringUtils.trim(null) = null 487 * StringUtils.trim("") = "" 488 * StringUtils.trim(" ") = "" 489 * StringUtils.trim("abc") = "abc" 490 * StringUtils.trim(" abc ") = "abc" 491 * </pre> 492 * 493 * @param str the String to be trimmed, may be null 494 * @return the trimmed string, {@code null} if null String input 495 */ 496 public static String trim(final String str) { 497 return str == null ? null : str.trim(); 498 } 499 500 /** 501 * <p>Removes control characters (char <= 32) from both 502 * ends of this String returning {@code null} if the String is 503 * empty ("") after the trim or if it is {@code null}. 504 * 505 * <p>The String is trimmed using {@link String#trim()}. 506 * Trim removes start and end characters <= 32. 507 * To strip whitespace use {@link #stripToNull(String)}.</p> 508 * 509 * <pre> 510 * StringUtils.trimToNull(null) = null 511 * StringUtils.trimToNull("") = null 512 * StringUtils.trimToNull(" ") = null 513 * StringUtils.trimToNull("abc") = "abc" 514 * StringUtils.trimToNull(" abc ") = "abc" 515 * </pre> 516 * 517 * @param str the String to be trimmed, may be null 518 * @return the trimmed String, 519 * {@code null} if only chars <= 32, empty or null String input 520 * @since 2.0 521 */ 522 public static String trimToNull(final String str) { 523 final String ts = trim(str); 524 return isEmpty(ts) ? null : ts; 525 } 526 527 /** 528 * <p>Removes control characters (char <= 32) from both 529 * ends of this String returning an empty String ("") if the String 530 * is empty ("") after the trim or if it is {@code null}. 531 * 532 * <p>The String is trimmed using {@link String#trim()}. 533 * Trim removes start and end characters <= 32. 534 * To strip whitespace use {@link #stripToEmpty(String)}.</p> 535 * 536 * <pre> 537 * StringUtils.trimToEmpty(null) = "" 538 * StringUtils.trimToEmpty("") = "" 539 * StringUtils.trimToEmpty(" ") = "" 540 * StringUtils.trimToEmpty("abc") = "abc" 541 * StringUtils.trimToEmpty(" abc ") = "abc" 542 * </pre> 543 * 544 * @param str the String to be trimmed, may be null 545 * @return the trimmed String, or an empty String if {@code null} input 546 * @since 2.0 547 */ 548 public static String trimToEmpty(final String str) { 549 return str == null ? EMPTY : str.trim(); 550 } 551 552 /** 553 * <p>Truncates a String. This will turn 554 * "Now is the time for all good men" into "Now is the time for".</p> 555 * 556 * <p>Specifically:</p> 557 * <ul> 558 * <li>If {@code str} is less than {@code maxWidth} characters 559 * long, return it.</li> 560 * <li>Else truncate it to {@code substring(str, 0, maxWidth)}.</li> 561 * <li>If {@code maxWidth} is less than {@code 0}, throw an 562 * {@code IllegalArgumentException}.</li> 563 * <li>In no case will it return a String of length greater than 564 * {@code maxWidth}.</li> 565 * </ul> 566 * 567 * <pre> 568 * StringUtils.truncate(null, 0) = null 569 * StringUtils.truncate(null, 2) = null 570 * StringUtils.truncate("", 4) = "" 571 * StringUtils.truncate("abcdefg", 4) = "abcd" 572 * StringUtils.truncate("abcdefg", 6) = "abcdef" 573 * StringUtils.truncate("abcdefg", 7) = "abcdefg" 574 * StringUtils.truncate("abcdefg", 8) = "abcdefg" 575 * StringUtils.truncate("abcdefg", -1) = throws an IllegalArgumentException 576 * </pre> 577 * 578 * @param str the String to truncate, may be null 579 * @param maxWidth maximum length of result String, must be positive 580 * @return truncated String, {@code null} if null String input 581 * @since 3.5 582 */ 583 public static String truncate(final String str, final int maxWidth) { 584 return truncate(str, 0, maxWidth); 585 } 586 587 /** 588 * <p>Truncates a String. This will turn 589 * "Now is the time for all good men" into "is the time for all".</p> 590 * 591 * <p>Works like {@code truncate(String, int)}, but allows you to specify 592 * a "left edge" offset. 593 * 594 * <p>Specifically:</p> 595 * <ul> 596 * <li>If {@code str} is less than {@code maxWidth} characters 597 * long, return it.</li> 598 * <li>Else truncate it to {@code substring(str, offset, maxWidth)}.</li> 599 * <li>If {@code maxWidth} is less than {@code 0}, throw an 600 * {@code IllegalArgumentException}.</li> 601 * <li>If {@code offset} is less than {@code 0}, throw an 602 * {@code IllegalArgumentException}.</li> 603 * <li>In no case will it return a String of length greater than 604 * {@code maxWidth}.</li> 605 * </ul> 606 * 607 * <pre> 608 * StringUtils.truncate(null, 0, 0) = null 609 * StringUtils.truncate(null, 2, 4) = null 610 * StringUtils.truncate("", 0, 10) = "" 611 * StringUtils.truncate("", 2, 10) = "" 612 * StringUtils.truncate("abcdefghij", 0, 3) = "abc" 613 * StringUtils.truncate("abcdefghij", 5, 6) = "fghij" 614 * StringUtils.truncate("raspberry peach", 10, 15) = "peach" 615 * StringUtils.truncate("abcdefghijklmno", 0, 10) = "abcdefghij" 616 * StringUtils.truncate("abcdefghijklmno", -1, 10) = throws an IllegalArgumentException 617 * StringUtils.truncate("abcdefghijklmno", Integer.MIN_VALUE, 10) = "abcdefghij" 618 * StringUtils.truncate("abcdefghijklmno", Integer.MIN_VALUE, Integer.MAX_VALUE) = "abcdefghijklmno" 619 * StringUtils.truncate("abcdefghijklmno", 0, Integer.MAX_VALUE) = "abcdefghijklmno" 620 * StringUtils.truncate("abcdefghijklmno", 1, 10) = "bcdefghijk" 621 * StringUtils.truncate("abcdefghijklmno", 2, 10) = "cdefghijkl" 622 * StringUtils.truncate("abcdefghijklmno", 3, 10) = "defghijklm" 623 * StringUtils.truncate("abcdefghijklmno", 4, 10) = "efghijklmn" 624 * StringUtils.truncate("abcdefghijklmno", 5, 10) = "fghijklmno" 625 * StringUtils.truncate("abcdefghijklmno", 5, 5) = "fghij" 626 * StringUtils.truncate("abcdefghijklmno", 5, 3) = "fgh" 627 * StringUtils.truncate("abcdefghijklmno", 10, 3) = "klm" 628 * StringUtils.truncate("abcdefghijklmno", 10, Integer.MAX_VALUE) = "klmno" 629 * StringUtils.truncate("abcdefghijklmno", 13, 1) = "n" 630 * StringUtils.truncate("abcdefghijklmno", 13, Integer.MAX_VALUE) = "no" 631 * StringUtils.truncate("abcdefghijklmno", 14, 1) = "o" 632 * StringUtils.truncate("abcdefghijklmno", 14, Integer.MAX_VALUE) = "o" 633 * StringUtils.truncate("abcdefghijklmno", 15, 1) = "" 634 * StringUtils.truncate("abcdefghijklmno", 15, Integer.MAX_VALUE) = "" 635 * StringUtils.truncate("abcdefghijklmno", Integer.MAX_VALUE, Integer.MAX_VALUE) = "" 636 * StringUtils.truncate("abcdefghij", 3, -1) = throws an IllegalArgumentException 637 * StringUtils.truncate("abcdefghij", -2, 4) = throws an IllegalArgumentException 638 * </pre> 639 * 640 * @param str the String to check, may be null 641 * @param offset left edge of source String 642 * @param maxWidth maximum length of result String, must be positive 643 * @return truncated String, {@code null} if null String input 644 * @since 3.5 645 */ 646 public static String truncate(final String str, final int offset, final int maxWidth) { 647 if (offset < 0) { 648 throw new IllegalArgumentException("offset cannot be negative"); 649 } 650 if (maxWidth < 0) { 651 throw new IllegalArgumentException("maxWith cannot be negative"); 652 } 653 if (str == null) { 654 return null; 655 } 656 if (offset > str.length()) { 657 return EMPTY; 658 } 659 if (str.length() > maxWidth) { 660 final int ix = offset + maxWidth > str.length() ? str.length() : offset + maxWidth; 661 return str.substring(offset, ix); 662 } 663 return str.substring(offset); 664 } 665 666 // Stripping 667 //----------------------------------------------------------------------- 668 /** 669 * <p>Strips whitespace from the start and end of a String.</p> 670 * 671 * <p>This is similar to {@link #trim(String)} but removes whitespace. 672 * Whitespace is defined by {@link Character#isWhitespace(char)}.</p> 673 * 674 * <p>A {@code null} input String returns {@code null}.</p> 675 * 676 * <pre> 677 * StringUtils.strip(null) = null 678 * StringUtils.strip("") = "" 679 * StringUtils.strip(" ") = "" 680 * StringUtils.strip("abc") = "abc" 681 * StringUtils.strip(" abc") = "abc" 682 * StringUtils.strip("abc ") = "abc" 683 * StringUtils.strip(" abc ") = "abc" 684 * StringUtils.strip(" ab c ") = "ab c" 685 * </pre> 686 * 687 * @param str the String to remove whitespace from, may be null 688 * @return the stripped String, {@code null} if null String input 689 */ 690 public static String strip(final String str) { 691 return strip(str, null); 692 } 693 694 /** 695 * <p>Strips whitespace from the start and end of a String returning 696 * {@code null} if the String is empty ("") after the strip.</p> 697 * 698 * <p>This is similar to {@link #trimToNull(String)} but removes whitespace. 699 * Whitespace is defined by {@link Character#isWhitespace(char)}.</p> 700 * 701 * <pre> 702 * StringUtils.stripToNull(null) = null 703 * StringUtils.stripToNull("") = null 704 * StringUtils.stripToNull(" ") = null 705 * StringUtils.stripToNull("abc") = "abc" 706 * StringUtils.stripToNull(" abc") = "abc" 707 * StringUtils.stripToNull("abc ") = "abc" 708 * StringUtils.stripToNull(" abc ") = "abc" 709 * StringUtils.stripToNull(" ab c ") = "ab c" 710 * </pre> 711 * 712 * @param str the String to be stripped, may be null 713 * @return the stripped String, 714 * {@code null} if whitespace, empty or null String input 715 * @since 2.0 716 */ 717 public static String stripToNull(String str) { 718 if (str == null) { 719 return null; 720 } 721 str = strip(str, null); 722 return str.isEmpty() ? null : str; 723 } 724 725 /** 726 * <p>Strips whitespace from the start and end of a String returning 727 * an empty String if {@code null} input.</p> 728 * 729 * <p>This is similar to {@link #trimToEmpty(String)} but removes whitespace. 730 * Whitespace is defined by {@link Character#isWhitespace(char)}.</p> 731 * 732 * <pre> 733 * StringUtils.stripToEmpty(null) = "" 734 * StringUtils.stripToEmpty("") = "" 735 * StringUtils.stripToEmpty(" ") = "" 736 * StringUtils.stripToEmpty("abc") = "abc" 737 * StringUtils.stripToEmpty(" abc") = "abc" 738 * StringUtils.stripToEmpty("abc ") = "abc" 739 * StringUtils.stripToEmpty(" abc ") = "abc" 740 * StringUtils.stripToEmpty(" ab c ") = "ab c" 741 * </pre> 742 * 743 * @param str the String to be stripped, may be null 744 * @return the trimmed String, or an empty String if {@code null} input 745 * @since 2.0 746 */ 747 public static String stripToEmpty(final String str) { 748 return str == null ? EMPTY : strip(str, null); 749 } 750 751 /** 752 * <p>Strips any of a set of characters from the start and end of a String. 753 * This is similar to {@link String#trim()} but allows the characters 754 * to be stripped to be controlled.</p> 755 * 756 * <p>A {@code null} input String returns {@code null}. 757 * An empty string ("") input returns the empty string.</p> 758 * 759 * <p>If the stripChars String is {@code null}, whitespace is 760 * stripped as defined by {@link Character#isWhitespace(char)}. 761 * Alternatively use {@link #strip(String)}.</p> 762 * 763 * <pre> 764 * StringUtils.strip(null, *) = null 765 * StringUtils.strip("", *) = "" 766 * StringUtils.strip("abc", null) = "abc" 767 * StringUtils.strip(" abc", null) = "abc" 768 * StringUtils.strip("abc ", null) = "abc" 769 * StringUtils.strip(" abc ", null) = "abc" 770 * StringUtils.strip(" abcyx", "xyz") = " abc" 771 * </pre> 772 * 773 * @param str the String to remove characters from, may be null 774 * @param stripChars the characters to remove, null treated as whitespace 775 * @return the stripped String, {@code null} if null String input 776 */ 777 public static String strip(String str, final String stripChars) { 778 if (isEmpty(str)) { 779 return str; 780 } 781 str = stripStart(str, stripChars); 782 return stripEnd(str, stripChars); 783 } 784 785 /** 786 * <p>Strips any of a set of characters from the start of a String.</p> 787 * 788 * <p>A {@code null} input String returns {@code null}. 789 * An empty string ("") input returns the empty string.</p> 790 * 791 * <p>If the stripChars String is {@code null}, whitespace is 792 * stripped as defined by {@link Character#isWhitespace(char)}.</p> 793 * 794 * <pre> 795 * StringUtils.stripStart(null, *) = null 796 * StringUtils.stripStart("", *) = "" 797 * StringUtils.stripStart("abc", "") = "abc" 798 * StringUtils.stripStart("abc", null) = "abc" 799 * StringUtils.stripStart(" abc", null) = "abc" 800 * StringUtils.stripStart("abc ", null) = "abc " 801 * StringUtils.stripStart(" abc ", null) = "abc " 802 * StringUtils.stripStart("yxabc ", "xyz") = "abc " 803 * </pre> 804 * 805 * @param str the String to remove characters from, may be null 806 * @param stripChars the characters to remove, null treated as whitespace 807 * @return the stripped String, {@code null} if null String input 808 */ 809 public static String stripStart(final String str, final String stripChars) { 810 int strLen; 811 if (str == null || (strLen = str.length()) == 0) { 812 return str; 813 } 814 int start = 0; 815 if (stripChars == null) { 816 while (start != strLen && Character.isWhitespace(str.charAt(start))) { 817 start++; 818 } 819 } else if (stripChars.isEmpty()) { 820 return str; 821 } else { 822 while (start != strLen && stripChars.indexOf(str.charAt(start)) != INDEX_NOT_FOUND) { 823 start++; 824 } 825 } 826 return str.substring(start); 827 } 828 829 /** 830 * <p>Strips any of a set of characters from the end of a String.</p> 831 * 832 * <p>A {@code null} input String returns {@code null}. 833 * An empty string ("") input returns the empty string.</p> 834 * 835 * <p>If the stripChars String is {@code null}, whitespace is 836 * stripped as defined by {@link Character#isWhitespace(char)}.</p> 837 * 838 * <pre> 839 * StringUtils.stripEnd(null, *) = null 840 * StringUtils.stripEnd("", *) = "" 841 * StringUtils.stripEnd("abc", "") = "abc" 842 * StringUtils.stripEnd("abc", null) = "abc" 843 * StringUtils.stripEnd(" abc", null) = " abc" 844 * StringUtils.stripEnd("abc ", null) = "abc" 845 * StringUtils.stripEnd(" abc ", null) = " abc" 846 * StringUtils.stripEnd(" abcyx", "xyz") = " abc" 847 * StringUtils.stripEnd("120.00", ".0") = "12" 848 * </pre> 849 * 850 * @param str the String to remove characters from, may be null 851 * @param stripChars the set of characters to remove, null treated as whitespace 852 * @return the stripped String, {@code null} if null String input 853 */ 854 public static String stripEnd(final String str, final String stripChars) { 855 int end; 856 if (str == null || (end = str.length()) == 0) { 857 return str; 858 } 859 860 if (stripChars == null) { 861 while (end != 0 && Character.isWhitespace(str.charAt(end - 1))) { 862 end--; 863 } 864 } else if (stripChars.isEmpty()) { 865 return str; 866 } else { 867 while (end != 0 && stripChars.indexOf(str.charAt(end - 1)) != INDEX_NOT_FOUND) { 868 end--; 869 } 870 } 871 return str.substring(0, end); 872 } 873 874 // StripAll 875 //----------------------------------------------------------------------- 876 /** 877 * <p>Strips whitespace from the start and end of every String in an array. 878 * Whitespace is defined by {@link Character#isWhitespace(char)}.</p> 879 * 880 * <p>A new array is returned each time, except for length zero. 881 * A {@code null} array will return {@code null}. 882 * An empty array will return itself. 883 * A {@code null} array entry will be ignored.</p> 884 * 885 * <pre> 886 * StringUtils.stripAll(null) = null 887 * StringUtils.stripAll([]) = [] 888 * StringUtils.stripAll(["abc", " abc"]) = ["abc", "abc"] 889 * StringUtils.stripAll(["abc ", null]) = ["abc", null] 890 * </pre> 891 * 892 * @param strs the array to remove whitespace from, may be null 893 * @return the stripped Strings, {@code null} if null array input 894 */ 895 public static String[] stripAll(final String... strs) { 896 return stripAll(strs, null); 897 } 898 899 /** 900 * <p>Strips any of a set of characters from the start and end of every 901 * String in an array.</p> 902 * <p>Whitespace is defined by {@link Character#isWhitespace(char)}.</p> 903 * 904 * <p>A new array is returned each time, except for length zero. 905 * A {@code null} array will return {@code null}. 906 * An empty array will return itself. 907 * A {@code null} array entry will be ignored. 908 * A {@code null} stripChars will strip whitespace as defined by 909 * {@link Character#isWhitespace(char)}.</p> 910 * 911 * <pre> 912 * StringUtils.stripAll(null, *) = null 913 * StringUtils.stripAll([], *) = [] 914 * StringUtils.stripAll(["abc", " abc"], null) = ["abc", "abc"] 915 * StringUtils.stripAll(["abc ", null], null) = ["abc", null] 916 * StringUtils.stripAll(["abc ", null], "yz") = ["abc ", null] 917 * StringUtils.stripAll(["yabcz", null], "yz") = ["abc", null] 918 * </pre> 919 * 920 * @param strs the array to remove characters from, may be null 921 * @param stripChars the characters to remove, null treated as whitespace 922 * @return the stripped Strings, {@code null} if null array input 923 */ 924 public static String[] stripAll(final String[] strs, final String stripChars) { 925 int strsLen; 926 if (strs == null || (strsLen = strs.length) == 0) { 927 return strs; 928 } 929 final String[] newArr = new String[strsLen]; 930 for (int i = 0; i < strsLen; i++) { 931 newArr[i] = strip(strs[i], stripChars); 932 } 933 return newArr; 934 } 935 936 /** 937 * <p>Removes diacritics (~= accents) from a string. The case will not be altered.</p> 938 * <p>For instance, 'à' will be replaced by 'a'.</p> 939 * <p>Note that ligatures will be left as is.</p> 940 * 941 * <pre> 942 * StringUtils.stripAccents(null) = null 943 * StringUtils.stripAccents("") = "" 944 * StringUtils.stripAccents("control") = "control" 945 * StringUtils.stripAccents("éclair") = "eclair" 946 * </pre> 947 * 948 * @param input String to be stripped 949 * @return input text with diacritics removed 950 * 951 * @since 3.0 952 */ 953 // 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). 954 public static String stripAccents(final String input) { 955 if(input == null) { 956 return null; 957 } 958 final Pattern pattern = Pattern.compile("\\p{InCombiningDiacriticalMarks}+");//$NON-NLS-1$ 959 final StringBuilder decomposed = new StringBuilder(Normalizer.normalize(input, Normalizer.Form.NFD)); 960 convertRemainingAccentCharacters(decomposed); 961 // Note that this doesn't correctly remove ligatures... 962 return pattern.matcher(decomposed).replaceAll(EMPTY); 963 } 964 965 private static void convertRemainingAccentCharacters(final StringBuilder decomposed) { 966 for (int i = 0; i < decomposed.length(); i++) { 967 if (decomposed.charAt(i) == '\u0141') { 968 decomposed.deleteCharAt(i); 969 decomposed.insert(i, 'L'); 970 } else if (decomposed.charAt(i) == '\u0142') { 971 decomposed.deleteCharAt(i); 972 decomposed.insert(i, 'l'); 973 } 974 } 975 } 976 977 // Equals 978 //----------------------------------------------------------------------- 979 /** 980 * <p>Compares two CharSequences, returning {@code true} if they represent 981 * equal sequences of characters.</p> 982 * 983 * <p>{@code null}s are handled without exceptions. Two {@code null} 984 * references are considered to be equal. The comparison is case sensitive.</p> 985 * 986 * <pre> 987 * StringUtils.equals(null, null) = true 988 * StringUtils.equals(null, "abc") = false 989 * StringUtils.equals("abc", null) = false 990 * StringUtils.equals("abc", "abc") = true 991 * StringUtils.equals("abc", "ABC") = false 992 * </pre> 993 * 994 * @see Object#equals(Object) 995 * @param cs1 the first CharSequence, may be {@code null} 996 * @param cs2 the second CharSequence, may be {@code null} 997 * @return {@code true} if the CharSequences are equal (case-sensitive), or both {@code null} 998 * @since 3.0 Changed signature from equals(String, String) to equals(CharSequence, CharSequence) 999 */ 1000 public static boolean equals(final CharSequence cs1, final CharSequence cs2) { 1001 if (cs1 == cs2) { 1002 return true; 1003 } 1004 if (cs1 == null || cs2 == null) { 1005 return false; 1006 } 1007 if (cs1.length() != cs2.length()) { 1008 return false; 1009 } 1010 if (cs1 instanceof String && cs2 instanceof String) { 1011 return cs1.equals(cs2); 1012 } 1013 return CharSequenceUtils.regionMatches(cs1, false, 0, cs2, 0, cs1.length()); 1014 } 1015 1016 /** 1017 * <p>Compares two CharSequences, returning {@code true} if they represent 1018 * equal sequences of characters, ignoring case.</p> 1019 * 1020 * <p>{@code null}s are handled without exceptions. Two {@code null} 1021 * references are considered equal. Comparison is case insensitive.</p> 1022 * 1023 * <pre> 1024 * StringUtils.equalsIgnoreCase(null, null) = true 1025 * StringUtils.equalsIgnoreCase(null, "abc") = false 1026 * StringUtils.equalsIgnoreCase("abc", null) = false 1027 * StringUtils.equalsIgnoreCase("abc", "abc") = true 1028 * StringUtils.equalsIgnoreCase("abc", "ABC") = true 1029 * </pre> 1030 * 1031 * @param str1 the first CharSequence, may be null 1032 * @param str2 the second CharSequence, may be null 1033 * @return {@code true} if the CharSequence are equal, case insensitive, or 1034 * both {@code null} 1035 * @since 3.0 Changed signature from equalsIgnoreCase(String, String) to equalsIgnoreCase(CharSequence, CharSequence) 1036 */ 1037 public static boolean equalsIgnoreCase(final CharSequence str1, final CharSequence str2) { 1038 if (str1 == null || str2 == null) { 1039 return str1 == str2; 1040 } else if (str1 == str2) { 1041 return true; 1042 } else if (str1.length() != str2.length()) { 1043 return false; 1044 } else { 1045 return CharSequenceUtils.regionMatches(str1, true, 0, str2, 0, str1.length()); 1046 } 1047 } 1048 1049 // Compare 1050 //----------------------------------------------------------------------- 1051 /** 1052 * <p>Compare two Strings lexicographically, as per {@link String#compareTo(String)}, returning :</p> 1053 * <ul> 1054 * <li>{@code int = 0}, if {@code str1} is equal to {@code str2} (or both {@code null})</li> 1055 * <li>{@code int < 0}, if {@code str1} is less than {@code str2}</li> 1056 * <li>{@code int > 0}, if {@code str1} is greater than {@code str2}</li> 1057 * </ul> 1058 * 1059 * <p>This is a {@code null} safe version of :</p> 1060 * <blockquote><pre>str1.compareTo(str2)</pre></blockquote> 1061 * 1062 * <p>{@code null} value is considered less than non-{@code null} value. 1063 * Two {@code null} references are considered equal.</p> 1064 * 1065 * <pre> 1066 * StringUtils.compare(null, null) = 0 1067 * StringUtils.compare(null , "a") < 0 1068 * StringUtils.compare("a", null) > 0 1069 * StringUtils.compare("abc", "abc") = 0 1070 * StringUtils.compare("a", "b") < 0 1071 * StringUtils.compare("b", "a") > 0 1072 * StringUtils.compare("a", "B") > 0 1073 * StringUtils.compare("ab", "abc") < 0 1074 * </pre> 1075 * 1076 * @see #compare(String, String, boolean) 1077 * @see String#compareTo(String) 1078 * @param str1 the String to compare from 1079 * @param str2 the String to compare to 1080 * @return < 0, 0, > 0, if {@code str1} is respectively less, equal or greater than {@code str2} 1081 * @since 3.5 1082 */ 1083 public static int compare(final String str1, final String str2) { 1084 return compare(str1, str2, true); 1085 } 1086 1087 /** 1088 * <p>Compare two Strings lexicographically, as per {@link String#compareTo(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.compareTo(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.</p> 1100 * 1101 * <pre> 1102 * StringUtils.compare(null, null, *) = 0 1103 * StringUtils.compare(null , "a", true) < 0 1104 * StringUtils.compare(null , "a", false) > 0 1105 * StringUtils.compare("a", null, true) > 0 1106 * StringUtils.compare("a", null, false) < 0 1107 * StringUtils.compare("abc", "abc", *) = 0 1108 * StringUtils.compare("a", "b", *) < 0 1109 * StringUtils.compare("b", "a", *) > 0 1110 * StringUtils.compare("a", "B", *) > 0 1111 * StringUtils.compare("ab", "abc", *) < 0 1112 * </pre> 1113 * 1114 * @see String#compareTo(String) 1115 * @param str1 the String to compare from 1116 * @param str2 the String to compare to 1117 * @param nullIsLess whether consider {@code null} value less than non-{@code null} value 1118 * @return < 0, 0, > 0, if {@code str1} is respectively less, equal ou greater than {@code str2} 1119 * @since 3.5 1120 */ 1121 public static int compare(final String str1, final String str2, final boolean nullIsLess) { 1122 if (str1 == str2) { 1123 return 0; 1124 } 1125 if (str1 == null) { 1126 return nullIsLess ? -1 : 1; 1127 } 1128 if (str2 == null) { 1129 return nullIsLess ? 1 : - 1; 1130 } 1131 return str1.compareTo(str2); 1132 } 1133 1134 /** 1135 * <p>Compare two Strings lexicographically, ignoring case differences, 1136 * as per {@link String#compareToIgnoreCase(String)}, returning :</p> 1137 * <ul> 1138 * <li>{@code int = 0}, if {@code str1} is equal to {@code str2} (or both {@code null})</li> 1139 * <li>{@code int < 0}, if {@code str1} is less than {@code str2}</li> 1140 * <li>{@code int > 0}, if {@code str1} is greater than {@code str2}</li> 1141 * </ul> 1142 * 1143 * <p>This is a {@code null} safe version of :</p> 1144 * <blockquote><pre>str1.compareToIgnoreCase(str2)</pre></blockquote> 1145 * 1146 * <p>{@code null} value is considered less than non-{@code null} value. 1147 * Two {@code null} references are considered equal. 1148 * Comparison is case insensitive.</p> 1149 * 1150 * <pre> 1151 * StringUtils.compareIgnoreCase(null, null) = 0 1152 * StringUtils.compareIgnoreCase(null , "a") < 0 1153 * StringUtils.compareIgnoreCase("a", null) > 0 1154 * StringUtils.compareIgnoreCase("abc", "abc") = 0 1155 * StringUtils.compareIgnoreCase("abc", "ABC") = 0 1156 * StringUtils.compareIgnoreCase("a", "b") < 0 1157 * StringUtils.compareIgnoreCase("b", "a") > 0 1158 * StringUtils.compareIgnoreCase("a", "B") < 0 1159 * StringUtils.compareIgnoreCase("A", "b") < 0 1160 * StringUtils.compareIgnoreCase("ab", "ABC") < 0 1161 * </pre> 1162 * 1163 * @see #compareIgnoreCase(String, String, boolean) 1164 * @see String#compareToIgnoreCase(String) 1165 * @param str1 the String to compare from 1166 * @param str2 the String to compare to 1167 * @return < 0, 0, > 0, if {@code str1} is respectively less, equal ou greater than {@code str2}, 1168 * ignoring case differences. 1169 * @since 3.5 1170 */ 1171 public static int compareIgnoreCase(final String str1, final String str2) { 1172 return compareIgnoreCase(str1, str2, true); 1173 } 1174 1175 /** 1176 * <p>Compare two Strings lexicographically, ignoring case differences, 1177 * as per {@link String#compareToIgnoreCase(String)}, returning :</p> 1178 * <ul> 1179 * <li>{@code int = 0}, if {@code str1} is equal to {@code str2} (or both {@code null})</li> 1180 * <li>{@code int < 0}, if {@code str1} is less than {@code str2}</li> 1181 * <li>{@code int > 0}, if {@code str1} is greater than {@code str2}</li> 1182 * </ul> 1183 * 1184 * <p>This is a {@code null} safe version of :</p> 1185 * <blockquote><pre>str1.compareToIgnoreCase(str2)</pre></blockquote> 1186 * 1187 * <p>{@code null} inputs are handled according to the {@code nullIsLess} parameter. 1188 * Two {@code null} references are considered equal. 1189 * Comparison is case insensitive.</p> 1190 * 1191 * <pre> 1192 * StringUtils.compareIgnoreCase(null, null, *) = 0 1193 * StringUtils.compareIgnoreCase(null , "a", true) < 0 1194 * StringUtils.compareIgnoreCase(null , "a", false) > 0 1195 * StringUtils.compareIgnoreCase("a", null, true) > 0 1196 * StringUtils.compareIgnoreCase("a", null, false) < 0 1197 * StringUtils.compareIgnoreCase("abc", "abc", *) = 0 1198 * StringUtils.compareIgnoreCase("abc", "ABC", *) = 0 1199 * StringUtils.compareIgnoreCase("a", "b", *) < 0 1200 * StringUtils.compareIgnoreCase("b", "a", *) > 0 1201 * StringUtils.compareIgnoreCase("a", "B", *) < 0 1202 * StringUtils.compareIgnoreCase("A", "b", *) < 0 1203 * StringUtils.compareIgnoreCase("ab", "abc", *) < 0 1204 * </pre> 1205 * 1206 * @see String#compareToIgnoreCase(String) 1207 * @param str1 the String to compare from 1208 * @param str2 the String to compare to 1209 * @param nullIsLess whether consider {@code null} value less than non-{@code null} value 1210 * @return < 0, 0, > 0, if {@code str1} is respectively less, equal ou greater than {@code str2}, 1211 * ignoring case differences. 1212 * @since 3.5 1213 */ 1214 public static int compareIgnoreCase(final String str1, final String str2, final boolean nullIsLess) { 1215 if (str1 == str2) { 1216 return 0; 1217 } 1218 if (str1 == null) { 1219 return nullIsLess ? -1 : 1; 1220 } 1221 if (str2 == null) { 1222 return nullIsLess ? 1 : - 1; 1223 } 1224 return str1.compareToIgnoreCase(str2); 1225 } 1226 1227 /** 1228 * <p>Compares given <code>string</code> to a CharSequences vararg of <code>searchStrings</code>, 1229 * returning {@code true} if the <code>string</code> is equal to any of the <code>searchStrings</code>.</p> 1230 * 1231 * <pre> 1232 * StringUtils.equalsAny(null, (CharSequence[]) null) = false 1233 * StringUtils.equalsAny(null, null, null) = true 1234 * StringUtils.equalsAny(null, "abc", "def") = false 1235 * StringUtils.equalsAny("abc", null, "def") = false 1236 * StringUtils.equalsAny("abc", "abc", "def") = true 1237 * StringUtils.equalsAny("abc", "ABC", "DEF") = false 1238 * </pre> 1239 * 1240 * @param string to compare, may be {@code null}. 1241 * @param searchStrings a vararg of strings, may be {@code null}. 1242 * @return {@code true} if the string is equal (case-sensitive) to any other element of <code>searchStrings</code>; 1243 * {@code false} if <code>searchStrings</code> is null or contains no matches. 1244 * @since 3.5 1245 */ 1246 public static boolean equalsAny(final CharSequence string, final CharSequence... searchStrings) { 1247 if (ArrayUtils.isNotEmpty(searchStrings)) { 1248 for (final CharSequence next : searchStrings) { 1249 if (equals(string, next)) { 1250 return true; 1251 } 1252 } 1253 } 1254 return false; 1255 } 1256 1257 1258 /** 1259 * <p>Compares given <code>string</code> to a CharSequences vararg of <code>searchStrings</code>, 1260 * returning {@code true} if the <code>string</code> is equal to any of the <code>searchStrings</code>, ignoring case.</p> 1261 * 1262 * <pre> 1263 * StringUtils.equalsAnyIgnoreCase(null, (CharSequence[]) null) = false 1264 * StringUtils.equalsAnyIgnoreCase(null, null, null) = true 1265 * StringUtils.equalsAnyIgnoreCase(null, "abc", "def") = false 1266 * StringUtils.equalsAnyIgnoreCase("abc", null, "def") = false 1267 * StringUtils.equalsAnyIgnoreCase("abc", "abc", "def") = true 1268 * StringUtils.equalsAnyIgnoreCase("abc", "ABC", "DEF") = true 1269 * </pre> 1270 * 1271 * @param string to compare, may be {@code null}. 1272 * @param searchStrings a vararg of strings, may be {@code null}. 1273 * @return {@code true} if the string is equal (case-insensitive) to any other element of <code>searchStrings</code>; 1274 * {@code false} if <code>searchStrings</code> is null or contains no matches. 1275 * @since 3.5 1276 */ 1277 public static boolean equalsAnyIgnoreCase(final CharSequence string, final CharSequence...searchStrings) { 1278 if (ArrayUtils.isNotEmpty(searchStrings)) { 1279 for (final CharSequence next : searchStrings) { 1280 if (equalsIgnoreCase(string, next)) { 1281 return true; 1282 } 1283 } 1284 } 1285 return false; 1286 } 1287 1288 // IndexOf 1289 //----------------------------------------------------------------------- 1290 /** 1291 * Returns the index within <code>seq</code> of the first occurrence of 1292 * the specified character. If a character with value 1293 * <code>searchChar</code> occurs in the character sequence represented by 1294 * <code>seq</code> <code>CharSequence</code> object, then the index (in Unicode 1295 * code units) of the first such occurrence is returned. For 1296 * values of <code>searchChar</code> in the range from 0 to 0xFFFF 1297 * (inclusive), this is the smallest value <i>k</i> such that: 1298 * <blockquote><pre> 1299 * this.charAt(<i>k</i>) == searchChar 1300 * </pre></blockquote> 1301 * is true. For other values of <code>searchChar</code>, it is the 1302 * smallest value <i>k</i> such that: 1303 * <blockquote><pre> 1304 * this.codePointAt(<i>k</i>) == searchChar 1305 * </pre></blockquote> 1306 * is true. In either case, if no such character occurs in <code>seq</code>, 1307 * then {@code INDEX_NOT_FOUND (-1)} is returned. 1308 * 1309 * <p>Furthermore, a {@code null} or empty ("") CharSequence will 1310 * return {@code INDEX_NOT_FOUND (-1)}.</p> 1311 * 1312 * <pre> 1313 * StringUtils.indexOf(null, *) = -1 1314 * StringUtils.indexOf("", *) = -1 1315 * StringUtils.indexOf("aabaabaa", 'a') = 0 1316 * StringUtils.indexOf("aabaabaa", 'b') = 2 1317 * </pre> 1318 * 1319 * @param seq the CharSequence to check, may be null 1320 * @param searchChar the character to find 1321 * @return the first index of the search character, 1322 * -1 if no match or {@code null} string input 1323 * @since 2.0 1324 * @since 3.0 Changed signature from indexOf(String, int) to indexOf(CharSequence, int) 1325 * @since 3.6 Updated {@link CharSequenceUtils} call to behave more like <code>String</code> 1326 */ 1327 public static int indexOf(final CharSequence seq, final int searchChar) { 1328 if (isEmpty(seq)) { 1329 return INDEX_NOT_FOUND; 1330 } 1331 return CharSequenceUtils.indexOf(seq, searchChar, 0); 1332 } 1333 1334 /** 1335 * 1336 * Returns the index within <code>seq</code> of the first occurrence of the 1337 * specified character, starting the search at the specified index. 1338 * <p> 1339 * If a character with value <code>searchChar</code> occurs in the 1340 * character sequence represented by the <code>seq</code> <code>CharSequence</code> 1341 * object at an index no smaller than <code>startPos</code>, then 1342 * the index of the first such occurrence is returned. For values 1343 * of <code>searchChar</code> in the range from 0 to 0xFFFF (inclusive), 1344 * this is the smallest value <i>k</i> such that: 1345 * <blockquote><pre> 1346 * (this.charAt(<i>k</i>) == searchChar) && (<i>k</i> >= startPos) 1347 * </pre></blockquote> 1348 * is true. For other values of <code>searchChar</code>, it is the 1349 * smallest value <i>k</i> such that: 1350 * <blockquote><pre> 1351 * (this.codePointAt(<i>k</i>) == searchChar) && (<i>k</i> >= startPos) 1352 * </pre></blockquote> 1353 * is true. In either case, if no such character occurs in <code>seq</code> 1354 * at or after position <code>startPos</code>, then 1355 * <code>-1</code> is returned. 1356 * 1357 * <p> 1358 * There is no restriction on the value of <code>startPos</code>. If it 1359 * is negative, it has the same effect as if it were zero: this entire 1360 * string may be searched. If it is greater than the length of this 1361 * string, it has the same effect as if it were equal to the length of 1362 * this string: {@code (INDEX_NOT_FOUND) -1} is returned. Furthermore, a 1363 * {@code null} or empty ("") CharSequence will 1364 * return {@code (INDEX_NOT_FOUND) -1}. 1365 * 1366 * <p>All indices are specified in <code>char</code> values 1367 * (Unicode code units). 1368 * 1369 * <pre> 1370 * StringUtils.indexOf(null, *, *) = -1 1371 * StringUtils.indexOf("", *, *) = -1 1372 * StringUtils.indexOf("aabaabaa", 'b', 0) = 2 1373 * StringUtils.indexOf("aabaabaa", 'b', 3) = 5 1374 * StringUtils.indexOf("aabaabaa", 'b', 9) = -1 1375 * StringUtils.indexOf("aabaabaa", 'b', -1) = 2 1376 * </pre> 1377 * 1378 * @param seq the CharSequence to check, may be null 1379 * @param searchChar the character to find 1380 * @param startPos the start position, negative treated as zero 1381 * @return the first index of the search character (always ≥ startPos), 1382 * -1 if no match or {@code null} string input 1383 * @since 2.0 1384 * @since 3.0 Changed signature from indexOf(String, int, int) to indexOf(CharSequence, int, int) 1385 * @since 3.6 Updated {@link CharSequenceUtils} call to behave more like <code>String</code> 1386 */ 1387 public static int indexOf(final CharSequence seq, final int searchChar, final int startPos) { 1388 if (isEmpty(seq)) { 1389 return INDEX_NOT_FOUND; 1390 } 1391 return CharSequenceUtils.indexOf(seq, searchChar, startPos); 1392 } 1393 1394 /** 1395 * <p>Finds the first index within a CharSequence, handling {@code null}. 1396 * This method uses {@link String#indexOf(String, int)} if possible.</p> 1397 * 1398 * <p>A {@code null} CharSequence will return {@code -1}.</p> 1399 * 1400 * <pre> 1401 * StringUtils.indexOf(null, *) = -1 1402 * StringUtils.indexOf(*, null) = -1 1403 * StringUtils.indexOf("", "") = 0 1404 * StringUtils.indexOf("", *) = -1 (except when * = "") 1405 * StringUtils.indexOf("aabaabaa", "a") = 0 1406 * StringUtils.indexOf("aabaabaa", "b") = 2 1407 * StringUtils.indexOf("aabaabaa", "ab") = 1 1408 * StringUtils.indexOf("aabaabaa", "") = 0 1409 * </pre> 1410 * 1411 * @param seq the CharSequence to check, may be null 1412 * @param searchSeq the CharSequence to find, may be null 1413 * @return the first index of the search CharSequence, 1414 * -1 if no match or {@code null} string input 1415 * @since 2.0 1416 * @since 3.0 Changed signature from indexOf(String, String) to indexOf(CharSequence, CharSequence) 1417 */ 1418 public static int indexOf(final CharSequence seq, final CharSequence searchSeq) { 1419 if (seq == null || searchSeq == null) { 1420 return INDEX_NOT_FOUND; 1421 } 1422 return CharSequenceUtils.indexOf(seq, searchSeq, 0); 1423 } 1424 1425 /** 1426 * <p>Finds the first index within a CharSequence, handling {@code null}. 1427 * This method uses {@link String#indexOf(String, int)} if possible.</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.indexOf(null, *, *) = -1 1437 * StringUtils.indexOf(*, null, *) = -1 1438 * StringUtils.indexOf("", "", 0) = 0 1439 * StringUtils.indexOf("", *, 0) = -1 (except when * = "") 1440 * StringUtils.indexOf("aabaabaa", "a", 0) = 0 1441 * StringUtils.indexOf("aabaabaa", "b", 0) = 2 1442 * StringUtils.indexOf("aabaabaa", "ab", 0) = 1 1443 * StringUtils.indexOf("aabaabaa", "b", 3) = 5 1444 * StringUtils.indexOf("aabaabaa", "b", 9) = -1 1445 * StringUtils.indexOf("aabaabaa", "b", -1) = 2 1446 * StringUtils.indexOf("aabaabaa", "", 2) = 2 1447 * StringUtils.indexOf("abc", "", 9) = 3 1448 * </pre> 1449 * 1450 * @param seq the CharSequence to check, may be null 1451 * @param searchSeq the CharSequence to find, may be null 1452 * @param startPos the start position, negative treated as zero 1453 * @return the first index of the search CharSequence (always ≥ startPos), 1454 * -1 if no match or {@code null} string input 1455 * @since 2.0 1456 * @since 3.0 Changed signature from indexOf(String, String, int) to indexOf(CharSequence, CharSequence, int) 1457 */ 1458 public static int indexOf(final CharSequence seq, final CharSequence searchSeq, final int startPos) { 1459 if (seq == null || searchSeq == null) { 1460 return INDEX_NOT_FOUND; 1461 } 1462 return CharSequenceUtils.indexOf(seq, searchSeq, startPos); 1463 } 1464 1465 /** 1466 * <p>Finds the n-th index within a CharSequence, handling {@code null}. 1467 * This method uses {@link String#indexOf(String)} if possible.</p> 1468 * <p><b>Note:</b> The code starts looking for a match at the start of the target, 1469 * incrementing the starting index by one after each successful match 1470 * (unless {@code searchStr} is an empty string in which case the position 1471 * is never incremented and {@code 0} is returned immediately). 1472 * This means that matches may overlap.</p> 1473 * <p>A {@code null} CharSequence will return {@code -1}.</p> 1474 * 1475 * <pre> 1476 * StringUtils.ordinalIndexOf(null, *, *) = -1 1477 * StringUtils.ordinalIndexOf(*, null, *) = -1 1478 * StringUtils.ordinalIndexOf("", "", *) = 0 1479 * StringUtils.ordinalIndexOf("aabaabaa", "a", 1) = 0 1480 * StringUtils.ordinalIndexOf("aabaabaa", "a", 2) = 1 1481 * StringUtils.ordinalIndexOf("aabaabaa", "b", 1) = 2 1482 * StringUtils.ordinalIndexOf("aabaabaa", "b", 2) = 5 1483 * StringUtils.ordinalIndexOf("aabaabaa", "ab", 1) = 1 1484 * StringUtils.ordinalIndexOf("aabaabaa", "ab", 2) = 4 1485 * StringUtils.ordinalIndexOf("aabaabaa", "", 1) = 0 1486 * StringUtils.ordinalIndexOf("aabaabaa", "", 2) = 0 1487 * </pre> 1488 * 1489 * <p>Matches may overlap:</p> 1490 * <pre> 1491 * StringUtils.ordinalIndexOf("ababab","aba", 1) = 0 1492 * StringUtils.ordinalIndexOf("ababab","aba", 2) = 2 1493 * StringUtils.ordinalIndexOf("ababab","aba", 3) = -1 1494 * 1495 * StringUtils.ordinalIndexOf("abababab", "abab", 1) = 0 1496 * StringUtils.ordinalIndexOf("abababab", "abab", 2) = 2 1497 * StringUtils.ordinalIndexOf("abababab", "abab", 3) = 4 1498 * StringUtils.ordinalIndexOf("abababab", "abab", 4) = -1 1499 * </pre> 1500 * 1501 * <p>Note that 'head(CharSequence str, int n)' may be implemented as: </p> 1502 * 1503 * <pre> 1504 * str.substring(0, lastOrdinalIndexOf(str, "\n", n)) 1505 * </pre> 1506 * 1507 * @param str the CharSequence to check, may be null 1508 * @param searchStr the CharSequence to find, may be null 1509 * @param ordinal the n-th {@code searchStr} to find 1510 * @return the n-th index of the search CharSequence, 1511 * {@code -1} ({@code INDEX_NOT_FOUND}) if no match or {@code null} string input 1512 * @since 2.1 1513 * @since 3.0 Changed signature from ordinalIndexOf(String, String, int) to ordinalIndexOf(CharSequence, CharSequence, int) 1514 */ 1515 public static int ordinalIndexOf(final CharSequence str, final CharSequence searchStr, final int ordinal) { 1516 return ordinalIndexOf(str, searchStr, ordinal, false); 1517 } 1518 1519 /** 1520 * <p>Finds the n-th index within a String, handling {@code null}. 1521 * This method uses {@link String#indexOf(String)} if possible.</p> 1522 * <p>Note that matches may overlap<p> 1523 * 1524 * <p>A {@code null} CharSequence will return {@code -1}.</p> 1525 * 1526 * @param str the CharSequence to check, may be null 1527 * @param searchStr the CharSequence to find, may be null 1528 * @param ordinal the n-th {@code searchStr} to find, overlapping matches are allowed. 1529 * @param lastIndex true if lastOrdinalIndexOf() otherwise false if ordinalIndexOf() 1530 * @return the n-th index of the search CharSequence, 1531 * {@code -1} ({@code INDEX_NOT_FOUND}) if no match or {@code null} string input 1532 */ 1533 // Shared code between ordinalIndexOf(String,String,int) and lastOrdinalIndexOf(String,String,int) 1534 private static int ordinalIndexOf(final CharSequence str, final CharSequence searchStr, final int ordinal, final boolean lastIndex) { 1535 if (str == null || searchStr == null || ordinal <= 0) { 1536 return INDEX_NOT_FOUND; 1537 } 1538 if (searchStr.length() == 0) { 1539 return lastIndex ? str.length() : 0; 1540 } 1541 int found = 0; 1542 // set the initial index beyond the end of the string 1543 // this is to allow for the initial index decrement/increment 1544 int index = lastIndex ? str.length() : INDEX_NOT_FOUND; 1545 do { 1546 if (lastIndex) { 1547 index = CharSequenceUtils.lastIndexOf(str, searchStr, index - 1); // step backwards thru string 1548 } else { 1549 index = CharSequenceUtils.indexOf(str, searchStr, index + 1); // step forwards through string 1550 } 1551 if (index < 0) { 1552 return index; 1553 } 1554 found++; 1555 } while (found < ordinal); 1556 return index; 1557 } 1558 1559 /** 1560 * <p>Case in-sensitive find of the first index within a CharSequence.</p> 1561 * 1562 * <p>A {@code null} CharSequence will return {@code -1}. 1563 * A negative start position is treated as zero. 1564 * An empty ("") search CharSequence always matches. 1565 * A start position greater than the string length only matches 1566 * an empty search CharSequence.</p> 1567 * 1568 * <pre> 1569 * StringUtils.indexOfIgnoreCase(null, *) = -1 1570 * StringUtils.indexOfIgnoreCase(*, null) = -1 1571 * StringUtils.indexOfIgnoreCase("", "") = 0 1572 * StringUtils.indexOfIgnoreCase("aabaabaa", "a") = 0 1573 * StringUtils.indexOfIgnoreCase("aabaabaa", "b") = 2 1574 * StringUtils.indexOfIgnoreCase("aabaabaa", "ab") = 1 1575 * </pre> 1576 * 1577 * @param str the CharSequence to check, may be null 1578 * @param searchStr the CharSequence to find, may be null 1579 * @return the first index of the search CharSequence, 1580 * -1 if no match or {@code null} string input 1581 * @since 2.5 1582 * @since 3.0 Changed signature from indexOfIgnoreCase(String, String) to indexOfIgnoreCase(CharSequence, CharSequence) 1583 */ 1584 public static int indexOfIgnoreCase(final CharSequence str, final CharSequence searchStr) { 1585 return indexOfIgnoreCase(str, searchStr, 0); 1586 } 1587 1588 /** 1589 * <p>Case in-sensitive find of the first index within a CharSequence 1590 * from the specified position.</p> 1591 * 1592 * <p>A {@code null} CharSequence will return {@code -1}. 1593 * A negative start position is treated as zero. 1594 * An empty ("") search CharSequence always matches. 1595 * A start position greater than the string length only matches 1596 * an empty search CharSequence.</p> 1597 * 1598 * <pre> 1599 * StringUtils.indexOfIgnoreCase(null, *, *) = -1 1600 * StringUtils.indexOfIgnoreCase(*, null, *) = -1 1601 * StringUtils.indexOfIgnoreCase("", "", 0) = 0 1602 * StringUtils.indexOfIgnoreCase("aabaabaa", "A", 0) = 0 1603 * StringUtils.indexOfIgnoreCase("aabaabaa", "B", 0) = 2 1604 * StringUtils.indexOfIgnoreCase("aabaabaa", "AB", 0) = 1 1605 * StringUtils.indexOfIgnoreCase("aabaabaa", "B", 3) = 5 1606 * StringUtils.indexOfIgnoreCase("aabaabaa", "B", 9) = -1 1607 * StringUtils.indexOfIgnoreCase("aabaabaa", "B", -1) = 2 1608 * StringUtils.indexOfIgnoreCase("aabaabaa", "", 2) = 2 1609 * StringUtils.indexOfIgnoreCase("abc", "", 9) = -1 1610 * </pre> 1611 * 1612 * @param str the CharSequence to check, may be null 1613 * @param searchStr the CharSequence to find, may be null 1614 * @param startPos the start position, negative treated as zero 1615 * @return the first index of the search CharSequence (always ≥ startPos), 1616 * -1 if no match or {@code null} string input 1617 * @since 2.5 1618 * @since 3.0 Changed signature from indexOfIgnoreCase(String, String, int) to indexOfIgnoreCase(CharSequence, CharSequence, int) 1619 */ 1620 public static int indexOfIgnoreCase(final CharSequence str, final CharSequence searchStr, int startPos) { 1621 if (str == null || searchStr == null) { 1622 return INDEX_NOT_FOUND; 1623 } 1624 if (startPos < 0) { 1625 startPos = 0; 1626 } 1627 final int endLimit = str.length() - searchStr.length() + 1; 1628 if (startPos > endLimit) { 1629 return INDEX_NOT_FOUND; 1630 } 1631 if (searchStr.length() == 0) { 1632 return startPos; 1633 } 1634 for (int i = startPos; i < endLimit; i++) { 1635 if (CharSequenceUtils.regionMatches(str, true, i, searchStr, 0, searchStr.length())) { 1636 return i; 1637 } 1638 } 1639 return INDEX_NOT_FOUND; 1640 } 1641 1642 // LastIndexOf 1643 //----------------------------------------------------------------------- 1644 /** 1645 * Returns the index within <code>seq</code> of the last occurrence of 1646 * the specified character. For values of <code>searchChar</code> in the 1647 * range from 0 to 0xFFFF (inclusive), the index (in Unicode code 1648 * units) returned is the largest value <i>k</i> such that: 1649 * <blockquote><pre> 1650 * this.charAt(<i>k</i>) == searchChar 1651 * </pre></blockquote> 1652 * is true. For other values of <code>searchChar</code>, it is the 1653 * largest value <i>k</i> such that: 1654 * <blockquote><pre> 1655 * this.codePointAt(<i>k</i>) == searchChar 1656 * </pre></blockquote> 1657 * is true. In either case, if no such character occurs in this 1658 * string, then <code>-1</code> is returned. Furthermore, a {@code null} or empty ("") 1659 * <code>CharSequence</code> will return {@code -1}. The 1660 * <code>seq</code> <code>CharSequence</code> object is searched backwards 1661 * starting at the last character. 1662 * 1663 * <pre> 1664 * StringUtils.lastIndexOf(null, *) = -1 1665 * StringUtils.lastIndexOf("", *) = -1 1666 * StringUtils.lastIndexOf("aabaabaa", 'a') = 7 1667 * StringUtils.lastIndexOf("aabaabaa", 'b') = 5 1668 * </pre> 1669 * 1670 * @param seq the <code>CharSequence</code> to check, may be null 1671 * @param searchChar the character to find 1672 * @return the last index of the search character, 1673 * -1 if no match or {@code null} string input 1674 * @since 2.0 1675 * @since 3.0 Changed signature from lastIndexOf(String, int) to lastIndexOf(CharSequence, int) 1676 * @since 3.6 Updated {@link CharSequenceUtils} call to behave more like <code>String</code> 1677 */ 1678 public static int lastIndexOf(final CharSequence seq, final int searchChar) { 1679 if (isEmpty(seq)) { 1680 return INDEX_NOT_FOUND; 1681 } 1682 return CharSequenceUtils.lastIndexOf(seq, searchChar, seq.length()); 1683 } 1684 1685 /** 1686 * Returns the index within <code>seq</code> of the last occurrence of 1687 * the specified character, searching backward starting at the 1688 * specified index. For values of <code>searchChar</code> in the range 1689 * from 0 to 0xFFFF (inclusive), the index returned is the largest 1690 * value <i>k</i> such that: 1691 * <blockquote><pre> 1692 * (this.charAt(<i>k</i>) == searchChar) && (<i>k</i> <= startPos) 1693 * </pre></blockquote> 1694 * is true. For other values of <code>searchChar</code>, it is the 1695 * largest value <i>k</i> such that: 1696 * <blockquote><pre> 1697 * (this.codePointAt(<i>k</i>) == searchChar) && (<i>k</i> <= startPos) 1698 * </pre></blockquote> 1699 * is true. In either case, if no such character occurs in <code>seq</code> 1700 * at or before position <code>startPos</code>, then 1701 * <code>-1</code> is returned. Furthermore, a {@code null} or empty ("") 1702 * <code>CharSequence</code> will return {@code -1}. A start position greater 1703 * than the string length searches the whole string. 1704 * The search starts at the <code>startPos</code> and works backwards; 1705 * matches starting after the start position are ignored. 1706 * 1707 * <p>All indices are specified in <code>char</code> values 1708 * (Unicode code units). 1709 * 1710 * <pre> 1711 * StringUtils.lastIndexOf(null, *, *) = -1 1712 * StringUtils.lastIndexOf("", *, *) = -1 1713 * StringUtils.lastIndexOf("aabaabaa", 'b', 8) = 5 1714 * StringUtils.lastIndexOf("aabaabaa", 'b', 4) = 2 1715 * StringUtils.lastIndexOf("aabaabaa", 'b', 0) = -1 1716 * StringUtils.lastIndexOf("aabaabaa", 'b', 9) = 5 1717 * StringUtils.lastIndexOf("aabaabaa", 'b', -1) = -1 1718 * StringUtils.lastIndexOf("aabaabaa", 'a', 0) = 0 1719 * </pre> 1720 * 1721 * @param seq the CharSequence to check, may be null 1722 * @param searchChar the character to find 1723 * @param startPos the start position 1724 * @return the last index of the search character (always ≤ startPos), 1725 * -1 if no match or {@code null} string input 1726 * @since 2.0 1727 * @since 3.0 Changed signature from lastIndexOf(String, int, int) to lastIndexOf(CharSequence, int, int) 1728 */ 1729 public static int lastIndexOf(final CharSequence seq, final int searchChar, final int startPos) { 1730 if (isEmpty(seq)) { 1731 return INDEX_NOT_FOUND; 1732 } 1733 return CharSequenceUtils.lastIndexOf(seq, searchChar, startPos); 1734 } 1735 1736 /** 1737 * <p>Finds the last index within a CharSequence, handling {@code null}. 1738 * This method uses {@link String#lastIndexOf(String)} if possible.</p> 1739 * 1740 * <p>A {@code null} CharSequence will return {@code -1}.</p> 1741 * 1742 * <pre> 1743 * StringUtils.lastIndexOf(null, *) = -1 1744 * StringUtils.lastIndexOf(*, null) = -1 1745 * StringUtils.lastIndexOf("", "") = 0 1746 * StringUtils.lastIndexOf("aabaabaa", "a") = 7 1747 * StringUtils.lastIndexOf("aabaabaa", "b") = 5 1748 * StringUtils.lastIndexOf("aabaabaa", "ab") = 4 1749 * StringUtils.lastIndexOf("aabaabaa", "") = 8 1750 * </pre> 1751 * 1752 * @param seq the CharSequence to check, may be null 1753 * @param searchSeq the CharSequence to find, may be null 1754 * @return the last index of the search String, 1755 * -1 if no match or {@code null} string input 1756 * @since 2.0 1757 * @since 3.0 Changed signature from lastIndexOf(String, String) to lastIndexOf(CharSequence, CharSequence) 1758 */ 1759 public static int lastIndexOf(final CharSequence seq, final CharSequence searchSeq) { 1760 if (seq == null || searchSeq == null) { 1761 return INDEX_NOT_FOUND; 1762 } 1763 return CharSequenceUtils.lastIndexOf(seq, searchSeq, seq.length()); 1764 } 1765 1766 /** 1767 * <p>Finds the n-th last index within a String, handling {@code null}. 1768 * This method uses {@link String#lastIndexOf(String)}.</p> 1769 * 1770 * <p>A {@code null} String will return {@code -1}.</p> 1771 * 1772 * <pre> 1773 * StringUtils.lastOrdinalIndexOf(null, *, *) = -1 1774 * StringUtils.lastOrdinalIndexOf(*, null, *) = -1 1775 * StringUtils.lastOrdinalIndexOf("", "", *) = 0 1776 * StringUtils.lastOrdinalIndexOf("aabaabaa", "a", 1) = 7 1777 * StringUtils.lastOrdinalIndexOf("aabaabaa", "a", 2) = 6 1778 * StringUtils.lastOrdinalIndexOf("aabaabaa", "b", 1) = 5 1779 * StringUtils.lastOrdinalIndexOf("aabaabaa", "b", 2) = 2 1780 * StringUtils.lastOrdinalIndexOf("aabaabaa", "ab", 1) = 4 1781 * StringUtils.lastOrdinalIndexOf("aabaabaa", "ab", 2) = 1 1782 * StringUtils.lastOrdinalIndexOf("aabaabaa", "", 1) = 8 1783 * StringUtils.lastOrdinalIndexOf("aabaabaa", "", 2) = 8 1784 * </pre> 1785 * 1786 * <p>Note that 'tail(CharSequence str, int n)' may be implemented as: </p> 1787 * 1788 * <pre> 1789 * str.substring(lastOrdinalIndexOf(str, "\n", n) + 1) 1790 * </pre> 1791 * 1792 * @param str the CharSequence to check, may be null 1793 * @param searchStr the CharSequence to find, may be null 1794 * @param ordinal the n-th last {@code searchStr} to find 1795 * @return the n-th last index of the search CharSequence, 1796 * {@code -1} ({@code INDEX_NOT_FOUND}) if no match or {@code null} string input 1797 * @since 2.5 1798 * @since 3.0 Changed signature from lastOrdinalIndexOf(String, String, int) to lastOrdinalIndexOf(CharSequence, CharSequence, int) 1799 */ 1800 public static int lastOrdinalIndexOf(final CharSequence str, final CharSequence searchStr, final int ordinal) { 1801 return ordinalIndexOf(str, searchStr, ordinal, true); 1802 } 1803 1804 /** 1805 * <p>Finds the last index within a CharSequence, handling {@code null}. 1806 * This method uses {@link String#lastIndexOf(String, int)} if possible.</p> 1807 * 1808 * <p>A {@code null} CharSequence will return {@code -1}. 1809 * A negative start position returns {@code -1}. 1810 * An empty ("") search CharSequence always matches unless the start position is negative. 1811 * A start position greater than the string length searches the whole string. 1812 * The search starts at the startPos and works backwards; matches starting after the start 1813 * position are ignored. 1814 * </p> 1815 * 1816 * <pre> 1817 * StringUtils.lastIndexOf(null, *, *) = -1 1818 * StringUtils.lastIndexOf(*, null, *) = -1 1819 * StringUtils.lastIndexOf("aabaabaa", "a", 8) = 7 1820 * StringUtils.lastIndexOf("aabaabaa", "b", 8) = 5 1821 * StringUtils.lastIndexOf("aabaabaa", "ab", 8) = 4 1822 * StringUtils.lastIndexOf("aabaabaa", "b", 9) = 5 1823 * StringUtils.lastIndexOf("aabaabaa", "b", -1) = -1 1824 * StringUtils.lastIndexOf("aabaabaa", "a", 0) = 0 1825 * StringUtils.lastIndexOf("aabaabaa", "b", 0) = -1 1826 * StringUtils.lastIndexOf("aabaabaa", "b", 1) = -1 1827 * StringUtils.lastIndexOf("aabaabaa", "b", 2) = 2 1828 * StringUtils.lastIndexOf("aabaabaa", "ba", 2) = 2 1829 * </pre> 1830 * 1831 * @param seq the CharSequence to check, may be null 1832 * @param searchSeq the CharSequence to find, may be null 1833 * @param startPos the start position, negative treated as zero 1834 * @return the last index of the search CharSequence (always ≤ startPos), 1835 * -1 if no match or {@code null} string input 1836 * @since 2.0 1837 * @since 3.0 Changed signature from lastIndexOf(String, String, int) to lastIndexOf(CharSequence, CharSequence, int) 1838 */ 1839 public static int lastIndexOf(final CharSequence seq, final CharSequence searchSeq, final int startPos) { 1840 if (seq == null || searchSeq == null) { 1841 return INDEX_NOT_FOUND; 1842 } 1843 return CharSequenceUtils.lastIndexOf(seq, searchSeq, startPos); 1844 } 1845 1846 /** 1847 * <p>Case in-sensitive find of the last index within a CharSequence.</p> 1848 * 1849 * <p>A {@code null} CharSequence will return {@code -1}. 1850 * A negative start position returns {@code -1}. 1851 * An empty ("") search CharSequence always matches unless the start position is negative. 1852 * A start position greater than the string length searches the whole string.</p> 1853 * 1854 * <pre> 1855 * StringUtils.lastIndexOfIgnoreCase(null, *) = -1 1856 * StringUtils.lastIndexOfIgnoreCase(*, null) = -1 1857 * StringUtils.lastIndexOfIgnoreCase("aabaabaa", "A") = 7 1858 * StringUtils.lastIndexOfIgnoreCase("aabaabaa", "B") = 5 1859 * StringUtils.lastIndexOfIgnoreCase("aabaabaa", "AB") = 4 1860 * </pre> 1861 * 1862 * @param str the CharSequence to check, may be null 1863 * @param searchStr the CharSequence to find, may be null 1864 * @return the first index of the search CharSequence, 1865 * -1 if no match or {@code null} string input 1866 * @since 2.5 1867 * @since 3.0 Changed signature from lastIndexOfIgnoreCase(String, String) to lastIndexOfIgnoreCase(CharSequence, CharSequence) 1868 */ 1869 public static int lastIndexOfIgnoreCase(final CharSequence str, final CharSequence searchStr) { 1870 if (str == null || searchStr == null) { 1871 return INDEX_NOT_FOUND; 1872 } 1873 return lastIndexOfIgnoreCase(str, searchStr, str.length()); 1874 } 1875 1876 /** 1877 * <p>Case in-sensitive find of the last index within a CharSequence 1878 * from the specified position.</p> 1879 * 1880 * <p>A {@code null} CharSequence will return {@code -1}. 1881 * A negative start position returns {@code -1}. 1882 * An empty ("") search CharSequence always matches unless the start position is negative. 1883 * A start position greater than the string length searches the whole string. 1884 * The search starts at the startPos and works backwards; matches starting after the start 1885 * position are ignored. 1886 * </p> 1887 * 1888 * <pre> 1889 * StringUtils.lastIndexOfIgnoreCase(null, *, *) = -1 1890 * StringUtils.lastIndexOfIgnoreCase(*, null, *) = -1 1891 * StringUtils.lastIndexOfIgnoreCase("aabaabaa", "A", 8) = 7 1892 * StringUtils.lastIndexOfIgnoreCase("aabaabaa", "B", 8) = 5 1893 * StringUtils.lastIndexOfIgnoreCase("aabaabaa", "AB", 8) = 4 1894 * StringUtils.lastIndexOfIgnoreCase("aabaabaa", "B", 9) = 5 1895 * StringUtils.lastIndexOfIgnoreCase("aabaabaa", "B", -1) = -1 1896 * StringUtils.lastIndexOfIgnoreCase("aabaabaa", "A", 0) = 0 1897 * StringUtils.lastIndexOfIgnoreCase("aabaabaa", "B", 0) = -1 1898 * </pre> 1899 * 1900 * @param str the CharSequence to check, may be null 1901 * @param searchStr the CharSequence to find, may be null 1902 * @param startPos the start position 1903 * @return the last index of the search CharSequence (always ≤ startPos), 1904 * -1 if no match or {@code null} input 1905 * @since 2.5 1906 * @since 3.0 Changed signature from lastIndexOfIgnoreCase(String, String, int) to lastIndexOfIgnoreCase(CharSequence, CharSequence, int) 1907 */ 1908 public static int lastIndexOfIgnoreCase(final CharSequence str, final CharSequence searchStr, int startPos) { 1909 if (str == null || searchStr == null) { 1910 return INDEX_NOT_FOUND; 1911 } 1912 if (startPos > str.length() - searchStr.length()) { 1913 startPos = str.length() - searchStr.length(); 1914 } 1915 if (startPos < 0) { 1916 return INDEX_NOT_FOUND; 1917 } 1918 if (searchStr.length() == 0) { 1919 return startPos; 1920 } 1921 1922 for (int i = startPos; i >= 0; i--) { 1923 if (CharSequenceUtils.regionMatches(str, true, i, searchStr, 0, searchStr.length())) { 1924 return i; 1925 } 1926 } 1927 return INDEX_NOT_FOUND; 1928 } 1929 1930 // Contains 1931 //----------------------------------------------------------------------- 1932 /** 1933 * <p>Checks if CharSequence contains a search character, handling {@code null}. 1934 * This method uses {@link String#indexOf(int)} if possible.</p> 1935 * 1936 * <p>A {@code null} or empty ("") CharSequence will return {@code false}.</p> 1937 * 1938 * <pre> 1939 * StringUtils.contains(null, *) = false 1940 * StringUtils.contains("", *) = false 1941 * StringUtils.contains("abc", 'a') = true 1942 * StringUtils.contains("abc", 'z') = false 1943 * </pre> 1944 * 1945 * @param seq the CharSequence to check, may be null 1946 * @param searchChar the character to find 1947 * @return true if the CharSequence contains the search character, 1948 * false if not or {@code null} string input 1949 * @since 2.0 1950 * @since 3.0 Changed signature from contains(String, int) to contains(CharSequence, int) 1951 */ 1952 public static boolean contains(final CharSequence seq, final int searchChar) { 1953 if (isEmpty(seq)) { 1954 return false; 1955 } 1956 return CharSequenceUtils.indexOf(seq, searchChar, 0) >= 0; 1957 } 1958 1959 /** 1960 * <p>Checks if CharSequence contains a search CharSequence, handling {@code null}. 1961 * This method uses {@link String#indexOf(String)} if possible.</p> 1962 * 1963 * <p>A {@code null} CharSequence will return {@code false}.</p> 1964 * 1965 * <pre> 1966 * StringUtils.contains(null, *) = false 1967 * StringUtils.contains(*, null) = false 1968 * StringUtils.contains("", "") = true 1969 * StringUtils.contains("abc", "") = true 1970 * StringUtils.contains("abc", "a") = true 1971 * StringUtils.contains("abc", "z") = false 1972 * </pre> 1973 * 1974 * @param seq the CharSequence to check, may be null 1975 * @param searchSeq the CharSequence to find, may be null 1976 * @return true if the CharSequence contains the search CharSequence, 1977 * false if not or {@code null} string input 1978 * @since 2.0 1979 * @since 3.0 Changed signature from contains(String, String) to contains(CharSequence, CharSequence) 1980 */ 1981 public static boolean contains(final CharSequence seq, final CharSequence searchSeq) { 1982 if (seq == null || searchSeq == null) { 1983 return false; 1984 } 1985 return CharSequenceUtils.indexOf(seq, searchSeq, 0) >= 0; 1986 } 1987 1988 /** 1989 * <p>Checks if CharSequence contains a search CharSequence irrespective of case, 1990 * handling {@code null}. Case-insensitivity is defined as by 1991 * {@link String#equalsIgnoreCase(String)}. 1992 * 1993 * <p>A {@code null} CharSequence will return {@code false}.</p> 1994 * 1995 * <pre> 1996 * StringUtils.containsIgnoreCase(null, *) = false 1997 * StringUtils.containsIgnoreCase(*, null) = false 1998 * StringUtils.containsIgnoreCase("", "") = true 1999 * StringUtils.containsIgnoreCase("abc", "") = true 2000 * StringUtils.containsIgnoreCase("abc", "a") = true 2001 * StringUtils.containsIgnoreCase("abc", "z") = false 2002 * StringUtils.containsIgnoreCase("abc", "A") = true 2003 * StringUtils.containsIgnoreCase("abc", "Z") = false 2004 * </pre> 2005 * 2006 * @param str the CharSequence to check, may be null 2007 * @param searchStr the CharSequence to find, may be null 2008 * @return true if the CharSequence contains the search CharSequence irrespective of 2009 * case or false if not or {@code null} string input 2010 * @since 3.0 Changed signature from containsIgnoreCase(String, String) to containsIgnoreCase(CharSequence, CharSequence) 2011 */ 2012 public static boolean containsIgnoreCase(final CharSequence str, final CharSequence searchStr) { 2013 if (str == null || searchStr == null) { 2014 return false; 2015 } 2016 final int len = searchStr.length(); 2017 final int max = str.length() - len; 2018 for (int i = 0; i <= max; i++) { 2019 if (CharSequenceUtils.regionMatches(str, true, i, searchStr, 0, len)) { 2020 return true; 2021 } 2022 } 2023 return false; 2024 } 2025 2026 /** 2027 * <p>Check whether the given CharSequence contains any whitespace characters.</p> 2028 * 2029 * <p>Whitespace is defined by {@link Character#isWhitespace(char)}.</p> 2030 * 2031 * @param seq the CharSequence to check (may be {@code null}) 2032 * @return {@code true} if the CharSequence is not empty and 2033 * contains at least 1 (breaking) whitespace character 2034 * @since 3.0 2035 */ 2036 // From org.springframework.util.StringUtils, under Apache License 2.0 2037 public static boolean containsWhitespace(final CharSequence seq) { 2038 if (isEmpty(seq)) { 2039 return false; 2040 } 2041 final int strLen = seq.length(); 2042 for (int i = 0; i < strLen; i++) { 2043 if (Character.isWhitespace(seq.charAt(i))) { 2044 return true; 2045 } 2046 } 2047 return false; 2048 } 2049 2050 // IndexOfAny chars 2051 //----------------------------------------------------------------------- 2052 /** 2053 * <p>Search a CharSequence to find the first index of any 2054 * character in the given set of characters.</p> 2055 * 2056 * <p>A {@code null} String will return {@code -1}. 2057 * A {@code null} or zero length search array will return {@code -1}.</p> 2058 * 2059 * <pre> 2060 * StringUtils.indexOfAny(null, *) = -1 2061 * StringUtils.indexOfAny("", *) = -1 2062 * StringUtils.indexOfAny(*, null) = -1 2063 * StringUtils.indexOfAny(*, []) = -1 2064 * StringUtils.indexOfAny("zzabyycdxx",['z','a']) = 0 2065 * StringUtils.indexOfAny("zzabyycdxx",['b','y']) = 3 2066 * StringUtils.indexOfAny("aba", ['z']) = -1 2067 * </pre> 2068 * 2069 * @param cs the CharSequence to check, may be null 2070 * @param searchChars the chars to search for, may be null 2071 * @return the index of any of the chars, -1 if no match or null input 2072 * @since 2.0 2073 * @since 3.0 Changed signature from indexOfAny(String, char[]) to indexOfAny(CharSequence, char...) 2074 */ 2075 public static int indexOfAny(final CharSequence cs, final char... searchChars) { 2076 if (isEmpty(cs) || ArrayUtils.isEmpty(searchChars)) { 2077 return INDEX_NOT_FOUND; 2078 } 2079 final int csLen = cs.length(); 2080 final int csLast = csLen - 1; 2081 final int searchLen = searchChars.length; 2082 final int searchLast = searchLen - 1; 2083 for (int i = 0; i < csLen; i++) { 2084 final char ch = cs.charAt(i); 2085 for (int j = 0; j < searchLen; j++) { 2086 if (searchChars[j] == ch) { 2087 if (i < csLast && j < searchLast && Character.isHighSurrogate(ch)) { 2088 // ch is a supplementary character 2089 if (searchChars[j + 1] == cs.charAt(i + 1)) { 2090 return i; 2091 } 2092 } else { 2093 return i; 2094 } 2095 } 2096 } 2097 } 2098 return INDEX_NOT_FOUND; 2099 } 2100 2101 /** 2102 * <p>Search a CharSequence to find the first index of any 2103 * character in the given set of characters.</p> 2104 * 2105 * <p>A {@code null} String will return {@code -1}. 2106 * A {@code null} search string will return {@code -1}.</p> 2107 * 2108 * <pre> 2109 * StringUtils.indexOfAny(null, *) = -1 2110 * StringUtils.indexOfAny("", *) = -1 2111 * StringUtils.indexOfAny(*, null) = -1 2112 * StringUtils.indexOfAny(*, "") = -1 2113 * StringUtils.indexOfAny("zzabyycdxx", "za") = 0 2114 * StringUtils.indexOfAny("zzabyycdxx", "by") = 3 2115 * StringUtils.indexOfAny("aba","z") = -1 2116 * </pre> 2117 * 2118 * @param cs the CharSequence to check, may be null 2119 * @param searchChars the chars to search for, may be null 2120 * @return the index of any of the chars, -1 if no match or null input 2121 * @since 2.0 2122 * @since 3.0 Changed signature from indexOfAny(String, String) to indexOfAny(CharSequence, String) 2123 */ 2124 public static int indexOfAny(final CharSequence cs, final String searchChars) { 2125 if (isEmpty(cs) || isEmpty(searchChars)) { 2126 return INDEX_NOT_FOUND; 2127 } 2128 return indexOfAny(cs, searchChars.toCharArray()); 2129 } 2130 2131 // ContainsAny 2132 //----------------------------------------------------------------------- 2133 /** 2134 * <p>Checks if the CharSequence contains any character in the given 2135 * set of characters.</p> 2136 * 2137 * <p>A {@code null} CharSequence will return {@code false}. 2138 * A {@code null} or zero length search array will return {@code false}.</p> 2139 * 2140 * <pre> 2141 * StringUtils.containsAny(null, *) = false 2142 * StringUtils.containsAny("", *) = false 2143 * StringUtils.containsAny(*, null) = false 2144 * StringUtils.containsAny(*, []) = false 2145 * StringUtils.containsAny("zzabyycdxx",['z','a']) = true 2146 * StringUtils.containsAny("zzabyycdxx",['b','y']) = true 2147 * StringUtils.containsAny("zzabyycdxx",['z','y']) = true 2148 * StringUtils.containsAny("aba", ['z']) = false 2149 * </pre> 2150 * 2151 * @param cs the CharSequence to check, may be null 2152 * @param searchChars the chars to search for, may be null 2153 * @return the {@code true} if any of the chars are found, 2154 * {@code false} if no match or null input 2155 * @since 2.4 2156 * @since 3.0 Changed signature from containsAny(String, char[]) to containsAny(CharSequence, char...) 2157 */ 2158 public static boolean containsAny(final CharSequence cs, final char... searchChars) { 2159 if (isEmpty(cs) || ArrayUtils.isEmpty(searchChars)) { 2160 return false; 2161 } 2162 final int csLength = cs.length(); 2163 final int searchLength = searchChars.length; 2164 final int csLast = csLength - 1; 2165 final int searchLast = searchLength - 1; 2166 for (int i = 0; i < csLength; i++) { 2167 final char ch = cs.charAt(i); 2168 for (int j = 0; j < searchLength; j++) { 2169 if (searchChars[j] == ch) { 2170 if (Character.isHighSurrogate(ch)) { 2171 if (j == searchLast) { 2172 // missing low surrogate, fine, like String.indexOf(String) 2173 return true; 2174 } 2175 if (i < csLast && searchChars[j + 1] == cs.charAt(i + 1)) { 2176 return true; 2177 } 2178 } else { 2179 // ch is in the Basic Multilingual Plane 2180 return true; 2181 } 2182 } 2183 } 2184 } 2185 return false; 2186 } 2187 2188 /** 2189 * <p> 2190 * Checks if the CharSequence contains any character in the given set of characters. 2191 * </p> 2192 * 2193 * <p> 2194 * A {@code null} CharSequence will return {@code false}. A {@code null} search CharSequence will return 2195 * {@code false}. 2196 * </p> 2197 * 2198 * <pre> 2199 * StringUtils.containsAny(null, *) = false 2200 * StringUtils.containsAny("", *) = false 2201 * StringUtils.containsAny(*, null) = false 2202 * StringUtils.containsAny(*, "") = false 2203 * StringUtils.containsAny("zzabyycdxx", "za") = true 2204 * StringUtils.containsAny("zzabyycdxx", "by") = true 2205 * StringUtils.containsAny("zzabyycdxx", "zy") = true 2206 * StringUtils.containsAny("zzabyycdxx", "\tx") = true 2207 * StringUtils.containsAny("zzabyycdxx", "$.#yF") = true 2208 * StringUtils.containsAny("aba","z") = false 2209 * </pre> 2210 * 2211 * @param cs 2212 * the CharSequence to check, may be null 2213 * @param searchChars 2214 * the chars to search for, may be null 2215 * @return the {@code true} if any of the chars are found, {@code false} if no match or null input 2216 * @since 2.4 2217 * @since 3.0 Changed signature from containsAny(String, String) to containsAny(CharSequence, CharSequence) 2218 */ 2219 public static boolean containsAny(final CharSequence cs, final CharSequence searchChars) { 2220 if (searchChars == null) { 2221 return false; 2222 } 2223 return containsAny(cs, CharSequenceUtils.toCharArray(searchChars)); 2224 } 2225 2226 /** 2227 * <p>Checks if the CharSequence contains any of the CharSequences in the given array.</p> 2228 * 2229 * <p> 2230 * A {@code null} {@code cs} CharSequence will return {@code false}. A {@code null} or zero 2231 * length search array will return {@code false}. 2232 * </p> 2233 * 2234 * <pre> 2235 * StringUtils.containsAny(null, *) = false 2236 * StringUtils.containsAny("", *) = false 2237 * StringUtils.containsAny(*, null) = false 2238 * StringUtils.containsAny(*, []) = false 2239 * StringUtils.containsAny("abcd", "ab", null) = true 2240 * StringUtils.containsAny("abcd", "ab", "cd") = true 2241 * StringUtils.containsAny("abc", "d", "abc") = true 2242 * </pre> 2243 * 2244 * 2245 * @param cs The CharSequence to check, may be null 2246 * @param searchCharSequences The array of CharSequences to search for, may be null. 2247 * Individual CharSequences may be null as well. 2248 * @return {@code true} if any of the search CharSequences are found, {@code false} otherwise 2249 * @since 3.4 2250 */ 2251 public static boolean containsAny(final CharSequence cs, final CharSequence... searchCharSequences) { 2252 if (isEmpty(cs) || ArrayUtils.isEmpty(searchCharSequences)) { 2253 return false; 2254 } 2255 for (final CharSequence searchCharSequence : searchCharSequences) { 2256 if (contains(cs, searchCharSequence)) { 2257 return true; 2258 } 2259 } 2260 return false; 2261 } 2262 2263 // IndexOfAnyBut chars 2264 //----------------------------------------------------------------------- 2265 /** 2266 * <p>Searches a CharSequence to find the first index of any 2267 * character not in the given set of characters.</p> 2268 * 2269 * <p>A {@code null} CharSequence will return {@code -1}. 2270 * A {@code null} or zero length search array will return {@code -1}.</p> 2271 * 2272 * <pre> 2273 * StringUtils.indexOfAnyBut(null, *) = -1 2274 * StringUtils.indexOfAnyBut("", *) = -1 2275 * StringUtils.indexOfAnyBut(*, null) = -1 2276 * StringUtils.indexOfAnyBut(*, []) = -1 2277 * StringUtils.indexOfAnyBut("zzabyycdxx", new char[] {'z', 'a'} ) = 3 2278 * StringUtils.indexOfAnyBut("aba", new char[] {'z'} ) = 0 2279 * StringUtils.indexOfAnyBut("aba", new char[] {'a', 'b'} ) = -1 2280 2281 * </pre> 2282 * 2283 * @param cs the CharSequence to check, may be null 2284 * @param searchChars the chars to search for, may be null 2285 * @return the index of any of the chars, -1 if no match or null input 2286 * @since 2.0 2287 * @since 3.0 Changed signature from indexOfAnyBut(String, char[]) to indexOfAnyBut(CharSequence, char...) 2288 */ 2289 public static int indexOfAnyBut(final CharSequence cs, final char... searchChars) { 2290 if (isEmpty(cs) || ArrayUtils.isEmpty(searchChars)) { 2291 return INDEX_NOT_FOUND; 2292 } 2293 final int csLen = cs.length(); 2294 final int csLast = csLen - 1; 2295 final int searchLen = searchChars.length; 2296 final int searchLast = searchLen - 1; 2297 outer: 2298 for (int i = 0; i < csLen; i++) { 2299 final char ch = cs.charAt(i); 2300 for (int j = 0; j < searchLen; j++) { 2301 if (searchChars[j] == ch) { 2302 if (i < csLast && j < searchLast && Character.isHighSurrogate(ch)) { 2303 if (searchChars[j + 1] == cs.charAt(i + 1)) { 2304 continue outer; 2305 } 2306 } else { 2307 continue outer; 2308 } 2309 } 2310 } 2311 return i; 2312 } 2313 return INDEX_NOT_FOUND; 2314 } 2315 2316 /** 2317 * <p>Search a CharSequence to find the first index of any 2318 * character not in the given set of characters.</p> 2319 * 2320 * <p>A {@code null} CharSequence will return {@code -1}. 2321 * A {@code null} or empty search string will return {@code -1}.</p> 2322 * 2323 * <pre> 2324 * StringUtils.indexOfAnyBut(null, *) = -1 2325 * StringUtils.indexOfAnyBut("", *) = -1 2326 * StringUtils.indexOfAnyBut(*, null) = -1 2327 * StringUtils.indexOfAnyBut(*, "") = -1 2328 * StringUtils.indexOfAnyBut("zzabyycdxx", "za") = 3 2329 * StringUtils.indexOfAnyBut("zzabyycdxx", "") = -1 2330 * StringUtils.indexOfAnyBut("aba","ab") = -1 2331 * </pre> 2332 * 2333 * @param seq the CharSequence to check, may be null 2334 * @param searchChars the chars to search for, may be null 2335 * @return the index of any of the chars, -1 if no match or null input 2336 * @since 2.0 2337 * @since 3.0 Changed signature from indexOfAnyBut(String, String) to indexOfAnyBut(CharSequence, CharSequence) 2338 */ 2339 public static int indexOfAnyBut(final CharSequence seq, final CharSequence searchChars) { 2340 if (isEmpty(seq) || isEmpty(searchChars)) { 2341 return INDEX_NOT_FOUND; 2342 } 2343 final int strLen = seq.length(); 2344 for (int i = 0; i < strLen; i++) { 2345 final char ch = seq.charAt(i); 2346 final boolean chFound = CharSequenceUtils.indexOf(searchChars, ch, 0) >= 0; 2347 if (i + 1 < strLen && Character.isHighSurrogate(ch)) { 2348 final char ch2 = seq.charAt(i + 1); 2349 if (chFound && CharSequenceUtils.indexOf(searchChars, ch2, 0) < 0) { 2350 return i; 2351 } 2352 } else { 2353 if (!chFound) { 2354 return i; 2355 } 2356 } 2357 } 2358 return INDEX_NOT_FOUND; 2359 } 2360 2361 // ContainsOnly 2362 //----------------------------------------------------------------------- 2363 /** 2364 * <p>Checks if the CharSequence contains only certain characters.</p> 2365 * 2366 * <p>A {@code null} CharSequence will return {@code false}. 2367 * A {@code null} valid character array will return {@code false}. 2368 * An empty CharSequence (length()=0) always returns {@code true}.</p> 2369 * 2370 * <pre> 2371 * StringUtils.containsOnly(null, *) = false 2372 * StringUtils.containsOnly(*, null) = false 2373 * StringUtils.containsOnly("", *) = true 2374 * StringUtils.containsOnly("ab", '') = false 2375 * StringUtils.containsOnly("abab", 'abc') = true 2376 * StringUtils.containsOnly("ab1", 'abc') = false 2377 * StringUtils.containsOnly("abz", 'abc') = false 2378 * </pre> 2379 * 2380 * @param cs the String to check, may be null 2381 * @param valid an array of valid chars, may be null 2382 * @return true if it only contains valid chars and is non-null 2383 * @since 3.0 Changed signature from containsOnly(String, char[]) to containsOnly(CharSequence, char...) 2384 */ 2385 public static boolean containsOnly(final CharSequence cs, final char... valid) { 2386 // All these pre-checks are to maintain API with an older version 2387 if (valid == null || cs == null) { 2388 return false; 2389 } 2390 if (cs.length() == 0) { 2391 return true; 2392 } 2393 if (valid.length == 0) { 2394 return false; 2395 } 2396 return indexOfAnyBut(cs, valid) == INDEX_NOT_FOUND; 2397 } 2398 2399 /** 2400 * <p>Checks if the CharSequence contains only certain characters.</p> 2401 * 2402 * <p>A {@code null} CharSequence will return {@code false}. 2403 * A {@code null} valid character String will return {@code false}. 2404 * An empty String (length()=0) always returns {@code true}.</p> 2405 * 2406 * <pre> 2407 * StringUtils.containsOnly(null, *) = false 2408 * StringUtils.containsOnly(*, null) = false 2409 * StringUtils.containsOnly("", *) = true 2410 * StringUtils.containsOnly("ab", "") = false 2411 * StringUtils.containsOnly("abab", "abc") = true 2412 * StringUtils.containsOnly("ab1", "abc") = false 2413 * StringUtils.containsOnly("abz", "abc") = false 2414 * </pre> 2415 * 2416 * @param cs the CharSequence to check, may be null 2417 * @param validChars a String of valid chars, may be null 2418 * @return true if it only contains valid chars and is non-null 2419 * @since 2.0 2420 * @since 3.0 Changed signature from containsOnly(String, String) to containsOnly(CharSequence, String) 2421 */ 2422 public static boolean containsOnly(final CharSequence cs, final String validChars) { 2423 if (cs == null || validChars == null) { 2424 return false; 2425 } 2426 return containsOnly(cs, validChars.toCharArray()); 2427 } 2428 2429 // ContainsNone 2430 //----------------------------------------------------------------------- 2431 /** 2432 * <p>Checks that the CharSequence does not contain certain characters.</p> 2433 * 2434 * <p>A {@code null} CharSequence will return {@code true}. 2435 * A {@code null} invalid character array will return {@code true}. 2436 * An empty CharSequence (length()=0) always returns true.</p> 2437 * 2438 * <pre> 2439 * StringUtils.containsNone(null, *) = true 2440 * StringUtils.containsNone(*, null) = true 2441 * StringUtils.containsNone("", *) = true 2442 * StringUtils.containsNone("ab", '') = true 2443 * StringUtils.containsNone("abab", 'xyz') = true 2444 * StringUtils.containsNone("ab1", 'xyz') = true 2445 * StringUtils.containsNone("abz", 'xyz') = false 2446 * </pre> 2447 * 2448 * @param cs the CharSequence to check, may be null 2449 * @param searchChars an array of invalid chars, may be null 2450 * @return true if it contains none of the invalid chars, or is null 2451 * @since 2.0 2452 * @since 3.0 Changed signature from containsNone(String, char[]) to containsNone(CharSequence, char...) 2453 */ 2454 public static boolean containsNone(final CharSequence cs, final char... searchChars) { 2455 if (cs == null || searchChars == null) { 2456 return true; 2457 } 2458 final int csLen = cs.length(); 2459 final int csLast = csLen - 1; 2460 final int searchLen = searchChars.length; 2461 final int searchLast = searchLen - 1; 2462 for (int i = 0; i < csLen; i++) { 2463 final char ch = cs.charAt(i); 2464 for (int j = 0; j < searchLen; j++) { 2465 if (searchChars[j] == ch) { 2466 if (Character.isHighSurrogate(ch)) { 2467 if (j == searchLast) { 2468 // missing low surrogate, fine, like String.indexOf(String) 2469 return false; 2470 } 2471 if (i < csLast && searchChars[j + 1] == cs.charAt(i + 1)) { 2472 return false; 2473 } 2474 } else { 2475 // ch is in the Basic Multilingual Plane 2476 return false; 2477 } 2478 } 2479 } 2480 } 2481 return true; 2482 } 2483 2484 /** 2485 * <p>Checks that the CharSequence does not contain certain characters.</p> 2486 * 2487 * <p>A {@code null} CharSequence will return {@code true}. 2488 * A {@code null} invalid character array will return {@code true}. 2489 * An empty String ("") always returns true.</p> 2490 * 2491 * <pre> 2492 * StringUtils.containsNone(null, *) = true 2493 * StringUtils.containsNone(*, null) = true 2494 * StringUtils.containsNone("", *) = true 2495 * StringUtils.containsNone("ab", "") = true 2496 * StringUtils.containsNone("abab", "xyz") = true 2497 * StringUtils.containsNone("ab1", "xyz") = true 2498 * StringUtils.containsNone("abz", "xyz") = false 2499 * </pre> 2500 * 2501 * @param cs the CharSequence to check, may be null 2502 * @param invalidChars a String of invalid chars, may be null 2503 * @return true if it contains none of the invalid chars, or is null 2504 * @since 2.0 2505 * @since 3.0 Changed signature from containsNone(String, String) to containsNone(CharSequence, String) 2506 */ 2507 public static boolean containsNone(final CharSequence cs, final String invalidChars) { 2508 if (cs == null || invalidChars == null) { 2509 return true; 2510 } 2511 return containsNone(cs, invalidChars.toCharArray()); 2512 } 2513 2514 // IndexOfAny strings 2515 //----------------------------------------------------------------------- 2516 /** 2517 * <p>Find the first index of any of a set of potential substrings.</p> 2518 * 2519 * <p>A {@code null} CharSequence will return {@code -1}. 2520 * A {@code null} or zero length search array will return {@code -1}. 2521 * A {@code null} search array entry will be ignored, but a search 2522 * array containing "" will return {@code 0} if {@code str} is not 2523 * null. This method uses {@link String#indexOf(String)} if possible.</p> 2524 * 2525 * <pre> 2526 * StringUtils.indexOfAny(null, *) = -1 2527 * StringUtils.indexOfAny(*, null) = -1 2528 * StringUtils.indexOfAny(*, []) = -1 2529 * StringUtils.indexOfAny("zzabyycdxx", ["ab","cd"]) = 2 2530 * StringUtils.indexOfAny("zzabyycdxx", ["cd","ab"]) = 2 2531 * StringUtils.indexOfAny("zzabyycdxx", ["mn","op"]) = -1 2532 * StringUtils.indexOfAny("zzabyycdxx", ["zab","aby"]) = 1 2533 * StringUtils.indexOfAny("zzabyycdxx", [""]) = 0 2534 * StringUtils.indexOfAny("", [""]) = 0 2535 * StringUtils.indexOfAny("", ["a"]) = -1 2536 * </pre> 2537 * 2538 * @param str the CharSequence to check, may be null 2539 * @param searchStrs the CharSequences to search for, may be null 2540 * @return the first index of any of the searchStrs in str, -1 if no match 2541 * @since 3.0 Changed signature from indexOfAny(String, String[]) to indexOfAny(CharSequence, CharSequence...) 2542 */ 2543 public static int indexOfAny(final CharSequence str, final CharSequence... searchStrs) { 2544 if (str == null || searchStrs == null) { 2545 return INDEX_NOT_FOUND; 2546 } 2547 2548 // String's can't have a MAX_VALUEth index. 2549 int ret = Integer.MAX_VALUE; 2550 2551 int tmp = 0; 2552 for (final CharSequence search : searchStrs) { 2553 if (search == null) { 2554 continue; 2555 } 2556 tmp = CharSequenceUtils.indexOf(str, search, 0); 2557 if (tmp == INDEX_NOT_FOUND) { 2558 continue; 2559 } 2560 2561 if (tmp < ret) { 2562 ret = tmp; 2563 } 2564 } 2565 2566 return ret == Integer.MAX_VALUE ? INDEX_NOT_FOUND : ret; 2567 } 2568 2569 /** 2570 * <p>Find the latest index of any of a set of potential substrings.</p> 2571 * 2572 * <p>A {@code null} CharSequence will return {@code -1}. 2573 * A {@code null} search array will return {@code -1}. 2574 * A {@code null} or zero length search array entry will be ignored, 2575 * but a search array containing "" will return the length of {@code str} 2576 * if {@code str} is not null. This method uses {@link String#indexOf(String)} if possible</p> 2577 * 2578 * <pre> 2579 * StringUtils.lastIndexOfAny(null, *) = -1 2580 * StringUtils.lastIndexOfAny(*, null) = -1 2581 * StringUtils.lastIndexOfAny(*, []) = -1 2582 * StringUtils.lastIndexOfAny(*, [null]) = -1 2583 * StringUtils.lastIndexOfAny("zzabyycdxx", ["ab","cd"]) = 6 2584 * StringUtils.lastIndexOfAny("zzabyycdxx", ["cd","ab"]) = 6 2585 * StringUtils.lastIndexOfAny("zzabyycdxx", ["mn","op"]) = -1 2586 * StringUtils.lastIndexOfAny("zzabyycdxx", ["mn","op"]) = -1 2587 * StringUtils.lastIndexOfAny("zzabyycdxx", ["mn",""]) = 10 2588 * </pre> 2589 * 2590 * @param str the CharSequence to check, may be null 2591 * @param searchStrs the CharSequences to search for, may be null 2592 * @return the last index of any of the CharSequences, -1 if no match 2593 * @since 3.0 Changed signature from lastIndexOfAny(String, String[]) to lastIndexOfAny(CharSequence, CharSequence) 2594 */ 2595 public static int lastIndexOfAny(final CharSequence str, final CharSequence... searchStrs) { 2596 if (str == null || searchStrs == null) { 2597 return INDEX_NOT_FOUND; 2598 } 2599 int ret = INDEX_NOT_FOUND; 2600 int tmp = 0; 2601 for (final CharSequence search : searchStrs) { 2602 if (search == null) { 2603 continue; 2604 } 2605 tmp = CharSequenceUtils.lastIndexOf(str, search, str.length()); 2606 if (tmp > ret) { 2607 ret = tmp; 2608 } 2609 } 2610 return ret; 2611 } 2612 2613 // Substring 2614 //----------------------------------------------------------------------- 2615 /** 2616 * <p>Gets a substring from the specified String avoiding exceptions.</p> 2617 * 2618 * <p>A negative start position can be used to start {@code n} 2619 * characters from the end of the String.</p> 2620 * 2621 * <p>A {@code null} String will return {@code null}. 2622 * An empty ("") String will return "".</p> 2623 * 2624 * <pre> 2625 * StringUtils.substring(null, *) = null 2626 * StringUtils.substring("", *) = "" 2627 * StringUtils.substring("abc", 0) = "abc" 2628 * StringUtils.substring("abc", 2) = "c" 2629 * StringUtils.substring("abc", 4) = "" 2630 * StringUtils.substring("abc", -2) = "bc" 2631 * StringUtils.substring("abc", -4) = "abc" 2632 * </pre> 2633 * 2634 * @param str the String to get the substring from, may be null 2635 * @param start the position to start from, negative means 2636 * count back from the end of the String by this many characters 2637 * @return substring from start position, {@code null} if null String input 2638 */ 2639 public static String substring(final String str, int start) { 2640 if (str == null) { 2641 return null; 2642 } 2643 2644 // handle negatives, which means last n characters 2645 if (start < 0) { 2646 start = str.length() + start; // remember start is negative 2647 } 2648 2649 if (start < 0) { 2650 start = 0; 2651 } 2652 if (start > str.length()) { 2653 return EMPTY; 2654 } 2655 2656 return str.substring(start); 2657 } 2658 2659 /** 2660 * <p>Gets a substring from the specified String avoiding exceptions.</p> 2661 * 2662 * <p>A negative start position can be used to start/end {@code n} 2663 * characters from the end of the String.</p> 2664 * 2665 * <p>The returned substring starts with the character in the {@code start} 2666 * position and ends before the {@code end} position. All position counting is 2667 * zero-based -- i.e., to start at the beginning of the string use 2668 * {@code start = 0}. Negative start and end positions can be used to 2669 * specify offsets relative to the end of the String.</p> 2670 * 2671 * <p>If {@code start} is not strictly to the left of {@code end}, "" 2672 * is returned.</p> 2673 * 2674 * <pre> 2675 * StringUtils.substring(null, *, *) = null 2676 * StringUtils.substring("", * , *) = ""; 2677 * StringUtils.substring("abc", 0, 2) = "ab" 2678 * StringUtils.substring("abc", 2, 0) = "" 2679 * StringUtils.substring("abc", 2, 4) = "c" 2680 * StringUtils.substring("abc", 4, 6) = "" 2681 * StringUtils.substring("abc", 2, 2) = "" 2682 * StringUtils.substring("abc", -2, -1) = "b" 2683 * StringUtils.substring("abc", -4, 2) = "ab" 2684 * </pre> 2685 * 2686 * @param str the String to get the substring from, may be null 2687 * @param start the position to start from, negative means 2688 * count back from the end of the String by this many characters 2689 * @param end the position to end at (exclusive), negative means 2690 * count back from the end of the String by this many characters 2691 * @return substring from start position to end position, 2692 * {@code null} if null String input 2693 */ 2694 public static String substring(final String str, int start, int end) { 2695 if (str == null) { 2696 return null; 2697 } 2698 2699 // handle negatives 2700 if (end < 0) { 2701 end = str.length() + end; // remember end is negative 2702 } 2703 if (start < 0) { 2704 start = str.length() + start; // remember start is negative 2705 } 2706 2707 // check length next 2708 if (end > str.length()) { 2709 end = str.length(); 2710 } 2711 2712 // if start is greater than end, return "" 2713 if (start > end) { 2714 return EMPTY; 2715 } 2716 2717 if (start < 0) { 2718 start = 0; 2719 } 2720 if (end < 0) { 2721 end = 0; 2722 } 2723 2724 return str.substring(start, end); 2725 } 2726 2727 // Left/Right/Mid 2728 //----------------------------------------------------------------------- 2729 /** 2730 * <p>Gets the leftmost {@code len} characters of a String.</p> 2731 * 2732 * <p>If {@code len} characters are not available, or the 2733 * String is {@code null}, the String will be returned without 2734 * an exception. An empty String is returned if len is negative.</p> 2735 * 2736 * <pre> 2737 * StringUtils.left(null, *) = null 2738 * StringUtils.left(*, -ve) = "" 2739 * StringUtils.left("", *) = "" 2740 * StringUtils.left("abc", 0) = "" 2741 * StringUtils.left("abc", 2) = "ab" 2742 * StringUtils.left("abc", 4) = "abc" 2743 * </pre> 2744 * 2745 * @param str the String to get the leftmost characters from, may be null 2746 * @param len the length of the required String 2747 * @return the leftmost characters, {@code null} if null String input 2748 */ 2749 public static String left(final String str, final int len) { 2750 if (str == null) { 2751 return null; 2752 } 2753 if (len < 0) { 2754 return EMPTY; 2755 } 2756 if (str.length() <= len) { 2757 return str; 2758 } 2759 return str.substring(0, len); 2760 } 2761 2762 /** 2763 * <p>Gets the rightmost {@code len} characters of a String.</p> 2764 * 2765 * <p>If {@code len} characters are not available, or the String 2766 * is {@code null}, the String will be returned without an 2767 * an exception. An empty String is returned if len is negative.</p> 2768 * 2769 * <pre> 2770 * StringUtils.right(null, *) = null 2771 * StringUtils.right(*, -ve) = "" 2772 * StringUtils.right("", *) = "" 2773 * StringUtils.right("abc", 0) = "" 2774 * StringUtils.right("abc", 2) = "bc" 2775 * StringUtils.right("abc", 4) = "abc" 2776 * </pre> 2777 * 2778 * @param str the String to get the rightmost characters from, may be null 2779 * @param len the length of the required String 2780 * @return the rightmost characters, {@code null} if null String input 2781 */ 2782 public static String right(final String str, final int len) { 2783 if (str == null) { 2784 return null; 2785 } 2786 if (len < 0) { 2787 return EMPTY; 2788 } 2789 if (str.length() <= len) { 2790 return str; 2791 } 2792 return str.substring(str.length() - len); 2793 } 2794 2795 /** 2796 * <p>Gets {@code len} characters from the middle of a String.</p> 2797 * 2798 * <p>If {@code len} characters are not available, the remainder 2799 * of the String will be returned without an exception. If the 2800 * String is {@code null}, {@code null} will be returned. 2801 * An empty String is returned if len is negative or exceeds the 2802 * length of {@code str}.</p> 2803 * 2804 * <pre> 2805 * StringUtils.mid(null, *, *) = null 2806 * StringUtils.mid(*, *, -ve) = "" 2807 * StringUtils.mid("", 0, *) = "" 2808 * StringUtils.mid("abc", 0, 2) = "ab" 2809 * StringUtils.mid("abc", 0, 4) = "abc" 2810 * StringUtils.mid("abc", 2, 4) = "c" 2811 * StringUtils.mid("abc", 4, 2) = "" 2812 * StringUtils.mid("abc", -2, 2) = "ab" 2813 * </pre> 2814 * 2815 * @param str the String to get the characters from, may be null 2816 * @param pos the position to start from, negative treated as zero 2817 * @param len the length of the required String 2818 * @return the middle characters, {@code null} if null String input 2819 */ 2820 public static String mid(final String str, int pos, final int len) { 2821 if (str == null) { 2822 return null; 2823 } 2824 if (len < 0 || pos > str.length()) { 2825 return EMPTY; 2826 } 2827 if (pos < 0) { 2828 pos = 0; 2829 } 2830 if (str.length() <= pos + len) { 2831 return str.substring(pos); 2832 } 2833 return str.substring(pos, pos + len); 2834 } 2835 2836 private static StringBuilder newStringBuilder(final int noOfItems) { 2837 return new StringBuilder(noOfItems * 16); 2838 } 2839 2840 // SubStringAfter/SubStringBefore 2841 //----------------------------------------------------------------------- 2842 /** 2843 * <p>Gets the substring before the first occurrence of a separator. 2844 * The separator is not returned.</p> 2845 * 2846 * <p>A {@code null} string input will return {@code null}. 2847 * An empty ("") string input will return the empty string. 2848 * A {@code null} separator will return the input string.</p> 2849 * 2850 * <p>If nothing is found, the string input is returned.</p> 2851 * 2852 * <pre> 2853 * StringUtils.substringBefore(null, *) = null 2854 * StringUtils.substringBefore("", *) = "" 2855 * StringUtils.substringBefore("abc", "a") = "" 2856 * StringUtils.substringBefore("abcba", "b") = "a" 2857 * StringUtils.substringBefore("abc", "c") = "ab" 2858 * StringUtils.substringBefore("abc", "d") = "abc" 2859 * StringUtils.substringBefore("abc", "") = "" 2860 * StringUtils.substringBefore("abc", null) = "abc" 2861 * </pre> 2862 * 2863 * @param str the String to get a substring from, may be null 2864 * @param separator the String to search for, may be null 2865 * @return the substring before the first occurrence of the separator, 2866 * {@code null} if null String input 2867 * @since 2.0 2868 */ 2869 public static String substringBefore(final String str, final String separator) { 2870 if (isEmpty(str) || separator == null) { 2871 return str; 2872 } 2873 if (separator.isEmpty()) { 2874 return EMPTY; 2875 } 2876 final int pos = str.indexOf(separator); 2877 if (pos == INDEX_NOT_FOUND) { 2878 return str; 2879 } 2880 return str.substring(0, pos); 2881 } 2882 2883 /** 2884 * <p>Gets the substring after the first occurrence of a separator. 2885 * The separator is not returned.</p> 2886 * 2887 * <p>A {@code null} string input will return {@code null}. 2888 * An empty ("") string input will return the empty string. 2889 * A {@code null} separator will return the empty string if the 2890 * input string is not {@code null}.</p> 2891 * 2892 * <p>If nothing is found, the empty string is returned.</p> 2893 * 2894 * <pre> 2895 * StringUtils.substringAfter(null, *) = null 2896 * StringUtils.substringAfter("", *) = "" 2897 * StringUtils.substringAfter(*, null) = "" 2898 * StringUtils.substringAfter("abc", "a") = "bc" 2899 * StringUtils.substringAfter("abcba", "b") = "cba" 2900 * StringUtils.substringAfter("abc", "c") = "" 2901 * StringUtils.substringAfter("abc", "d") = "" 2902 * StringUtils.substringAfter("abc", "") = "abc" 2903 * </pre> 2904 * 2905 * @param str the String to get a substring from, may be null 2906 * @param separator the String to search for, may be null 2907 * @return the substring after the first occurrence of the separator, 2908 * {@code null} if null String input 2909 * @since 2.0 2910 */ 2911 public static String substringAfter(final String str, final String separator) { 2912 if (isEmpty(str)) { 2913 return str; 2914 } 2915 if (separator == null) { 2916 return EMPTY; 2917 } 2918 final int pos = str.indexOf(separator); 2919 if (pos == INDEX_NOT_FOUND) { 2920 return EMPTY; 2921 } 2922 return str.substring(pos + separator.length()); 2923 } 2924 2925 /** 2926 * <p>Gets the substring before the last occurrence of a separator. 2927 * The separator is not returned.</p> 2928 * 2929 * <p>A {@code null} string input will return {@code null}. 2930 * An empty ("") string input will return the empty string. 2931 * An empty or {@code null} separator will return the input string.</p> 2932 * 2933 * <p>If nothing is found, the string input is returned.</p> 2934 * 2935 * <pre> 2936 * StringUtils.substringBeforeLast(null, *) = null 2937 * StringUtils.substringBeforeLast("", *) = "" 2938 * StringUtils.substringBeforeLast("abcba", "b") = "abc" 2939 * StringUtils.substringBeforeLast("abc", "c") = "ab" 2940 * StringUtils.substringBeforeLast("a", "a") = "" 2941 * StringUtils.substringBeforeLast("a", "z") = "a" 2942 * StringUtils.substringBeforeLast("a", null) = "a" 2943 * StringUtils.substringBeforeLast("a", "") = "a" 2944 * </pre> 2945 * 2946 * @param str the String to get a substring from, may be null 2947 * @param separator the String to search for, may be null 2948 * @return the substring before the last occurrence of the separator, 2949 * {@code null} if null String input 2950 * @since 2.0 2951 */ 2952 public static String substringBeforeLast(final String str, final String separator) { 2953 if (isEmpty(str) || isEmpty(separator)) { 2954 return str; 2955 } 2956 final int pos = str.lastIndexOf(separator); 2957 if (pos == INDEX_NOT_FOUND) { 2958 return str; 2959 } 2960 return str.substring(0, pos); 2961 } 2962 2963 /** 2964 * <p>Gets the substring after the last occurrence of a separator. 2965 * The separator is not returned.</p> 2966 * 2967 * <p>A {@code null} string input will return {@code null}. 2968 * An empty ("") string input will return the empty string. 2969 * An empty or {@code null} separator will return the empty string if 2970 * the input string is not {@code null}.</p> 2971 * 2972 * <p>If nothing is found, the empty string is returned.</p> 2973 * 2974 * <pre> 2975 * StringUtils.substringAfterLast(null, *) = null 2976 * StringUtils.substringAfterLast("", *) = "" 2977 * StringUtils.substringAfterLast(*, "") = "" 2978 * StringUtils.substringAfterLast(*, null) = "" 2979 * StringUtils.substringAfterLast("abc", "a") = "bc" 2980 * StringUtils.substringAfterLast("abcba", "b") = "a" 2981 * StringUtils.substringAfterLast("abc", "c") = "" 2982 * StringUtils.substringAfterLast("a", "a") = "" 2983 * StringUtils.substringAfterLast("a", "z") = "" 2984 * </pre> 2985 * 2986 * @param str the String to get a substring from, may be null 2987 * @param separator the String to search for, may be null 2988 * @return the substring after the last occurrence of the separator, 2989 * {@code null} if null String input 2990 * @since 2.0 2991 */ 2992 public static String substringAfterLast(final String str, final String separator) { 2993 if (isEmpty(str)) { 2994 return str; 2995 } 2996 if (isEmpty(separator)) { 2997 return EMPTY; 2998 } 2999 final int pos = str.lastIndexOf(separator); 3000 if (pos == INDEX_NOT_FOUND || pos == str.length() - separator.length()) { 3001 return EMPTY; 3002 } 3003 return str.substring(pos + separator.length()); 3004 } 3005 3006 // Substring between 3007 //----------------------------------------------------------------------- 3008 /** 3009 * <p>Gets the String that is nested in between two instances of the 3010 * same String.</p> 3011 * 3012 * <p>A {@code null} input String returns {@code null}. 3013 * A {@code null} tag returns {@code null}.</p> 3014 * 3015 * <pre> 3016 * StringUtils.substringBetween(null, *) = null 3017 * StringUtils.substringBetween("", "") = "" 3018 * StringUtils.substringBetween("", "tag") = null 3019 * StringUtils.substringBetween("tagabctag", null) = null 3020 * StringUtils.substringBetween("tagabctag", "") = "" 3021 * StringUtils.substringBetween("tagabctag", "tag") = "abc" 3022 * </pre> 3023 * 3024 * @param str the String containing the substring, may be null 3025 * @param tag the String before and after the substring, may be null 3026 * @return the substring, {@code null} if no match 3027 * @since 2.0 3028 */ 3029 public static String substringBetween(final String str, final String tag) { 3030 return substringBetween(str, tag, tag); 3031 } 3032 3033 /** 3034 * <p>Gets the String that is nested in between two Strings. 3035 * Only the first match is returned.</p> 3036 * 3037 * <p>A {@code null} input String returns {@code null}. 3038 * A {@code null} open/close returns {@code null} (no match). 3039 * An empty ("") open and close returns an empty string.</p> 3040 * 3041 * <pre> 3042 * StringUtils.substringBetween("wx[b]yz", "[", "]") = "b" 3043 * StringUtils.substringBetween(null, *, *) = null 3044 * StringUtils.substringBetween(*, null, *) = null 3045 * StringUtils.substringBetween(*, *, null) = null 3046 * StringUtils.substringBetween("", "", "") = "" 3047 * StringUtils.substringBetween("", "", "]") = null 3048 * StringUtils.substringBetween("", "[", "]") = null 3049 * StringUtils.substringBetween("yabcz", "", "") = "" 3050 * StringUtils.substringBetween("yabcz", "y", "z") = "abc" 3051 * StringUtils.substringBetween("yabczyabcz", "y", "z") = "abc" 3052 * </pre> 3053 * 3054 * @param str the String containing the substring, may be null 3055 * @param open the String before the substring, may be null 3056 * @param close the String after the substring, may be null 3057 * @return the substring, {@code null} if no match 3058 * @since 2.0 3059 */ 3060 public static String substringBetween(final String str, final String open, final String close) { 3061 if (str == null || open == null || close == null) { 3062 return null; 3063 } 3064 final int start = str.indexOf(open); 3065 if (start != INDEX_NOT_FOUND) { 3066 final int end = str.indexOf(close, start + open.length()); 3067 if (end != INDEX_NOT_FOUND) { 3068 return str.substring(start + open.length(), end); 3069 } 3070 } 3071 return null; 3072 } 3073 3074 /** 3075 * <p>Searches a String for substrings delimited by a start and end tag, 3076 * returning all matching substrings in an array.</p> 3077 * 3078 * <p>A {@code null} input String returns {@code null}. 3079 * A {@code null} open/close returns {@code null} (no match). 3080 * An empty ("") open/close returns {@code null} (no match).</p> 3081 * 3082 * <pre> 3083 * StringUtils.substringsBetween("[a][b][c]", "[", "]") = ["a","b","c"] 3084 * StringUtils.substringsBetween(null, *, *) = null 3085 * StringUtils.substringsBetween(*, null, *) = null 3086 * StringUtils.substringsBetween(*, *, null) = null 3087 * StringUtils.substringsBetween("", "[", "]") = [] 3088 * </pre> 3089 * 3090 * @param str the String containing the substrings, null returns null, empty returns empty 3091 * @param open the String identifying the start of the substring, empty returns null 3092 * @param close the String identifying the end of the substring, empty returns null 3093 * @return a String Array of substrings, or {@code null} if no match 3094 * @since 2.3 3095 */ 3096 public static String[] substringsBetween(final String str, final String open, final String close) { 3097 if (str == null || isEmpty(open) || isEmpty(close)) { 3098 return null; 3099 } 3100 final int strLen = str.length(); 3101 if (strLen == 0) { 3102 return ArrayUtils.EMPTY_STRING_ARRAY; 3103 } 3104 final int closeLen = close.length(); 3105 final int openLen = open.length(); 3106 final List<String> list = new ArrayList<>(); 3107 int pos = 0; 3108 while (pos < strLen - closeLen) { 3109 int start = str.indexOf(open, pos); 3110 if (start < 0) { 3111 break; 3112 } 3113 start += openLen; 3114 final int end = str.indexOf(close, start); 3115 if (end < 0) { 3116 break; 3117 } 3118 list.add(str.substring(start, end)); 3119 pos = end + closeLen; 3120 } 3121 if (list.isEmpty()) { 3122 return null; 3123 } 3124 return list.toArray(new String [list.size()]); 3125 } 3126 3127 // Nested extraction 3128 //----------------------------------------------------------------------- 3129 3130 // Splitting 3131 //----------------------------------------------------------------------- 3132 /** 3133 * <p>Splits the provided text into an array, using whitespace as the 3134 * separator. 3135 * Whitespace is defined by {@link Character#isWhitespace(char)}.</p> 3136 * 3137 * <p>The separator is not included in the returned String array. 3138 * Adjacent separators are treated as one separator. 3139 * For more control over the split use the StrTokenizer class.</p> 3140 * 3141 * <p>A {@code null} input String returns {@code null}.</p> 3142 * 3143 * <pre> 3144 * StringUtils.split(null) = null 3145 * StringUtils.split("") = [] 3146 * StringUtils.split("abc def") = ["abc", "def"] 3147 * StringUtils.split("abc def") = ["abc", "def"] 3148 * StringUtils.split(" abc ") = ["abc"] 3149 * </pre> 3150 * 3151 * @param str the String to parse, may be null 3152 * @return an array of parsed Strings, {@code null} if null String input 3153 */ 3154 public static String[] split(final String str) { 3155 return split(str, null, -1); 3156 } 3157 3158 /** 3159 * <p>Splits the provided text into an array, separator specified. 3160 * This is an alternative to using StringTokenizer.</p> 3161 * 3162 * <p>The separator is not included in the returned String array. 3163 * Adjacent separators are treated as one separator. 3164 * For more control over the split use the StrTokenizer class.</p> 3165 * 3166 * <p>A {@code null} input String returns {@code null}.</p> 3167 * 3168 * <pre> 3169 * StringUtils.split(null, *) = null 3170 * StringUtils.split("", *) = [] 3171 * StringUtils.split("a.b.c", '.') = ["a", "b", "c"] 3172 * StringUtils.split("a..b.c", '.') = ["a", "b", "c"] 3173 * StringUtils.split("a:b:c", '.') = ["a:b:c"] 3174 * StringUtils.split("a b c", ' ') = ["a", "b", "c"] 3175 * </pre> 3176 * 3177 * @param str the String to parse, may be null 3178 * @param separatorChar the character used as the delimiter 3179 * @return an array of parsed Strings, {@code null} if null String input 3180 * @since 2.0 3181 */ 3182 public static String[] split(final String str, final char separatorChar) { 3183 return splitWorker(str, separatorChar, false); 3184 } 3185 3186 /** 3187 * <p>Splits the provided text into an array, separators specified. 3188 * This is an alternative to using StringTokenizer.</p> 3189 * 3190 * <p>The separator is not included in the returned String array. 3191 * Adjacent separators are treated as one separator. 3192 * For more control over the split use the StrTokenizer class.</p> 3193 * 3194 * <p>A {@code null} input String returns {@code null}. 3195 * A {@code null} separatorChars splits on whitespace.</p> 3196 * 3197 * <pre> 3198 * StringUtils.split(null, *) = null 3199 * StringUtils.split("", *) = [] 3200 * StringUtils.split("abc def", null) = ["abc", "def"] 3201 * StringUtils.split("abc def", " ") = ["abc", "def"] 3202 * StringUtils.split("abc def", " ") = ["abc", "def"] 3203 * StringUtils.split("ab:cd:ef", ":") = ["ab", "cd", "ef"] 3204 * </pre> 3205 * 3206 * @param str the String to parse, may be null 3207 * @param separatorChars the characters used as the delimiters, 3208 * {@code null} splits on whitespace 3209 * @return an array of parsed Strings, {@code null} if null String input 3210 */ 3211 public static String[] split(final String str, final String separatorChars) { 3212 return splitWorker(str, separatorChars, -1, false); 3213 } 3214 3215 /** 3216 * <p>Splits the provided text into an array with a maximum length, 3217 * separators specified.</p> 3218 * 3219 * <p>The separator is not included in the returned String array. 3220 * Adjacent separators are treated as one separator.</p> 3221 * 3222 * <p>A {@code null} input String returns {@code null}. 3223 * A {@code null} separatorChars splits on whitespace.</p> 3224 * 3225 * <p>If more than {@code max} delimited substrings are found, the last 3226 * returned string includes all characters after the first {@code max - 1} 3227 * returned strings (including separator characters).</p> 3228 * 3229 * <pre> 3230 * StringUtils.split(null, *, *) = null 3231 * StringUtils.split("", *, *) = [] 3232 * StringUtils.split("ab cd ef", null, 0) = ["ab", "cd", "ef"] 3233 * StringUtils.split("ab cd ef", null, 0) = ["ab", "cd", "ef"] 3234 * StringUtils.split("ab:cd:ef", ":", 0) = ["ab", "cd", "ef"] 3235 * StringUtils.split("ab:cd:ef", ":", 2) = ["ab", "cd:ef"] 3236 * </pre> 3237 * 3238 * @param str the String to parse, may be null 3239 * @param separatorChars the characters used as the delimiters, 3240 * {@code null} splits on whitespace 3241 * @param max the maximum number of elements to include in the 3242 * array. A zero or negative value implies no limit 3243 * @return an array of parsed Strings, {@code null} if null String input 3244 */ 3245 public static String[] split(final String str, final String separatorChars, final int max) { 3246 return splitWorker(str, separatorChars, max, false); 3247 } 3248 3249 /** 3250 * <p>Splits the provided text into an array, separator string specified.</p> 3251 * 3252 * <p>The separator(s) will not be included in the returned String array. 3253 * Adjacent separators are treated as one separator.</p> 3254 * 3255 * <p>A {@code null} input String returns {@code null}. 3256 * A {@code null} separator splits on whitespace.</p> 3257 * 3258 * <pre> 3259 * StringUtils.splitByWholeSeparator(null, *) = null 3260 * StringUtils.splitByWholeSeparator("", *) = [] 3261 * StringUtils.splitByWholeSeparator("ab de fg", null) = ["ab", "de", "fg"] 3262 * StringUtils.splitByWholeSeparator("ab de fg", null) = ["ab", "de", "fg"] 3263 * StringUtils.splitByWholeSeparator("ab:cd:ef", ":") = ["ab", "cd", "ef"] 3264 * StringUtils.splitByWholeSeparator("ab-!-cd-!-ef", "-!-") = ["ab", "cd", "ef"] 3265 * </pre> 3266 * 3267 * @param str the String to parse, may be null 3268 * @param separator String containing the String to be used as a delimiter, 3269 * {@code null} splits on whitespace 3270 * @return an array of parsed Strings, {@code null} if null String was input 3271 */ 3272 public static String[] splitByWholeSeparator(final String str, final String separator) { 3273 return splitByWholeSeparatorWorker(str, separator, -1, false ) ; 3274 } 3275 3276 /** 3277 * <p>Splits the provided text into an array, separator string specified. 3278 * Returns a maximum of {@code max} substrings.</p> 3279 * 3280 * <p>The separator(s) will not be included in the returned String array. 3281 * Adjacent separators are treated as one separator.</p> 3282 * 3283 * <p>A {@code null} input String returns {@code null}. 3284 * A {@code null} separator splits on whitespace.</p> 3285 * 3286 * <pre> 3287 * StringUtils.splitByWholeSeparator(null, *, *) = null 3288 * StringUtils.splitByWholeSeparator("", *, *) = [] 3289 * StringUtils.splitByWholeSeparator("ab de fg", null, 0) = ["ab", "de", "fg"] 3290 * StringUtils.splitByWholeSeparator("ab de fg", null, 0) = ["ab", "de", "fg"] 3291 * StringUtils.splitByWholeSeparator("ab:cd:ef", ":", 2) = ["ab", "cd:ef"] 3292 * StringUtils.splitByWholeSeparator("ab-!-cd-!-ef", "-!-", 5) = ["ab", "cd", "ef"] 3293 * StringUtils.splitByWholeSeparator("ab-!-cd-!-ef", "-!-", 2) = ["ab", "cd-!-ef"] 3294 * </pre> 3295 * 3296 * @param str the String to parse, may be null 3297 * @param separator String containing the String to be used as a delimiter, 3298 * {@code null} splits on whitespace 3299 * @param max the maximum number of elements to include in the returned 3300 * array. A zero or negative value implies no limit. 3301 * @return an array of parsed Strings, {@code null} if null String was input 3302 */ 3303 public static String[] splitByWholeSeparator( final String str, final String separator, final int max) { 3304 return splitByWholeSeparatorWorker(str, separator, max, false); 3305 } 3306 3307 /** 3308 * <p>Splits the provided text into an array, separator string specified. </p> 3309 * 3310 * <p>The separator is not included in the returned String array. 3311 * Adjacent separators are treated as separators for empty tokens. 3312 * For more control over the split use the StrTokenizer class.</p> 3313 * 3314 * <p>A {@code null} input String returns {@code null}. 3315 * A {@code null} separator splits on whitespace.</p> 3316 * 3317 * <pre> 3318 * StringUtils.splitByWholeSeparatorPreserveAllTokens(null, *) = null 3319 * StringUtils.splitByWholeSeparatorPreserveAllTokens("", *) = [] 3320 * StringUtils.splitByWholeSeparatorPreserveAllTokens("ab de fg", null) = ["ab", "de", "fg"] 3321 * StringUtils.splitByWholeSeparatorPreserveAllTokens("ab de fg", null) = ["ab", "", "", "de", "fg"] 3322 * StringUtils.splitByWholeSeparatorPreserveAllTokens("ab:cd:ef", ":") = ["ab", "cd", "ef"] 3323 * StringUtils.splitByWholeSeparatorPreserveAllTokens("ab-!-cd-!-ef", "-!-") = ["ab", "cd", "ef"] 3324 * </pre> 3325 * 3326 * @param str the String to parse, may be null 3327 * @param separator String containing the String to be used as a delimiter, 3328 * {@code null} splits on whitespace 3329 * @return an array of parsed Strings, {@code null} if null String was input 3330 * @since 2.4 3331 */ 3332 public static String[] splitByWholeSeparatorPreserveAllTokens(final String str, final String separator) { 3333 return splitByWholeSeparatorWorker(str, separator, -1, true); 3334 } 3335 3336 /** 3337 * <p>Splits the provided text into an array, separator string specified. 3338 * Returns a maximum of {@code max} substrings.</p> 3339 * 3340 * <p>The separator is not included in the returned String array. 3341 * Adjacent separators are treated as separators for empty tokens. 3342 * For more control over the split use the StrTokenizer class.</p> 3343 * 3344 * <p>A {@code null} input String returns {@code null}. 3345 * A {@code null} separator splits on whitespace.</p> 3346 * 3347 * <pre> 3348 * StringUtils.splitByWholeSeparatorPreserveAllTokens(null, *, *) = null 3349 * StringUtils.splitByWholeSeparatorPreserveAllTokens("", *, *) = [] 3350 * StringUtils.splitByWholeSeparatorPreserveAllTokens("ab de fg", null, 0) = ["ab", "de", "fg"] 3351 * StringUtils.splitByWholeSeparatorPreserveAllTokens("ab de fg", null, 0) = ["ab", "", "", "de", "fg"] 3352 * StringUtils.splitByWholeSeparatorPreserveAllTokens("ab:cd:ef", ":", 2) = ["ab", "cd:ef"] 3353 * StringUtils.splitByWholeSeparatorPreserveAllTokens("ab-!-cd-!-ef", "-!-", 5) = ["ab", "cd", "ef"] 3354 * StringUtils.splitByWholeSeparatorPreserveAllTokens("ab-!-cd-!-ef", "-!-", 2) = ["ab", "cd-!-ef"] 3355 * </pre> 3356 * 3357 * @param str the String to parse, may be null 3358 * @param separator String containing the String to be used as a delimiter, 3359 * {@code null} splits on whitespace 3360 * @param max the maximum number of elements to include in the returned 3361 * array. A zero or negative value implies no limit. 3362 * @return an array of parsed Strings, {@code null} if null String was input 3363 * @since 2.4 3364 */ 3365 public static String[] splitByWholeSeparatorPreserveAllTokens(final String str, final String separator, final int max) { 3366 return splitByWholeSeparatorWorker(str, separator, max, true); 3367 } 3368 3369 /** 3370 * Performs the logic for the {@code splitByWholeSeparatorPreserveAllTokens} methods. 3371 * 3372 * @param str the String to parse, may be {@code null} 3373 * @param separator String containing the String to be used as a delimiter, 3374 * {@code null} splits on whitespace 3375 * @param max the maximum number of elements to include in the returned 3376 * array. A zero or negative value implies no limit. 3377 * @param preserveAllTokens if {@code true}, adjacent separators are 3378 * treated as empty token separators; if {@code false}, adjacent 3379 * separators are treated as one separator. 3380 * @return an array of parsed Strings, {@code null} if null String input 3381 * @since 2.4 3382 */ 3383 private static String[] splitByWholeSeparatorWorker( 3384 final String str, final String separator, final int max, final boolean preserveAllTokens) { 3385 if (str == null) { 3386 return null; 3387 } 3388 3389 final int len = str.length(); 3390 3391 if (len == 0) { 3392 return ArrayUtils.EMPTY_STRING_ARRAY; 3393 } 3394 3395 if (separator == null || EMPTY.equals(separator)) { 3396 // Split on whitespace. 3397 return splitWorker(str, null, max, preserveAllTokens); 3398 } 3399 3400 final int separatorLength = separator.length(); 3401 3402 final ArrayList<String> substrings = new ArrayList<>(); 3403 int numberOfSubstrings = 0; 3404 int beg = 0; 3405 int end = 0; 3406 while (end < len) { 3407 end = str.indexOf(separator, beg); 3408 3409 if (end > -1) { 3410 if (end > beg) { 3411 numberOfSubstrings += 1; 3412 3413 if (numberOfSubstrings == max) { 3414 end = len; 3415 substrings.add(str.substring(beg)); 3416 } else { 3417 // The following is OK, because String.substring( beg, end ) excludes 3418 // the character at the position 'end'. 3419 substrings.add(str.substring(beg, end)); 3420 3421 // Set the starting point for the next search. 3422 // The following is equivalent to beg = end + (separatorLength - 1) + 1, 3423 // which is the right calculation: 3424 beg = end + separatorLength; 3425 } 3426 } else { 3427 // We found a consecutive occurrence of the separator, so skip it. 3428 if (preserveAllTokens) { 3429 numberOfSubstrings += 1; 3430 if (numberOfSubstrings == max) { 3431 end = len; 3432 substrings.add(str.substring(beg)); 3433 } else { 3434 substrings.add(EMPTY); 3435 } 3436 } 3437 beg = end + separatorLength; 3438 } 3439 } else { 3440 // String.substring( beg ) goes from 'beg' to the end of the String. 3441 substrings.add(str.substring(beg)); 3442 end = len; 3443 } 3444 } 3445 3446 return substrings.toArray(new String[substrings.size()]); 3447 } 3448 3449 // ----------------------------------------------------------------------- 3450 /** 3451 * <p>Splits the provided text into an array, using whitespace as the 3452 * separator, preserving all tokens, including empty tokens created by 3453 * adjacent separators. This is an alternative to using StringTokenizer. 3454 * Whitespace is defined by {@link Character#isWhitespace(char)}.</p> 3455 * 3456 * <p>The separator is not included in the returned String array. 3457 * Adjacent separators are treated as separators for empty tokens. 3458 * For more control over the split use the StrTokenizer class.</p> 3459 * 3460 * <p>A {@code null} input String returns {@code null}.</p> 3461 * 3462 * <pre> 3463 * StringUtils.splitPreserveAllTokens(null) = null 3464 * StringUtils.splitPreserveAllTokens("") = [] 3465 * StringUtils.splitPreserveAllTokens("abc def") = ["abc", "def"] 3466 * StringUtils.splitPreserveAllTokens("abc def") = ["abc", "", "def"] 3467 * StringUtils.splitPreserveAllTokens(" abc ") = ["", "abc", ""] 3468 * </pre> 3469 * 3470 * @param str the String to parse, may be {@code null} 3471 * @return an array of parsed Strings, {@code null} if null String input 3472 * @since 2.1 3473 */ 3474 public static String[] splitPreserveAllTokens(final String str) { 3475 return splitWorker(str, null, -1, true); 3476 } 3477 3478 /** 3479 * <p>Splits the provided text into an array, separator specified, 3480 * preserving all tokens, including empty tokens created by adjacent 3481 * separators. This is an alternative to using StringTokenizer.</p> 3482 * 3483 * <p>The separator is not included in the returned String array. 3484 * Adjacent separators are treated as separators for empty tokens. 3485 * For more control over the split use the StrTokenizer class.</p> 3486 * 3487 * <p>A {@code null} input String returns {@code null}.</p> 3488 * 3489 * <pre> 3490 * StringUtils.splitPreserveAllTokens(null, *) = null 3491 * StringUtils.splitPreserveAllTokens("", *) = [] 3492 * StringUtils.splitPreserveAllTokens("a.b.c", '.') = ["a", "b", "c"] 3493 * StringUtils.splitPreserveAllTokens("a..b.c", '.') = ["a", "", "b", "c"] 3494 * StringUtils.splitPreserveAllTokens("a:b:c", '.') = ["a:b:c"] 3495 * StringUtils.splitPreserveAllTokens("a\tb\nc", null) = ["a", "b", "c"] 3496 * StringUtils.splitPreserveAllTokens("a b c", ' ') = ["a", "b", "c"] 3497 * StringUtils.splitPreserveAllTokens("a b c ", ' ') = ["a", "b", "c", ""] 3498 * StringUtils.splitPreserveAllTokens("a b c ", ' ') = ["a", "b", "c", "", ""] 3499 * StringUtils.splitPreserveAllTokens(" a b c", ' ') = ["", a", "b", "c"] 3500 * StringUtils.splitPreserveAllTokens(" a b c", ' ') = ["", "", a", "b", "c"] 3501 * StringUtils.splitPreserveAllTokens(" a b c ", ' ') = ["", a", "b", "c", ""] 3502 * </pre> 3503 * 3504 * @param str the String to parse, may be {@code null} 3505 * @param separatorChar the character used as the delimiter, 3506 * {@code null} splits on whitespace 3507 * @return an array of parsed Strings, {@code null} if null String input 3508 * @since 2.1 3509 */ 3510 public static String[] splitPreserveAllTokens(final String str, final char separatorChar) { 3511 return splitWorker(str, separatorChar, true); 3512 } 3513 3514 /** 3515 * Performs the logic for the {@code split} and 3516 * {@code splitPreserveAllTokens} methods that do not return a 3517 * maximum array length. 3518 * 3519 * @param str the String to parse, may be {@code null} 3520 * @param separatorChar the separate character 3521 * @param preserveAllTokens if {@code true}, adjacent separators are 3522 * treated as empty token separators; if {@code false}, adjacent 3523 * separators are treated as one separator. 3524 * @return an array of parsed Strings, {@code null} if null String input 3525 */ 3526 private static String[] splitWorker(final String str, final char separatorChar, final boolean preserveAllTokens) { 3527 // Performance tuned for 2.0 (JDK1.4) 3528 3529 if (str == null) { 3530 return null; 3531 } 3532 final int len = str.length(); 3533 if (len == 0) { 3534 return ArrayUtils.EMPTY_STRING_ARRAY; 3535 } 3536 final List<String> list = new ArrayList<>(); 3537 int i = 0, start = 0; 3538 boolean match = false; 3539 boolean lastMatch = false; 3540 while (i < len) { 3541 if (str.charAt(i) == separatorChar) { 3542 if (match || preserveAllTokens) { 3543 list.add(str.substring(start, i)); 3544 match = false; 3545 lastMatch = true; 3546 } 3547 start = ++i; 3548 continue; 3549 } 3550 lastMatch = false; 3551 match = true; 3552 i++; 3553 } 3554 if (match || preserveAllTokens && lastMatch) { 3555 list.add(str.substring(start, i)); 3556 } 3557 return list.toArray(new String[list.size()]); 3558 } 3559 3560 /** 3561 * <p>Splits the provided text into an array, separators specified, 3562 * preserving all tokens, including empty tokens created by adjacent 3563 * separators. This is an alternative to using StringTokenizer.</p> 3564 * 3565 * <p>The separator is not included in the returned String array. 3566 * Adjacent separators are treated as separators for empty tokens. 3567 * For more control over the split use the StrTokenizer class.</p> 3568 * 3569 * <p>A {@code null} input String returns {@code null}. 3570 * A {@code null} separatorChars splits on whitespace.</p> 3571 * 3572 * <pre> 3573 * StringUtils.splitPreserveAllTokens(null, *) = null 3574 * StringUtils.splitPreserveAllTokens("", *) = [] 3575 * StringUtils.splitPreserveAllTokens("abc def", null) = ["abc", "def"] 3576 * StringUtils.splitPreserveAllTokens("abc def", " ") = ["abc", "def"] 3577 * StringUtils.splitPreserveAllTokens("abc def", " ") = ["abc", "", def"] 3578 * StringUtils.splitPreserveAllTokens("ab:cd:ef", ":") = ["ab", "cd", "ef"] 3579 * StringUtils.splitPreserveAllTokens("ab:cd:ef:", ":") = ["ab", "cd", "ef", ""] 3580 * StringUtils.splitPreserveAllTokens("ab:cd:ef::", ":") = ["ab", "cd", "ef", "", ""] 3581 * StringUtils.splitPreserveAllTokens("ab::cd:ef", ":") = ["ab", "", cd", "ef"] 3582 * StringUtils.splitPreserveAllTokens(":cd:ef", ":") = ["", cd", "ef"] 3583 * StringUtils.splitPreserveAllTokens("::cd:ef", ":") = ["", "", cd", "ef"] 3584 * StringUtils.splitPreserveAllTokens(":cd:ef:", ":") = ["", cd", "ef", ""] 3585 * </pre> 3586 * 3587 * @param str the String to parse, may be {@code null} 3588 * @param separatorChars the characters used as the delimiters, 3589 * {@code null} splits on whitespace 3590 * @return an array of parsed Strings, {@code null} if null String input 3591 * @since 2.1 3592 */ 3593 public static String[] splitPreserveAllTokens(final String str, final String separatorChars) { 3594 return splitWorker(str, separatorChars, -1, true); 3595 } 3596 3597 /** 3598 * <p>Splits the provided text into an array with a maximum length, 3599 * separators specified, preserving all tokens, including empty tokens 3600 * created by adjacent separators.</p> 3601 * 3602 * <p>The separator is not included in the returned String array. 3603 * Adjacent separators are treated as separators for empty tokens. 3604 * Adjacent separators are treated as one separator.</p> 3605 * 3606 * <p>A {@code null} input String returns {@code null}. 3607 * A {@code null} separatorChars splits on whitespace.</p> 3608 * 3609 * <p>If more than {@code max} delimited substrings are found, the last 3610 * returned string includes all characters after the first {@code max - 1} 3611 * returned strings (including separator characters).</p> 3612 * 3613 * <pre> 3614 * StringUtils.splitPreserveAllTokens(null, *, *) = null 3615 * StringUtils.splitPreserveAllTokens("", *, *) = [] 3616 * StringUtils.splitPreserveAllTokens("ab de fg", null, 0) = ["ab", "cd", "ef"] 3617 * StringUtils.splitPreserveAllTokens("ab de fg", null, 0) = ["ab", "cd", "ef"] 3618 * StringUtils.splitPreserveAllTokens("ab:cd:ef", ":", 0) = ["ab", "cd", "ef"] 3619 * StringUtils.splitPreserveAllTokens("ab:cd:ef", ":", 2) = ["ab", "cd:ef"] 3620 * StringUtils.splitPreserveAllTokens("ab de fg", null, 2) = ["ab", " de fg"] 3621 * StringUtils.splitPreserveAllTokens("ab de fg", null, 3) = ["ab", "", " de fg"] 3622 * StringUtils.splitPreserveAllTokens("ab de fg", null, 4) = ["ab", "", "", "de fg"] 3623 * </pre> 3624 * 3625 * @param str the String to parse, may be {@code null} 3626 * @param separatorChars the characters used as the delimiters, 3627 * {@code null} splits on whitespace 3628 * @param max the maximum number of elements to include in the 3629 * array. A zero or negative value implies no limit 3630 * @return an array of parsed Strings, {@code null} if null String input 3631 * @since 2.1 3632 */ 3633 public static String[] splitPreserveAllTokens(final String str, final String separatorChars, final int max) { 3634 return splitWorker(str, separatorChars, max, true); 3635 } 3636 3637 /** 3638 * Performs the logic for the {@code split} and 3639 * {@code splitPreserveAllTokens} methods that return a maximum array 3640 * length. 3641 * 3642 * @param str the String to parse, may be {@code null} 3643 * @param separatorChars the separate character 3644 * @param max the maximum number of elements to include in the 3645 * array. A zero or negative value implies no limit. 3646 * @param preserveAllTokens if {@code true}, adjacent separators are 3647 * treated as empty token separators; if {@code false}, adjacent 3648 * separators are treated as one separator. 3649 * @return an array of parsed Strings, {@code null} if null String input 3650 */ 3651 private static String[] splitWorker(final String str, final String separatorChars, final int max, final boolean preserveAllTokens) { 3652 // Performance tuned for 2.0 (JDK1.4) 3653 // Direct code is quicker than StringTokenizer. 3654 // Also, StringTokenizer uses isSpace() not isWhitespace() 3655 3656 if (str == null) { 3657 return null; 3658 } 3659 final int len = str.length(); 3660 if (len == 0) { 3661 return ArrayUtils.EMPTY_STRING_ARRAY; 3662 } 3663 final List<String> list = new ArrayList<>(); 3664 int sizePlus1 = 1; 3665 int i = 0, start = 0; 3666 boolean match = false; 3667 boolean lastMatch = false; 3668 if (separatorChars == null) { 3669 // Null separator means use whitespace 3670 while (i < len) { 3671 if (Character.isWhitespace(str.charAt(i))) { 3672 if (match || preserveAllTokens) { 3673 lastMatch = true; 3674 if (sizePlus1++ == max) { 3675 i = len; 3676 lastMatch = false; 3677 } 3678 list.add(str.substring(start, i)); 3679 match = false; 3680 } 3681 start = ++i; 3682 continue; 3683 } 3684 lastMatch = false; 3685 match = true; 3686 i++; 3687 } 3688 } else if (separatorChars.length() == 1) { 3689 // Optimise 1 character case 3690 final char sep = separatorChars.charAt(0); 3691 while (i < len) { 3692 if (str.charAt(i) == sep) { 3693 if (match || preserveAllTokens) { 3694 lastMatch = true; 3695 if (sizePlus1++ == max) { 3696 i = len; 3697 lastMatch = false; 3698 } 3699 list.add(str.substring(start, i)); 3700 match = false; 3701 } 3702 start = ++i; 3703 continue; 3704 } 3705 lastMatch = false; 3706 match = true; 3707 i++; 3708 } 3709 } else { 3710 // standard case 3711 while (i < len) { 3712 if (separatorChars.indexOf(str.charAt(i)) >= 0) { 3713 if (match || preserveAllTokens) { 3714 lastMatch = true; 3715 if (sizePlus1++ == max) { 3716 i = len; 3717 lastMatch = false; 3718 } 3719 list.add(str.substring(start, i)); 3720 match = false; 3721 } 3722 start = ++i; 3723 continue; 3724 } 3725 lastMatch = false; 3726 match = true; 3727 i++; 3728 } 3729 } 3730 if (match || preserveAllTokens && lastMatch) { 3731 list.add(str.substring(start, i)); 3732 } 3733 return list.toArray(new String[list.size()]); 3734 } 3735 3736 /** 3737 * <p>Splits a String by Character type as returned by 3738 * {@code java.lang.Character.getType(char)}. Groups of contiguous 3739 * characters of the same type are returned as complete tokens. 3740 * <pre> 3741 * StringUtils.splitByCharacterType(null) = null 3742 * StringUtils.splitByCharacterType("") = [] 3743 * StringUtils.splitByCharacterType("ab de fg") = ["ab", " ", "de", " ", "fg"] 3744 * StringUtils.splitByCharacterType("ab de fg") = ["ab", " ", "de", " ", "fg"] 3745 * StringUtils.splitByCharacterType("ab:cd:ef") = ["ab", ":", "cd", ":", "ef"] 3746 * StringUtils.splitByCharacterType("number5") = ["number", "5"] 3747 * StringUtils.splitByCharacterType("fooBar") = ["foo", "B", "ar"] 3748 * StringUtils.splitByCharacterType("foo200Bar") = ["foo", "200", "B", "ar"] 3749 * StringUtils.splitByCharacterType("ASFRules") = ["ASFR", "ules"] 3750 * </pre> 3751 * @param str the String to split, may be {@code null} 3752 * @return an array of parsed Strings, {@code null} if null String input 3753 * @since 2.4 3754 */ 3755 public static String[] splitByCharacterType(final String str) { 3756 return splitByCharacterType(str, false); 3757 } 3758 3759 /** 3760 * <p>Splits a String by Character type as returned by 3761 * {@code java.lang.Character.getType(char)}. Groups of contiguous 3762 * characters of the same type are returned as complete tokens, with the 3763 * following exception: the character of type 3764 * {@code Character.UPPERCASE_LETTER}, if any, immediately 3765 * preceding a token of type {@code Character.LOWERCASE_LETTER} 3766 * will belong to the following token rather than to the preceding, if any, 3767 * {@code Character.UPPERCASE_LETTER} token. 3768 * <pre> 3769 * StringUtils.splitByCharacterTypeCamelCase(null) = null 3770 * StringUtils.splitByCharacterTypeCamelCase("") = [] 3771 * StringUtils.splitByCharacterTypeCamelCase("ab de fg") = ["ab", " ", "de", " ", "fg"] 3772 * StringUtils.splitByCharacterTypeCamelCase("ab de fg") = ["ab", " ", "de", " ", "fg"] 3773 * StringUtils.splitByCharacterTypeCamelCase("ab:cd:ef") = ["ab", ":", "cd", ":", "ef"] 3774 * StringUtils.splitByCharacterTypeCamelCase("number5") = ["number", "5"] 3775 * StringUtils.splitByCharacterTypeCamelCase("fooBar") = ["foo", "Bar"] 3776 * StringUtils.splitByCharacterTypeCamelCase("foo200Bar") = ["foo", "200", "Bar"] 3777 * StringUtils.splitByCharacterTypeCamelCase("ASFRules") = ["ASF", "Rules"] 3778 * </pre> 3779 * @param str the String to split, may be {@code null} 3780 * @return an array of parsed Strings, {@code null} if null String input 3781 * @since 2.4 3782 */ 3783 public static String[] splitByCharacterTypeCamelCase(final String str) { 3784 return splitByCharacterType(str, true); 3785 } 3786 3787 /** 3788 * <p>Splits a String by Character type as returned by 3789 * {@code java.lang.Character.getType(char)}. Groups of contiguous 3790 * characters of the same type are returned as complete tokens, with the 3791 * following exception: if {@code camelCase} is {@code true}, 3792 * the character of type {@code Character.UPPERCASE_LETTER}, if any, 3793 * immediately preceding a token of type {@code Character.LOWERCASE_LETTER} 3794 * will belong to the following token rather than to the preceding, if any, 3795 * {@code Character.UPPERCASE_LETTER} token. 3796 * @param str the String to split, may be {@code null} 3797 * @param camelCase whether to use so-called "camel-case" for letter types 3798 * @return an array of parsed Strings, {@code null} if null String input 3799 * @since 2.4 3800 */ 3801 private static String[] splitByCharacterType(final String str, final boolean camelCase) { 3802 if (str == null) { 3803 return null; 3804 } 3805 if (str.isEmpty()) { 3806 return ArrayUtils.EMPTY_STRING_ARRAY; 3807 } 3808 final char[] c = str.toCharArray(); 3809 final List<String> list = new ArrayList<>(); 3810 int tokenStart = 0; 3811 int currentType = Character.getType(c[tokenStart]); 3812 for (int pos = tokenStart + 1; pos < c.length; pos++) { 3813 final int type = Character.getType(c[pos]); 3814 if (type == currentType) { 3815 continue; 3816 } 3817 if (camelCase && type == Character.LOWERCASE_LETTER && currentType == Character.UPPERCASE_LETTER) { 3818 final int newTokenStart = pos - 1; 3819 if (newTokenStart != tokenStart) { 3820 list.add(new String(c, tokenStart, newTokenStart - tokenStart)); 3821 tokenStart = newTokenStart; 3822 } 3823 } else { 3824 list.add(new String(c, tokenStart, pos - tokenStart)); 3825 tokenStart = pos; 3826 } 3827 currentType = type; 3828 } 3829 list.add(new String(c, tokenStart, c.length - tokenStart)); 3830 return list.toArray(new String[list.size()]); 3831 } 3832 3833 // Joining 3834 //----------------------------------------------------------------------- 3835 /** 3836 * <p>Joins the elements of the provided array into a single String 3837 * containing the provided list of elements.</p> 3838 * 3839 * <p>No separator is added to the joined String. 3840 * Null objects or empty strings within the array are represented by 3841 * empty strings.</p> 3842 * 3843 * <pre> 3844 * StringUtils.join(null) = null 3845 * StringUtils.join([]) = "" 3846 * StringUtils.join([null]) = "" 3847 * StringUtils.join(["a", "b", "c"]) = "abc" 3848 * StringUtils.join([null, "", "a"]) = "a" 3849 * </pre> 3850 * 3851 * @param <T> the specific type of values to join together 3852 * @param elements the values to join together, may be null 3853 * @return the joined String, {@code null} if null array input 3854 * @since 2.0 3855 * @since 3.0 Changed signature to use varargs 3856 */ 3857 @SafeVarargs 3858 public static <T> String join(final T... elements) { 3859 return join(elements, null); 3860 } 3861 3862 /** 3863 * <p>Joins the elements of the provided array into a single String 3864 * containing the provided list of elements.</p> 3865 * 3866 * <p>No delimiter is added before or after the list. 3867 * Null objects or empty strings within the array are represented by 3868 * empty strings.</p> 3869 * 3870 * <pre> 3871 * StringUtils.join(null, *) = null 3872 * StringUtils.join([], *) = "" 3873 * StringUtils.join([null], *) = "" 3874 * StringUtils.join(["a", "b", "c"], ';') = "a;b;c" 3875 * StringUtils.join(["a", "b", "c"], null) = "abc" 3876 * StringUtils.join([null, "", "a"], ';') = ";;a" 3877 * </pre> 3878 * 3879 * @param array the array of values to join together, may be null 3880 * @param separator the separator character to use 3881 * @return the joined String, {@code null} if null array input 3882 * @since 2.0 3883 */ 3884 public static String join(final Object[] array, final char separator) { 3885 if (array == null) { 3886 return null; 3887 } 3888 return join(array, separator, 0, array.length); 3889 } 3890 3891 /** 3892 * <p> 3893 * Joins the elements of the provided array into a single String containing the provided list of elements. 3894 * </p> 3895 * 3896 * <p> 3897 * No delimiter is added before or after the list. Null objects or empty strings within the array are represented 3898 * by empty strings. 3899 * </p> 3900 * 3901 * <pre> 3902 * StringUtils.join(null, *) = null 3903 * StringUtils.join([], *) = "" 3904 * StringUtils.join([null], *) = "" 3905 * StringUtils.join([1, 2, 3], ';') = "1;2;3" 3906 * StringUtils.join([1, 2, 3], null) = "123" 3907 * </pre> 3908 * 3909 * @param array 3910 * the array of values to join together, may be null 3911 * @param separator 3912 * the separator character to use 3913 * @return the joined String, {@code null} if null array input 3914 * @since 3.2 3915 */ 3916 public static String join(final long[] array, final char separator) { 3917 if (array == null) { 3918 return null; 3919 } 3920 return join(array, separator, 0, array.length); 3921 } 3922 3923 /** 3924 * <p> 3925 * Joins the elements of the provided array into a single String containing the provided list of elements. 3926 * </p> 3927 * 3928 * <p> 3929 * No delimiter is added before or after the list. Null objects or empty strings within the array are represented 3930 * by empty strings. 3931 * </p> 3932 * 3933 * <pre> 3934 * StringUtils.join(null, *) = null 3935 * StringUtils.join([], *) = "" 3936 * StringUtils.join([null], *) = "" 3937 * StringUtils.join([1, 2, 3], ';') = "1;2;3" 3938 * StringUtils.join([1, 2, 3], null) = "123" 3939 * </pre> 3940 * 3941 * @param array 3942 * the array of values to join together, may be null 3943 * @param separator 3944 * the separator character to use 3945 * @return the joined String, {@code null} if null array input 3946 * @since 3.2 3947 */ 3948 public static String join(final int[] array, final char separator) { 3949 if (array == null) { 3950 return null; 3951 } 3952 return join(array, separator, 0, array.length); 3953 } 3954 3955 /** 3956 * <p> 3957 * Joins the elements of the provided array into a single String containing the provided list of elements. 3958 * </p> 3959 * 3960 * <p> 3961 * No delimiter is added before or after the list. Null objects or empty strings within the array are represented 3962 * by empty strings. 3963 * </p> 3964 * 3965 * <pre> 3966 * StringUtils.join(null, *) = null 3967 * StringUtils.join([], *) = "" 3968 * StringUtils.join([null], *) = "" 3969 * StringUtils.join([1, 2, 3], ';') = "1;2;3" 3970 * StringUtils.join([1, 2, 3], null) = "123" 3971 * </pre> 3972 * 3973 * @param array 3974 * the array of values to join together, may be null 3975 * @param separator 3976 * the separator character to use 3977 * @return the joined String, {@code null} if null array input 3978 * @since 3.2 3979 */ 3980 public static String join(final short[] array, final char separator) { 3981 if (array == null) { 3982 return null; 3983 } 3984 return join(array, separator, 0, array.length); 3985 } 3986 3987 /** 3988 * <p> 3989 * Joins the elements of the provided array into a single String containing the provided list of elements. 3990 * </p> 3991 * 3992 * <p> 3993 * No delimiter is added before or after the list. Null objects or empty strings within the array are represented 3994 * by empty strings. 3995 * </p> 3996 * 3997 * <pre> 3998 * StringUtils.join(null, *) = null 3999 * StringUtils.join([], *) = "" 4000 * StringUtils.join([null], *) = "" 4001 * StringUtils.join([1, 2, 3], ';') = "1;2;3" 4002 * StringUtils.join([1, 2, 3], null) = "123" 4003 * </pre> 4004 * 4005 * @param array 4006 * the array of values to join together, may be null 4007 * @param separator 4008 * the separator character to use 4009 * @return the joined String, {@code null} if null array input 4010 * @since 3.2 4011 */ 4012 public static String join(final byte[] array, final char separator) { 4013 if (array == null) { 4014 return null; 4015 } 4016 return join(array, separator, 0, array.length); 4017 } 4018 4019 /** 4020 * <p> 4021 * Joins the elements of the provided array into a single String containing the provided list of elements. 4022 * </p> 4023 * 4024 * <p> 4025 * No delimiter is added before or after the list. Null objects or empty strings within the array are represented 4026 * by empty strings. 4027 * </p> 4028 * 4029 * <pre> 4030 * StringUtils.join(null, *) = null 4031 * StringUtils.join([], *) = "" 4032 * StringUtils.join([null], *) = "" 4033 * StringUtils.join([1, 2, 3], ';') = "1;2;3" 4034 * StringUtils.join([1, 2, 3], null) = "123" 4035 * </pre> 4036 * 4037 * @param array 4038 * the array of values to join together, may be null 4039 * @param separator 4040 * the separator character to use 4041 * @return the joined String, {@code null} if null array input 4042 * @since 3.2 4043 */ 4044 public static String join(final char[] array, final char separator) { 4045 if (array == null) { 4046 return null; 4047 } 4048 return join(array, separator, 0, array.length); 4049 } 4050 4051 /** 4052 * <p> 4053 * Joins the elements of the provided array into a single String containing the provided list of elements. 4054 * </p> 4055 * 4056 * <p> 4057 * No delimiter is added before or after the list. Null objects or empty strings within the array are represented 4058 * by empty strings. 4059 * </p> 4060 * 4061 * <pre> 4062 * StringUtils.join(null, *) = null 4063 * StringUtils.join([], *) = "" 4064 * StringUtils.join([null], *) = "" 4065 * StringUtils.join([1, 2, 3], ';') = "1;2;3" 4066 * StringUtils.join([1, 2, 3], null) = "123" 4067 * </pre> 4068 * 4069 * @param array 4070 * the array of values to join together, may be null 4071 * @param separator 4072 * the separator character to use 4073 * @return the joined String, {@code null} if null array input 4074 * @since 3.2 4075 */ 4076 public static String join(final float[] array, final char separator) { 4077 if (array == null) { 4078 return null; 4079 } 4080 return join(array, separator, 0, array.length); 4081 } 4082 4083 /** 4084 * <p> 4085 * Joins the elements of the provided array into a single String containing the provided list of elements. 4086 * </p> 4087 * 4088 * <p> 4089 * No delimiter is added before or after the list. Null objects or empty strings within the array are represented 4090 * by empty strings. 4091 * </p> 4092 * 4093 * <pre> 4094 * StringUtils.join(null, *) = null 4095 * StringUtils.join([], *) = "" 4096 * StringUtils.join([null], *) = "" 4097 * StringUtils.join([1, 2, 3], ';') = "1;2;3" 4098 * StringUtils.join([1, 2, 3], null) = "123" 4099 * </pre> 4100 * 4101 * @param array 4102 * the array of values to join together, may be null 4103 * @param separator 4104 * the separator character to use 4105 * @return the joined String, {@code null} if null array input 4106 * @since 3.2 4107 */ 4108 public static String join(final double[] array, final char separator) { 4109 if (array == null) { 4110 return null; 4111 } 4112 return join(array, separator, 0, array.length); 4113 } 4114 4115 4116 /** 4117 * <p>Joins the elements of the provided array into a single String 4118 * containing the provided list of elements.</p> 4119 * 4120 * <p>No delimiter is added before or after the list. 4121 * Null objects or empty strings within the array are represented by 4122 * empty strings.</p> 4123 * 4124 * <pre> 4125 * StringUtils.join(null, *) = null 4126 * StringUtils.join([], *) = "" 4127 * StringUtils.join([null], *) = "" 4128 * StringUtils.join(["a", "b", "c"], ';') = "a;b;c" 4129 * StringUtils.join(["a", "b", "c"], null) = "abc" 4130 * StringUtils.join([null, "", "a"], ';') = ";;a" 4131 * </pre> 4132 * 4133 * @param array the array of values to join together, may be null 4134 * @param separator the separator character to use 4135 * @param startIndex the first index to start joining from. It is 4136 * an error to pass in an end index past the end of the array 4137 * @param endIndex the index to stop joining from (exclusive). It is 4138 * an error to pass in an end index past the end of the array 4139 * @return the joined String, {@code null} if null array input 4140 * @since 2.0 4141 */ 4142 public static String join(final Object[] array, final char separator, final int startIndex, final int endIndex) { 4143 if (array == null) { 4144 return null; 4145 } 4146 final int noOfItems = endIndex - startIndex; 4147 if (noOfItems <= 0) { 4148 return EMPTY; 4149 } 4150 final StringBuilder buf = newStringBuilder(noOfItems); 4151 for (int i = startIndex; i < endIndex; i++) { 4152 if (i > startIndex) { 4153 buf.append(separator); 4154 } 4155 if (array[i] != null) { 4156 buf.append(array[i]); 4157 } 4158 } 4159 return buf.toString(); 4160 } 4161 4162 /** 4163 * <p> 4164 * Joins the elements of the provided array into a single String containing the provided list of elements. 4165 * </p> 4166 * 4167 * <p> 4168 * No delimiter is added before or after the list. Null objects or empty strings within the array are represented 4169 * by empty strings. 4170 * </p> 4171 * 4172 * <pre> 4173 * StringUtils.join(null, *) = null 4174 * StringUtils.join([], *) = "" 4175 * StringUtils.join([null], *) = "" 4176 * StringUtils.join([1, 2, 3], ';') = "1;2;3" 4177 * StringUtils.join([1, 2, 3], null) = "123" 4178 * </pre> 4179 * 4180 * @param array 4181 * the array of values to join together, may be null 4182 * @param separator 4183 * the separator character to use 4184 * @param startIndex 4185 * the first index to start joining from. It is an error to pass in an end index past the end of the 4186 * array 4187 * @param endIndex 4188 * the index to stop joining from (exclusive). It is an error to pass in an end index past the end of 4189 * the array 4190 * @return the joined String, {@code null} if null array input 4191 * @since 3.2 4192 */ 4193 public static String join(final long[] array, final char separator, final int startIndex, final int endIndex) { 4194 if (array == null) { 4195 return null; 4196 } 4197 final int noOfItems = endIndex - startIndex; 4198 if (noOfItems <= 0) { 4199 return EMPTY; 4200 } 4201 final StringBuilder buf = newStringBuilder(noOfItems); 4202 for (int i = startIndex; i < endIndex; i++) { 4203 if (i > startIndex) { 4204 buf.append(separator); 4205 } 4206 buf.append(array[i]); 4207 } 4208 return buf.toString(); 4209 } 4210 4211 /** 4212 * <p> 4213 * Joins the elements of the provided array into a single String containing the provided list of elements. 4214 * </p> 4215 * 4216 * <p> 4217 * No delimiter is added before or after the list. Null objects or empty strings within the array are represented 4218 * by empty strings. 4219 * </p> 4220 * 4221 * <pre> 4222 * StringUtils.join(null, *) = null 4223 * StringUtils.join([], *) = "" 4224 * StringUtils.join([null], *) = "" 4225 * StringUtils.join([1, 2, 3], ';') = "1;2;3" 4226 * StringUtils.join([1, 2, 3], null) = "123" 4227 * </pre> 4228 * 4229 * @param array 4230 * the array of values to join together, may be null 4231 * @param separator 4232 * the separator character to use 4233 * @param startIndex 4234 * the first index to start joining from. It is an error to pass in an end index past the end of the 4235 * array 4236 * @param endIndex 4237 * the index to stop joining from (exclusive). It is an error to pass in an end index past the end of 4238 * the array 4239 * @return the joined String, {@code null} if null array input 4240 * @since 3.2 4241 */ 4242 public static String join(final int[] array, final char separator, final int startIndex, final int endIndex) { 4243 if (array == null) { 4244 return null; 4245 } 4246 final int noOfItems = endIndex - startIndex; 4247 if (noOfItems <= 0) { 4248 return EMPTY; 4249 } 4250 final StringBuilder buf = newStringBuilder(noOfItems); 4251 for (int i = startIndex; i < endIndex; i++) { 4252 if (i > startIndex) { 4253 buf.append(separator); 4254 } 4255 buf.append(array[i]); 4256 } 4257 return buf.toString(); 4258 } 4259 4260 /** 4261 * <p> 4262 * Joins the elements of the provided array into a single String containing the provided list of elements. 4263 * </p> 4264 * 4265 * <p> 4266 * No delimiter is added before or after the list. Null objects or empty strings within the array are represented 4267 * by empty strings. 4268 * </p> 4269 * 4270 * <pre> 4271 * StringUtils.join(null, *) = null 4272 * StringUtils.join([], *) = "" 4273 * StringUtils.join([null], *) = "" 4274 * StringUtils.join([1, 2, 3], ';') = "1;2;3" 4275 * StringUtils.join([1, 2, 3], null) = "123" 4276 * </pre> 4277 * 4278 * @param array 4279 * the array of values to join together, may be null 4280 * @param separator 4281 * the separator character to use 4282 * @param startIndex 4283 * the first index to start joining from. It is an error to pass in an end index past the end of the 4284 * array 4285 * @param endIndex 4286 * the index to stop joining from (exclusive). It is an error to pass in an end index past the end of 4287 * the array 4288 * @return the joined String, {@code null} if null array input 4289 * @since 3.2 4290 */ 4291 public static String join(final byte[] array, final char separator, final int startIndex, final int endIndex) { 4292 if (array == null) { 4293 return null; 4294 } 4295 final int noOfItems = endIndex - startIndex; 4296 if (noOfItems <= 0) { 4297 return EMPTY; 4298 } 4299 final StringBuilder buf = newStringBuilder(noOfItems); 4300 for (int i = startIndex; i < endIndex; i++) { 4301 if (i > startIndex) { 4302 buf.append(separator); 4303 } 4304 buf.append(array[i]); 4305 } 4306 return buf.toString(); 4307 } 4308 4309 /** 4310 * <p> 4311 * Joins the elements of the provided array into a single String containing the provided list of elements. 4312 * </p> 4313 * 4314 * <p> 4315 * No delimiter is added before or after the list. Null objects or empty strings within the array are represented 4316 * by empty strings. 4317 * </p> 4318 * 4319 * <pre> 4320 * StringUtils.join(null, *) = null 4321 * StringUtils.join([], *) = "" 4322 * StringUtils.join([null], *) = "" 4323 * StringUtils.join([1, 2, 3], ';') = "1;2;3" 4324 * StringUtils.join([1, 2, 3], null) = "123" 4325 * </pre> 4326 * 4327 * @param array 4328 * the array of values to join together, may be null 4329 * @param separator 4330 * the separator character to use 4331 * @param startIndex 4332 * the first index to start joining from. It is an error to pass in an end index past the end of the 4333 * array 4334 * @param endIndex 4335 * the index to stop joining from (exclusive). It is an error to pass in an end index past the end of 4336 * the array 4337 * @return the joined String, {@code null} if null array input 4338 * @since 3.2 4339 */ 4340 public static String join(final short[] array, final char separator, final int startIndex, final int endIndex) { 4341 if (array == null) { 4342 return null; 4343 } 4344 final int noOfItems = endIndex - startIndex; 4345 if (noOfItems <= 0) { 4346 return EMPTY; 4347 } 4348 final StringBuilder buf = newStringBuilder(noOfItems); 4349 for (int i = startIndex; i < endIndex; i++) { 4350 if (i > startIndex) { 4351 buf.append(separator); 4352 } 4353 buf.append(array[i]); 4354 } 4355 return buf.toString(); 4356 } 4357 4358 /** 4359 * <p> 4360 * Joins the elements of the provided array into a single String containing the provided list of elements. 4361 * </p> 4362 * 4363 * <p> 4364 * No delimiter is added before or after the list. Null objects or empty strings within the array are represented 4365 * by empty strings. 4366 * </p> 4367 * 4368 * <pre> 4369 * StringUtils.join(null, *) = null 4370 * StringUtils.join([], *) = "" 4371 * StringUtils.join([null], *) = "" 4372 * StringUtils.join([1, 2, 3], ';') = "1;2;3" 4373 * StringUtils.join([1, 2, 3], null) = "123" 4374 * </pre> 4375 * 4376 * @param array 4377 * the array of values to join together, may be null 4378 * @param separator 4379 * the separator character to use 4380 * @param startIndex 4381 * the first index to start joining from. It is an error to pass in an end index past the end of the 4382 * array 4383 * @param endIndex 4384 * the index to stop joining from (exclusive). It is an error to pass in an end index past the end of 4385 * the array 4386 * @return the joined String, {@code null} if null array input 4387 * @since 3.2 4388 */ 4389 public static String join(final char[] array, final char separator, final int startIndex, final int endIndex) { 4390 if (array == null) { 4391 return null; 4392 } 4393 final int noOfItems = endIndex - startIndex; 4394 if (noOfItems <= 0) { 4395 return EMPTY; 4396 } 4397 final StringBuilder buf = newStringBuilder(noOfItems); 4398 for (int i = startIndex; i < endIndex; i++) { 4399 if (i > startIndex) { 4400 buf.append(separator); 4401 } 4402 buf.append(array[i]); 4403 } 4404 return buf.toString(); 4405 } 4406 4407 /** 4408 * <p> 4409 * Joins the elements of the provided array into a single String containing the provided list of elements. 4410 * </p> 4411 * 4412 * <p> 4413 * No delimiter is added before or after the list. Null objects or empty strings within the array are represented 4414 * by empty strings. 4415 * </p> 4416 * 4417 * <pre> 4418 * StringUtils.join(null, *) = null 4419 * StringUtils.join([], *) = "" 4420 * StringUtils.join([null], *) = "" 4421 * StringUtils.join([1, 2, 3], ';') = "1;2;3" 4422 * StringUtils.join([1, 2, 3], null) = "123" 4423 * </pre> 4424 * 4425 * @param array 4426 * the array of values to join together, may be null 4427 * @param separator 4428 * the separator character to use 4429 * @param startIndex 4430 * the first index to start joining from. It is an error to pass in an end index past the end of the 4431 * array 4432 * @param endIndex 4433 * the index to stop joining from (exclusive). It is an error to pass in an end index past the end of 4434 * the array 4435 * @return the joined String, {@code null} if null array input 4436 * @since 3.2 4437 */ 4438 public static String join(final double[] array, final char separator, final int startIndex, final int endIndex) { 4439 if (array == null) { 4440 return null; 4441 } 4442 final int noOfItems = endIndex - startIndex; 4443 if (noOfItems <= 0) { 4444 return EMPTY; 4445 } 4446 final StringBuilder buf = newStringBuilder(noOfItems); 4447 for (int i = startIndex; i < endIndex; i++) { 4448 if (i > startIndex) { 4449 buf.append(separator); 4450 } 4451 buf.append(array[i]); 4452 } 4453 return buf.toString(); 4454 } 4455 4456 /** 4457 * <p> 4458 * Joins the elements of the provided array into a single String containing the provided list of elements. 4459 * </p> 4460 * 4461 * <p> 4462 * No delimiter is added before or after the list. Null objects or empty strings within the array are represented 4463 * by empty strings. 4464 * </p> 4465 * 4466 * <pre> 4467 * StringUtils.join(null, *) = null 4468 * StringUtils.join([], *) = "" 4469 * StringUtils.join([null], *) = "" 4470 * StringUtils.join([1, 2, 3], ';') = "1;2;3" 4471 * StringUtils.join([1, 2, 3], null) = "123" 4472 * </pre> 4473 * 4474 * @param array 4475 * the array of values to join together, may be null 4476 * @param separator 4477 * the separator character to use 4478 * @param startIndex 4479 * the first index to start joining from. It is an error to pass in an end index past the end of the 4480 * array 4481 * @param endIndex 4482 * the index to stop joining from (exclusive). It is an error to pass in an end index past the end of 4483 * the array 4484 * @return the joined String, {@code null} if null array input 4485 * @since 3.2 4486 */ 4487 public static String join(final float[] array, final char separator, final int startIndex, final int endIndex) { 4488 if (array == null) { 4489 return null; 4490 } 4491 final int noOfItems = endIndex - startIndex; 4492 if (noOfItems <= 0) { 4493 return EMPTY; 4494 } 4495 final StringBuilder buf = newStringBuilder(noOfItems); 4496 for (int i = startIndex; i < endIndex; i++) { 4497 if (i > startIndex) { 4498 buf.append(separator); 4499 } 4500 buf.append(array[i]); 4501 } 4502 return buf.toString(); 4503 } 4504 4505 4506 /** 4507 * <p>Joins the elements of the provided array into a single String 4508 * containing the provided list of elements.</p> 4509 * 4510 * <p>No delimiter is added before or after the list. 4511 * A {@code null} separator is the same as an empty String (""). 4512 * Null objects or empty strings within the array are represented by 4513 * empty strings.</p> 4514 * 4515 * <pre> 4516 * StringUtils.join(null, *) = null 4517 * StringUtils.join([], *) = "" 4518 * StringUtils.join([null], *) = "" 4519 * StringUtils.join(["a", "b", "c"], "--") = "a--b--c" 4520 * StringUtils.join(["a", "b", "c"], null) = "abc" 4521 * StringUtils.join(["a", "b", "c"], "") = "abc" 4522 * StringUtils.join([null, "", "a"], ',') = ",,a" 4523 * </pre> 4524 * 4525 * @param array the array of values to join together, may be null 4526 * @param separator the separator character to use, null treated as "" 4527 * @return the joined String, {@code null} if null array input 4528 */ 4529 public static String join(final Object[] array, final String separator) { 4530 if (array == null) { 4531 return null; 4532 } 4533 return join(array, separator, 0, array.length); 4534 } 4535 4536 /** 4537 * <p>Joins the elements of the provided array into a single String 4538 * containing the provided list of elements.</p> 4539 * 4540 * <p>No delimiter is added before or after the list. 4541 * A {@code null} separator is the same as an empty String (""). 4542 * Null objects or empty strings within the array are represented by 4543 * empty strings.</p> 4544 * 4545 * <pre> 4546 * StringUtils.join(null, *, *, *) = null 4547 * StringUtils.join([], *, *, *) = "" 4548 * StringUtils.join([null], *, *, *) = "" 4549 * StringUtils.join(["a", "b", "c"], "--", 0, 3) = "a--b--c" 4550 * StringUtils.join(["a", "b", "c"], "--", 1, 3) = "b--c" 4551 * StringUtils.join(["a", "b", "c"], "--", 2, 3) = "c" 4552 * StringUtils.join(["a", "b", "c"], "--", 2, 2) = "" 4553 * StringUtils.join(["a", "b", "c"], null, 0, 3) = "abc" 4554 * StringUtils.join(["a", "b", "c"], "", 0, 3) = "abc" 4555 * StringUtils.join([null, "", "a"], ',', 0, 3) = ",,a" 4556 * </pre> 4557 * 4558 * @param array the array of values to join together, may be null 4559 * @param separator the separator character to use, null treated as "" 4560 * @param startIndex the first index to start joining from. 4561 * @param endIndex the index to stop joining from (exclusive). 4562 * @return the joined String, {@code null} if null array input; or the empty string 4563 * if {@code endIndex - startIndex <= 0}. The number of joined entries is given by 4564 * {@code endIndex - startIndex} 4565 * @throws ArrayIndexOutOfBoundsException ife<br> 4566 * {@code startIndex < 0} or <br> 4567 * {@code startIndex >= array.length()} or <br> 4568 * {@code endIndex < 0} or <br> 4569 * {@code endIndex > array.length()} 4570 */ 4571 public static String join(final Object[] array, String separator, final int startIndex, final int endIndex) { 4572 if (array == null) { 4573 return null; 4574 } 4575 if (separator == null) { 4576 separator = EMPTY; 4577 } 4578 4579 // endIndex - startIndex > 0: Len = NofStrings *(len(firstString) + len(separator)) 4580 // (Assuming that all Strings are roughly equally long) 4581 final int noOfItems = endIndex - startIndex; 4582 if (noOfItems <= 0) { 4583 return EMPTY; 4584 } 4585 4586 final StringBuilder buf = newStringBuilder(noOfItems); 4587 4588 for (int i = startIndex; i < endIndex; i++) { 4589 if (i > startIndex) { 4590 buf.append(separator); 4591 } 4592 if (array[i] != null) { 4593 buf.append(array[i]); 4594 } 4595 } 4596 return buf.toString(); 4597 } 4598 4599 /** 4600 * <p>Joins the elements of the provided {@code Iterator} into 4601 * a single String containing the provided elements.</p> 4602 * 4603 * <p>No delimiter is added before or after the list. Null objects or empty 4604 * strings within the iteration are represented by empty strings.</p> 4605 * 4606 * <p>See the examples here: {@link #join(Object[],char)}. </p> 4607 * 4608 * @param iterator the {@code Iterator} of values to join together, may be null 4609 * @param separator the separator character to use 4610 * @return the joined String, {@code null} if null iterator input 4611 * @since 2.0 4612 */ 4613 public static String join(final Iterator<?> iterator, final char separator) { 4614 4615 // handle null, zero and one elements before building a buffer 4616 if (iterator == null) { 4617 return null; 4618 } 4619 if (!iterator.hasNext()) { 4620 return EMPTY; 4621 } 4622 final Object first = iterator.next(); 4623 if (!iterator.hasNext()) { 4624 return Objects.toString(first, EMPTY); 4625 } 4626 4627 // two or more elements 4628 final StringBuilder buf = new StringBuilder(STRING_BUILDER_SIZE); // Java default is 16, probably too small 4629 if (first != null) { 4630 buf.append(first); 4631 } 4632 4633 while (iterator.hasNext()) { 4634 buf.append(separator); 4635 final Object obj = iterator.next(); 4636 if (obj != null) { 4637 buf.append(obj); 4638 } 4639 } 4640 4641 return buf.toString(); 4642 } 4643 4644 /** 4645 * <p>Joins the elements of the provided {@code Iterator} into 4646 * a single String containing the provided elements.</p> 4647 * 4648 * <p>No delimiter is added before or after the list. 4649 * A {@code null} separator is the same as an empty String ("").</p> 4650 * 4651 * <p>See the examples here: {@link #join(Object[],String)}. </p> 4652 * 4653 * @param iterator the {@code Iterator} of values to join together, may be null 4654 * @param separator the separator character to use, null treated as "" 4655 * @return the joined String, {@code null} if null iterator input 4656 */ 4657 public static String join(final Iterator<?> iterator, final String separator) { 4658 4659 // handle null, zero and one elements before building a buffer 4660 if (iterator == null) { 4661 return null; 4662 } 4663 if (!iterator.hasNext()) { 4664 return EMPTY; 4665 } 4666 final Object first = iterator.next(); 4667 if (!iterator.hasNext()) { 4668 return Objects.toString(first, ""); 4669 } 4670 4671 // two or more elements 4672 final StringBuilder buf = new StringBuilder(STRING_BUILDER_SIZE); // Java default is 16, probably too small 4673 if (first != null) { 4674 buf.append(first); 4675 } 4676 4677 while (iterator.hasNext()) { 4678 if (separator != null) { 4679 buf.append(separator); 4680 } 4681 final Object obj = iterator.next(); 4682 if (obj != null) { 4683 buf.append(obj); 4684 } 4685 } 4686 return buf.toString(); 4687 } 4688 4689 /** 4690 * <p>Joins the elements of the provided {@code Iterable} into 4691 * a single String containing the provided elements.</p> 4692 * 4693 * <p>No delimiter is added before or after the list. Null objects or empty 4694 * strings within the iteration are represented by empty strings.</p> 4695 * 4696 * <p>See the examples here: {@link #join(Object[],char)}. </p> 4697 * 4698 * @param iterable the {@code Iterable} providing the values to join together, may be null 4699 * @param separator the separator character to use 4700 * @return the joined String, {@code null} if null iterator input 4701 * @since 2.3 4702 */ 4703 public static String join(final Iterable<?> iterable, final char separator) { 4704 if (iterable == null) { 4705 return null; 4706 } 4707 return join(iterable.iterator(), separator); 4708 } 4709 4710 /** 4711 * <p>Joins the elements of the provided {@code Iterable} into 4712 * a single String containing the provided elements.</p> 4713 * 4714 * <p>No delimiter is added before or after the list. 4715 * A {@code null} separator is the same as an empty String ("").</p> 4716 * 4717 * <p>See the examples here: {@link #join(Object[],String)}. </p> 4718 * 4719 * @param iterable the {@code Iterable} providing the values to join together, may be null 4720 * @param separator the separator character to use, null treated as "" 4721 * @return the joined String, {@code null} if null iterator input 4722 * @since 2.3 4723 */ 4724 public static String join(final Iterable<?> iterable, final String separator) { 4725 if (iterable == null) { 4726 return null; 4727 } 4728 return join(iterable.iterator(), separator); 4729 } 4730 4731 /** 4732 * <p>Joins the elements of the provided {@code List} into a single String 4733 * containing the provided list of elements.</p> 4734 * 4735 * <p>No delimiter is added before or after the list. 4736 * Null objects or empty strings within the array are represented by 4737 * empty strings.</p> 4738 * 4739 * <pre> 4740 * StringUtils.join(null, *) = null 4741 * StringUtils.join([], *) = "" 4742 * StringUtils.join([null], *) = "" 4743 * StringUtils.join(["a", "b", "c"], ';') = "a;b;c" 4744 * StringUtils.join(["a", "b", "c"], null) = "abc" 4745 * StringUtils.join([null, "", "a"], ';') = ";;a" 4746 * </pre> 4747 * 4748 * @param list the {@code List} of values to join together, may be null 4749 * @param separator the separator character to use 4750 * @param startIndex the first index to start joining from. It is 4751 * an error to pass in an end index past the end of the list 4752 * @param endIndex the index to stop joining from (exclusive). It is 4753 * an error to pass in an end index past the end of the list 4754 * @return the joined String, {@code null} if null list input 4755 * @since 3.8 4756 */ 4757 public static String join(final List<?> list, final char separator, final int startIndex, final int endIndex) { 4758 if (list == null) { 4759 return null; 4760 } 4761 final int noOfItems = endIndex - startIndex; 4762 if (noOfItems <= 0) { 4763 return EMPTY; 4764 } 4765 final List<?> subList = list.subList(startIndex, endIndex); 4766 return join(subList.iterator(), separator); 4767 } 4768 4769 /** 4770 * <p>Joins the elements of the provided {@code List} into a single String 4771 * containing the provided list of elements.</p> 4772 * 4773 * <p>No delimiter is added before or after the list. 4774 * Null objects or empty strings within the array are represented by 4775 * empty strings.</p> 4776 * 4777 * <pre> 4778 * StringUtils.join(null, *) = null 4779 * StringUtils.join([], *) = "" 4780 * StringUtils.join([null], *) = "" 4781 * StringUtils.join(["a", "b", "c"], ';') = "a;b;c" 4782 * StringUtils.join(["a", "b", "c"], null) = "abc" 4783 * StringUtils.join([null, "", "a"], ';') = ";;a" 4784 * </pre> 4785 * 4786 * @param list the {@code List} of values to join together, may be null 4787 * @param separator the separator character to use 4788 * @param startIndex the first index to start joining from. It is 4789 * an error to pass in an end index past the end of the list 4790 * @param endIndex the index to stop joining from (exclusive). It is 4791 * an error to pass in an end index past the end of the list 4792 * @return the joined String, {@code null} if null list input 4793 * @since 3.8 4794 */ 4795 public static String join(final List<?> list, final String separator, final int startIndex, final int endIndex) { 4796 if (list == null) { 4797 return null; 4798 } 4799 final int noOfItems = endIndex - startIndex; 4800 if (noOfItems <= 0) { 4801 return EMPTY; 4802 } 4803 final List<?> subList = list.subList(startIndex, endIndex); 4804 return join(subList.iterator(), separator); 4805 } 4806 4807 /** 4808 * <p>Joins the elements of the provided varargs into a 4809 * single String containing the provided elements.</p> 4810 * 4811 * <p>No delimiter is added before or after the list. 4812 * {@code null} elements and separator are treated as empty Strings ("").</p> 4813 * 4814 * <pre> 4815 * StringUtils.joinWith(",", {"a", "b"}) = "a,b" 4816 * StringUtils.joinWith(",", {"a", "b",""}) = "a,b," 4817 * StringUtils.joinWith(",", {"a", null, "b"}) = "a,,b" 4818 * StringUtils.joinWith(null, {"a", "b"}) = "ab" 4819 * </pre> 4820 * 4821 * @param separator the separator character to use, null treated as "" 4822 * @param objects the varargs providing the values to join together. {@code null} elements are treated as "" 4823 * @return the joined String. 4824 * @throws java.lang.IllegalArgumentException if a null varargs is provided 4825 * @since 3.5 4826 */ 4827 public static String joinWith(final String separator, final Object... objects) { 4828 if (objects == null) { 4829 throw new IllegalArgumentException("Object varargs must not be null"); 4830 } 4831 4832 final String sanitizedSeparator = defaultString(separator); 4833 4834 final StringBuilder result = new StringBuilder(); 4835 4836 final Iterator<Object> iterator = Arrays.asList(objects).iterator(); 4837 while (iterator.hasNext()) { 4838 final String value = Objects.toString(iterator.next(), ""); 4839 result.append(value); 4840 4841 if (iterator.hasNext()) { 4842 result.append(sanitizedSeparator); 4843 } 4844 } 4845 4846 return result.toString(); 4847 } 4848 4849 // Delete 4850 //----------------------------------------------------------------------- 4851 /** 4852 * <p>Deletes all whitespaces from a String as defined by 4853 * {@link Character#isWhitespace(char)}.</p> 4854 * 4855 * <pre> 4856 * StringUtils.deleteWhitespace(null) = null 4857 * StringUtils.deleteWhitespace("") = "" 4858 * StringUtils.deleteWhitespace("abc") = "abc" 4859 * StringUtils.deleteWhitespace(" ab c ") = "abc" 4860 * </pre> 4861 * 4862 * @param str the String to delete whitespace from, may be null 4863 * @return the String without whitespaces, {@code null} if null String input 4864 */ 4865 public static String deleteWhitespace(final String str) { 4866 if (isEmpty(str)) { 4867 return str; 4868 } 4869 final int sz = str.length(); 4870 final char[] chs = new char[sz]; 4871 int count = 0; 4872 for (int i = 0; i < sz; i++) { 4873 if (!Character.isWhitespace(str.charAt(i))) { 4874 chs[count++] = str.charAt(i); 4875 } 4876 } 4877 if (count == sz) { 4878 return str; 4879 } 4880 return new String(chs, 0, count); 4881 } 4882 4883 // Remove 4884 //----------------------------------------------------------------------- 4885 /** 4886 * <p>Removes a substring only if it is at the beginning of a source string, 4887 * otherwise returns the source string.</p> 4888 * 4889 * <p>A {@code null} source string will return {@code null}. 4890 * An empty ("") source string will return the empty string. 4891 * A {@code null} search string will return the source string.</p> 4892 * 4893 * <pre> 4894 * StringUtils.removeStart(null, *) = null 4895 * StringUtils.removeStart("", *) = "" 4896 * StringUtils.removeStart(*, null) = * 4897 * StringUtils.removeStart("www.domain.com", "www.") = "domain.com" 4898 * StringUtils.removeStart("domain.com", "www.") = "domain.com" 4899 * StringUtils.removeStart("www.domain.com", "domain") = "www.domain.com" 4900 * StringUtils.removeStart("abc", "") = "abc" 4901 * </pre> 4902 * 4903 * @param str the source String to search, may be null 4904 * @param remove the String to search for and remove, may be null 4905 * @return the substring with the string removed if found, 4906 * {@code null} if null String input 4907 * @since 2.1 4908 */ 4909 public static String removeStart(final String str, final String remove) { 4910 if (isEmpty(str) || isEmpty(remove)) { 4911 return str; 4912 } 4913 if (str.startsWith(remove)){ 4914 return str.substring(remove.length()); 4915 } 4916 return str; 4917 } 4918 4919 /** 4920 * <p>Case insensitive removal of a substring if it is at the beginning of a source string, 4921 * otherwise returns the source string.</p> 4922 * 4923 * <p>A {@code null} source string will return {@code null}. 4924 * An empty ("") source string will return the empty string. 4925 * A {@code null} search string will return the source string.</p> 4926 * 4927 * <pre> 4928 * StringUtils.removeStartIgnoreCase(null, *) = null 4929 * StringUtils.removeStartIgnoreCase("", *) = "" 4930 * StringUtils.removeStartIgnoreCase(*, null) = * 4931 * StringUtils.removeStartIgnoreCase("www.domain.com", "www.") = "domain.com" 4932 * StringUtils.removeStartIgnoreCase("www.domain.com", "WWW.") = "domain.com" 4933 * StringUtils.removeStartIgnoreCase("domain.com", "www.") = "domain.com" 4934 * StringUtils.removeStartIgnoreCase("www.domain.com", "domain") = "www.domain.com" 4935 * StringUtils.removeStartIgnoreCase("abc", "") = "abc" 4936 * </pre> 4937 * 4938 * @param str the source String to search, may be null 4939 * @param remove the String to search for (case insensitive) and remove, may be null 4940 * @return the substring with the string removed if found, 4941 * {@code null} if null String input 4942 * @since 2.4 4943 */ 4944 public static String removeStartIgnoreCase(final String str, final String remove) { 4945 if (isEmpty(str) || isEmpty(remove)) { 4946 return str; 4947 } 4948 if (startsWithIgnoreCase(str, remove)) { 4949 return str.substring(remove.length()); 4950 } 4951 return str; 4952 } 4953 4954 /** 4955 * <p>Removes a substring only if it is at the end of a source string, 4956 * otherwise returns the source string.</p> 4957 * 4958 * <p>A {@code null} source string will return {@code null}. 4959 * An empty ("") source string will return the empty string. 4960 * A {@code null} search string will return the source string.</p> 4961 * 4962 * <pre> 4963 * StringUtils.removeEnd(null, *) = null 4964 * StringUtils.removeEnd("", *) = "" 4965 * StringUtils.removeEnd(*, null) = * 4966 * StringUtils.removeEnd("www.domain.com", ".com.") = "www.domain.com" 4967 * StringUtils.removeEnd("www.domain.com", ".com") = "www.domain" 4968 * StringUtils.removeEnd("www.domain.com", "domain") = "www.domain.com" 4969 * StringUtils.removeEnd("abc", "") = "abc" 4970 * </pre> 4971 * 4972 * @param str the source String to search, may be null 4973 * @param remove the String to search for and remove, may be null 4974 * @return the substring with the string removed if found, 4975 * {@code null} if null String input 4976 * @since 2.1 4977 */ 4978 public static String removeEnd(final String str, final String remove) { 4979 if (isEmpty(str) || isEmpty(remove)) { 4980 return str; 4981 } 4982 if (str.endsWith(remove)) { 4983 return str.substring(0, str.length() - remove.length()); 4984 } 4985 return str; 4986 } 4987 4988 /** 4989 * <p>Case insensitive removal of a substring if it is at the end of a source string, 4990 * otherwise returns the source string.</p> 4991 * 4992 * <p>A {@code null} source string will return {@code null}. 4993 * An empty ("") source string will return the empty string. 4994 * A {@code null} search string will return the source string.</p> 4995 * 4996 * <pre> 4997 * StringUtils.removeEndIgnoreCase(null, *) = null 4998 * StringUtils.removeEndIgnoreCase("", *) = "" 4999 * StringUtils.removeEndIgnoreCase(*, null) = * 5000 * StringUtils.removeEndIgnoreCase("www.domain.com", ".com.") = "www.domain.com" 5001 * StringUtils.removeEndIgnoreCase("www.domain.com", ".com") = "www.domain" 5002 * StringUtils.removeEndIgnoreCase("www.domain.com", "domain") = "www.domain.com" 5003 * StringUtils.removeEndIgnoreCase("abc", "") = "abc" 5004 * StringUtils.removeEndIgnoreCase("www.domain.com", ".COM") = "www.domain") 5005 * StringUtils.removeEndIgnoreCase("www.domain.COM", ".com") = "www.domain") 5006 * </pre> 5007 * 5008 * @param str the source String to search, may be null 5009 * @param remove the String to search for (case insensitive) and remove, may be null 5010 * @return the substring with the string removed if found, 5011 * {@code null} if null String input 5012 * @since 2.4 5013 */ 5014 public static String removeEndIgnoreCase(final String str, final String remove) { 5015 if (isEmpty(str) || isEmpty(remove)) { 5016 return str; 5017 } 5018 if (endsWithIgnoreCase(str, remove)) { 5019 return str.substring(0, str.length() - remove.length()); 5020 } 5021 return str; 5022 } 5023 5024 /** 5025 * <p>Removes all occurrences of a substring from within the source string.</p> 5026 * 5027 * <p>A {@code null} source string will return {@code null}. 5028 * An empty ("") source string will return the empty string. 5029 * A {@code null} remove string will return the source string. 5030 * An empty ("") remove string will return the source string.</p> 5031 * 5032 * <pre> 5033 * StringUtils.remove(null, *) = null 5034 * StringUtils.remove("", *) = "" 5035 * StringUtils.remove(*, null) = * 5036 * StringUtils.remove(*, "") = * 5037 * StringUtils.remove("queued", "ue") = "qd" 5038 * StringUtils.remove("queued", "zz") = "queued" 5039 * </pre> 5040 * 5041 * @param str the source String to search, may be null 5042 * @param remove the String to search for and remove, may be null 5043 * @return the substring with the string removed if found, 5044 * {@code null} if null String input 5045 * @since 2.1 5046 */ 5047 public static String remove(final String str, final String remove) { 5048 if (isEmpty(str) || isEmpty(remove)) { 5049 return str; 5050 } 5051 return replace(str, remove, EMPTY, -1); 5052 } 5053 5054 /** 5055 * <p> 5056 * Case insensitive removal of all occurrences of a substring from within 5057 * the source string. 5058 * </p> 5059 * 5060 * <p> 5061 * A {@code null} source string will return {@code null}. An empty ("") 5062 * source string will return the empty string. A {@code null} remove string 5063 * will return the source string. An empty ("") remove string will return 5064 * the source string. 5065 * </p> 5066 * 5067 * <pre> 5068 * StringUtils.removeIgnoreCase(null, *) = null 5069 * StringUtils.removeIgnoreCase("", *) = "" 5070 * StringUtils.removeIgnoreCase(*, null) = * 5071 * StringUtils.removeIgnoreCase(*, "") = * 5072 * StringUtils.removeIgnoreCase("queued", "ue") = "qd" 5073 * StringUtils.removeIgnoreCase("queued", "zz") = "queued" 5074 * StringUtils.removeIgnoreCase("quEUed", "UE") = "qd" 5075 * StringUtils.removeIgnoreCase("queued", "zZ") = "queued" 5076 * </pre> 5077 * 5078 * @param str 5079 * the source String to search, may be null 5080 * @param remove 5081 * the String to search for (case insensitive) and remove, may be 5082 * null 5083 * @return the substring with the string removed if found, {@code null} if 5084 * null String input 5085 * @since 3.5 5086 */ 5087 public static String removeIgnoreCase(final String str, final String remove) { 5088 if (isEmpty(str) || isEmpty(remove)) { 5089 return str; 5090 } 5091 return replaceIgnoreCase(str, remove, EMPTY, -1); 5092 } 5093 5094 /** 5095 * <p>Removes all occurrences of a character from within the source string.</p> 5096 * 5097 * <p>A {@code null} source string will return {@code null}. 5098 * An empty ("") source string will return the empty string.</p> 5099 * 5100 * <pre> 5101 * StringUtils.remove(null, *) = null 5102 * StringUtils.remove("", *) = "" 5103 * StringUtils.remove("queued", 'u') = "qeed" 5104 * StringUtils.remove("queued", 'z') = "queued" 5105 * </pre> 5106 * 5107 * @param str the source String to search, may be null 5108 * @param remove the char to search for and remove, may be null 5109 * @return the substring with the char removed if found, 5110 * {@code null} if null String input 5111 * @since 2.1 5112 */ 5113 public static String remove(final String str, final char remove) { 5114 if (isEmpty(str) || str.indexOf(remove) == INDEX_NOT_FOUND) { 5115 return str; 5116 } 5117 final char[] chars = str.toCharArray(); 5118 int pos = 0; 5119 for (int i = 0; i < chars.length; i++) { 5120 if (chars[i] != remove) { 5121 chars[pos++] = chars[i]; 5122 } 5123 } 5124 return new String(chars, 0, pos); 5125 } 5126 5127 /** 5128 * <p>Removes each substring of the text String that matches the given regular expression.</p> 5129 * 5130 * This method is a {@code null} safe equivalent to: 5131 * <ul> 5132 * <li>{@code text.replaceAll(regex, StringUtils.EMPTY)}</li> 5133 * <li>{@code Pattern.compile(regex).matcher(text).replaceAll(StringUtils.EMPTY)}</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 #removePattern(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 known as single-line mode in Perl.</p> 5142 * 5143 * <pre> 5144 * StringUtils.removeAll(null, *) = null 5145 * StringUtils.removeAll("any", (String) null) = "any" 5146 * StringUtils.removeAll("any", "") = "any" 5147 * StringUtils.removeAll("any", ".*") = "" 5148 * StringUtils.removeAll("any", ".+") = "" 5149 * StringUtils.removeAll("abc", ".?") = "" 5150 * StringUtils.removeAll("A<__>\n<__>B", "<.*>") = "A\nB" 5151 * StringUtils.removeAll("A<__>\n<__>B", "(?s)<.*>") = "AB" 5152 * StringUtils.removeAll("ABCabc123abc", "[a-z]") = "ABC123" 5153 * </pre> 5154 * 5155 * @param text text to remove from, may be null 5156 * @param regex the regular expression to which this string is to be matched 5157 * @return the text with any removes processed, 5158 * {@code null} if null String input 5159 * 5160 * @throws java.util.regex.PatternSyntaxException 5161 * if the regular expression's syntax is invalid 5162 * 5163 * @see #replaceAll(String, String, String) 5164 * @see #removePattern(String, String) 5165 * @see String#replaceAll(String, String) 5166 * @see java.util.regex.Pattern 5167 * @see java.util.regex.Pattern#DOTALL 5168 * @since 3.5 5169 * 5170 * @deprecated Moved to RegExUtils. 5171 */ 5172 @Deprecated 5173 public static String removeAll(final String text, final String regex) { 5174 return RegExUtils.removeAll(text, regex); 5175 } 5176 5177 /** 5178 * <p>Removes the first substring of the text string that matches the given regular expression.</p> 5179 * 5180 * This method is a {@code null} safe equivalent to: 5181 * <ul> 5182 * <li>{@code text.replaceFirst(regex, StringUtils.EMPTY)}</li> 5183 * <li>{@code Pattern.compile(regex).matcher(text).replaceFirst(StringUtils.EMPTY)}</li> 5184 * </ul> 5185 * 5186 * <p>A {@code null} reference passed to this method is a no-op.</p> 5187 * 5188 * <p>The {@link Pattern#DOTALL} option is NOT automatically added. 5189 * To use the DOTALL option prepend <code>"(?s)"</code> to the regex. 5190 * DOTALL is also known as single-line mode in Perl.</p> 5191 * 5192 * <pre> 5193 * StringUtils.removeFirst(null, *) = null 5194 * StringUtils.removeFirst("any", (String) null) = "any" 5195 * StringUtils.removeFirst("any", "") = "any" 5196 * StringUtils.removeFirst("any", ".*") = "" 5197 * StringUtils.removeFirst("any", ".+") = "" 5198 * StringUtils.removeFirst("abc", ".?") = "bc" 5199 * StringUtils.removeFirst("A<__>\n<__>B", "<.*>") = "A\n<__>B" 5200 * StringUtils.removeFirst("A<__>\n<__>B", "(?s)<.*>") = "AB" 5201 * StringUtils.removeFirst("ABCabc123", "[a-z]") = "ABCbc123" 5202 * StringUtils.removeFirst("ABCabc123abc", "[a-z]+") = "ABC123abc" 5203 * </pre> 5204 * 5205 * @param text text to remove from, may be null 5206 * @param regex the regular expression to which this string is to be matched 5207 * @return the text with the first replacement processed, 5208 * {@code null} if null String input 5209 * 5210 * @throws java.util.regex.PatternSyntaxException 5211 * if the regular expression's syntax is invalid 5212 * 5213 * @see #replaceFirst(String, String, String) 5214 * @see String#replaceFirst(String, String) 5215 * @see java.util.regex.Pattern 5216 * @see java.util.regex.Pattern#DOTALL 5217 * @since 3.5 5218 * 5219 * @deprecated Moved to RegExUtils. 5220 */ 5221 @Deprecated 5222 public static String removeFirst(final String text, final String regex) { 5223 return replaceFirst(text, regex, EMPTY); 5224 } 5225 5226 // Replacing 5227 //----------------------------------------------------------------------- 5228 /** 5229 * <p>Replaces a String with another String inside a larger String, once.</p> 5230 * 5231 * <p>A {@code null} reference passed to this method is a no-op.</p> 5232 * 5233 * <pre> 5234 * StringUtils.replaceOnce(null, *, *) = null 5235 * StringUtils.replaceOnce("", *, *) = "" 5236 * StringUtils.replaceOnce("any", null, *) = "any" 5237 * StringUtils.replaceOnce("any", *, null) = "any" 5238 * StringUtils.replaceOnce("any", "", *) = "any" 5239 * StringUtils.replaceOnce("aba", "a", null) = "aba" 5240 * StringUtils.replaceOnce("aba", "a", "") = "ba" 5241 * StringUtils.replaceOnce("aba", "a", "z") = "zba" 5242 * </pre> 5243 * 5244 * @see #replace(String text, String searchString, String replacement, int max) 5245 * @param text text to search and replace in, may be null 5246 * @param searchString the String to search for, may be null 5247 * @param replacement the String to replace with, may be null 5248 * @return the text with any replacements processed, 5249 * {@code null} if null String input 5250 */ 5251 public static String replaceOnce(final String text, final String searchString, final String replacement) { 5252 return replace(text, searchString, replacement, 1); 5253 } 5254 5255 /** 5256 * <p>Case insensitively replaces a String with another String inside a larger String, once.</p> 5257 * 5258 * <p>A {@code null} reference passed to this method is a no-op.</p> 5259 * 5260 * <pre> 5261 * StringUtils.replaceOnceIgnoreCase(null, *, *) = null 5262 * StringUtils.replaceOnceIgnoreCase("", *, *) = "" 5263 * StringUtils.replaceOnceIgnoreCase("any", null, *) = "any" 5264 * StringUtils.replaceOnceIgnoreCase("any", *, null) = "any" 5265 * StringUtils.replaceOnceIgnoreCase("any", "", *) = "any" 5266 * StringUtils.replaceOnceIgnoreCase("aba", "a", null) = "aba" 5267 * StringUtils.replaceOnceIgnoreCase("aba", "a", "") = "ba" 5268 * StringUtils.replaceOnceIgnoreCase("aba", "a", "z") = "zba" 5269 * StringUtils.replaceOnceIgnoreCase("FoOFoofoo", "foo", "") = "Foofoo" 5270 * </pre> 5271 * 5272 * @see #replaceIgnoreCase(String text, String searchString, String replacement, int max) 5273 * @param text text to search and replace in, may be null 5274 * @param searchString the String to search for (case insensitive), may be null 5275 * @param replacement the String to replace with, may be null 5276 * @return the text with any replacements processed, 5277 * {@code null} if null String input 5278 * @since 3.5 5279 */ 5280 public static String replaceOnceIgnoreCase(final String text, final String searchString, final String replacement) { 5281 return replaceIgnoreCase(text, searchString, replacement, 1); 5282 } 5283 5284 /** 5285 * <p>Replaces each substring of the source String that matches the given regular expression with the given 5286 * replacement using the {@link Pattern#DOTALL} option. DOTALL is also known as single-line mode in Perl.</p> 5287 * 5288 * This call is a {@code null} safe equivalent to: 5289 * <ul> 5290 * <li>{@code source.replaceAll("(?s)" + regex, replacement)}</li> 5291 * <li>{@code Pattern.compile(regex, Pattern.DOTALL).matcher(source).replaceAll(replacement)}</li> 5292 * </ul> 5293 * 5294 * <p>A {@code null} reference passed to this method is a no-op.</p> 5295 * 5296 * <pre> 5297 * StringUtils.replacePattern(null, *, *) = null 5298 * StringUtils.replacePattern("any", (String) null, *) = "any" 5299 * StringUtils.replacePattern("any", *, null) = "any" 5300 * StringUtils.replacePattern("", "", "zzz") = "zzz" 5301 * StringUtils.replacePattern("", ".*", "zzz") = "zzz" 5302 * StringUtils.replacePattern("", ".+", "zzz") = "" 5303 * StringUtils.replacePattern("<__>\n<__>", "<.*>", "z") = "z" 5304 * StringUtils.replacePattern("ABCabc123", "[a-z]", "_") = "ABC___123" 5305 * StringUtils.replacePattern("ABCabc123", "[^A-Z0-9]+", "_") = "ABC_123" 5306 * StringUtils.replacePattern("ABCabc123", "[^A-Z0-9]+", "") = "ABC123" 5307 * StringUtils.replacePattern("Lorem ipsum dolor sit", "( +)([a-z]+)", "_$2") = "Lorem_ipsum_dolor_sit" 5308 * </pre> 5309 * 5310 * @param source 5311 * the source string 5312 * @param regex 5313 * the regular expression to which this string is to be matched 5314 * @param replacement 5315 * the string to be substituted for each match 5316 * @return The resulting {@code String} 5317 * @see #replaceAll(String, String, String) 5318 * @see String#replaceAll(String, String) 5319 * @see Pattern#DOTALL 5320 * @since 3.2 5321 * @since 3.5 Changed {@code null} reference passed to this method is a no-op. 5322 * 5323 * @deprecated Moved to RegExUtils. 5324 */ 5325 @Deprecated 5326 public static String replacePattern(final String source, final String regex, final String replacement) { 5327 return RegExUtils.replacePattern(source, regex, replacement); 5328 } 5329 5330 /** 5331 * <p>Removes each substring of the source String that matches the given regular expression using the DOTALL option. 5332 * </p> 5333 * 5334 * This call is a {@code null} safe equivalent to: 5335 * <ul> 5336 * <li>{@code source.replaceAll("(?s)" + regex, StringUtils.EMPTY)}</li> 5337 * <li>{@code Pattern.compile(regex, Pattern.DOTALL).matcher(source).replaceAll(StringUtils.EMPTY)}</li> 5338 * </ul> 5339 * 5340 * <p>A {@code null} reference passed to this method is a no-op.</p> 5341 * 5342 * <pre> 5343 * StringUtils.removePattern(null, *) = null 5344 * StringUtils.removePattern("any", (String) null) = "any" 5345 * StringUtils.removePattern("A<__>\n<__>B", "<.*>") = "AB" 5346 * StringUtils.removePattern("ABCabc123", "[a-z]") = "ABC123" 5347 * </pre> 5348 * 5349 * @param source 5350 * the source string 5351 * @param regex 5352 * the regular expression to which this string is to be matched 5353 * @return The resulting {@code String} 5354 * @see #replacePattern(String, String, String) 5355 * @see String#replaceAll(String, String) 5356 * @see Pattern#DOTALL 5357 * @since 3.2 5358 * @since 3.5 Changed {@code null} reference passed to this method is a no-op. 5359 * 5360 * @deprecated Moved to RegExUtils. 5361 */ 5362 @Deprecated 5363 public static String removePattern(final String source, final String regex) { 5364 return RegExUtils.removePattern(source, regex); 5365 } 5366 5367 /** 5368 * <p>Replaces each substring of the text String that matches the given regular expression 5369 * with the given replacement.</p> 5370 * 5371 * This method is a {@code null} safe equivalent to: 5372 * <ul> 5373 * <li>{@code text.replaceAll(regex, replacement)}</li> 5374 * <li>{@code Pattern.compile(regex).matcher(text).replaceAll(replacement)}</li> 5375 * </ul> 5376 * 5377 * <p>A {@code null} reference passed to this method is a no-op.</p> 5378 * 5379 * <p>Unlike in the {@link #replacePattern(String, String, String)} method, the {@link Pattern#DOTALL} option 5380 * is NOT automatically added. 5381 * To use the DOTALL option prepend <code>"(?s)"</code> to the regex. 5382 * DOTALL is also known as single-line mode in Perl.</p> 5383 * 5384 * <pre> 5385 * StringUtils.replaceAll(null, *, *) = null 5386 * StringUtils.replaceAll("any", (String) null, *) = "any" 5387 * StringUtils.replaceAll("any", *, null) = "any" 5388 * StringUtils.replaceAll("", "", "zzz") = "zzz" 5389 * StringUtils.replaceAll("", ".*", "zzz") = "zzz" 5390 * StringUtils.replaceAll("", ".+", "zzz") = "" 5391 * StringUtils.replaceAll("abc", "", "ZZ") = "ZZaZZbZZcZZ" 5392 * StringUtils.replaceAll("<__>\n<__>", "<.*>", "z") = "z\nz" 5393 * StringUtils.replaceAll("<__>\n<__>", "(?s)<.*>", "z") = "z" 5394 * StringUtils.replaceAll("ABCabc123", "[a-z]", "_") = "ABC___123" 5395 * StringUtils.replaceAll("ABCabc123", "[^A-Z0-9]+", "_") = "ABC_123" 5396 * StringUtils.replaceAll("ABCabc123", "[^A-Z0-9]+", "") = "ABC123" 5397 * StringUtils.replaceAll("Lorem ipsum dolor sit", "( +)([a-z]+)", "_$2") = "Lorem_ipsum_dolor_sit" 5398 * </pre> 5399 * 5400 * @param text text to search and replace in, may be null 5401 * @param regex the regular expression to which this string is to be matched 5402 * @param replacement the string to be substituted for each match 5403 * @return the text with any replacements processed, 5404 * {@code null} if null String input 5405 * 5406 * @throws java.util.regex.PatternSyntaxException 5407 * if the regular expression's syntax is invalid 5408 * 5409 * @see #replacePattern(String, String, String) 5410 * @see String#replaceAll(String, String) 5411 * @see java.util.regex.Pattern 5412 * @see java.util.regex.Pattern#DOTALL 5413 * @since 3.5 5414 * 5415 * @deprecated Moved to RegExUtils. 5416 */ 5417 @Deprecated 5418 public static String replaceAll(final String text, final String regex, final String replacement) { 5419 return RegExUtils.replaceAll(text, regex, replacement); 5420 } 5421 5422 /** 5423 * <p>Replaces the first substring of the text string that matches the given regular expression 5424 * with the given replacement.</p> 5425 * 5426 * This method is a {@code null} safe equivalent to: 5427 * <ul> 5428 * <li>{@code text.replaceFirst(regex, replacement)}</li> 5429 * <li>{@code Pattern.compile(regex).matcher(text).replaceFirst(replacement)}</li> 5430 * </ul> 5431 * 5432 * <p>A {@code null} reference passed to this method is a no-op.</p> 5433 * 5434 * <p>The {@link Pattern#DOTALL} option is NOT automatically added. 5435 * To use the DOTALL option prepend <code>"(?s)"</code> to the regex. 5436 * DOTALL is also known as single-line mode in Perl.</p> 5437 * 5438 * <pre> 5439 * StringUtils.replaceFirst(null, *, *) = null 5440 * StringUtils.replaceFirst("any", (String) null, *) = "any" 5441 * StringUtils.replaceFirst("any", *, null) = "any" 5442 * StringUtils.replaceFirst("", "", "zzz") = "zzz" 5443 * StringUtils.replaceFirst("", ".*", "zzz") = "zzz" 5444 * StringUtils.replaceFirst("", ".+", "zzz") = "" 5445 * StringUtils.replaceFirst("abc", "", "ZZ") = "ZZabc" 5446 * StringUtils.replaceFirst("<__>\n<__>", "<.*>", "z") = "z\n<__>" 5447 * StringUtils.replaceFirst("<__>\n<__>", "(?s)<.*>", "z") = "z" 5448 * StringUtils.replaceFirst("ABCabc123", "[a-z]", "_") = "ABC_bc123" 5449 * StringUtils.replaceFirst("ABCabc123abc", "[^A-Z0-9]+", "_") = "ABC_123abc" 5450 * StringUtils.replaceFirst("ABCabc123abc", "[^A-Z0-9]+", "") = "ABC123abc" 5451 * StringUtils.replaceFirst("Lorem ipsum dolor sit", "( +)([a-z]+)", "_$2") = "Lorem_ipsum dolor sit" 5452 * </pre> 5453 * 5454 * @param text text to search and replace in, may be null 5455 * @param regex the regular expression to which this string is to be matched 5456 * @param replacement the string to be substituted for the first match 5457 * @return the text with the first replacement processed, 5458 * {@code null} if null String input 5459 * 5460 * @throws java.util.regex.PatternSyntaxException 5461 * if the regular expression's syntax is invalid 5462 * 5463 * @see String#replaceFirst(String, String) 5464 * @see java.util.regex.Pattern 5465 * @see java.util.regex.Pattern#DOTALL 5466 * @since 3.5 5467 * 5468 * @deprecated Moved to RegExUtils. 5469 */ 5470 @Deprecated 5471 public static String replaceFirst(final String text, final String regex, final String replacement) { 5472 return RegExUtils.replaceFirst(text, regex, replacement); 5473 } 5474 5475 /** 5476 * <p>Replaces all occurrences of a String within another String.</p> 5477 * 5478 * <p>A {@code null} reference passed to this method is a no-op.</p> 5479 * 5480 * <pre> 5481 * StringUtils.replace(null, *, *) = null 5482 * StringUtils.replace("", *, *) = "" 5483 * StringUtils.replace("any", null, *) = "any" 5484 * StringUtils.replace("any", *, null) = "any" 5485 * StringUtils.replace("any", "", *) = "any" 5486 * StringUtils.replace("aba", "a", null) = "aba" 5487 * StringUtils.replace("aba", "a", "") = "b" 5488 * StringUtils.replace("aba", "a", "z") = "zbz" 5489 * </pre> 5490 * 5491 * @see #replace(String text, String searchString, String replacement, int max) 5492 * @param text text to search and replace in, may be null 5493 * @param searchString the String to search for, may be null 5494 * @param replacement the String to replace it with, may be null 5495 * @return the text with any replacements processed, 5496 * {@code null} if null String input 5497 */ 5498 public static String replace(final String text, final String searchString, final String replacement) { 5499 return replace(text, searchString, replacement, -1); 5500 } 5501 5502 /** 5503 * <p>Case insensitively replaces all occurrences of a String within another String.</p> 5504 * 5505 * <p>A {@code null} reference passed to this method is a no-op.</p> 5506 * 5507 * <pre> 5508 * StringUtils.replaceIgnoreCase(null, *, *) = null 5509 * StringUtils.replaceIgnoreCase("", *, *) = "" 5510 * StringUtils.replaceIgnoreCase("any", null, *) = "any" 5511 * StringUtils.replaceIgnoreCase("any", *, null) = "any" 5512 * StringUtils.replaceIgnoreCase("any", "", *) = "any" 5513 * StringUtils.replaceIgnoreCase("aba", "a", null) = "aba" 5514 * StringUtils.replaceIgnoreCase("abA", "A", "") = "b" 5515 * StringUtils.replaceIgnoreCase("aba", "A", "z") = "zbz" 5516 * </pre> 5517 * 5518 * @see #replaceIgnoreCase(String text, String searchString, String replacement, int max) 5519 * @param text text to search and replace in, may be null 5520 * @param searchString the String to search for (case insensitive), may be null 5521 * @param replacement the String to replace it with, may be null 5522 * @return the text with any replacements processed, 5523 * {@code null} if null String input 5524 * @since 3.5 5525 */ 5526 public static String replaceIgnoreCase(final String text, final String searchString, final String replacement) { 5527 return replaceIgnoreCase(text, searchString, replacement, -1); 5528 } 5529 5530 /** 5531 * <p>Replaces a String with another String inside a larger String, 5532 * for the first {@code max} values of the search String.</p> 5533 * 5534 * <p>A {@code null} reference passed to this method is a no-op.</p> 5535 * 5536 * <pre> 5537 * StringUtils.replace(null, *, *, *) = null 5538 * StringUtils.replace("", *, *, *) = "" 5539 * StringUtils.replace("any", null, *, *) = "any" 5540 * StringUtils.replace("any", *, null, *) = "any" 5541 * StringUtils.replace("any", "", *, *) = "any" 5542 * StringUtils.replace("any", *, *, 0) = "any" 5543 * StringUtils.replace("abaa", "a", null, -1) = "abaa" 5544 * StringUtils.replace("abaa", "a", "", -1) = "b" 5545 * StringUtils.replace("abaa", "a", "z", 0) = "abaa" 5546 * StringUtils.replace("abaa", "a", "z", 1) = "zbaa" 5547 * StringUtils.replace("abaa", "a", "z", 2) = "zbza" 5548 * StringUtils.replace("abaa", "a", "z", -1) = "zbzz" 5549 * </pre> 5550 * 5551 * @param text text to search and replace in, may be null 5552 * @param searchString the String to search for, may be null 5553 * @param replacement the String to replace it with, may be null 5554 * @param max maximum number of values to replace, or {@code -1} if no maximum 5555 * @return the text with any replacements processed, 5556 * {@code null} if null String input 5557 */ 5558 public static String replace(final String text, final String searchString, final String replacement, final int max) { 5559 return replace(text, searchString, replacement, max, false); 5560 } 5561 5562 /** 5563 * <p>Replaces a String with another String inside a larger String, 5564 * for the first {@code max} values of the search String, 5565 * case sensitively/insensisitively based on {@code ignoreCase} value.</p> 5566 * 5567 * <p>A {@code null} reference passed to this method is a no-op.</p> 5568 * 5569 * <pre> 5570 * StringUtils.replace(null, *, *, *, false) = null 5571 * StringUtils.replace("", *, *, *, false) = "" 5572 * StringUtils.replace("any", null, *, *, false) = "any" 5573 * StringUtils.replace("any", *, null, *, false) = "any" 5574 * StringUtils.replace("any", "", *, *, false) = "any" 5575 * StringUtils.replace("any", *, *, 0, false) = "any" 5576 * StringUtils.replace("abaa", "a", null, -1, false) = "abaa" 5577 * StringUtils.replace("abaa", "a", "", -1, false) = "b" 5578 * StringUtils.replace("abaa", "a", "z", 0, false) = "abaa" 5579 * StringUtils.replace("abaa", "A", "z", 1, false) = "abaa" 5580 * StringUtils.replace("abaa", "A", "z", 1, true) = "zbaa" 5581 * StringUtils.replace("abAa", "a", "z", 2, true) = "zbza" 5582 * StringUtils.replace("abAa", "a", "z", -1, true) = "zbzz" 5583 * </pre> 5584 * 5585 * @param text text to search and replace in, may be null 5586 * @param searchString the String to search for (case insensitive), may be null 5587 * @param replacement the String to replace it with, may be null 5588 * @param max maximum number of values to replace, or {@code -1} if no maximum 5589 * @param ignoreCase if true replace is case insensitive, otherwise case sensitive 5590 * @return the text with any replacements processed, 5591 * {@code null} if null String input 5592 */ 5593 private static String replace(final String text, String searchString, final String replacement, int max, final boolean ignoreCase) { 5594 if (isEmpty(text) || isEmpty(searchString) || replacement == null || max == 0) { 5595 return text; 5596 } 5597 String searchText = text; 5598 if (ignoreCase) { 5599 searchText = text.toLowerCase(); 5600 searchString = searchString.toLowerCase(); 5601 } 5602 int start = 0; 5603 int end = searchText.indexOf(searchString, start); 5604 if (end == INDEX_NOT_FOUND) { 5605 return text; 5606 } 5607 final int replLength = searchString.length(); 5608 int increase = replacement.length() - replLength; 5609 increase = increase < 0 ? 0 : increase; 5610 increase *= max < 0 ? 16 : max > 64 ? 64 : max; 5611 final StringBuilder buf = new StringBuilder(text.length() + increase); 5612 while (end != INDEX_NOT_FOUND) { 5613 buf.append(text, start, end).append(replacement); 5614 start = end + replLength; 5615 if (--max == 0) { 5616 break; 5617 } 5618 end = searchText.indexOf(searchString, start); 5619 } 5620 buf.append(text, start, text.length()); 5621 return buf.toString(); 5622 } 5623 5624 /** 5625 * <p>Case insensitively replaces a String with another String inside a larger String, 5626 * for the first {@code max} values of the search String.</p> 5627 * 5628 * <p>A {@code null} reference passed to this method is a no-op.</p> 5629 * 5630 * <pre> 5631 * StringUtils.replaceIgnoreCase(null, *, *, *) = null 5632 * StringUtils.replaceIgnoreCase("", *, *, *) = "" 5633 * StringUtils.replaceIgnoreCase("any", null, *, *) = "any" 5634 * StringUtils.replaceIgnoreCase("any", *, null, *) = "any" 5635 * StringUtils.replaceIgnoreCase("any", "", *, *) = "any" 5636 * StringUtils.replaceIgnoreCase("any", *, *, 0) = "any" 5637 * StringUtils.replaceIgnoreCase("abaa", "a", null, -1) = "abaa" 5638 * StringUtils.replaceIgnoreCase("abaa", "a", "", -1) = "b" 5639 * StringUtils.replaceIgnoreCase("abaa", "a", "z", 0) = "abaa" 5640 * StringUtils.replaceIgnoreCase("abaa", "A", "z", 1) = "zbaa" 5641 * StringUtils.replaceIgnoreCase("abAa", "a", "z", 2) = "zbza" 5642 * StringUtils.replaceIgnoreCase("abAa", "a", "z", -1) = "zbzz" 5643 * </pre> 5644 * 5645 * @param text text to search and replace in, may be null 5646 * @param searchString the String to search for (case insensitive), may be null 5647 * @param replacement the String to replace it with, may be null 5648 * @param max maximum number of values to replace, or {@code -1} if no maximum 5649 * @return the text with any replacements processed, 5650 * {@code null} if null String input 5651 * @since 3.5 5652 */ 5653 public static String replaceIgnoreCase(final String text, final String searchString, final String replacement, final int max) { 5654 return replace(text, searchString, replacement, max, true); 5655 } 5656 5657 /** 5658 * <p> 5659 * Replaces all occurrences of Strings within another String. 5660 * </p> 5661 * 5662 * <p> 5663 * A {@code null} reference passed to this method is a no-op, or if 5664 * any "search string" or "string to replace" is null, that replace will be 5665 * ignored. This will not repeat. For repeating replaces, call the 5666 * overloaded method. 5667 * </p> 5668 * 5669 * <pre> 5670 * StringUtils.replaceEach(null, *, *) = null 5671 * StringUtils.replaceEach("", *, *) = "" 5672 * StringUtils.replaceEach("aba", null, null) = "aba" 5673 * StringUtils.replaceEach("aba", new String[0], null) = "aba" 5674 * StringUtils.replaceEach("aba", null, new String[0]) = "aba" 5675 * StringUtils.replaceEach("aba", new String[]{"a"}, null) = "aba" 5676 * StringUtils.replaceEach("aba", new String[]{"a"}, new String[]{""}) = "b" 5677 * StringUtils.replaceEach("aba", new String[]{null}, new String[]{"a"}) = "aba" 5678 * StringUtils.replaceEach("abcde", new String[]{"ab", "d"}, new String[]{"w", "t"}) = "wcte" 5679 * (example of how it does not repeat) 5680 * StringUtils.replaceEach("abcde", new String[]{"ab", "d"}, new String[]{"d", "t"}) = "dcte" 5681 * </pre> 5682 * 5683 * @param text 5684 * text to search and replace in, no-op if null 5685 * @param searchList 5686 * the Strings to search for, no-op if null 5687 * @param replacementList 5688 * the Strings to replace them with, no-op if null 5689 * @return the text with any replacements processed, {@code null} if 5690 * null String input 5691 * @throws IllegalArgumentException 5692 * if the lengths of the arrays are not the same (null is ok, 5693 * and/or size 0) 5694 * @since 2.4 5695 */ 5696 public static String replaceEach(final String text, final String[] searchList, final String[] replacementList) { 5697 return replaceEach(text, searchList, replacementList, false, 0); 5698 } 5699 5700 /** 5701 * <p> 5702 * Replaces all occurrences of Strings within another String. 5703 * </p> 5704 * 5705 * <p> 5706 * A {@code null} reference passed to this method is a no-op, or if 5707 * any "search string" or "string to replace" is null, that replace will be 5708 * ignored. 5709 * </p> 5710 * 5711 * <pre> 5712 * StringUtils.replaceEachRepeatedly(null, *, *) = null 5713 * StringUtils.replaceEachRepeatedly("", *, *) = "" 5714 * StringUtils.replaceEachRepeatedly("aba", null, null) = "aba" 5715 * StringUtils.replaceEachRepeatedly("aba", new String[0], null) = "aba" 5716 * StringUtils.replaceEachRepeatedly("aba", null, new String[0]) = "aba" 5717 * StringUtils.replaceEachRepeatedly("aba", new String[]{"a"}, null) = "aba" 5718 * StringUtils.replaceEachRepeatedly("aba", new String[]{"a"}, new String[]{""}) = "b" 5719 * StringUtils.replaceEachRepeatedly("aba", new String[]{null}, new String[]{"a"}) = "aba" 5720 * StringUtils.replaceEachRepeatedly("abcde", new String[]{"ab", "d"}, new String[]{"w", "t"}) = "wcte" 5721 * (example of how it repeats) 5722 * StringUtils.replaceEachRepeatedly("abcde", new String[]{"ab", "d"}, new String[]{"d", "t"}) = "tcte" 5723 * StringUtils.replaceEachRepeatedly("abcde", new String[]{"ab", "d"}, new String[]{"d", "ab"}) = IllegalStateException 5724 * </pre> 5725 * 5726 * @param text 5727 * text to search and replace in, no-op if null 5728 * @param searchList 5729 * the Strings to search for, no-op if null 5730 * @param replacementList 5731 * the Strings to replace them with, no-op if null 5732 * @return the text with any replacements processed, {@code null} if 5733 * null String input 5734 * @throws IllegalStateException 5735 * if the search is repeating and there is an endless loop due 5736 * to outputs of one being inputs to another 5737 * @throws IllegalArgumentException 5738 * if the lengths of the arrays are not the same (null is ok, 5739 * and/or size 0) 5740 * @since 2.4 5741 */ 5742 public static String replaceEachRepeatedly(final String text, final String[] searchList, final String[] replacementList) { 5743 // timeToLive should be 0 if not used or nothing to replace, else it's 5744 // the length of the replace array 5745 final int timeToLive = searchList == null ? 0 : searchList.length; 5746 return replaceEach(text, searchList, replacementList, true, timeToLive); 5747 } 5748 5749 /** 5750 * <p> 5751 * Replace all occurrences of Strings within another String. 5752 * This is a private recursive helper method for {@link #replaceEachRepeatedly(String, String[], String[])} and 5753 * {@link #replaceEach(String, String[], String[])} 5754 * </p> 5755 * 5756 * <p> 5757 * A {@code null} reference passed to this method is a no-op, or if 5758 * any "search string" or "string to replace" is null, that replace will be 5759 * ignored. 5760 * </p> 5761 * 5762 * <pre> 5763 * StringUtils.replaceEach(null, *, *, *, *) = null 5764 * StringUtils.replaceEach("", *, *, *, *) = "" 5765 * StringUtils.replaceEach("aba", null, null, *, *) = "aba" 5766 * StringUtils.replaceEach("aba", new String[0], null, *, *) = "aba" 5767 * StringUtils.replaceEach("aba", null, new String[0], *, *) = "aba" 5768 * StringUtils.replaceEach("aba", new String[]{"a"}, null, *, *) = "aba" 5769 * StringUtils.replaceEach("aba", new String[]{"a"}, new String[]{""}, *, >=0) = "b" 5770 * StringUtils.replaceEach("aba", new String[]{null}, new String[]{"a"}, *, >=0) = "aba" 5771 * StringUtils.replaceEach("abcde", new String[]{"ab", "d"}, new String[]{"w", "t"}, *, >=0) = "wcte" 5772 * (example of how it repeats) 5773 * StringUtils.replaceEach("abcde", new String[]{"ab", "d"}, new String[]{"d", "t"}, false, >=0) = "dcte" 5774 * StringUtils.replaceEach("abcde", new String[]{"ab", "d"}, new String[]{"d", "t"}, true, >=2) = "tcte" 5775 * StringUtils.replaceEach("abcde", new String[]{"ab", "d"}, new String[]{"d", "ab"}, *, *) = IllegalStateException 5776 * </pre> 5777 * 5778 * @param text 5779 * text to search and replace in, no-op if null 5780 * @param searchList 5781 * the Strings to search for, no-op if null 5782 * @param replacementList 5783 * the Strings to replace them with, no-op if null 5784 * @param repeat if true, then replace repeatedly 5785 * until there are no more possible replacements or timeToLive < 0 5786 * @param timeToLive 5787 * if less than 0 then there is a circular reference and endless 5788 * loop 5789 * @return the text with any replacements processed, {@code null} if 5790 * null String input 5791 * @throws IllegalStateException 5792 * if the search is repeating and there is an endless loop due 5793 * to outputs of one being inputs to another 5794 * @throws IllegalArgumentException 5795 * if the lengths of the arrays are not the same (null is ok, 5796 * and/or size 0) 5797 * @since 2.4 5798 */ 5799 private static String replaceEach( 5800 final String text, final String[] searchList, final String[] replacementList, final boolean repeat, final int timeToLive) { 5801 5802 // mchyzer Performance note: This creates very few new objects (one major goal) 5803 // let me know if there are performance requests, we can create a harness to measure 5804 5805 if (text == null || text.isEmpty() || searchList == null || 5806 searchList.length == 0 || replacementList == null || replacementList.length == 0) { 5807 return text; 5808 } 5809 5810 // if recursing, this shouldn't be less than 0 5811 if (timeToLive < 0) { 5812 throw new IllegalStateException("Aborting to protect against StackOverflowError - " + 5813 "output of one loop is the input of another"); 5814 } 5815 5816 final int searchLength = searchList.length; 5817 final int replacementLength = replacementList.length; 5818 5819 // make sure lengths are ok, these need to be equal 5820 if (searchLength != replacementLength) { 5821 throw new IllegalArgumentException("Search and Replace array lengths don't match: " 5822 + searchLength 5823 + " vs " 5824 + replacementLength); 5825 } 5826 5827 // keep track of which still have matches 5828 final boolean[] noMoreMatchesForReplIndex = new boolean[searchLength]; 5829 5830 // index on index that the match was found 5831 int textIndex = -1; 5832 int replaceIndex = -1; 5833 int tempIndex = -1; 5834 5835 // index of replace array that will replace the search string found 5836 // NOTE: logic duplicated below START 5837 for (int i = 0; i < searchLength; i++) { 5838 if (noMoreMatchesForReplIndex[i] || searchList[i] == null || 5839 searchList[i].isEmpty() || replacementList[i] == null) { 5840 continue; 5841 } 5842 tempIndex = text.indexOf(searchList[i]); 5843 5844 // see if we need to keep searching for this 5845 if (tempIndex == -1) { 5846 noMoreMatchesForReplIndex[i] = true; 5847 } else { 5848 if (textIndex == -1 || tempIndex < textIndex) { 5849 textIndex = tempIndex; 5850 replaceIndex = i; 5851 } 5852 } 5853 } 5854 // NOTE: logic mostly below END 5855 5856 // no search strings found, we are done 5857 if (textIndex == -1) { 5858 return text; 5859 } 5860 5861 int start = 0; 5862 5863 // get a good guess on the size of the result buffer so it doesn't have to double if it goes over a bit 5864 int increase = 0; 5865 5866 // count the replacement text elements that are larger than their corresponding text being replaced 5867 for (int i = 0; i < searchList.length; i++) { 5868 if (searchList[i] == null || replacementList[i] == null) { 5869 continue; 5870 } 5871 final int greater = replacementList[i].length() - searchList[i].length(); 5872 if (greater > 0) { 5873 increase += 3 * greater; // assume 3 matches 5874 } 5875 } 5876 // have upper-bound at 20% increase, then let Java take over 5877 increase = Math.min(increase, text.length() / 5); 5878 5879 final StringBuilder buf = new StringBuilder(text.length() + increase); 5880 5881 while (textIndex != -1) { 5882 5883 for (int i = start; i < textIndex; i++) { 5884 buf.append(text.charAt(i)); 5885 } 5886 buf.append(replacementList[replaceIndex]); 5887 5888 start = textIndex + searchList[replaceIndex].length(); 5889 5890 textIndex = -1; 5891 replaceIndex = -1; 5892 tempIndex = -1; 5893 // find the next earliest match 5894 // NOTE: logic mostly duplicated above START 5895 for (int i = 0; i < searchLength; i++) { 5896 if (noMoreMatchesForReplIndex[i] || searchList[i] == null || 5897 searchList[i].isEmpty() || replacementList[i] == null) { 5898 continue; 5899 } 5900 tempIndex = text.indexOf(searchList[i], start); 5901 5902 // see if we need to keep searching for this 5903 if (tempIndex == -1) { 5904 noMoreMatchesForReplIndex[i] = true; 5905 } else { 5906 if (textIndex == -1 || tempIndex < textIndex) { 5907 textIndex = tempIndex; 5908 replaceIndex = i; 5909 } 5910 } 5911 } 5912 // NOTE: logic duplicated above END 5913 5914 } 5915 final int textLength = text.length(); 5916 for (int i = start; i < textLength; i++) { 5917 buf.append(text.charAt(i)); 5918 } 5919 final String result = buf.toString(); 5920 if (!repeat) { 5921 return result; 5922 } 5923 5924 return replaceEach(result, searchList, replacementList, repeat, timeToLive - 1); 5925 } 5926 5927 // Replace, character based 5928 //----------------------------------------------------------------------- 5929 /** 5930 * <p>Replaces all occurrences of a character in a String with another. 5931 * This is a null-safe version of {@link String#replace(char, char)}.</p> 5932 * 5933 * <p>A {@code null} string input returns {@code null}. 5934 * An empty ("") string input returns an empty string.</p> 5935 * 5936 * <pre> 5937 * StringUtils.replaceChars(null, *, *) = null 5938 * StringUtils.replaceChars("", *, *) = "" 5939 * StringUtils.replaceChars("abcba", 'b', 'y') = "aycya" 5940 * StringUtils.replaceChars("abcba", 'z', 'y') = "abcba" 5941 * </pre> 5942 * 5943 * @param str String to replace characters in, may be null 5944 * @param searchChar the character to search for, may be null 5945 * @param replaceChar the character to replace, may be null 5946 * @return modified String, {@code null} if null string input 5947 * @since 2.0 5948 */ 5949 public static String replaceChars(final String str, final char searchChar, final char replaceChar) { 5950 if (str == null) { 5951 return null; 5952 } 5953 return str.replace(searchChar, replaceChar); 5954 } 5955 5956 /** 5957 * <p>Replaces multiple characters in a String in one go. 5958 * This method can also be used to delete characters.</p> 5959 * 5960 * <p>For example:<br> 5961 * <code>replaceChars("hello", "ho", "jy") = jelly</code>.</p> 5962 * 5963 * <p>A {@code null} string input returns {@code null}. 5964 * An empty ("") string input returns an empty string. 5965 * A null or empty set of search characters returns the input string.</p> 5966 * 5967 * <p>The length of the search characters should normally equal the length 5968 * of the replace characters. 5969 * If the search characters is longer, then the extra search characters 5970 * are deleted. 5971 * If the search characters is shorter, then the extra replace characters 5972 * are ignored.</p> 5973 * 5974 * <pre> 5975 * StringUtils.replaceChars(null, *, *) = null 5976 * StringUtils.replaceChars("", *, *) = "" 5977 * StringUtils.replaceChars("abc", null, *) = "abc" 5978 * StringUtils.replaceChars("abc", "", *) = "abc" 5979 * StringUtils.replaceChars("abc", "b", null) = "ac" 5980 * StringUtils.replaceChars("abc", "b", "") = "ac" 5981 * StringUtils.replaceChars("abcba", "bc", "yz") = "ayzya" 5982 * StringUtils.replaceChars("abcba", "bc", "y") = "ayya" 5983 * StringUtils.replaceChars("abcba", "bc", "yzx") = "ayzya" 5984 * </pre> 5985 * 5986 * @param str String to replace characters in, may be null 5987 * @param searchChars a set of characters to search for, may be null 5988 * @param replaceChars a set of characters to replace, may be null 5989 * @return modified String, {@code null} if null string input 5990 * @since 2.0 5991 */ 5992 public static String replaceChars(final String str, final String searchChars, String replaceChars) { 5993 if (isEmpty(str) || isEmpty(searchChars)) { 5994 return str; 5995 } 5996 if (replaceChars == null) { 5997 replaceChars = EMPTY; 5998 } 5999 boolean modified = false; 6000 final int replaceCharsLength = replaceChars.length(); 6001 final int strLength = str.length(); 6002 final StringBuilder buf = new StringBuilder(strLength); 6003 for (int i = 0; i < strLength; i++) { 6004 final char ch = str.charAt(i); 6005 final int index = searchChars.indexOf(ch); 6006 if (index >= 0) { 6007 modified = true; 6008 if (index < replaceCharsLength) { 6009 buf.append(replaceChars.charAt(index)); 6010 } 6011 } else { 6012 buf.append(ch); 6013 } 6014 } 6015 if (modified) { 6016 return buf.toString(); 6017 } 6018 return str; 6019 } 6020 6021 // Overlay 6022 //----------------------------------------------------------------------- 6023 /** 6024 * <p>Overlays part of a String with another String.</p> 6025 * 6026 * <p>A {@code null} string input returns {@code null}. 6027 * A negative index is treated as zero. 6028 * An index greater than the string length is treated as the string length. 6029 * The start index is always the smaller of the two indices.</p> 6030 * 6031 * <pre> 6032 * StringUtils.overlay(null, *, *, *) = null 6033 * StringUtils.overlay("", "abc", 0, 0) = "abc" 6034 * StringUtils.overlay("abcdef", null, 2, 4) = "abef" 6035 * StringUtils.overlay("abcdef", "", 2, 4) = "abef" 6036 * StringUtils.overlay("abcdef", "", 4, 2) = "abef" 6037 * StringUtils.overlay("abcdef", "zzzz", 2, 4) = "abzzzzef" 6038 * StringUtils.overlay("abcdef", "zzzz", 4, 2) = "abzzzzef" 6039 * StringUtils.overlay("abcdef", "zzzz", -1, 4) = "zzzzef" 6040 * StringUtils.overlay("abcdef", "zzzz", 2, 8) = "abzzzz" 6041 * StringUtils.overlay("abcdef", "zzzz", -2, -3) = "zzzzabcdef" 6042 * StringUtils.overlay("abcdef", "zzzz", 8, 10) = "abcdefzzzz" 6043 * </pre> 6044 * 6045 * @param str the String to do overlaying in, may be null 6046 * @param overlay the String to overlay, may be null 6047 * @param start the position to start overlaying at 6048 * @param end the position to stop overlaying before 6049 * @return overlayed String, {@code null} if null String input 6050 * @since 2.0 6051 */ 6052 public static String overlay(final String str, String overlay, int start, int end) { 6053 if (str == null) { 6054 return null; 6055 } 6056 if (overlay == null) { 6057 overlay = EMPTY; 6058 } 6059 final int len = str.length(); 6060 if (start < 0) { 6061 start = 0; 6062 } 6063 if (start > len) { 6064 start = len; 6065 } 6066 if (end < 0) { 6067 end = 0; 6068 } 6069 if (end > len) { 6070 end = len; 6071 } 6072 if (start > end) { 6073 final int temp = start; 6074 start = end; 6075 end = temp; 6076 } 6077 return str.substring(0, start) + 6078 overlay + 6079 str.substring(end); 6080 } 6081 6082 // Chomping 6083 //----------------------------------------------------------------------- 6084 /** 6085 * <p>Removes one newline from end of a String if it's there, 6086 * otherwise leave it alone. A newline is "{@code \n}", 6087 * "{@code \r}", or "{@code \r\n}".</p> 6088 * 6089 * <p>NOTE: This method changed in 2.0. 6090 * It now more closely matches Perl chomp.</p> 6091 * 6092 * <pre> 6093 * StringUtils.chomp(null) = null 6094 * StringUtils.chomp("") = "" 6095 * StringUtils.chomp("abc \r") = "abc " 6096 * StringUtils.chomp("abc\n") = "abc" 6097 * StringUtils.chomp("abc\r\n") = "abc" 6098 * StringUtils.chomp("abc\r\n\r\n") = "abc\r\n" 6099 * StringUtils.chomp("abc\n\r") = "abc\n" 6100 * StringUtils.chomp("abc\n\rabc") = "abc\n\rabc" 6101 * StringUtils.chomp("\r") = "" 6102 * StringUtils.chomp("\n") = "" 6103 * StringUtils.chomp("\r\n") = "" 6104 * </pre> 6105 * 6106 * @param str the String to chomp a newline from, may be null 6107 * @return String without newline, {@code null} if null String input 6108 */ 6109 public static String chomp(final String str) { 6110 if (isEmpty(str)) { 6111 return str; 6112 } 6113 6114 if (str.length() == 1) { 6115 final char ch = str.charAt(0); 6116 if (ch == CharUtils.CR || ch == CharUtils.LF) { 6117 return EMPTY; 6118 } 6119 return str; 6120 } 6121 6122 int lastIdx = str.length() - 1; 6123 final char last = str.charAt(lastIdx); 6124 6125 if (last == CharUtils.LF) { 6126 if (str.charAt(lastIdx - 1) == CharUtils.CR) { 6127 lastIdx--; 6128 } 6129 } else if (last != CharUtils.CR) { 6130 lastIdx++; 6131 } 6132 return str.substring(0, lastIdx); 6133 } 6134 6135 /** 6136 * <p>Removes {@code separator} from the end of 6137 * {@code str} if it's there, otherwise leave it alone.</p> 6138 * 6139 * <p>NOTE: This method changed in version 2.0. 6140 * It now more closely matches Perl chomp. 6141 * For the previous behavior, use {@link #substringBeforeLast(String, String)}. 6142 * This method uses {@link String#endsWith(String)}.</p> 6143 * 6144 * <pre> 6145 * StringUtils.chomp(null, *) = null 6146 * StringUtils.chomp("", *) = "" 6147 * StringUtils.chomp("foobar", "bar") = "foo" 6148 * StringUtils.chomp("foobar", "baz") = "foobar" 6149 * StringUtils.chomp("foo", "foo") = "" 6150 * StringUtils.chomp("foo ", "foo") = "foo " 6151 * StringUtils.chomp(" foo", "foo") = " " 6152 * StringUtils.chomp("foo", "foooo") = "foo" 6153 * StringUtils.chomp("foo", "") = "foo" 6154 * StringUtils.chomp("foo", null) = "foo" 6155 * </pre> 6156 * 6157 * @param str the String to chomp from, may be null 6158 * @param separator separator String, may be null 6159 * @return String without trailing separator, {@code null} if null String input 6160 * @deprecated This feature will be removed in Lang 4.0, use {@link StringUtils#removeEnd(String, String)} instead 6161 */ 6162 @Deprecated 6163 public static String chomp(final String str, final String separator) { 6164 return removeEnd(str,separator); 6165 } 6166 6167 // Chopping 6168 //----------------------------------------------------------------------- 6169 /** 6170 * <p>Remove the last character from a String.</p> 6171 * 6172 * <p>If the String ends in {@code \r\n}, then remove both 6173 * of them.</p> 6174 * 6175 * <pre> 6176 * StringUtils.chop(null) = null 6177 * StringUtils.chop("") = "" 6178 * StringUtils.chop("abc \r") = "abc " 6179 * StringUtils.chop("abc\n") = "abc" 6180 * StringUtils.chop("abc\r\n") = "abc" 6181 * StringUtils.chop("abc") = "ab" 6182 * StringUtils.chop("abc\nabc") = "abc\nab" 6183 * StringUtils.chop("a") = "" 6184 * StringUtils.chop("\r") = "" 6185 * StringUtils.chop("\n") = "" 6186 * StringUtils.chop("\r\n") = "" 6187 * </pre> 6188 * 6189 * @param str the String to chop last character from, may be null 6190 * @return String without last character, {@code null} if null String input 6191 */ 6192 public static String chop(final String str) { 6193 if (str == null) { 6194 return null; 6195 } 6196 final int strLen = str.length(); 6197 if (strLen < 2) { 6198 return EMPTY; 6199 } 6200 final int lastIdx = strLen - 1; 6201 final String ret = str.substring(0, lastIdx); 6202 final char last = str.charAt(lastIdx); 6203 if (last == CharUtils.LF && ret.charAt(lastIdx - 1) == CharUtils.CR) { 6204 return ret.substring(0, lastIdx - 1); 6205 } 6206 return ret; 6207 } 6208 6209 // Conversion 6210 //----------------------------------------------------------------------- 6211 6212 // Padding 6213 //----------------------------------------------------------------------- 6214 /** 6215 * <p>Repeat a String {@code repeat} times to form a 6216 * new String.</p> 6217 * 6218 * <pre> 6219 * StringUtils.repeat(null, 2) = null 6220 * StringUtils.repeat("", 0) = "" 6221 * StringUtils.repeat("", 2) = "" 6222 * StringUtils.repeat("a", 3) = "aaa" 6223 * StringUtils.repeat("ab", 2) = "abab" 6224 * StringUtils.repeat("a", -2) = "" 6225 * </pre> 6226 * 6227 * @param str the String to repeat, may be null 6228 * @param repeat number of times to repeat str, negative treated as zero 6229 * @return a new String consisting of the original String repeated, 6230 * {@code null} if null String input 6231 */ 6232 public static String repeat(final String str, final int repeat) { 6233 // Performance tuned for 2.0 (JDK1.4) 6234 6235 if (str == null) { 6236 return null; 6237 } 6238 if (repeat <= 0) { 6239 return EMPTY; 6240 } 6241 final int inputLength = str.length(); 6242 if (repeat == 1 || inputLength == 0) { 6243 return str; 6244 } 6245 if (inputLength == 1 && repeat <= PAD_LIMIT) { 6246 return repeat(str.charAt(0), repeat); 6247 } 6248 6249 final int outputLength = inputLength * repeat; 6250 switch (inputLength) { 6251 case 1 : 6252 return repeat(str.charAt(0), repeat); 6253 case 2 : 6254 final char ch0 = str.charAt(0); 6255 final char ch1 = str.charAt(1); 6256 final char[] output2 = new char[outputLength]; 6257 for (int i = repeat * 2 - 2; i >= 0; i--, i--) { 6258 output2[i] = ch0; 6259 output2[i + 1] = ch1; 6260 } 6261 return new String(output2); 6262 default : 6263 final StringBuilder buf = new StringBuilder(outputLength); 6264 for (int i = 0; i < repeat; i++) { 6265 buf.append(str); 6266 } 6267 return buf.toString(); 6268 } 6269 } 6270 6271 /** 6272 * <p>Repeat a String {@code repeat} times to form a 6273 * new String, with a String separator injected each time. </p> 6274 * 6275 * <pre> 6276 * StringUtils.repeat(null, null, 2) = null 6277 * StringUtils.repeat(null, "x", 2) = null 6278 * StringUtils.repeat("", null, 0) = "" 6279 * StringUtils.repeat("", "", 2) = "" 6280 * StringUtils.repeat("", "x", 3) = "xxx" 6281 * StringUtils.repeat("?", ", ", 3) = "?, ?, ?" 6282 * </pre> 6283 * 6284 * @param str the String to repeat, may be null 6285 * @param separator the String to inject, may be null 6286 * @param repeat number of times to repeat str, negative treated as zero 6287 * @return a new String consisting of the original String repeated, 6288 * {@code null} if null String input 6289 * @since 2.5 6290 */ 6291 public static String repeat(final String str, final String separator, final int repeat) { 6292 if(str == null || separator == null) { 6293 return repeat(str, repeat); 6294 } 6295 // given that repeat(String, int) is quite optimized, better to rely on it than try and splice this into it 6296 final String result = repeat(str + separator, repeat); 6297 return removeEnd(result, separator); 6298 } 6299 6300 /** 6301 * <p>Returns padding using the specified delimiter repeated 6302 * to a given length.</p> 6303 * 6304 * <pre> 6305 * StringUtils.repeat('e', 0) = "" 6306 * StringUtils.repeat('e', 3) = "eee" 6307 * StringUtils.repeat('e', -2) = "" 6308 * </pre> 6309 * 6310 * <p>Note: this method does not support padding with 6311 * <a href="http://www.unicode.org/glossary/#supplementary_character">Unicode Supplementary Characters</a> 6312 * as they require a pair of {@code char}s to be represented. 6313 * If you are needing to support full I18N of your applications 6314 * consider using {@link #repeat(String, int)} instead. 6315 * </p> 6316 * 6317 * @param ch character to repeat 6318 * @param repeat number of times to repeat char, negative treated as zero 6319 * @return String with repeated character 6320 * @see #repeat(String, int) 6321 */ 6322 public static String repeat(final char ch, final int repeat) { 6323 if (repeat <= 0) { 6324 return EMPTY; 6325 } 6326 final char[] buf = new char[repeat]; 6327 for (int i = repeat - 1; i >= 0; i--) { 6328 buf[i] = ch; 6329 } 6330 return new String(buf); 6331 } 6332 6333 /** 6334 * <p>Right pad a String with spaces (' ').</p> 6335 * 6336 * <p>The String is padded to the size of {@code size}.</p> 6337 * 6338 * <pre> 6339 * StringUtils.rightPad(null, *) = null 6340 * StringUtils.rightPad("", 3) = " " 6341 * StringUtils.rightPad("bat", 3) = "bat" 6342 * StringUtils.rightPad("bat", 5) = "bat " 6343 * StringUtils.rightPad("bat", 1) = "bat" 6344 * StringUtils.rightPad("bat", -1) = "bat" 6345 * </pre> 6346 * 6347 * @param str the String to pad out, may be null 6348 * @param size the size to pad to 6349 * @return right padded String or original String if no padding is necessary, 6350 * {@code null} if null String input 6351 */ 6352 public static String rightPad(final String str, final int size) { 6353 return rightPad(str, size, ' '); 6354 } 6355 6356 /** 6357 * <p>Right pad a String with a specified character.</p> 6358 * 6359 * <p>The String is padded to the size of {@code size}.</p> 6360 * 6361 * <pre> 6362 * StringUtils.rightPad(null, *, *) = null 6363 * StringUtils.rightPad("", 3, 'z') = "zzz" 6364 * StringUtils.rightPad("bat", 3, 'z') = "bat" 6365 * StringUtils.rightPad("bat", 5, 'z') = "batzz" 6366 * StringUtils.rightPad("bat", 1, 'z') = "bat" 6367 * StringUtils.rightPad("bat", -1, 'z') = "bat" 6368 * </pre> 6369 * 6370 * @param str the String to pad out, may be null 6371 * @param size the size to pad to 6372 * @param padChar the character to pad with 6373 * @return right padded String or original String if no padding is necessary, 6374 * {@code null} if null String input 6375 * @since 2.0 6376 */ 6377 public static String rightPad(final String str, final int size, final char padChar) { 6378 if (str == null) { 6379 return null; 6380 } 6381 final int pads = size - str.length(); 6382 if (pads <= 0) { 6383 return str; // returns original String when possible 6384 } 6385 if (pads > PAD_LIMIT) { 6386 return rightPad(str, size, String.valueOf(padChar)); 6387 } 6388 return str.concat(repeat(padChar, pads)); 6389 } 6390 6391 /** 6392 * <p>Right pad a String with a specified String.</p> 6393 * 6394 * <p>The String is padded to the size of {@code size}.</p> 6395 * 6396 * <pre> 6397 * StringUtils.rightPad(null, *, *) = null 6398 * StringUtils.rightPad("", 3, "z") = "zzz" 6399 * StringUtils.rightPad("bat", 3, "yz") = "bat" 6400 * StringUtils.rightPad("bat", 5, "yz") = "batyz" 6401 * StringUtils.rightPad("bat", 8, "yz") = "batyzyzy" 6402 * StringUtils.rightPad("bat", 1, "yz") = "bat" 6403 * StringUtils.rightPad("bat", -1, "yz") = "bat" 6404 * StringUtils.rightPad("bat", 5, null) = "bat " 6405 * StringUtils.rightPad("bat", 5, "") = "bat " 6406 * </pre> 6407 * 6408 * @param str the String to pad out, may be null 6409 * @param size the size to pad to 6410 * @param padStr the String to pad with, null or empty treated as single space 6411 * @return right padded String or original String if no padding is necessary, 6412 * {@code null} if null String input 6413 */ 6414 public static String rightPad(final String str, final int size, String padStr) { 6415 if (str == null) { 6416 return null; 6417 } 6418 if (isEmpty(padStr)) { 6419 padStr = SPACE; 6420 } 6421 final int padLen = padStr.length(); 6422 final int strLen = str.length(); 6423 final int pads = size - strLen; 6424 if (pads <= 0) { 6425 return str; // returns original String when possible 6426 } 6427 if (padLen == 1 && pads <= PAD_LIMIT) { 6428 return rightPad(str, size, padStr.charAt(0)); 6429 } 6430 6431 if (pads == padLen) { 6432 return str.concat(padStr); 6433 } else if (pads < padLen) { 6434 return str.concat(padStr.substring(0, pads)); 6435 } else { 6436 final char[] padding = new char[pads]; 6437 final char[] padChars = padStr.toCharArray(); 6438 for (int i = 0; i < pads; i++) { 6439 padding[i] = padChars[i % padLen]; 6440 } 6441 return str.concat(new String(padding)); 6442 } 6443 } 6444 6445 /** 6446 * <p>Left pad a String with spaces (' ').</p> 6447 * 6448 * <p>The String is padded to the size of {@code size}.</p> 6449 * 6450 * <pre> 6451 * StringUtils.leftPad(null, *) = null 6452 * StringUtils.leftPad("", 3) = " " 6453 * StringUtils.leftPad("bat", 3) = "bat" 6454 * StringUtils.leftPad("bat", 5) = " bat" 6455 * StringUtils.leftPad("bat", 1) = "bat" 6456 * StringUtils.leftPad("bat", -1) = "bat" 6457 * </pre> 6458 * 6459 * @param str the String to pad out, may be null 6460 * @param size the size to pad to 6461 * @return left padded String or original String if no padding is necessary, 6462 * {@code null} if null String input 6463 */ 6464 public static String leftPad(final String str, final int size) { 6465 return leftPad(str, size, ' '); 6466 } 6467 6468 /** 6469 * <p>Left pad a String with a specified character.</p> 6470 * 6471 * <p>Pad to a size of {@code size}.</p> 6472 * 6473 * <pre> 6474 * StringUtils.leftPad(null, *, *) = null 6475 * StringUtils.leftPad("", 3, 'z') = "zzz" 6476 * StringUtils.leftPad("bat", 3, 'z') = "bat" 6477 * StringUtils.leftPad("bat", 5, 'z') = "zzbat" 6478 * StringUtils.leftPad("bat", 1, 'z') = "bat" 6479 * StringUtils.leftPad("bat", -1, 'z') = "bat" 6480 * </pre> 6481 * 6482 * @param str the String to pad out, may be null 6483 * @param size the size to pad to 6484 * @param padChar the character to pad with 6485 * @return left padded String or original String if no padding is necessary, 6486 * {@code null} if null String input 6487 * @since 2.0 6488 */ 6489 public static String leftPad(final String str, final int size, final char padChar) { 6490 if (str == null) { 6491 return null; 6492 } 6493 final int pads = size - str.length(); 6494 if (pads <= 0) { 6495 return str; // returns original String when possible 6496 } 6497 if (pads > PAD_LIMIT) { 6498 return leftPad(str, size, String.valueOf(padChar)); 6499 } 6500 return repeat(padChar, pads).concat(str); 6501 } 6502 6503 /** 6504 * <p>Left pad a String with a specified String.</p> 6505 * 6506 * <p>Pad to a size of {@code size}.</p> 6507 * 6508 * <pre> 6509 * StringUtils.leftPad(null, *, *) = null 6510 * StringUtils.leftPad("", 3, "z") = "zzz" 6511 * StringUtils.leftPad("bat", 3, "yz") = "bat" 6512 * StringUtils.leftPad("bat", 5, "yz") = "yzbat" 6513 * StringUtils.leftPad("bat", 8, "yz") = "yzyzybat" 6514 * StringUtils.leftPad("bat", 1, "yz") = "bat" 6515 * StringUtils.leftPad("bat", -1, "yz") = "bat" 6516 * StringUtils.leftPad("bat", 5, null) = " bat" 6517 * StringUtils.leftPad("bat", 5, "") = " bat" 6518 * </pre> 6519 * 6520 * @param str the String to pad out, may be null 6521 * @param size the size to pad to 6522 * @param padStr the String to pad with, null or empty treated as single space 6523 * @return left padded String or original String if no padding is necessary, 6524 * {@code null} if null String input 6525 */ 6526 public static String leftPad(final String str, final int size, String padStr) { 6527 if (str == null) { 6528 return null; 6529 } 6530 if (isEmpty(padStr)) { 6531 padStr = SPACE; 6532 } 6533 final int padLen = padStr.length(); 6534 final int strLen = str.length(); 6535 final int pads = size - strLen; 6536 if (pads <= 0) { 6537 return str; // returns original String when possible 6538 } 6539 if (padLen == 1 && pads <= PAD_LIMIT) { 6540 return leftPad(str, size, padStr.charAt(0)); 6541 } 6542 6543 if (pads == padLen) { 6544 return padStr.concat(str); 6545 } else if (pads < padLen) { 6546 return padStr.substring(0, pads).concat(str); 6547 } else { 6548 final char[] padding = new char[pads]; 6549 final char[] padChars = padStr.toCharArray(); 6550 for (int i = 0; i < pads; i++) { 6551 padding[i] = padChars[i % padLen]; 6552 } 6553 return new String(padding).concat(str); 6554 } 6555 } 6556 6557 /** 6558 * Gets a CharSequence length or {@code 0} if the CharSequence is 6559 * {@code null}. 6560 * 6561 * @param cs 6562 * a CharSequence or {@code null} 6563 * @return CharSequence length or {@code 0} if the CharSequence is 6564 * {@code null}. 6565 * @since 2.4 6566 * @since 3.0 Changed signature from length(String) to length(CharSequence) 6567 */ 6568 public static int length(final CharSequence cs) { 6569 return cs == null ? 0 : cs.length(); 6570 } 6571 6572 // Centering 6573 //----------------------------------------------------------------------- 6574 /** 6575 * <p>Centers a String in a larger String of size {@code size} 6576 * using the space character (' ').</p> 6577 * 6578 * <p>If the size is less than the String length, the String is returned. 6579 * A {@code null} String returns {@code null}. 6580 * A negative size is treated as zero.</p> 6581 * 6582 * <p>Equivalent to {@code center(str, size, " ")}.</p> 6583 * 6584 * <pre> 6585 * StringUtils.center(null, *) = null 6586 * StringUtils.center("", 4) = " " 6587 * StringUtils.center("ab", -1) = "ab" 6588 * StringUtils.center("ab", 4) = " ab " 6589 * StringUtils.center("abcd", 2) = "abcd" 6590 * StringUtils.center("a", 4) = " a " 6591 * </pre> 6592 * 6593 * @param str the String to center, may be null 6594 * @param size the int size of new String, negative treated as zero 6595 * @return centered String, {@code null} if null String input 6596 */ 6597 public static String center(final String str, final int size) { 6598 return center(str, size, ' '); 6599 } 6600 6601 /** 6602 * <p>Centers a String in a larger String of size {@code size}. 6603 * Uses a supplied character as the value to pad the String with.</p> 6604 * 6605 * <p>If the size is less than the String length, the String is returned. 6606 * A {@code null} String returns {@code null}. 6607 * A negative size is treated as zero.</p> 6608 * 6609 * <pre> 6610 * StringUtils.center(null, *, *) = null 6611 * StringUtils.center("", 4, ' ') = " " 6612 * StringUtils.center("ab", -1, ' ') = "ab" 6613 * StringUtils.center("ab", 4, ' ') = " ab " 6614 * StringUtils.center("abcd", 2, ' ') = "abcd" 6615 * StringUtils.center("a", 4, ' ') = " a " 6616 * StringUtils.center("a", 4, 'y') = "yayy" 6617 * </pre> 6618 * 6619 * @param str the String to center, may be null 6620 * @param size the int size of new String, negative treated as zero 6621 * @param padChar the character to pad the new String with 6622 * @return centered String, {@code null} if null String input 6623 * @since 2.0 6624 */ 6625 public static String center(String str, final int size, final char padChar) { 6626 if (str == null || size <= 0) { 6627 return str; 6628 } 6629 final int strLen = str.length(); 6630 final int pads = size - strLen; 6631 if (pads <= 0) { 6632 return str; 6633 } 6634 str = leftPad(str, strLen + pads / 2, padChar); 6635 str = rightPad(str, size, padChar); 6636 return str; 6637 } 6638 6639 /** 6640 * <p>Centers a String in a larger String of size {@code size}. 6641 * Uses a supplied String as the value to pad the String with.</p> 6642 * 6643 * <p>If the size is less than the String length, the String is returned. 6644 * A {@code null} String returns {@code null}. 6645 * A negative size is treated as zero.</p> 6646 * 6647 * <pre> 6648 * StringUtils.center(null, *, *) = null 6649 * StringUtils.center("", 4, " ") = " " 6650 * StringUtils.center("ab", -1, " ") = "ab" 6651 * StringUtils.center("ab", 4, " ") = " ab " 6652 * StringUtils.center("abcd", 2, " ") = "abcd" 6653 * StringUtils.center("a", 4, " ") = " a " 6654 * StringUtils.center("a", 4, "yz") = "yayz" 6655 * StringUtils.center("abc", 7, null) = " abc " 6656 * StringUtils.center("abc", 7, "") = " abc " 6657 * </pre> 6658 * 6659 * @param str the String to center, may be null 6660 * @param size the int size of new String, negative treated as zero 6661 * @param padStr the String to pad the new String with, must not be null or empty 6662 * @return centered String, {@code null} if null String input 6663 * @throws IllegalArgumentException if padStr is {@code null} or empty 6664 */ 6665 public static String center(String str, final int size, String padStr) { 6666 if (str == null || size <= 0) { 6667 return str; 6668 } 6669 if (isEmpty(padStr)) { 6670 padStr = SPACE; 6671 } 6672 final int strLen = str.length(); 6673 final int pads = size - strLen; 6674 if (pads <= 0) { 6675 return str; 6676 } 6677 str = leftPad(str, strLen + pads / 2, padStr); 6678 str = rightPad(str, size, padStr); 6679 return str; 6680 } 6681 6682 // Case conversion 6683 //----------------------------------------------------------------------- 6684 /** 6685 * <p>Converts a String to upper case as per {@link String#toUpperCase()}.</p> 6686 * 6687 * <p>A {@code null} input String returns {@code null}.</p> 6688 * 6689 * <pre> 6690 * StringUtils.upperCase(null) = null 6691 * StringUtils.upperCase("") = "" 6692 * StringUtils.upperCase("aBc") = "ABC" 6693 * </pre> 6694 * 6695 * <p><strong>Note:</strong> As described in the documentation for {@link String#toUpperCase()}, 6696 * the result of this method is affected by the current locale. 6697 * For platform-independent case transformations, the method {@link #lowerCase(String, Locale)} 6698 * should be used with a specific locale (e.g. {@link Locale#ENGLISH}).</p> 6699 * 6700 * @param str the String to upper case, may be null 6701 * @return the upper cased String, {@code null} if null String input 6702 */ 6703 public static String upperCase(final String str) { 6704 if (str == null) { 6705 return null; 6706 } 6707 return str.toUpperCase(); 6708 } 6709 6710 /** 6711 * <p>Converts a String to upper case as per {@link String#toUpperCase(Locale)}.</p> 6712 * 6713 * <p>A {@code null} input String returns {@code null}.</p> 6714 * 6715 * <pre> 6716 * StringUtils.upperCase(null, Locale.ENGLISH) = null 6717 * StringUtils.upperCase("", Locale.ENGLISH) = "" 6718 * StringUtils.upperCase("aBc", Locale.ENGLISH) = "ABC" 6719 * </pre> 6720 * 6721 * @param str the String to upper case, may be null 6722 * @param locale the locale that defines the case transformation rules, must not be null 6723 * @return the upper cased String, {@code null} if null String input 6724 * @since 2.5 6725 */ 6726 public static String upperCase(final String str, final Locale locale) { 6727 if (str == null) { 6728 return null; 6729 } 6730 return str.toUpperCase(locale); 6731 } 6732 6733 /** 6734 * <p>Converts a String to lower case as per {@link String#toLowerCase()}.</p> 6735 * 6736 * <p>A {@code null} input String returns {@code null}.</p> 6737 * 6738 * <pre> 6739 * StringUtils.lowerCase(null) = null 6740 * StringUtils.lowerCase("") = "" 6741 * StringUtils.lowerCase("aBc") = "abc" 6742 * </pre> 6743 * 6744 * <p><strong>Note:</strong> As described in the documentation for {@link String#toLowerCase()}, 6745 * the result of this method is affected by the current locale. 6746 * For platform-independent case transformations, the method {@link #lowerCase(String, Locale)} 6747 * should be used with a specific locale (e.g. {@link Locale#ENGLISH}).</p> 6748 * 6749 * @param str the String to lower case, may be null 6750 * @return the lower cased String, {@code null} if null String input 6751 */ 6752 public static String lowerCase(final String str) { 6753 if (str == null) { 6754 return null; 6755 } 6756 return str.toLowerCase(); 6757 } 6758 6759 /** 6760 * <p>Converts a String to lower case as per {@link String#toLowerCase(Locale)}.</p> 6761 * 6762 * <p>A {@code null} input String returns {@code null}.</p> 6763 * 6764 * <pre> 6765 * StringUtils.lowerCase(null, Locale.ENGLISH) = null 6766 * StringUtils.lowerCase("", Locale.ENGLISH) = "" 6767 * StringUtils.lowerCase("aBc", Locale.ENGLISH) = "abc" 6768 * </pre> 6769 * 6770 * @param str the String to lower case, may be null 6771 * @param locale the locale that defines the case transformation rules, must not be null 6772 * @return the lower cased String, {@code null} if null String input 6773 * @since 2.5 6774 */ 6775 public static String lowerCase(final String str, final Locale locale) { 6776 if (str == null) { 6777 return null; 6778 } 6779 return str.toLowerCase(locale); 6780 } 6781 6782 /** 6783 * <p>Capitalizes a String changing the first character to title case as 6784 * per {@link Character#toTitleCase(int)}. No other characters are changed.</p> 6785 * 6786 * <p>For a word based algorithm, see {@link org.apache.commons.lang3.text.WordUtils#capitalize(String)}. 6787 * A {@code null} input String returns {@code null}.</p> 6788 * 6789 * <pre> 6790 * StringUtils.capitalize(null) = null 6791 * StringUtils.capitalize("") = "" 6792 * StringUtils.capitalize("cat") = "Cat" 6793 * StringUtils.capitalize("cAt") = "CAt" 6794 * StringUtils.capitalize("'cat'") = "'cat'" 6795 * </pre> 6796 * 6797 * @param str the String to capitalize, may be null 6798 * @return the capitalized String, {@code null} if null String input 6799 * @see org.apache.commons.lang3.text.WordUtils#capitalize(String) 6800 * @see #uncapitalize(String) 6801 * @since 2.0 6802 */ 6803 public static String capitalize(final String str) { 6804 int strLen; 6805 if (str == null || (strLen = str.length()) == 0) { 6806 return str; 6807 } 6808 6809 final int firstCodepoint = str.codePointAt(0); 6810 final int newCodePoint = Character.toTitleCase(firstCodepoint); 6811 if (firstCodepoint == newCodePoint) { 6812 // already capitalized 6813 return str; 6814 } 6815 6816 final int newCodePoints[] = new int[strLen]; // cannot be longer than the char array 6817 int outOffset = 0; 6818 newCodePoints[outOffset++] = newCodePoint; // copy the first codepoint 6819 for (int inOffset = Character.charCount(firstCodepoint); inOffset < strLen; ) { 6820 final int codepoint = str.codePointAt(inOffset); 6821 newCodePoints[outOffset++] = codepoint; // copy the remaining ones 6822 inOffset += Character.charCount(codepoint); 6823 } 6824 return new String(newCodePoints, 0, outOffset); 6825 } 6826 6827 /** 6828 * <p>Uncapitalizes a String, changing the first character to lower case as 6829 * per {@link Character#toLowerCase(int)}. No other characters are changed.</p> 6830 * 6831 * <p>For a word based algorithm, see {@link org.apache.commons.lang3.text.WordUtils#uncapitalize(String)}. 6832 * A {@code null} input String returns {@code null}.</p> 6833 * 6834 * <pre> 6835 * StringUtils.uncapitalize(null) = null 6836 * StringUtils.uncapitalize("") = "" 6837 * StringUtils.uncapitalize("cat") = "cat" 6838 * StringUtils.uncapitalize("Cat") = "cat" 6839 * StringUtils.uncapitalize("CAT") = "cAT" 6840 * </pre> 6841 * 6842 * @param str the String to uncapitalize, may be null 6843 * @return the uncapitalized String, {@code null} if null String input 6844 * @see org.apache.commons.lang3.text.WordUtils#uncapitalize(String) 6845 * @see #capitalize(String) 6846 * @since 2.0 6847 */ 6848 public static String uncapitalize(final String str) { 6849 int strLen; 6850 if (str == null || (strLen = str.length()) == 0) { 6851 return str; 6852 } 6853 6854 final int firstCodepoint = str.codePointAt(0); 6855 final int newCodePoint = Character.toLowerCase(firstCodepoint); 6856 if (firstCodepoint == newCodePoint) { 6857 // already capitalized 6858 return str; 6859 } 6860 6861 final int newCodePoints[] = new int[strLen]; // cannot be longer than the char array 6862 int outOffset = 0; 6863 newCodePoints[outOffset++] = newCodePoint; // copy the first codepoint 6864 for (int inOffset = Character.charCount(firstCodepoint); inOffset < strLen; ) { 6865 final int codepoint = str.codePointAt(inOffset); 6866 newCodePoints[outOffset++] = codepoint; // copy the remaining ones 6867 inOffset += Character.charCount(codepoint); 6868 } 6869 return new String(newCodePoints, 0, outOffset); 6870 } 6871 6872 /** 6873 * <p>Swaps the case of a String changing upper and title case to 6874 * lower case, and lower case to upper case.</p> 6875 * 6876 * <ul> 6877 * <li>Upper case character converts to Lower case</li> 6878 * <li>Title case character converts to Lower case</li> 6879 * <li>Lower case character converts to Upper case</li> 6880 * </ul> 6881 * 6882 * <p>For a word based algorithm, see {@link org.apache.commons.lang3.text.WordUtils#swapCase(String)}. 6883 * A {@code null} input String returns {@code null}.</p> 6884 * 6885 * <pre> 6886 * StringUtils.swapCase(null) = null 6887 * StringUtils.swapCase("") = "" 6888 * StringUtils.swapCase("The dog has a BONE") = "tHE DOG HAS A bone" 6889 * </pre> 6890 * 6891 * <p>NOTE: This method changed in Lang version 2.0. 6892 * It no longer performs a word based algorithm. 6893 * If you only use ASCII, you will notice no change. 6894 * That functionality is available in org.apache.commons.lang3.text.WordUtils.</p> 6895 * 6896 * @param str the String to swap case, may be null 6897 * @return the changed String, {@code null} if null String input 6898 */ 6899 public static String swapCase(final String str) { 6900 if (isEmpty(str)) { 6901 return str; 6902 } 6903 6904 final int strLen = str.length(); 6905 final int newCodePoints[] = new int[strLen]; // cannot be longer than the char array 6906 int outOffset = 0; 6907 for (int i = 0; i < strLen; ) { 6908 final int oldCodepoint = str.codePointAt(i); 6909 final int newCodePoint; 6910 if (Character.isUpperCase(oldCodepoint)) { 6911 newCodePoint = Character.toLowerCase(oldCodepoint); 6912 } else if (Character.isTitleCase(oldCodepoint)) { 6913 newCodePoint = Character.toLowerCase(oldCodepoint); 6914 } else if (Character.isLowerCase(oldCodepoint)) { 6915 newCodePoint = Character.toUpperCase(oldCodepoint); 6916 } else { 6917 newCodePoint = oldCodepoint; 6918 } 6919 newCodePoints[outOffset++] = newCodePoint; 6920 i += Character.charCount(newCodePoint); 6921 } 6922 return new String(newCodePoints, 0, outOffset); 6923 } 6924 6925 // Count matches 6926 //----------------------------------------------------------------------- 6927 /** 6928 * <p>Counts how many times the substring appears in the larger string.</p> 6929 * 6930 * <p>A {@code null} or empty ("") String input returns {@code 0}.</p> 6931 * 6932 * <pre> 6933 * StringUtils.countMatches(null, *) = 0 6934 * StringUtils.countMatches("", *) = 0 6935 * StringUtils.countMatches("abba", null) = 0 6936 * StringUtils.countMatches("abba", "") = 0 6937 * StringUtils.countMatches("abba", "a") = 2 6938 * StringUtils.countMatches("abba", "ab") = 1 6939 * StringUtils.countMatches("abba", "xxx") = 0 6940 * </pre> 6941 * 6942 * @param str the CharSequence to check, may be null 6943 * @param sub the substring to count, may be null 6944 * @return the number of occurrences, 0 if either CharSequence is {@code null} 6945 * @since 3.0 Changed signature from countMatches(String, String) to countMatches(CharSequence, CharSequence) 6946 */ 6947 public static int countMatches(final CharSequence str, final CharSequence sub) { 6948 if (isEmpty(str) || isEmpty(sub)) { 6949 return 0; 6950 } 6951 int count = 0; 6952 int idx = 0; 6953 while ((idx = CharSequenceUtils.indexOf(str, sub, idx)) != INDEX_NOT_FOUND) { 6954 count++; 6955 idx += sub.length(); 6956 } 6957 return count; 6958 } 6959 6960 /** 6961 * <p>Counts how many times the char appears in the given string.</p> 6962 * 6963 * <p>A {@code null} or empty ("") String input returns {@code 0}.</p> 6964 * 6965 * <pre> 6966 * StringUtils.countMatches(null, *) = 0 6967 * StringUtils.countMatches("", *) = 0 6968 * StringUtils.countMatches("abba", 0) = 0 6969 * StringUtils.countMatches("abba", 'a') = 2 6970 * StringUtils.countMatches("abba", 'b') = 2 6971 * StringUtils.countMatches("abba", 'x') = 0 6972 * </pre> 6973 * 6974 * @param str the CharSequence to check, may be null 6975 * @param ch the char to count 6976 * @return the number of occurrences, 0 if the CharSequence is {@code null} 6977 * @since 3.4 6978 */ 6979 public static int countMatches(final CharSequence str, final char ch) { 6980 if (isEmpty(str)) { 6981 return 0; 6982 } 6983 int count = 0; 6984 // We could also call str.toCharArray() for faster look ups but that would generate more garbage. 6985 for (int i = 0; i < str.length(); i++) { 6986 if (ch == str.charAt(i)) { 6987 count++; 6988 } 6989 } 6990 return count; 6991 } 6992 6993 // Character Tests 6994 //----------------------------------------------------------------------- 6995 /** 6996 * <p>Checks if the CharSequence contains only Unicode letters.</p> 6997 * 6998 * <p>{@code null} will return {@code false}. 6999 * An empty CharSequence (length()=0) will return {@code false}.</p> 7000 * 7001 * <pre> 7002 * StringUtils.isAlpha(null) = false 7003 * StringUtils.isAlpha("") = false 7004 * StringUtils.isAlpha(" ") = false 7005 * StringUtils.isAlpha("abc") = true 7006 * StringUtils.isAlpha("ab2c") = false 7007 * StringUtils.isAlpha("ab-c") = false 7008 * </pre> 7009 * 7010 * @param cs the CharSequence to check, may be null 7011 * @return {@code true} if only contains letters, and is non-null 7012 * @since 3.0 Changed signature from isAlpha(String) to isAlpha(CharSequence) 7013 * @since 3.0 Changed "" to return false and not true 7014 */ 7015 public static boolean isAlpha(final CharSequence cs) { 7016 if (isEmpty(cs)) { 7017 return false; 7018 } 7019 final int sz = cs.length(); 7020 for (int i = 0; i < sz; i++) { 7021 if (!Character.isLetter(cs.charAt(i))) { 7022 return false; 7023 } 7024 } 7025 return true; 7026 } 7027 7028 /** 7029 * <p>Checks if the CharSequence contains only Unicode letters and 7030 * space (' ').</p> 7031 * 7032 * <p>{@code null} will return {@code false} 7033 * An empty CharSequence (length()=0) will return {@code true}.</p> 7034 * 7035 * <pre> 7036 * StringUtils.isAlphaSpace(null) = false 7037 * StringUtils.isAlphaSpace("") = true 7038 * StringUtils.isAlphaSpace(" ") = true 7039 * StringUtils.isAlphaSpace("abc") = true 7040 * StringUtils.isAlphaSpace("ab c") = true 7041 * StringUtils.isAlphaSpace("ab2c") = false 7042 * StringUtils.isAlphaSpace("ab-c") = false 7043 * </pre> 7044 * 7045 * @param cs the CharSequence to check, may be null 7046 * @return {@code true} if only contains letters and space, 7047 * and is non-null 7048 * @since 3.0 Changed signature from isAlphaSpace(String) to isAlphaSpace(CharSequence) 7049 */ 7050 public static boolean isAlphaSpace(final CharSequence cs) { 7051 if (cs == null) { 7052 return false; 7053 } 7054 final int sz = cs.length(); 7055 for (int i = 0; i < sz; i++) { 7056 if (!Character.isLetter(cs.charAt(i)) && cs.charAt(i) != ' ') { 7057 return false; 7058 } 7059 } 7060 return true; 7061 } 7062 7063 /** 7064 * <p>Checks if the CharSequence contains only Unicode letters or digits.</p> 7065 * 7066 * <p>{@code null} will return {@code false}. 7067 * An empty CharSequence (length()=0) will return {@code false}.</p> 7068 * 7069 * <pre> 7070 * StringUtils.isAlphanumeric(null) = false 7071 * StringUtils.isAlphanumeric("") = false 7072 * StringUtils.isAlphanumeric(" ") = false 7073 * StringUtils.isAlphanumeric("abc") = true 7074 * StringUtils.isAlphanumeric("ab c") = false 7075 * StringUtils.isAlphanumeric("ab2c") = true 7076 * StringUtils.isAlphanumeric("ab-c") = false 7077 * </pre> 7078 * 7079 * @param cs the CharSequence to check, may be null 7080 * @return {@code true} if only contains letters or digits, 7081 * and is non-null 7082 * @since 3.0 Changed signature from isAlphanumeric(String) to isAlphanumeric(CharSequence) 7083 * @since 3.0 Changed "" to return false and not true 7084 */ 7085 public static boolean isAlphanumeric(final CharSequence cs) { 7086 if (isEmpty(cs)) { 7087 return false; 7088 } 7089 final int sz = cs.length(); 7090 for (int i = 0; i < sz; i++) { 7091 if (!Character.isLetterOrDigit(cs.charAt(i))) { 7092 return false; 7093 } 7094 } 7095 return true; 7096 } 7097 7098 /** 7099 * <p>Checks if the CharSequence contains only Unicode letters, digits 7100 * or space ({@code ' '}).</p> 7101 * 7102 * <p>{@code null} will return {@code false}. 7103 * An empty CharSequence (length()=0) will return {@code true}.</p> 7104 * 7105 * <pre> 7106 * StringUtils.isAlphanumericSpace(null) = false 7107 * StringUtils.isAlphanumericSpace("") = true 7108 * StringUtils.isAlphanumericSpace(" ") = true 7109 * StringUtils.isAlphanumericSpace("abc") = true 7110 * StringUtils.isAlphanumericSpace("ab c") = true 7111 * StringUtils.isAlphanumericSpace("ab2c") = true 7112 * StringUtils.isAlphanumericSpace("ab-c") = false 7113 * </pre> 7114 * 7115 * @param cs the CharSequence to check, may be null 7116 * @return {@code true} if only contains letters, digits or space, 7117 * and is non-null 7118 * @since 3.0 Changed signature from isAlphanumericSpace(String) to isAlphanumericSpace(CharSequence) 7119 */ 7120 public static boolean isAlphanumericSpace(final CharSequence cs) { 7121 if (cs == null) { 7122 return false; 7123 } 7124 final int sz = cs.length(); 7125 for (int i = 0; i < sz; i++) { 7126 if (!Character.isLetterOrDigit(cs.charAt(i)) && cs.charAt(i) != ' ') { 7127 return false; 7128 } 7129 } 7130 return true; 7131 } 7132 7133 /** 7134 * <p>Checks if the CharSequence contains only ASCII printable characters.</p> 7135 * 7136 * <p>{@code null} will return {@code false}. 7137 * An empty CharSequence (length()=0) will return {@code true}.</p> 7138 * 7139 * <pre> 7140 * StringUtils.isAsciiPrintable(null) = false 7141 * StringUtils.isAsciiPrintable("") = true 7142 * StringUtils.isAsciiPrintable(" ") = true 7143 * StringUtils.isAsciiPrintable("Ceki") = true 7144 * StringUtils.isAsciiPrintable("ab2c") = true 7145 * StringUtils.isAsciiPrintable("!ab-c~") = true 7146 * StringUtils.isAsciiPrintable("\u0020") = true 7147 * StringUtils.isAsciiPrintable("\u0021") = true 7148 * StringUtils.isAsciiPrintable("\u007e") = true 7149 * StringUtils.isAsciiPrintable("\u007f") = false 7150 * StringUtils.isAsciiPrintable("Ceki G\u00fclc\u00fc") = false 7151 * </pre> 7152 * 7153 * @param cs the CharSequence to check, may be null 7154 * @return {@code true} if every character is in the range 7155 * 32 thru 126 7156 * @since 2.1 7157 * @since 3.0 Changed signature from isAsciiPrintable(String) to isAsciiPrintable(CharSequence) 7158 */ 7159 public static boolean isAsciiPrintable(final CharSequence cs) { 7160 if (cs == null) { 7161 return false; 7162 } 7163 final int sz = cs.length(); 7164 for (int i = 0; i < sz; i++) { 7165 if (!CharUtils.isAsciiPrintable(cs.charAt(i))) { 7166 return false; 7167 } 7168 } 7169 return true; 7170 } 7171 7172 /** 7173 * <p>Checks if the CharSequence contains only Unicode digits. 7174 * A decimal point is not a Unicode digit and returns false.</p> 7175 * 7176 * <p>{@code null} will return {@code false}. 7177 * An empty CharSequence (length()=0) will return {@code false}.</p> 7178 * 7179 * <p>Note that the method does not allow for a leading sign, either positive or negative. 7180 * Also, if a String passes the numeric test, it may still generate a NumberFormatException 7181 * when parsed by Integer.parseInt or Long.parseLong, e.g. if the value is outside the range 7182 * for int or long respectively.</p> 7183 * 7184 * <pre> 7185 * StringUtils.isNumeric(null) = false 7186 * StringUtils.isNumeric("") = false 7187 * StringUtils.isNumeric(" ") = false 7188 * StringUtils.isNumeric("123") = true 7189 * StringUtils.isNumeric("\u0967\u0968\u0969") = true 7190 * StringUtils.isNumeric("12 3") = false 7191 * StringUtils.isNumeric("ab2c") = false 7192 * StringUtils.isNumeric("12-3") = false 7193 * StringUtils.isNumeric("12.3") = false 7194 * StringUtils.isNumeric("-123") = false 7195 * StringUtils.isNumeric("+123") = false 7196 * </pre> 7197 * 7198 * @param cs the CharSequence to check, may be null 7199 * @return {@code true} if only contains digits, and is non-null 7200 * @since 3.0 Changed signature from isNumeric(String) to isNumeric(CharSequence) 7201 * @since 3.0 Changed "" to return false and not true 7202 */ 7203 public static boolean isNumeric(final CharSequence cs) { 7204 if (isEmpty(cs)) { 7205 return false; 7206 } 7207 final int sz = cs.length(); 7208 for (int i = 0; i < sz; i++) { 7209 if (!Character.isDigit(cs.charAt(i))) { 7210 return false; 7211 } 7212 } 7213 return true; 7214 } 7215 7216 /** 7217 * <p>Checks if the CharSequence contains only Unicode digits or space 7218 * ({@code ' '}). 7219 * A decimal point is not a Unicode digit and returns false.</p> 7220 * 7221 * <p>{@code null} will return {@code false}. 7222 * An empty CharSequence (length()=0) will return {@code true}.</p> 7223 * 7224 * <pre> 7225 * StringUtils.isNumericSpace(null) = false 7226 * StringUtils.isNumericSpace("") = true 7227 * StringUtils.isNumericSpace(" ") = true 7228 * StringUtils.isNumericSpace("123") = true 7229 * StringUtils.isNumericSpace("12 3") = true 7230 * StringUtils.isNumeric("\u0967\u0968\u0969") = true 7231 * StringUtils.isNumeric("\u0967\u0968 \u0969") = true 7232 * StringUtils.isNumericSpace("ab2c") = false 7233 * StringUtils.isNumericSpace("12-3") = false 7234 * StringUtils.isNumericSpace("12.3") = false 7235 * </pre> 7236 * 7237 * @param cs the CharSequence to check, may be null 7238 * @return {@code true} if only contains digits or space, 7239 * and is non-null 7240 * @since 3.0 Changed signature from isNumericSpace(String) to isNumericSpace(CharSequence) 7241 */ 7242 public static boolean isNumericSpace(final CharSequence cs) { 7243 if (cs == null) { 7244 return false; 7245 } 7246 final int sz = cs.length(); 7247 for (int i = 0; i < sz; i++) { 7248 if (!Character.isDigit(cs.charAt(i)) && cs.charAt(i) != ' ') { 7249 return false; 7250 } 7251 } 7252 return true; 7253 } 7254 7255 /** 7256 * <p>Checks if a String {@code str} contains Unicode digits, 7257 * if yes then concatenate all the digits in {@code str} and return it as a String.</p> 7258 * 7259 * <p>An empty ("") String will be returned if no digits found in {@code str}.</p> 7260 * 7261 * <pre> 7262 * StringUtils.getDigits(null) = null 7263 * StringUtils.getDigits("") = "" 7264 * StringUtils.getDigits("abc") = "" 7265 * StringUtils.getDigits("1000$") = "1000" 7266 * StringUtils.getDigits("1123~45") = "112345" 7267 * StringUtils.getDigits("(541) 754-3010") = "5417543010" 7268 * StringUtils.getDigits("\u0967\u0968\u0969") = "\u0967\u0968\u0969" 7269 * </pre> 7270 * 7271 * @param str the String to extract digits from, may be null 7272 * @return String with only digits, 7273 * or an empty ("") String if no digits found, 7274 * or {@code null} String if {@code str} is null 7275 * @since 3.6 7276 */ 7277 public static String getDigits(final String str) { 7278 if (isEmpty(str)) { 7279 return str; 7280 } 7281 final int sz = str.length(); 7282 final StringBuilder strDigits = new StringBuilder(sz); 7283 for (int i = 0; i < sz; i++) { 7284 final char tempChar = str.charAt(i); 7285 if (Character.isDigit(tempChar)) { 7286 strDigits.append(tempChar); 7287 } 7288 } 7289 return strDigits.toString(); 7290 } 7291 7292 /** 7293 * <p>Checks if the CharSequence contains only whitespace.</p> 7294 * 7295 * <p>Whitespace is defined by {@link Character#isWhitespace(char)}.</p> 7296 * 7297 * <p>{@code null} will return {@code false}. 7298 * An empty CharSequence (length()=0) will return {@code true}.</p> 7299 * 7300 * <pre> 7301 * StringUtils.isWhitespace(null) = false 7302 * StringUtils.isWhitespace("") = true 7303 * StringUtils.isWhitespace(" ") = true 7304 * StringUtils.isWhitespace("abc") = false 7305 * StringUtils.isWhitespace("ab2c") = false 7306 * StringUtils.isWhitespace("ab-c") = false 7307 * </pre> 7308 * 7309 * @param cs the CharSequence to check, may be null 7310 * @return {@code true} if only contains whitespace, and is non-null 7311 * @since 2.0 7312 * @since 3.0 Changed signature from isWhitespace(String) to isWhitespace(CharSequence) 7313 */ 7314 public static boolean isWhitespace(final CharSequence cs) { 7315 if (cs == null) { 7316 return false; 7317 } 7318 final int sz = cs.length(); 7319 for (int i = 0; i < sz; i++) { 7320 if (!Character.isWhitespace(cs.charAt(i))) { 7321 return false; 7322 } 7323 } 7324 return true; 7325 } 7326 7327 /** 7328 * <p>Checks if the CharSequence contains only lowercase characters.</p> 7329 * 7330 * <p>{@code null} will return {@code false}. 7331 * An empty CharSequence (length()=0) will return {@code false}.</p> 7332 * 7333 * <pre> 7334 * StringUtils.isAllLowerCase(null) = false 7335 * StringUtils.isAllLowerCase("") = false 7336 * StringUtils.isAllLowerCase(" ") = false 7337 * StringUtils.isAllLowerCase("abc") = true 7338 * StringUtils.isAllLowerCase("abC") = false 7339 * StringUtils.isAllLowerCase("ab c") = false 7340 * StringUtils.isAllLowerCase("ab1c") = false 7341 * StringUtils.isAllLowerCase("ab/c") = false 7342 * </pre> 7343 * 7344 * @param cs the CharSequence to check, may be null 7345 * @return {@code true} if only contains lowercase characters, and is non-null 7346 * @since 2.5 7347 * @since 3.0 Changed signature from isAllLowerCase(String) to isAllLowerCase(CharSequence) 7348 */ 7349 public static boolean isAllLowerCase(final CharSequence cs) { 7350 if (cs == null || isEmpty(cs)) { 7351 return false; 7352 } 7353 final int sz = cs.length(); 7354 for (int i = 0; i < sz; i++) { 7355 if (!Character.isLowerCase(cs.charAt(i))) { 7356 return false; 7357 } 7358 } 7359 return true; 7360 } 7361 7362 /** 7363 * <p>Checks if the CharSequence contains only uppercase characters.</p> 7364 * 7365 * <p>{@code null} will return {@code false}. 7366 * An empty String (length()=0) will return {@code false}.</p> 7367 * 7368 * <pre> 7369 * StringUtils.isAllUpperCase(null) = false 7370 * StringUtils.isAllUpperCase("") = false 7371 * StringUtils.isAllUpperCase(" ") = false 7372 * StringUtils.isAllUpperCase("ABC") = true 7373 * StringUtils.isAllUpperCase("aBC") = false 7374 * StringUtils.isAllUpperCase("A C") = false 7375 * StringUtils.isAllUpperCase("A1C") = false 7376 * StringUtils.isAllUpperCase("A/C") = false 7377 * </pre> 7378 * 7379 * @param cs the CharSequence to check, may be null 7380 * @return {@code true} if only contains uppercase characters, and is non-null 7381 * @since 2.5 7382 * @since 3.0 Changed signature from isAllUpperCase(String) to isAllUpperCase(CharSequence) 7383 */ 7384 public static boolean isAllUpperCase(final CharSequence cs) { 7385 if (cs == null || isEmpty(cs)) { 7386 return false; 7387 } 7388 final int sz = cs.length(); 7389 for (int i = 0; i < sz; i++) { 7390 if (!Character.isUpperCase(cs.charAt(i))) { 7391 return false; 7392 } 7393 } 7394 return true; 7395 } 7396 7397 /** 7398 * <p>Checks if the CharSequence contains mixed casing of both uppercase and lowercase characters.</p> 7399 * 7400 * <p>{@code null} will return {@code false}. An empty CharSequence ({@code length()=0}) will return 7401 * {@code false}.</p> 7402 * 7403 * <pre> 7404 * StringUtils.isMixedCase(null) = false 7405 * StringUtils.isMixedCase("") = false 7406 * StringUtils.isMixedCase("ABC") = false 7407 * StringUtils.isMixedCase("abc") = false 7408 * StringUtils.isMixedCase("aBc") = true 7409 * StringUtils.isMixedCase("A c") = true 7410 * StringUtils.isMixedCase("A1c") = true 7411 * StringUtils.isMixedCase("a/C") = true 7412 * StringUtils.isMixedCase("aC\t") = true 7413 * </pre> 7414 * 7415 * @param cs the CharSequence to check, may be null 7416 * @return {@code true} if the CharSequence contains both uppercase and lowercase characters 7417 * @since 3.5 7418 */ 7419 public static boolean isMixedCase(final CharSequence cs) { 7420 if (isEmpty(cs) || cs.length() == 1) { 7421 return false; 7422 } 7423 boolean containsUppercase = false; 7424 boolean containsLowercase = false; 7425 final int sz = cs.length(); 7426 for (int i = 0; i < sz; i++) { 7427 if (containsUppercase && containsLowercase) { 7428 return true; 7429 } else if (Character.isUpperCase(cs.charAt(i))) { 7430 containsUppercase = true; 7431 } else if (Character.isLowerCase(cs.charAt(i))) { 7432 containsLowercase = true; 7433 } 7434 } 7435 return containsUppercase && containsLowercase; 7436 } 7437 7438 // Defaults 7439 //----------------------------------------------------------------------- 7440 /** 7441 * <p>Returns either the passed in String, 7442 * or if the String is {@code null}, an empty String ("").</p> 7443 * 7444 * <pre> 7445 * StringUtils.defaultString(null) = "" 7446 * StringUtils.defaultString("") = "" 7447 * StringUtils.defaultString("bat") = "bat" 7448 * </pre> 7449 * 7450 * @see ObjectUtils#toString(Object) 7451 * @see String#valueOf(Object) 7452 * @param str the String to check, may be null 7453 * @return the passed in String, or the empty String if it 7454 * was {@code null} 7455 */ 7456 public static String defaultString(final String str) { 7457 return defaultString(str, EMPTY); 7458 } 7459 7460 /** 7461 * <p>Returns either the passed in String, or if the String is 7462 * {@code null}, the value of {@code defaultStr}.</p> 7463 * 7464 * <pre> 7465 * StringUtils.defaultString(null, "NULL") = "NULL" 7466 * StringUtils.defaultString("", "NULL") = "" 7467 * StringUtils.defaultString("bat", "NULL") = "bat" 7468 * </pre> 7469 * 7470 * @see ObjectUtils#toString(Object,String) 7471 * @see String#valueOf(Object) 7472 * @param str the String to check, may be null 7473 * @param defaultStr the default String to return 7474 * if the input is {@code null}, may be null 7475 * @return the passed in String, or the default if it was {@code null} 7476 */ 7477 public static String defaultString(final String str, final String defaultStr) { 7478 return str == null ? defaultStr : str; 7479 } 7480 7481 /** 7482 * <p>Returns the first value in the array which is not empty (""), 7483 * {@code null} or whitespace only.</p> 7484 * 7485 * <p>Whitespace is defined by {@link Character#isWhitespace(char)}.</p> 7486 * 7487 * <p>If all values are blank or the array is {@code null} 7488 * or empty then {@code null} is returned.</p> 7489 * 7490 * <pre> 7491 * StringUtils.firstNonBlank(null, null, null) = null 7492 * StringUtils.firstNonBlank(null, "", " ") = null 7493 * StringUtils.firstNonBlank("abc") = "abc" 7494 * StringUtils.firstNonBlank(null, "xyz") = "xyz" 7495 * StringUtils.firstNonBlank(null, "", " ", "xyz") = "xyz" 7496 * StringUtils.firstNonBlank(null, "xyz", "abc") = "xyz" 7497 * StringUtils.firstNonBlank() = null 7498 * </pre> 7499 * 7500 * @param <T> the specific kind of CharSequence 7501 * @param values the values to test, may be {@code null} or empty 7502 * @return the first value from {@code values} which is not blank, 7503 * or {@code null} if there are no non-blank values 7504 * @since 3.8 7505 */ 7506 @SafeVarargs 7507 public static <T extends CharSequence> T firstNonBlank(final T... values) { 7508 if (values != null) { 7509 for (final T val : values) { 7510 if (isNotBlank(val)) { 7511 return val; 7512 } 7513 } 7514 } 7515 return null; 7516 } 7517 7518 /** 7519 * <p>Returns the first value in the array which is not empty.</p> 7520 * 7521 * <p>If all values are empty or the array is {@code null} 7522 * or empty then {@code null} is returned.</p> 7523 * 7524 * <pre> 7525 * StringUtils.firstNonEmpty(null, null, null) = null 7526 * StringUtils.firstNonEmpty(null, null, "") = null 7527 * StringUtils.firstNonEmpty(null, "", " ") = " " 7528 * StringUtils.firstNonEmpty("abc") = "abc" 7529 * StringUtils.firstNonEmpty(null, "xyz") = "xyz" 7530 * StringUtils.firstNonEmpty("", "xyz") = "xyz" 7531 * StringUtils.firstNonEmpty(null, "xyz", "abc") = "xyz" 7532 * StringUtils.firstNonEmpty() = null 7533 * </pre> 7534 * 7535 * @param <T> the specific kind of CharSequence 7536 * @param values the values to test, may be {@code null} or empty 7537 * @return the first value from {@code values} which is not empty, 7538 * or {@code null} if there are no non-empty values 7539 * @since 3.8 7540 */ 7541 @SafeVarargs 7542 public static <T extends CharSequence> T firstNonEmpty(final T... values) { 7543 if (values != null) { 7544 for (final T val : values) { 7545 if (isNotEmpty(val)) { 7546 return val; 7547 } 7548 } 7549 } 7550 return null; 7551 } 7552 7553 /** 7554 * <p>Returns either the passed in CharSequence, or if the CharSequence is 7555 * whitespace, empty ("") or {@code null}, the value of {@code defaultStr}.</p> 7556 * 7557 * <p>Whitespace is defined by {@link Character#isWhitespace(char)}.</p> 7558 * 7559 * <pre> 7560 * StringUtils.defaultIfBlank(null, "NULL") = "NULL" 7561 * StringUtils.defaultIfBlank("", "NULL") = "NULL" 7562 * StringUtils.defaultIfBlank(" ", "NULL") = "NULL" 7563 * StringUtils.defaultIfBlank("bat", "NULL") = "bat" 7564 * StringUtils.defaultIfBlank("", null) = null 7565 * </pre> 7566 * @param <T> the specific kind of CharSequence 7567 * @param str the CharSequence to check, may be null 7568 * @param defaultStr the default CharSequence to return 7569 * if the input is whitespace, empty ("") or {@code null}, may be null 7570 * @return the passed in CharSequence, or the default 7571 * @see StringUtils#defaultString(String, String) 7572 */ 7573 public static <T extends CharSequence> T defaultIfBlank(final T str, final T defaultStr) { 7574 return isBlank(str) ? defaultStr : str; 7575 } 7576 7577 /** 7578 * <p>Returns either the passed in CharSequence, or if the CharSequence is 7579 * empty or {@code null}, the value of {@code defaultStr}.</p> 7580 * 7581 * <pre> 7582 * StringUtils.defaultIfEmpty(null, "NULL") = "NULL" 7583 * StringUtils.defaultIfEmpty("", "NULL") = "NULL" 7584 * StringUtils.defaultIfEmpty(" ", "NULL") = " " 7585 * StringUtils.defaultIfEmpty("bat", "NULL") = "bat" 7586 * StringUtils.defaultIfEmpty("", null) = null 7587 * </pre> 7588 * @param <T> the specific kind of CharSequence 7589 * @param str the CharSequence to check, may be null 7590 * @param defaultStr the default CharSequence to return 7591 * if the input is empty ("") or {@code null}, may be null 7592 * @return the passed in CharSequence, or the default 7593 * @see StringUtils#defaultString(String, String) 7594 */ 7595 public static <T extends CharSequence> T defaultIfEmpty(final T str, final T defaultStr) { 7596 return isEmpty(str) ? defaultStr : str; 7597 } 7598 7599 // Rotating (circular shift) 7600 //----------------------------------------------------------------------- 7601 /** 7602 * <p>Rotate (circular shift) a String of {@code shift} characters.</p> 7603 * <ul> 7604 * <li>If {@code shift > 0}, right circular shift (ex : ABCDEF => FABCDE)</li> 7605 * <li>If {@code shift < 0}, left circular shift (ex : ABCDEF => BCDEFA)</li> 7606 * </ul> 7607 * 7608 * <pre> 7609 * StringUtils.rotate(null, *) = null 7610 * StringUtils.rotate("", *) = "" 7611 * StringUtils.rotate("abcdefg", 0) = "abcdefg" 7612 * StringUtils.rotate("abcdefg", 2) = "fgabcde" 7613 * StringUtils.rotate("abcdefg", -2) = "cdefgab" 7614 * StringUtils.rotate("abcdefg", 7) = "abcdefg" 7615 * StringUtils.rotate("abcdefg", -7) = "abcdefg" 7616 * StringUtils.rotate("abcdefg", 9) = "fgabcde" 7617 * StringUtils.rotate("abcdefg", -9) = "cdefgab" 7618 * </pre> 7619 * 7620 * @param str the String to rotate, may be null 7621 * @param shift number of time to shift (positive : right shift, negative : left shift) 7622 * @return the rotated String, 7623 * or the original String if {@code shift == 0}, 7624 * or {@code null} if null String input 7625 * @since 3.5 7626 */ 7627 public static String rotate(final String str, final int shift) { 7628 if (str == null) { 7629 return null; 7630 } 7631 7632 final int strLen = str.length(); 7633 if (shift == 0 || strLen == 0 || shift % strLen == 0) { 7634 return str; 7635 } 7636 7637 final StringBuilder builder = new StringBuilder(strLen); 7638 final int offset = - (shift % strLen); 7639 builder.append(substring(str, offset)); 7640 builder.append(substring(str, 0, offset)); 7641 return builder.toString(); 7642 } 7643 7644 // Reversing 7645 //----------------------------------------------------------------------- 7646 /** 7647 * <p>Reverses a String as per {@link StringBuilder#reverse()}.</p> 7648 * 7649 * <p>A {@code null} String returns {@code null}.</p> 7650 * 7651 * <pre> 7652 * StringUtils.reverse(null) = null 7653 * StringUtils.reverse("") = "" 7654 * StringUtils.reverse("bat") = "tab" 7655 * </pre> 7656 * 7657 * @param str the String to reverse, may be null 7658 * @return the reversed String, {@code null} if null String input 7659 */ 7660 public static String reverse(final String str) { 7661 if (str == null) { 7662 return null; 7663 } 7664 return new StringBuilder(str).reverse().toString(); 7665 } 7666 7667 /** 7668 * <p>Reverses a String that is delimited by a specific character.</p> 7669 * 7670 * <p>The Strings between the delimiters are not reversed. 7671 * Thus java.lang.String becomes String.lang.java (if the delimiter 7672 * is {@code '.'}).</p> 7673 * 7674 * <pre> 7675 * StringUtils.reverseDelimited(null, *) = null 7676 * StringUtils.reverseDelimited("", *) = "" 7677 * StringUtils.reverseDelimited("a.b.c", 'x') = "a.b.c" 7678 * StringUtils.reverseDelimited("a.b.c", ".") = "c.b.a" 7679 * </pre> 7680 * 7681 * @param str the String to reverse, may be null 7682 * @param separatorChar the separator character to use 7683 * @return the reversed String, {@code null} if null String input 7684 * @since 2.0 7685 */ 7686 public static String reverseDelimited(final String str, final char separatorChar) { 7687 if (str == null) { 7688 return null; 7689 } 7690 // could implement manually, but simple way is to reuse other, 7691 // probably slower, methods. 7692 final String[] strs = split(str, separatorChar); 7693 ArrayUtils.reverse(strs); 7694 return join(strs, separatorChar); 7695 } 7696 7697 // Abbreviating 7698 //----------------------------------------------------------------------- 7699 /** 7700 * <p>Abbreviates a String using ellipses. This will turn 7701 * "Now is the time for all good men" into "Now is the time for..."</p> 7702 * 7703 * <p>Specifically:</p> 7704 * <ul> 7705 * <li>If the number of characters in {@code str} is less than or equal to 7706 * {@code maxWidth}, return {@code str}.</li> 7707 * <li>Else abbreviate it to {@code (substring(str, 0, max-3) + "...")}.</li> 7708 * <li>If {@code maxWidth} is less than {@code 4}, throw an 7709 * {@code IllegalArgumentException}.</li> 7710 * <li>In no case will it return a String of length greater than 7711 * {@code maxWidth}.</li> 7712 * </ul> 7713 * 7714 * <pre> 7715 * StringUtils.abbreviate(null, *) = null 7716 * StringUtils.abbreviate("", 4) = "" 7717 * StringUtils.abbreviate("abcdefg", 6) = "abc..." 7718 * StringUtils.abbreviate("abcdefg", 7) = "abcdefg" 7719 * StringUtils.abbreviate("abcdefg", 8) = "abcdefg" 7720 * StringUtils.abbreviate("abcdefg", 4) = "a..." 7721 * StringUtils.abbreviate("abcdefg", 3) = IllegalArgumentException 7722 * </pre> 7723 * 7724 * @param str the String to check, may be null 7725 * @param maxWidth maximum length of result String, must be at least 4 7726 * @return abbreviated String, {@code null} if null String input 7727 * @throws IllegalArgumentException if the width is too small 7728 * @since 2.0 7729 */ 7730 public static String abbreviate(final String str, final int maxWidth) { 7731 final String defaultAbbrevMarker = "..."; 7732 return abbreviate(str, defaultAbbrevMarker, 0, maxWidth); 7733 } 7734 7735 /** 7736 * <p>Abbreviates a String using ellipses. This will turn 7737 * "Now is the time for all good men" into "...is the time for..."</p> 7738 * 7739 * <p>Works like {@code abbreviate(String, int)}, but allows you to specify 7740 * a "left edge" offset. Note that this left edge is not necessarily going to 7741 * be the leftmost character in the result, or the first character following the 7742 * ellipses, but it will appear somewhere in the result. 7743 * 7744 * <p>In no case will it return a String of length greater than 7745 * {@code maxWidth}.</p> 7746 * 7747 * <pre> 7748 * StringUtils.abbreviate(null, *, *) = null 7749 * StringUtils.abbreviate("", 0, 4) = "" 7750 * StringUtils.abbreviate("abcdefghijklmno", -1, 10) = "abcdefg..." 7751 * StringUtils.abbreviate("abcdefghijklmno", 0, 10) = "abcdefg..." 7752 * StringUtils.abbreviate("abcdefghijklmno", 1, 10) = "abcdefg..." 7753 * StringUtils.abbreviate("abcdefghijklmno", 4, 10) = "abcdefg..." 7754 * StringUtils.abbreviate("abcdefghijklmno", 5, 10) = "...fghi..." 7755 * StringUtils.abbreviate("abcdefghijklmno", 6, 10) = "...ghij..." 7756 * StringUtils.abbreviate("abcdefghijklmno", 8, 10) = "...ijklmno" 7757 * StringUtils.abbreviate("abcdefghijklmno", 10, 10) = "...ijklmno" 7758 * StringUtils.abbreviate("abcdefghijklmno", 12, 10) = "...ijklmno" 7759 * StringUtils.abbreviate("abcdefghij", 0, 3) = IllegalArgumentException 7760 * StringUtils.abbreviate("abcdefghij", 5, 6) = IllegalArgumentException 7761 * </pre> 7762 * 7763 * @param str the String to check, may be null 7764 * @param offset left edge of source String 7765 * @param maxWidth maximum length of result String, must be at least 4 7766 * @return abbreviated String, {@code null} if null String input 7767 * @throws IllegalArgumentException if the width is too small 7768 * @since 2.0 7769 */ 7770 public static String abbreviate(final String str, final int offset, final int maxWidth) { 7771 final String defaultAbbrevMarker = "..."; 7772 return abbreviate(str, defaultAbbrevMarker, offset, maxWidth); 7773 } 7774 7775 /** 7776 * <p>Abbreviates a String using another given String as replacement marker. This will turn 7777 * "Now is the time for all good men" into "Now is the time for..." if "..." was defined 7778 * as the replacement marker.</p> 7779 * 7780 * <p>Specifically:</p> 7781 * <ul> 7782 * <li>If the number of characters in {@code str} is less than or equal to 7783 * {@code maxWidth}, return {@code str}.</li> 7784 * <li>Else abbreviate it to {@code (substring(str, 0, max-abbrevMarker.length) + abbrevMarker)}.</li> 7785 * <li>If {@code maxWidth} is less than {@code abbrevMarker.length + 1}, throw an 7786 * {@code IllegalArgumentException}.</li> 7787 * <li>In no case will it return a String of length greater than 7788 * {@code maxWidth}.</li> 7789 * </ul> 7790 * 7791 * <pre> 7792 * StringUtils.abbreviate(null, "...", *) = null 7793 * StringUtils.abbreviate("abcdefg", null, *) = "abcdefg" 7794 * StringUtils.abbreviate("", "...", 4) = "" 7795 * StringUtils.abbreviate("abcdefg", ".", 5) = "abcd." 7796 * StringUtils.abbreviate("abcdefg", ".", 7) = "abcdefg" 7797 * StringUtils.abbreviate("abcdefg", ".", 8) = "abcdefg" 7798 * StringUtils.abbreviate("abcdefg", "..", 4) = "ab.." 7799 * StringUtils.abbreviate("abcdefg", "..", 3) = "a.." 7800 * StringUtils.abbreviate("abcdefg", "..", 2) = IllegalArgumentException 7801 * StringUtils.abbreviate("abcdefg", "...", 3) = IllegalArgumentException 7802 * </pre> 7803 * 7804 * @param str the String to check, may be null 7805 * @param abbrevMarker the String used as replacement marker 7806 * @param maxWidth maximum length of result String, must be at least {@code abbrevMarker.length + 1} 7807 * @return abbreviated String, {@code null} if null String input 7808 * @throws IllegalArgumentException if the width is too small 7809 * @since 3.6 7810 */ 7811 public static String abbreviate(final String str, final String abbrevMarker, final int maxWidth) { 7812 return abbreviate(str, abbrevMarker, 0, maxWidth); 7813 } 7814 7815 /** 7816 * <p>Abbreviates a String using a given replacement marker. This will turn 7817 * "Now is the time for all good men" into "...is the time for..." if "..." was defined 7818 * as the replacement marker.</p> 7819 * 7820 * <p>Works like {@code abbreviate(String, String, int)}, but allows you to specify 7821 * a "left edge" offset. Note that this left edge is not necessarily going to 7822 * be the leftmost character in the result, or the first character following the 7823 * replacement marker, but it will appear somewhere in the result. 7824 * 7825 * <p>In no case will it return a String of length greater than {@code maxWidth}.</p> 7826 * 7827 * <pre> 7828 * StringUtils.abbreviate(null, null, *, *) = null 7829 * StringUtils.abbreviate("abcdefghijklmno", null, *, *) = "abcdefghijklmno" 7830 * StringUtils.abbreviate("", "...", 0, 4) = "" 7831 * StringUtils.abbreviate("abcdefghijklmno", "---", -1, 10) = "abcdefg---" 7832 * StringUtils.abbreviate("abcdefghijklmno", ",", 0, 10) = "abcdefghi," 7833 * StringUtils.abbreviate("abcdefghijklmno", ",", 1, 10) = "abcdefghi," 7834 * StringUtils.abbreviate("abcdefghijklmno", ",", 2, 10) = "abcdefghi," 7835 * StringUtils.abbreviate("abcdefghijklmno", "::", 4, 10) = "::efghij::" 7836 * StringUtils.abbreviate("abcdefghijklmno", "...", 6, 10) = "...ghij..." 7837 * StringUtils.abbreviate("abcdefghijklmno", "*", 9, 10) = "*ghijklmno" 7838 * StringUtils.abbreviate("abcdefghijklmno", "'", 10, 10) = "'ghijklmno" 7839 * StringUtils.abbreviate("abcdefghijklmno", "!", 12, 10) = "!ghijklmno" 7840 * StringUtils.abbreviate("abcdefghij", "abra", 0, 4) = IllegalArgumentException 7841 * StringUtils.abbreviate("abcdefghij", "...", 5, 6) = IllegalArgumentException 7842 * </pre> 7843 * 7844 * @param str the String to check, may be null 7845 * @param abbrevMarker the String used as replacement marker 7846 * @param offset left edge of source String 7847 * @param maxWidth maximum length of result String, must be at least 4 7848 * @return abbreviated String, {@code null} if null String input 7849 * @throws IllegalArgumentException if the width is too small 7850 * @since 3.6 7851 */ 7852 public static String abbreviate(final String str, final String abbrevMarker, int offset, final int maxWidth) { 7853 if (isEmpty(str) || isEmpty(abbrevMarker)) { 7854 return str; 7855 } 7856 7857 final int abbrevMarkerLength = abbrevMarker.length(); 7858 final int minAbbrevWidth = abbrevMarkerLength + 1; 7859 final int minAbbrevWidthOffset = abbrevMarkerLength + abbrevMarkerLength + 1; 7860 7861 if (maxWidth < minAbbrevWidth) { 7862 throw new IllegalArgumentException(String.format("Minimum abbreviation width is %d", minAbbrevWidth)); 7863 } 7864 if (str.length() <= maxWidth) { 7865 return str; 7866 } 7867 if (offset > str.length()) { 7868 offset = str.length(); 7869 } 7870 if (str.length() - offset < maxWidth - abbrevMarkerLength) { 7871 offset = str.length() - (maxWidth - abbrevMarkerLength); 7872 } 7873 if (offset <= abbrevMarkerLength+1) { 7874 return str.substring(0, maxWidth - abbrevMarkerLength) + abbrevMarker; 7875 } 7876 if (maxWidth < minAbbrevWidthOffset) { 7877 throw new IllegalArgumentException(String.format("Minimum abbreviation width with offset is %d", minAbbrevWidthOffset)); 7878 } 7879 if (offset + maxWidth - abbrevMarkerLength < str.length()) { 7880 return abbrevMarker + abbreviate(str.substring(offset), abbrevMarker, maxWidth - abbrevMarkerLength); 7881 } 7882 return abbrevMarker + str.substring(str.length() - (maxWidth - abbrevMarkerLength)); 7883 } 7884 7885 /** 7886 * <p>Abbreviates a String to the length passed, replacing the middle characters with the supplied 7887 * replacement String.</p> 7888 * 7889 * <p>This abbreviation only occurs if the following criteria is met:</p> 7890 * <ul> 7891 * <li>Neither the String for abbreviation nor the replacement String are null or empty </li> 7892 * <li>The length to truncate to is less than the length of the supplied String</li> 7893 * <li>The length to truncate to is greater than 0</li> 7894 * <li>The abbreviated String will have enough room for the length supplied replacement String 7895 * and the first and last characters of the supplied String for abbreviation</li> 7896 * </ul> 7897 * <p>Otherwise, the returned String will be the same as the supplied String for abbreviation. 7898 * </p> 7899 * 7900 * <pre> 7901 * StringUtils.abbreviateMiddle(null, null, 0) = null 7902 * StringUtils.abbreviateMiddle("abc", null, 0) = "abc" 7903 * StringUtils.abbreviateMiddle("abc", ".", 0) = "abc" 7904 * StringUtils.abbreviateMiddle("abc", ".", 3) = "abc" 7905 * StringUtils.abbreviateMiddle("abcdef", ".", 4) = "ab.f" 7906 * </pre> 7907 * 7908 * @param str the String to abbreviate, may be null 7909 * @param middle the String to replace the middle characters with, may be null 7910 * @param length the length to abbreviate {@code str} to. 7911 * @return the abbreviated String if the above criteria is met, or the original String supplied for abbreviation. 7912 * @since 2.5 7913 */ 7914 public static String abbreviateMiddle(final String str, final String middle, final int length) { 7915 if (isEmpty(str) || isEmpty(middle)) { 7916 return str; 7917 } 7918 7919 if (length >= str.length() || length < middle.length()+2) { 7920 return str; 7921 } 7922 7923 final int targetSting = length-middle.length(); 7924 final int startOffset = targetSting/2+targetSting%2; 7925 final int endOffset = str.length()-targetSting/2; 7926 7927 return str.substring(0, startOffset) + 7928 middle + 7929 str.substring(endOffset); 7930 } 7931 7932 // Difference 7933 //----------------------------------------------------------------------- 7934 /** 7935 * <p>Compares two Strings, and returns the portion where they differ. 7936 * More precisely, return the remainder of the second String, 7937 * starting from where it's different from the first. This means that 7938 * the difference between "abc" and "ab" is the empty String and not "c". </p> 7939 * 7940 * <p>For example, 7941 * {@code difference("i am a machine", "i am a robot") -> "robot"}.</p> 7942 * 7943 * <pre> 7944 * StringUtils.difference(null, null) = null 7945 * StringUtils.difference("", "") = "" 7946 * StringUtils.difference("", "abc") = "abc" 7947 * StringUtils.difference("abc", "") = "" 7948 * StringUtils.difference("abc", "abc") = "" 7949 * StringUtils.difference("abc", "ab") = "" 7950 * StringUtils.difference("ab", "abxyz") = "xyz" 7951 * StringUtils.difference("abcde", "abxyz") = "xyz" 7952 * StringUtils.difference("abcde", "xyz") = "xyz" 7953 * </pre> 7954 * 7955 * @param str1 the first String, may be null 7956 * @param str2 the second String, may be null 7957 * @return the portion of str2 where it differs from str1; returns the 7958 * empty String if they are equal 7959 * @see #indexOfDifference(CharSequence,CharSequence) 7960 * @since 2.0 7961 */ 7962 public static String difference(final String str1, final String str2) { 7963 if (str1 == null) { 7964 return str2; 7965 } 7966 if (str2 == null) { 7967 return str1; 7968 } 7969 final int at = indexOfDifference(str1, str2); 7970 if (at == INDEX_NOT_FOUND) { 7971 return EMPTY; 7972 } 7973 return str2.substring(at); 7974 } 7975 7976 /** 7977 * <p>Compares two CharSequences, and returns the index at which the 7978 * CharSequences begin to differ.</p> 7979 * 7980 * <p>For example, 7981 * {@code indexOfDifference("i am a machine", "i am a robot") -> 7}</p> 7982 * 7983 * <pre> 7984 * StringUtils.indexOfDifference(null, null) = -1 7985 * StringUtils.indexOfDifference("", "") = -1 7986 * StringUtils.indexOfDifference("", "abc") = 0 7987 * StringUtils.indexOfDifference("abc", "") = 0 7988 * StringUtils.indexOfDifference("abc", "abc") = -1 7989 * StringUtils.indexOfDifference("ab", "abxyz") = 2 7990 * StringUtils.indexOfDifference("abcde", "abxyz") = 2 7991 * StringUtils.indexOfDifference("abcde", "xyz") = 0 7992 * </pre> 7993 * 7994 * @param cs1 the first CharSequence, may be null 7995 * @param cs2 the second CharSequence, may be null 7996 * @return the index where cs1 and cs2 begin to differ; -1 if they are equal 7997 * @since 2.0 7998 * @since 3.0 Changed signature from indexOfDifference(String, String) to 7999 * indexOfDifference(CharSequence, CharSequence) 8000 */ 8001 public static int indexOfDifference(final CharSequence cs1, final CharSequence cs2) { 8002 if (cs1 == cs2) { 8003 return INDEX_NOT_FOUND; 8004 } 8005 if (cs1 == null || cs2 == null) { 8006 return 0; 8007 } 8008 int i; 8009 for (i = 0; i < cs1.length() && i < cs2.length(); ++i) { 8010 if (cs1.charAt(i) != cs2.charAt(i)) { 8011 break; 8012 } 8013 } 8014 if (i < cs2.length() || i < cs1.length()) { 8015 return i; 8016 } 8017 return INDEX_NOT_FOUND; 8018 } 8019 8020 /** 8021 * <p>Compares all CharSequences in an array and returns the index at which the 8022 * CharSequences begin to differ.</p> 8023 * 8024 * <p>For example, 8025 * <code>indexOfDifference(new String[] {"i am a machine", "i am a robot"}) -> 7</code></p> 8026 * 8027 * <pre> 8028 * StringUtils.indexOfDifference(null) = -1 8029 * StringUtils.indexOfDifference(new String[] {}) = -1 8030 * StringUtils.indexOfDifference(new String[] {"abc"}) = -1 8031 * StringUtils.indexOfDifference(new String[] {null, null}) = -1 8032 * StringUtils.indexOfDifference(new String[] {"", ""}) = -1 8033 * StringUtils.indexOfDifference(new String[] {"", null}) = 0 8034 * StringUtils.indexOfDifference(new String[] {"abc", null, null}) = 0 8035 * StringUtils.indexOfDifference(new String[] {null, null, "abc"}) = 0 8036 * StringUtils.indexOfDifference(new String[] {"", "abc"}) = 0 8037 * StringUtils.indexOfDifference(new String[] {"abc", ""}) = 0 8038 * StringUtils.indexOfDifference(new String[] {"abc", "abc"}) = -1 8039 * StringUtils.indexOfDifference(new String[] {"abc", "a"}) = 1 8040 * StringUtils.indexOfDifference(new String[] {"ab", "abxyz"}) = 2 8041 * StringUtils.indexOfDifference(new String[] {"abcde", "abxyz"}) = 2 8042 * StringUtils.indexOfDifference(new String[] {"abcde", "xyz"}) = 0 8043 * StringUtils.indexOfDifference(new String[] {"xyz", "abcde"}) = 0 8044 * StringUtils.indexOfDifference(new String[] {"i am a machine", "i am a robot"}) = 7 8045 * </pre> 8046 * 8047 * @param css array of CharSequences, entries may be null 8048 * @return the index where the strings begin to differ; -1 if they are all equal 8049 * @since 2.4 8050 * @since 3.0 Changed signature from indexOfDifference(String...) to indexOfDifference(CharSequence...) 8051 */ 8052 public static int indexOfDifference(final CharSequence... css) { 8053 if (css == null || css.length <= 1) { 8054 return INDEX_NOT_FOUND; 8055 } 8056 boolean anyStringNull = false; 8057 boolean allStringsNull = true; 8058 final int arrayLen = css.length; 8059 int shortestStrLen = Integer.MAX_VALUE; 8060 int longestStrLen = 0; 8061 8062 // find the min and max string lengths; this avoids checking to make 8063 // sure we are not exceeding the length of the string each time through 8064 // the bottom loop. 8065 for (final CharSequence cs : css) { 8066 if (cs == null) { 8067 anyStringNull = true; 8068 shortestStrLen = 0; 8069 } else { 8070 allStringsNull = false; 8071 shortestStrLen = Math.min(cs.length(), shortestStrLen); 8072 longestStrLen = Math.max(cs.length(), longestStrLen); 8073 } 8074 } 8075 8076 // handle lists containing all nulls or all empty strings 8077 if (allStringsNull || longestStrLen == 0 && !anyStringNull) { 8078 return INDEX_NOT_FOUND; 8079 } 8080 8081 // handle lists containing some nulls or some empty strings 8082 if (shortestStrLen == 0) { 8083 return 0; 8084 } 8085 8086 // find the position with the first difference across all strings 8087 int firstDiff = -1; 8088 for (int stringPos = 0; stringPos < shortestStrLen; stringPos++) { 8089 final char comparisonChar = css[0].charAt(stringPos); 8090 for (int arrayPos = 1; arrayPos < arrayLen; arrayPos++) { 8091 if (css[arrayPos].charAt(stringPos) != comparisonChar) { 8092 firstDiff = stringPos; 8093 break; 8094 } 8095 } 8096 if (firstDiff != -1) { 8097 break; 8098 } 8099 } 8100 8101 if (firstDiff == -1 && shortestStrLen != longestStrLen) { 8102 // we compared all of the characters up to the length of the 8103 // shortest string and didn't find a match, but the string lengths 8104 // vary, so return the length of the shortest string. 8105 return shortestStrLen; 8106 } 8107 return firstDiff; 8108 } 8109 8110 /** 8111 * <p>Compares all Strings in an array and returns the initial sequence of 8112 * characters that is common to all of them.</p> 8113 * 8114 * <p>For example, 8115 * <code>getCommonPrefix(new String[] {"i am a machine", "i am a robot"}) -> "i am a "</code></p> 8116 * 8117 * <pre> 8118 * StringUtils.getCommonPrefix(null) = "" 8119 * StringUtils.getCommonPrefix(new String[] {}) = "" 8120 * StringUtils.getCommonPrefix(new String[] {"abc"}) = "abc" 8121 * StringUtils.getCommonPrefix(new String[] {null, null}) = "" 8122 * StringUtils.getCommonPrefix(new String[] {"", ""}) = "" 8123 * StringUtils.getCommonPrefix(new String[] {"", null}) = "" 8124 * StringUtils.getCommonPrefix(new String[] {"abc", null, null}) = "" 8125 * StringUtils.getCommonPrefix(new String[] {null, null, "abc"}) = "" 8126 * StringUtils.getCommonPrefix(new String[] {"", "abc"}) = "" 8127 * StringUtils.getCommonPrefix(new String[] {"abc", ""}) = "" 8128 * StringUtils.getCommonPrefix(new String[] {"abc", "abc"}) = "abc" 8129 * StringUtils.getCommonPrefix(new String[] {"abc", "a"}) = "a" 8130 * StringUtils.getCommonPrefix(new String[] {"ab", "abxyz"}) = "ab" 8131 * StringUtils.getCommonPrefix(new String[] {"abcde", "abxyz"}) = "ab" 8132 * StringUtils.getCommonPrefix(new String[] {"abcde", "xyz"}) = "" 8133 * StringUtils.getCommonPrefix(new String[] {"xyz", "abcde"}) = "" 8134 * StringUtils.getCommonPrefix(new String[] {"i am a machine", "i am a robot"}) = "i am a " 8135 * </pre> 8136 * 8137 * @param strs array of String objects, entries may be null 8138 * @return the initial sequence of characters that are common to all Strings 8139 * in the array; empty String if the array is null, the elements are all null 8140 * or if there is no common prefix. 8141 * @since 2.4 8142 */ 8143 public static String getCommonPrefix(final String... strs) { 8144 if (strs == null || strs.length == 0) { 8145 return EMPTY; 8146 } 8147 final int smallestIndexOfDiff = indexOfDifference(strs); 8148 if (smallestIndexOfDiff == INDEX_NOT_FOUND) { 8149 // all strings were identical 8150 if (strs[0] == null) { 8151 return EMPTY; 8152 } 8153 return strs[0]; 8154 } else if (smallestIndexOfDiff == 0) { 8155 // there were no common initial characters 8156 return EMPTY; 8157 } else { 8158 // we found a common initial character sequence 8159 return strs[0].substring(0, smallestIndexOfDiff); 8160 } 8161 } 8162 8163 // Misc 8164 //----------------------------------------------------------------------- 8165 /** 8166 * <p>Find the Levenshtein distance between two Strings.</p> 8167 * 8168 * <p>This is the number of changes needed to change one String into 8169 * another, where each change is a single character modification (deletion, 8170 * insertion or substitution).</p> 8171 * 8172 * <p>The implementation uses a single-dimensional array of length s.length() + 1. See 8173 * <a href="http://blog.softwx.net/2014/12/optimizing-levenshtein-algorithm-in-c.html"> 8174 * http://blog.softwx.net/2014/12/optimizing-levenshtein-algorithm-in-c.html</a> for details.</p> 8175 * 8176 * <pre> 8177 * StringUtils.getLevenshteinDistance(null, *) = IllegalArgumentException 8178 * StringUtils.getLevenshteinDistance(*, null) = IllegalArgumentException 8179 * StringUtils.getLevenshteinDistance("","") = 0 8180 * StringUtils.getLevenshteinDistance("","a") = 1 8181 * StringUtils.getLevenshteinDistance("aaapppp", "") = 7 8182 * StringUtils.getLevenshteinDistance("frog", "fog") = 1 8183 * StringUtils.getLevenshteinDistance("fly", "ant") = 3 8184 * StringUtils.getLevenshteinDistance("elephant", "hippo") = 7 8185 * StringUtils.getLevenshteinDistance("hippo", "elephant") = 7 8186 * StringUtils.getLevenshteinDistance("hippo", "zzzzzzzz") = 8 8187 * StringUtils.getLevenshteinDistance("hello", "hallo") = 1 8188 * </pre> 8189 * 8190 * @param s the first String, must not be null 8191 * @param t the second String, must not be null 8192 * @return result distance 8193 * @throws IllegalArgumentException if either String input {@code null} 8194 * @since 3.0 Changed signature from getLevenshteinDistance(String, String) to 8195 * getLevenshteinDistance(CharSequence, CharSequence) 8196 * @deprecated as of 3.6, use commons-text 8197 * <a href="https://commons.apache.org/proper/commons-text/javadocs/api-release/org/apache/commons/text/similarity/LevenshteinDistance.html"> 8198 * LevenshteinDistance</a> instead 8199 */ 8200 @Deprecated 8201 public static int getLevenshteinDistance(CharSequence s, CharSequence t) { 8202 if (s == null || t == null) { 8203 throw new IllegalArgumentException("Strings must not be null"); 8204 } 8205 8206 int n = s.length(); 8207 int m = t.length(); 8208 8209 if (n == 0) { 8210 return m; 8211 } else if (m == 0) { 8212 return n; 8213 } 8214 8215 if (n > m) { 8216 // swap the input strings to consume less memory 8217 final CharSequence tmp = s; 8218 s = t; 8219 t = tmp; 8220 n = m; 8221 m = t.length(); 8222 } 8223 8224 final int p[] = new int[n + 1]; 8225 // indexes into strings s and t 8226 int i; // iterates through s 8227 int j; // iterates through t 8228 int upper_left; 8229 int upper; 8230 8231 char t_j; // jth character of t 8232 int cost; 8233 8234 for (i = 0; i <= n; i++) { 8235 p[i] = i; 8236 } 8237 8238 for (j = 1; j <= m; j++) { 8239 upper_left = p[0]; 8240 t_j = t.charAt(j - 1); 8241 p[0] = j; 8242 8243 for (i = 1; i <= n; i++) { 8244 upper = p[i]; 8245 cost = s.charAt(i - 1) == t_j ? 0 : 1; 8246 // minimum of cell to the left+1, to the top+1, diagonally left and up +cost 8247 p[i] = Math.min(Math.min(p[i - 1] + 1, p[i] + 1), upper_left + cost); 8248 upper_left = upper; 8249 } 8250 } 8251 8252 return p[n]; 8253 } 8254 8255 /** 8256 * <p>Find the Levenshtein distance between two Strings if it's less than or equal to a given 8257 * threshold.</p> 8258 * 8259 * <p>This is the number of changes needed to change one String into 8260 * another, where each change is a single character modification (deletion, 8261 * insertion or substitution).</p> 8262 * 8263 * <p>This implementation follows from Algorithms on Strings, Trees and Sequences by Dan Gusfield 8264 * and Chas Emerick's implementation of the Levenshtein distance algorithm from 8265 * <a href="http://www.merriampark.com/ld.htm">http://www.merriampark.com/ld.htm</a></p> 8266 * 8267 * <pre> 8268 * StringUtils.getLevenshteinDistance(null, *, *) = IllegalArgumentException 8269 * StringUtils.getLevenshteinDistance(*, null, *) = IllegalArgumentException 8270 * StringUtils.getLevenshteinDistance(*, *, -1) = IllegalArgumentException 8271 * StringUtils.getLevenshteinDistance("","", 0) = 0 8272 * StringUtils.getLevenshteinDistance("aaapppp", "", 8) = 7 8273 * StringUtils.getLevenshteinDistance("aaapppp", "", 7) = 7 8274 * StringUtils.getLevenshteinDistance("aaapppp", "", 6)) = -1 8275 * StringUtils.getLevenshteinDistance("elephant", "hippo", 7) = 7 8276 * StringUtils.getLevenshteinDistance("elephant", "hippo", 6) = -1 8277 * StringUtils.getLevenshteinDistance("hippo", "elephant", 7) = 7 8278 * StringUtils.getLevenshteinDistance("hippo", "elephant", 6) = -1 8279 * </pre> 8280 * 8281 * @param s the first String, must not be null 8282 * @param t the second String, must not be null 8283 * @param threshold the target threshold, must not be negative 8284 * @return result distance, or {@code -1} if the distance would be greater than the threshold 8285 * @throws IllegalArgumentException if either String input {@code null} or negative threshold 8286 * @deprecated as of 3.6, use commons-text 8287 * <a href="https://commons.apache.org/proper/commons-text/javadocs/api-release/org/apache/commons/text/similarity/LevenshteinDistance.html"> 8288 * LevenshteinDistance</a> instead 8289 */ 8290 @Deprecated 8291 public static int getLevenshteinDistance(CharSequence s, CharSequence t, final int threshold) { 8292 if (s == null || t == null) { 8293 throw new IllegalArgumentException("Strings must not be null"); 8294 } 8295 if (threshold < 0) { 8296 throw new IllegalArgumentException("Threshold must not be negative"); 8297 } 8298 8299 /* 8300 This implementation only computes the distance if it's less than or equal to the 8301 threshold value, returning -1 if it's greater. The advantage is performance: unbounded 8302 distance is O(nm), but a bound of k allows us to reduce it to O(km) time by only 8303 computing a diagonal stripe of width 2k + 1 of the cost table. 8304 It is also possible to use this to compute the unbounded Levenshtein distance by starting 8305 the threshold at 1 and doubling each time until the distance is found; this is O(dm), where 8306 d is the distance. 8307 8308 One subtlety comes from needing to ignore entries on the border of our stripe 8309 eg. 8310 p[] = |#|#|#|* 8311 d[] = *|#|#|#| 8312 We must ignore the entry to the left of the leftmost member 8313 We must ignore the entry above the rightmost member 8314 8315 Another subtlety comes from our stripe running off the matrix if the strings aren't 8316 of the same size. Since string s is always swapped to be the shorter of the two, 8317 the stripe will always run off to the upper right instead of the lower left of the matrix. 8318 8319 As a concrete example, suppose s is of length 5, t is of length 7, and our threshold is 1. 8320 In this case we're going to walk a stripe of length 3. The matrix would look like so: 8321 8322 1 2 3 4 5 8323 1 |#|#| | | | 8324 2 |#|#|#| | | 8325 3 | |#|#|#| | 8326 4 | | |#|#|#| 8327 5 | | | |#|#| 8328 6 | | | | |#| 8329 7 | | | | | | 8330 8331 Note how the stripe leads off the table as there is no possible way to turn a string of length 5 8332 into one of length 7 in edit distance of 1. 8333 8334 Additionally, this implementation decreases memory usage by using two 8335 single-dimensional arrays and swapping them back and forth instead of allocating 8336 an entire n by m matrix. This requires a few minor changes, such as immediately returning 8337 when it's detected that the stripe has run off the matrix and initially filling the arrays with 8338 large values so that entries we don't compute are ignored. 8339 8340 See Algorithms on Strings, Trees and Sequences by Dan Gusfield for some discussion. 8341 */ 8342 8343 int n = s.length(); // length of s 8344 int m = t.length(); // length of t 8345 8346 // if one string is empty, the edit distance is necessarily the length of the other 8347 if (n == 0) { 8348 return m <= threshold ? m : -1; 8349 } else if (m == 0) { 8350 return n <= threshold ? n : -1; 8351 } else if (Math.abs(n - m) > threshold) { 8352 // no need to calculate the distance if the length difference is greater than the threshold 8353 return -1; 8354 } 8355 8356 if (n > m) { 8357 // swap the two strings to consume less memory 8358 final CharSequence tmp = s; 8359 s = t; 8360 t = tmp; 8361 n = m; 8362 m = t.length(); 8363 } 8364 8365 int p[] = new int[n + 1]; // 'previous' cost array, horizontally 8366 int d[] = new int[n + 1]; // cost array, horizontally 8367 int _d[]; // placeholder to assist in swapping p and d 8368 8369 // fill in starting table values 8370 final int boundary = Math.min(n, threshold) + 1; 8371 for (int i = 0; i < boundary; i++) { 8372 p[i] = i; 8373 } 8374 // these fills ensure that the value above the rightmost entry of our 8375 // stripe will be ignored in following loop iterations 8376 Arrays.fill(p, boundary, p.length, Integer.MAX_VALUE); 8377 Arrays.fill(d, Integer.MAX_VALUE); 8378 8379 // iterates through t 8380 for (int j = 1; j <= m; j++) { 8381 final char t_j = t.charAt(j - 1); // jth character of t 8382 d[0] = j; 8383 8384 // compute stripe indices, constrain to array size 8385 final int min = Math.max(1, j - threshold); 8386 final int max = j > Integer.MAX_VALUE - threshold ? n : Math.min(n, j + threshold); 8387 8388 // the stripe may lead off of the table if s and t are of different sizes 8389 if (min > max) { 8390 return -1; 8391 } 8392 8393 // ignore entry left of leftmost 8394 if (min > 1) { 8395 d[min - 1] = Integer.MAX_VALUE; 8396 } 8397 8398 // iterates through [min, max] in s 8399 for (int i = min; i <= max; i++) { 8400 if (s.charAt(i - 1) == t_j) { 8401 // diagonally left and up 8402 d[i] = p[i - 1]; 8403 } else { 8404 // 1 + minimum of cell to the left, to the top, diagonally left and up 8405 d[i] = 1 + Math.min(Math.min(d[i - 1], p[i]), p[i - 1]); 8406 } 8407 } 8408 8409 // copy current distance counts to 'previous row' distance counts 8410 _d = p; 8411 p = d; 8412 d = _d; 8413 } 8414 8415 // if p[n] is greater than the threshold, there's no guarantee on it being the correct 8416 // distance 8417 if (p[n] <= threshold) { 8418 return p[n]; 8419 } 8420 return -1; 8421 } 8422 8423 /** 8424 * <p>Find the Jaro Winkler Distance which indicates the similarity score between two Strings.</p> 8425 * 8426 * <p>The Jaro measure is the weighted sum of percentage of matched characters from each file and transposed characters. 8427 * Winkler increased this measure for matching initial characters.</p> 8428 * 8429 * <p>This implementation is based on the Jaro Winkler similarity algorithm 8430 * 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> 8431 * 8432 * <pre> 8433 * StringUtils.getJaroWinklerDistance(null, null) = IllegalArgumentException 8434 * StringUtils.getJaroWinklerDistance("","") = 0.0 8435 * StringUtils.getJaroWinklerDistance("","a") = 0.0 8436 * StringUtils.getJaroWinklerDistance("aaapppp", "") = 0.0 8437 * StringUtils.getJaroWinklerDistance("frog", "fog") = 0.93 8438 * StringUtils.getJaroWinklerDistance("fly", "ant") = 0.0 8439 * StringUtils.getJaroWinklerDistance("elephant", "hippo") = 0.44 8440 * StringUtils.getJaroWinklerDistance("hippo", "elephant") = 0.44 8441 * StringUtils.getJaroWinklerDistance("hippo", "zzzzzzzz") = 0.0 8442 * StringUtils.getJaroWinklerDistance("hello", "hallo") = 0.88 8443 * StringUtils.getJaroWinklerDistance("ABC Corporation", "ABC Corp") = 0.93 8444 * StringUtils.getJaroWinklerDistance("D N H Enterprises Inc", "D & H Enterprises, Inc.") = 0.95 8445 * StringUtils.getJaroWinklerDistance("My Gym Children's Fitness Center", "My Gym. Childrens Fitness") = 0.92 8446 * StringUtils.getJaroWinklerDistance("PENNSYLVANIA", "PENNCISYLVNIA") = 0.88 8447 * </pre> 8448 * 8449 * @param first the first String, must not be null 8450 * @param second the second String, must not be null 8451 * @return result distance 8452 * @throws IllegalArgumentException if either String input {@code null} 8453 * @since 3.3 8454 * @deprecated as of 3.6, use commons-text 8455 * <a href="https://commons.apache.org/proper/commons-text/javadocs/api-release/org/apache/commons/text/similarity/JaroWinklerDistance.html"> 8456 * JaroWinklerDistance</a> instead 8457 */ 8458 @Deprecated 8459 public static double getJaroWinklerDistance(final CharSequence first, final CharSequence second) { 8460 final double DEFAULT_SCALING_FACTOR = 0.1; 8461 8462 if (first == null || second == null) { 8463 throw new IllegalArgumentException("Strings must not be null"); 8464 } 8465 8466 final int[] mtp = matches(first, second); 8467 final double m = mtp[0]; 8468 if (m == 0) { 8469 return 0D; 8470 } 8471 final double j = ((m / first.length() + m / second.length() + (m - mtp[1]) / m)) / 3; 8472 final double jw = j < 0.7D ? j : j + Math.min(DEFAULT_SCALING_FACTOR, 1D / mtp[3]) * mtp[2] * (1D - j); 8473 return Math.round(jw * 100.0D) / 100.0D; 8474 } 8475 8476 private static int[] matches(final CharSequence first, final CharSequence second) { 8477 CharSequence max, min; 8478 if (first.length() > second.length()) { 8479 max = first; 8480 min = second; 8481 } else { 8482 max = second; 8483 min = first; 8484 } 8485 final int range = Math.max(max.length() / 2 - 1, 0); 8486 final int[] matchIndexes = new int[min.length()]; 8487 Arrays.fill(matchIndexes, -1); 8488 final boolean[] matchFlags = new boolean[max.length()]; 8489 int matches = 0; 8490 for (int mi = 0; mi < min.length(); mi++) { 8491 final char c1 = min.charAt(mi); 8492 for (int xi = Math.max(mi - range, 0), xn = Math.min(mi + range + 1, max.length()); xi < xn; xi++) { 8493 if (!matchFlags[xi] && c1 == max.charAt(xi)) { 8494 matchIndexes[mi] = xi; 8495 matchFlags[xi] = true; 8496 matches++; 8497 break; 8498 } 8499 } 8500 } 8501 final char[] ms1 = new char[matches]; 8502 final char[] ms2 = new char[matches]; 8503 for (int i = 0, si = 0; i < min.length(); i++) { 8504 if (matchIndexes[i] != -1) { 8505 ms1[si] = min.charAt(i); 8506 si++; 8507 } 8508 } 8509 for (int i = 0, si = 0; i < max.length(); i++) { 8510 if (matchFlags[i]) { 8511 ms2[si] = max.charAt(i); 8512 si++; 8513 } 8514 } 8515 int transpositions = 0; 8516 for (int mi = 0; mi < ms1.length; mi++) { 8517 if (ms1[mi] != ms2[mi]) { 8518 transpositions++; 8519 } 8520 } 8521 int prefix = 0; 8522 for (int mi = 0; mi < min.length(); mi++) { 8523 if (first.charAt(mi) == second.charAt(mi)) { 8524 prefix++; 8525 } else { 8526 break; 8527 } 8528 } 8529 return new int[] { matches, transpositions / 2, prefix, max.length() }; 8530 } 8531 8532 /** 8533 * <p>Find the Fuzzy Distance which indicates the similarity score between two Strings.</p> 8534 * 8535 * <p>This string matching algorithm is similar to the algorithms of editors such as Sublime Text, 8536 * TextMate, Atom and others. One point is given for every matched character. Subsequent 8537 * matches yield two bonus points. A higher score indicates a higher similarity.</p> 8538 * 8539 * <pre> 8540 * StringUtils.getFuzzyDistance(null, null, null) = IllegalArgumentException 8541 * StringUtils.getFuzzyDistance("", "", Locale.ENGLISH) = 0 8542 * StringUtils.getFuzzyDistance("Workshop", "b", Locale.ENGLISH) = 0 8543 * StringUtils.getFuzzyDistance("Room", "o", Locale.ENGLISH) = 1 8544 * StringUtils.getFuzzyDistance("Workshop", "w", Locale.ENGLISH) = 1 8545 * StringUtils.getFuzzyDistance("Workshop", "ws", Locale.ENGLISH) = 2 8546 * StringUtils.getFuzzyDistance("Workshop", "wo", Locale.ENGLISH) = 4 8547 * StringUtils.getFuzzyDistance("Apache Software Foundation", "asf", Locale.ENGLISH) = 3 8548 * </pre> 8549 * 8550 * @param term a full term that should be matched against, must not be null 8551 * @param query the query that will be matched against a term, must not be null 8552 * @param locale This string matching logic is case insensitive. A locale is necessary to normalize 8553 * both Strings to lower case. 8554 * @return result score 8555 * @throws IllegalArgumentException if either String input {@code null} or Locale input {@code null} 8556 * @since 3.4 8557 * @deprecated as of 3.6, use commons-text 8558 * <a href="https://commons.apache.org/proper/commons-text/javadocs/api-release/org/apache/commons/text/similarity/FuzzyScore.html"> 8559 * FuzzyScore</a> instead 8560 */ 8561 @Deprecated 8562 public static int getFuzzyDistance(final CharSequence term, final CharSequence query, final Locale locale) { 8563 if (term == null || query == null) { 8564 throw new IllegalArgumentException("Strings must not be null"); 8565 } else if (locale == null) { 8566 throw new IllegalArgumentException("Locale must not be null"); 8567 } 8568 8569 // fuzzy logic is case insensitive. We normalize the Strings to lower 8570 // case right from the start. Turning characters to lower case 8571 // via Character.toLowerCase(char) is unfortunately insufficient 8572 // as it does not accept a locale. 8573 final String termLowerCase = term.toString().toLowerCase(locale); 8574 final String queryLowerCase = query.toString().toLowerCase(locale); 8575 8576 // the resulting score 8577 int score = 0; 8578 8579 // the position in the term which will be scanned next for potential 8580 // query character matches 8581 int termIndex = 0; 8582 8583 // index of the previously matched character in the term 8584 int previousMatchingCharacterIndex = Integer.MIN_VALUE; 8585 8586 for (int queryIndex = 0; queryIndex < queryLowerCase.length(); queryIndex++) { 8587 final char queryChar = queryLowerCase.charAt(queryIndex); 8588 8589 boolean termCharacterMatchFound = false; 8590 for (; termIndex < termLowerCase.length() && !termCharacterMatchFound; termIndex++) { 8591 final char termChar = termLowerCase.charAt(termIndex); 8592 8593 if (queryChar == termChar) { 8594 // simple character matches result in one point 8595 score++; 8596 8597 // subsequent character matches further improve 8598 // the score. 8599 if (previousMatchingCharacterIndex + 1 == termIndex) { 8600 score += 2; 8601 } 8602 8603 previousMatchingCharacterIndex = termIndex; 8604 8605 // we can leave the nested loop. Every character in the 8606 // query can match at most one character in the term. 8607 termCharacterMatchFound = true; 8608 } 8609 } 8610 } 8611 8612 return score; 8613 } 8614 8615 // startsWith 8616 //----------------------------------------------------------------------- 8617 8618 /** 8619 * <p>Check if a CharSequence starts with a specified prefix.</p> 8620 * 8621 * <p>{@code null}s are handled without exceptions. Two {@code null} 8622 * references are considered to be equal. The comparison is case sensitive.</p> 8623 * 8624 * <pre> 8625 * StringUtils.startsWith(null, null) = true 8626 * StringUtils.startsWith(null, "abc") = false 8627 * StringUtils.startsWith("abcdef", null) = false 8628 * StringUtils.startsWith("abcdef", "abc") = true 8629 * StringUtils.startsWith("ABCDEF", "abc") = false 8630 * </pre> 8631 * 8632 * @see java.lang.String#startsWith(String) 8633 * @param str the CharSequence to check, may be null 8634 * @param prefix the prefix to find, may be null 8635 * @return {@code true} if the CharSequence starts with the prefix, case sensitive, or 8636 * both {@code null} 8637 * @since 2.4 8638 * @since 3.0 Changed signature from startsWith(String, String) to startsWith(CharSequence, CharSequence) 8639 */ 8640 public static boolean startsWith(final CharSequence str, final CharSequence prefix) { 8641 return startsWith(str, prefix, false); 8642 } 8643 8644 /** 8645 * <p>Case insensitive check if a CharSequence starts with a specified prefix.</p> 8646 * 8647 * <p>{@code null}s are handled without exceptions. Two {@code null} 8648 * references are considered to be equal. The comparison is case insensitive.</p> 8649 * 8650 * <pre> 8651 * StringUtils.startsWithIgnoreCase(null, null) = true 8652 * StringUtils.startsWithIgnoreCase(null, "abc") = false 8653 * StringUtils.startsWithIgnoreCase("abcdef", null) = false 8654 * StringUtils.startsWithIgnoreCase("abcdef", "abc") = true 8655 * StringUtils.startsWithIgnoreCase("ABCDEF", "abc") = true 8656 * </pre> 8657 * 8658 * @see java.lang.String#startsWith(String) 8659 * @param str the CharSequence to check, may be null 8660 * @param prefix the prefix to find, may be null 8661 * @return {@code true} if the CharSequence starts with the prefix, case insensitive, or 8662 * both {@code null} 8663 * @since 2.4 8664 * @since 3.0 Changed signature from startsWithIgnoreCase(String, String) to startsWithIgnoreCase(CharSequence, CharSequence) 8665 */ 8666 public static boolean startsWithIgnoreCase(final CharSequence str, final CharSequence prefix) { 8667 return startsWith(str, prefix, true); 8668 } 8669 8670 /** 8671 * <p>Check if a CharSequence starts with a specified prefix (optionally case insensitive).</p> 8672 * 8673 * @see java.lang.String#startsWith(String) 8674 * @param str the CharSequence to check, may be null 8675 * @param prefix the prefix to find, may be null 8676 * @param ignoreCase indicates whether the compare should ignore case 8677 * (case insensitive) or not. 8678 * @return {@code true} if the CharSequence starts with the prefix or 8679 * both {@code null} 8680 */ 8681 private static boolean startsWith(final CharSequence str, final CharSequence prefix, final boolean ignoreCase) { 8682 if (str == null || prefix == null) { 8683 return str == prefix; 8684 } 8685 if (prefix.length() > str.length()) { 8686 return false; 8687 } 8688 return CharSequenceUtils.regionMatches(str, ignoreCase, 0, prefix, 0, prefix.length()); 8689 } 8690 8691 /** 8692 * <p>Check if a CharSequence starts with any of the provided case-sensitive prefixes.</p> 8693 * 8694 * <pre> 8695 * StringUtils.startsWithAny(null, null) = false 8696 * StringUtils.startsWithAny(null, new String[] {"abc"}) = false 8697 * StringUtils.startsWithAny("abcxyz", null) = false 8698 * StringUtils.startsWithAny("abcxyz", new String[] {""}) = true 8699 * StringUtils.startsWithAny("abcxyz", new String[] {"abc"}) = true 8700 * StringUtils.startsWithAny("abcxyz", new String[] {null, "xyz", "abc"}) = true 8701 * StringUtils.startsWithAny("abcxyz", null, "xyz", "ABCX") = false 8702 * StringUtils.startsWithAny("ABCXYZ", null, "xyz", "abc") = false 8703 * </pre> 8704 * 8705 * @param sequence the CharSequence to check, may be null 8706 * @param searchStrings the case-sensitive CharSequence prefixes, may be empty or contain {@code null} 8707 * @see StringUtils#startsWith(CharSequence, CharSequence) 8708 * @return {@code true} if the input {@code sequence} is {@code null} AND no {@code searchStrings} are provided, or 8709 * the input {@code sequence} begins with any of the provided case-sensitive {@code searchStrings}. 8710 * @since 2.5 8711 * @since 3.0 Changed signature from startsWithAny(String, String[]) to startsWithAny(CharSequence, CharSequence...) 8712 */ 8713 public static boolean startsWithAny(final CharSequence sequence, final CharSequence... searchStrings) { 8714 if (isEmpty(sequence) || ArrayUtils.isEmpty(searchStrings)) { 8715 return false; 8716 } 8717 for (final CharSequence searchString : searchStrings) { 8718 if (startsWith(sequence, searchString)) { 8719 return true; 8720 } 8721 } 8722 return false; 8723 } 8724 8725 // endsWith 8726 //----------------------------------------------------------------------- 8727 8728 /** 8729 * <p>Check if a CharSequence ends with a specified suffix.</p> 8730 * 8731 * <p>{@code null}s are handled without exceptions. Two {@code null} 8732 * references are considered to be equal. The comparison is case sensitive.</p> 8733 * 8734 * <pre> 8735 * StringUtils.endsWith(null, null) = true 8736 * StringUtils.endsWith(null, "def") = false 8737 * StringUtils.endsWith("abcdef", null) = false 8738 * StringUtils.endsWith("abcdef", "def") = true 8739 * StringUtils.endsWith("ABCDEF", "def") = false 8740 * StringUtils.endsWith("ABCDEF", "cde") = false 8741 * StringUtils.endsWith("ABCDEF", "") = true 8742 * </pre> 8743 * 8744 * @see java.lang.String#endsWith(String) 8745 * @param str the CharSequence to check, may be null 8746 * @param suffix the suffix to find, may be null 8747 * @return {@code true} if the CharSequence ends with the suffix, case sensitive, or 8748 * both {@code null} 8749 * @since 2.4 8750 * @since 3.0 Changed signature from endsWith(String, String) to endsWith(CharSequence, CharSequence) 8751 */ 8752 public static boolean endsWith(final CharSequence str, final CharSequence suffix) { 8753 return endsWith(str, suffix, false); 8754 } 8755 8756 /** 8757 * <p>Case insensitive check if a CharSequence ends with a specified suffix.</p> 8758 * 8759 * <p>{@code null}s are handled without exceptions. Two {@code null} 8760 * references are considered to be equal. The comparison is case insensitive.</p> 8761 * 8762 * <pre> 8763 * StringUtils.endsWithIgnoreCase(null, null) = true 8764 * StringUtils.endsWithIgnoreCase(null, "def") = false 8765 * StringUtils.endsWithIgnoreCase("abcdef", null) = false 8766 * StringUtils.endsWithIgnoreCase("abcdef", "def") = true 8767 * StringUtils.endsWithIgnoreCase("ABCDEF", "def") = true 8768 * StringUtils.endsWithIgnoreCase("ABCDEF", "cde") = false 8769 * </pre> 8770 * 8771 * @see java.lang.String#endsWith(String) 8772 * @param str the CharSequence to check, may be null 8773 * @param suffix the suffix to find, may be null 8774 * @return {@code true} if the CharSequence ends with the suffix, case insensitive, or 8775 * both {@code null} 8776 * @since 2.4 8777 * @since 3.0 Changed signature from endsWithIgnoreCase(String, String) to endsWithIgnoreCase(CharSequence, CharSequence) 8778 */ 8779 public static boolean endsWithIgnoreCase(final CharSequence str, final CharSequence suffix) { 8780 return endsWith(str, suffix, true); 8781 } 8782 8783 /** 8784 * <p>Check if a CharSequence ends with a specified suffix (optionally case insensitive).</p> 8785 * 8786 * @see java.lang.String#endsWith(String) 8787 * @param str the CharSequence to check, may be null 8788 * @param suffix the suffix to find, may be null 8789 * @param ignoreCase indicates whether the compare should ignore case 8790 * (case insensitive) or not. 8791 * @return {@code true} if the CharSequence starts with the prefix or 8792 * both {@code null} 8793 */ 8794 private static boolean endsWith(final CharSequence str, final CharSequence suffix, final boolean ignoreCase) { 8795 if (str == null || suffix == null) { 8796 return str == suffix; 8797 } 8798 if (suffix.length() > str.length()) { 8799 return false; 8800 } 8801 final int strOffset = str.length() - suffix.length(); 8802 return CharSequenceUtils.regionMatches(str, ignoreCase, strOffset, suffix, 0, suffix.length()); 8803 } 8804 8805 /** 8806 * <p> 8807 * Similar to <a 8808 * href="http://www.w3.org/TR/xpath/#function-normalize-space">http://www.w3.org/TR/xpath/#function-normalize 8809 * -space</a> 8810 * </p> 8811 * <p> 8812 * The function returns the argument string with whitespace normalized by using 8813 * <code>{@link #trim(String)}</code> to remove leading and trailing whitespace 8814 * and then replacing sequences of whitespace characters by a single space. 8815 * </p> 8816 * In XML Whitespace characters are the same as those allowed by the <a 8817 * href="http://www.w3.org/TR/REC-xml/#NT-S">S</a> production, which is S ::= (#x20 | #x9 | #xD | #xA)+ 8818 * <p> 8819 * Java's regexp pattern \s defines whitespace as [ \t\n\x0B\f\r] 8820 * 8821 * <p>For reference:</p> 8822 * <ul> 8823 * <li>\x0B = vertical tab</li> 8824 * <li>\f = #xC = form feed</li> 8825 * <li>#x20 = space</li> 8826 * <li>#x9 = \t</li> 8827 * <li>#xA = \n</li> 8828 * <li>#xD = \r</li> 8829 * </ul> 8830 * 8831 * <p> 8832 * The difference is that Java's whitespace includes vertical tab and form feed, which this functional will also 8833 * normalize. Additionally <code>{@link #trim(String)}</code> removes control characters (char <= 32) from both 8834 * ends of this String. 8835 * </p> 8836 * 8837 * @see Pattern 8838 * @see #trim(String) 8839 * @see <a 8840 * href="http://www.w3.org/TR/xpath/#function-normalize-space">http://www.w3.org/TR/xpath/#function-normalize-space</a> 8841 * @param str the source String to normalize whitespaces from, may be null 8842 * @return the modified string with whitespace normalized, {@code null} if null String input 8843 * 8844 * @since 3.0 8845 */ 8846 public static String normalizeSpace(final String str) { 8847 // LANG-1020: Improved performance significantly by normalizing manually instead of using regex 8848 // See https://github.com/librucha/commons-lang-normalizespaces-benchmark for performance test 8849 if (isEmpty(str)) { 8850 return str; 8851 } 8852 final int size = str.length(); 8853 final char[] newChars = new char[size]; 8854 int count = 0; 8855 int whitespacesCount = 0; 8856 boolean startWhitespaces = true; 8857 for (int i = 0; i < size; i++) { 8858 final char actualChar = str.charAt(i); 8859 final boolean isWhitespace = Character.isWhitespace(actualChar); 8860 if (isWhitespace) { 8861 if (whitespacesCount == 0 && !startWhitespaces) { 8862 newChars[count++] = SPACE.charAt(0); 8863 } 8864 whitespacesCount++; 8865 } else { 8866 startWhitespaces = false; 8867 newChars[count++] = (actualChar == 160 ? 32 : actualChar); 8868 whitespacesCount = 0; 8869 } 8870 } 8871 if (startWhitespaces) { 8872 return EMPTY; 8873 } 8874 return new String(newChars, 0, count - (whitespacesCount > 0 ? 1 : 0)).trim(); 8875 } 8876 8877 /** 8878 * <p>Check if a CharSequence ends with any of the provided case-sensitive suffixes.</p> 8879 * 8880 * <pre> 8881 * StringUtils.endsWithAny(null, null) = false 8882 * StringUtils.endsWithAny(null, new String[] {"abc"}) = false 8883 * StringUtils.endsWithAny("abcxyz", null) = false 8884 * StringUtils.endsWithAny("abcxyz", new String[] {""}) = true 8885 * StringUtils.endsWithAny("abcxyz", new String[] {"xyz"}) = true 8886 * StringUtils.endsWithAny("abcxyz", new String[] {null, "xyz", "abc"}) = true 8887 * StringUtils.endsWithAny("abcXYZ", "def", "XYZ") = true 8888 * StringUtils.endsWithAny("abcXYZ", "def", "xyz") = false 8889 * </pre> 8890 * 8891 * @param sequence the CharSequence to check, may be null 8892 * @param searchStrings the case-sensitive CharSequences to find, may be empty or contain {@code null} 8893 * @see StringUtils#endsWith(CharSequence, CharSequence) 8894 * @return {@code true} if the input {@code sequence} is {@code null} AND no {@code searchStrings} are provided, or 8895 * the input {@code sequence} ends in any of the provided case-sensitive {@code searchStrings}. 8896 * @since 3.0 8897 */ 8898 public static boolean endsWithAny(final CharSequence sequence, final CharSequence... searchStrings) { 8899 if (isEmpty(sequence) || ArrayUtils.isEmpty(searchStrings)) { 8900 return false; 8901 } 8902 for (final CharSequence searchString : searchStrings) { 8903 if (endsWith(sequence, searchString)) { 8904 return true; 8905 } 8906 } 8907 return false; 8908 } 8909 8910 /** 8911 * Appends the suffix to the end of the string if the string does not 8912 * already end with the suffix. 8913 * 8914 * @param str The string. 8915 * @param suffix The suffix to append to the end of the string. 8916 * @param ignoreCase Indicates whether the compare should ignore case. 8917 * @param suffixes Additional suffixes that are valid terminators (optional). 8918 * 8919 * @return A new String if suffix was appended, the same string otherwise. 8920 */ 8921 private static String appendIfMissing(final String str, final CharSequence suffix, final boolean ignoreCase, final CharSequence... suffixes) { 8922 if (str == null || isEmpty(suffix) || endsWith(str, suffix, ignoreCase)) { 8923 return str; 8924 } 8925 if (suffixes != null && suffixes.length > 0) { 8926 for (final CharSequence s : suffixes) { 8927 if (endsWith(str, s, ignoreCase)) { 8928 return str; 8929 } 8930 } 8931 } 8932 return str + suffix.toString(); 8933 } 8934 8935 /** 8936 * Appends the suffix to the end of the string if the string does not 8937 * already end with any of the suffixes. 8938 * 8939 * <pre> 8940 * StringUtils.appendIfMissing(null, null) = null 8941 * StringUtils.appendIfMissing("abc", null) = "abc" 8942 * StringUtils.appendIfMissing("", "xyz") = "xyz" 8943 * StringUtils.appendIfMissing("abc", "xyz") = "abcxyz" 8944 * StringUtils.appendIfMissing("abcxyz", "xyz") = "abcxyz" 8945 * StringUtils.appendIfMissing("abcXYZ", "xyz") = "abcXYZxyz" 8946 * </pre> 8947 * <p>With additional suffixes,</p> 8948 * <pre> 8949 * StringUtils.appendIfMissing(null, null, null) = null 8950 * StringUtils.appendIfMissing("abc", null, null) = "abc" 8951 * StringUtils.appendIfMissing("", "xyz", null) = "xyz" 8952 * StringUtils.appendIfMissing("abc", "xyz", new CharSequence[]{null}) = "abcxyz" 8953 * StringUtils.appendIfMissing("abc", "xyz", "") = "abc" 8954 * StringUtils.appendIfMissing("abc", "xyz", "mno") = "abcxyz" 8955 * StringUtils.appendIfMissing("abcxyz", "xyz", "mno") = "abcxyz" 8956 * StringUtils.appendIfMissing("abcmno", "xyz", "mno") = "abcmno" 8957 * StringUtils.appendIfMissing("abcXYZ", "xyz", "mno") = "abcXYZxyz" 8958 * StringUtils.appendIfMissing("abcMNO", "xyz", "mno") = "abcMNOxyz" 8959 * </pre> 8960 * 8961 * @param str The string. 8962 * @param suffix The suffix to append to the end of the string. 8963 * @param suffixes Additional suffixes that are valid terminators. 8964 * 8965 * @return A new String if suffix was appended, the same string otherwise. 8966 * 8967 * @since 3.2 8968 */ 8969 public static String appendIfMissing(final String str, final CharSequence suffix, final CharSequence... suffixes) { 8970 return appendIfMissing(str, suffix, false, suffixes); 8971 } 8972 8973 /** 8974 * Appends the suffix to the end of the string if the string does not 8975 * already end, case insensitive, with any of the suffixes. 8976 * 8977 * <pre> 8978 * StringUtils.appendIfMissingIgnoreCase(null, null) = null 8979 * StringUtils.appendIfMissingIgnoreCase("abc", null) = "abc" 8980 * StringUtils.appendIfMissingIgnoreCase("", "xyz") = "xyz" 8981 * StringUtils.appendIfMissingIgnoreCase("abc", "xyz") = "abcxyz" 8982 * StringUtils.appendIfMissingIgnoreCase("abcxyz", "xyz") = "abcxyz" 8983 * StringUtils.appendIfMissingIgnoreCase("abcXYZ", "xyz") = "abcXYZ" 8984 * </pre> 8985 * <p>With additional suffixes,</p> 8986 * <pre> 8987 * StringUtils.appendIfMissingIgnoreCase(null, null, null) = null 8988 * StringUtils.appendIfMissingIgnoreCase("abc", null, null) = "abc" 8989 * StringUtils.appendIfMissingIgnoreCase("", "xyz", null) = "xyz" 8990 * StringUtils.appendIfMissingIgnoreCase("abc", "xyz", new CharSequence[]{null}) = "abcxyz" 8991 * StringUtils.appendIfMissingIgnoreCase("abc", "xyz", "") = "abc" 8992 * StringUtils.appendIfMissingIgnoreCase("abc", "xyz", "mno") = "axyz" 8993 * StringUtils.appendIfMissingIgnoreCase("abcxyz", "xyz", "mno") = "abcxyz" 8994 * StringUtils.appendIfMissingIgnoreCase("abcmno", "xyz", "mno") = "abcmno" 8995 * StringUtils.appendIfMissingIgnoreCase("abcXYZ", "xyz", "mno") = "abcXYZ" 8996 * StringUtils.appendIfMissingIgnoreCase("abcMNO", "xyz", "mno") = "abcMNO" 8997 * </pre> 8998 * 8999 * @param str The string. 9000 * @param suffix The suffix to append to the end of the string. 9001 * @param suffixes Additional suffixes that are valid terminators. 9002 * 9003 * @return A new String if suffix was appended, the same string otherwise. 9004 * 9005 * @since 3.2 9006 */ 9007 public static String appendIfMissingIgnoreCase(final String str, final CharSequence suffix, final CharSequence... suffixes) { 9008 return appendIfMissing(str, suffix, true, suffixes); 9009 } 9010 9011 /** 9012 * Prepends the prefix to the start of the string if the string does not 9013 * already start with any of the prefixes. 9014 * 9015 * @param str The string. 9016 * @param prefix The prefix to prepend to the start of the string. 9017 * @param ignoreCase Indicates whether the compare should ignore case. 9018 * @param prefixes Additional prefixes that are valid (optional). 9019 * 9020 * @return A new String if prefix was prepended, the same string otherwise. 9021 */ 9022 private static String prependIfMissing(final String str, final CharSequence prefix, final boolean ignoreCase, final CharSequence... prefixes) { 9023 if (str == null || isEmpty(prefix) || startsWith(str, prefix, ignoreCase)) { 9024 return str; 9025 } 9026 if (prefixes != null && prefixes.length > 0) { 9027 for (final CharSequence p : prefixes) { 9028 if (startsWith(str, p, ignoreCase)) { 9029 return str; 9030 } 9031 } 9032 } 9033 return prefix.toString() + str; 9034 } 9035 9036 /** 9037 * Prepends the prefix to the start of the string if the string does not 9038 * already start with any of the prefixes. 9039 * 9040 * <pre> 9041 * StringUtils.prependIfMissing(null, null) = null 9042 * StringUtils.prependIfMissing("abc", null) = "abc" 9043 * StringUtils.prependIfMissing("", "xyz") = "xyz" 9044 * StringUtils.prependIfMissing("abc", "xyz") = "xyzabc" 9045 * StringUtils.prependIfMissing("xyzabc", "xyz") = "xyzabc" 9046 * StringUtils.prependIfMissing("XYZabc", "xyz") = "xyzXYZabc" 9047 * </pre> 9048 * <p>With additional prefixes,</p> 9049 * <pre> 9050 * StringUtils.prependIfMissing(null, null, null) = null 9051 * StringUtils.prependIfMissing("abc", null, null) = "abc" 9052 * StringUtils.prependIfMissing("", "xyz", null) = "xyz" 9053 * StringUtils.prependIfMissing("abc", "xyz", new CharSequence[]{null}) = "xyzabc" 9054 * StringUtils.prependIfMissing("abc", "xyz", "") = "abc" 9055 * StringUtils.prependIfMissing("abc", "xyz", "mno") = "xyzabc" 9056 * StringUtils.prependIfMissing("xyzabc", "xyz", "mno") = "xyzabc" 9057 * StringUtils.prependIfMissing("mnoabc", "xyz", "mno") = "mnoabc" 9058 * StringUtils.prependIfMissing("XYZabc", "xyz", "mno") = "xyzXYZabc" 9059 * StringUtils.prependIfMissing("MNOabc", "xyz", "mno") = "xyzMNOabc" 9060 * </pre> 9061 * 9062 * @param str The string. 9063 * @param prefix The prefix to prepend to the start of the string. 9064 * @param prefixes Additional prefixes that are valid. 9065 * 9066 * @return A new String if prefix was prepended, the same string otherwise. 9067 * 9068 * @since 3.2 9069 */ 9070 public static String prependIfMissing(final String str, final CharSequence prefix, final CharSequence... prefixes) { 9071 return prependIfMissing(str, prefix, false, prefixes); 9072 } 9073 9074 /** 9075 * Prepends the prefix to the start of the string if the string does not 9076 * already start, case insensitive, with any of the prefixes. 9077 * 9078 * <pre> 9079 * StringUtils.prependIfMissingIgnoreCase(null, null) = null 9080 * StringUtils.prependIfMissingIgnoreCase("abc", null) = "abc" 9081 * StringUtils.prependIfMissingIgnoreCase("", "xyz") = "xyz" 9082 * StringUtils.prependIfMissingIgnoreCase("abc", "xyz") = "xyzabc" 9083 * StringUtils.prependIfMissingIgnoreCase("xyzabc", "xyz") = "xyzabc" 9084 * StringUtils.prependIfMissingIgnoreCase("XYZabc", "xyz") = "XYZabc" 9085 * </pre> 9086 * <p>With additional prefixes,</p> 9087 * <pre> 9088 * StringUtils.prependIfMissingIgnoreCase(null, null, null) = null 9089 * StringUtils.prependIfMissingIgnoreCase("abc", null, null) = "abc" 9090 * StringUtils.prependIfMissingIgnoreCase("", "xyz", null) = "xyz" 9091 * StringUtils.prependIfMissingIgnoreCase("abc", "xyz", new CharSequence[]{null}) = "xyzabc" 9092 * StringUtils.prependIfMissingIgnoreCase("abc", "xyz", "") = "abc" 9093 * StringUtils.prependIfMissingIgnoreCase("abc", "xyz", "mno") = "xyzabc" 9094 * StringUtils.prependIfMissingIgnoreCase("xyzabc", "xyz", "mno") = "xyzabc" 9095 * StringUtils.prependIfMissingIgnoreCase("mnoabc", "xyz", "mno") = "mnoabc" 9096 * StringUtils.prependIfMissingIgnoreCase("XYZabc", "xyz", "mno") = "XYZabc" 9097 * StringUtils.prependIfMissingIgnoreCase("MNOabc", "xyz", "mno") = "MNOabc" 9098 * </pre> 9099 * 9100 * @param str The string. 9101 * @param prefix The prefix to prepend to the start of the string. 9102 * @param prefixes Additional prefixes that are valid (optional). 9103 * 9104 * @return A new String if prefix was prepended, the same string otherwise. 9105 * 9106 * @since 3.2 9107 */ 9108 public static String prependIfMissingIgnoreCase(final String str, final CharSequence prefix, final CharSequence... prefixes) { 9109 return prependIfMissing(str, prefix, true, prefixes); 9110 } 9111 9112 /** 9113 * Converts a <code>byte[]</code> to a String using the specified character encoding. 9114 * 9115 * @param bytes 9116 * the byte array to read from 9117 * @param charsetName 9118 * the encoding to use, if null then use the platform default 9119 * @return a new String 9120 * @throws UnsupportedEncodingException 9121 * If the named charset is not supported 9122 * @throws NullPointerException 9123 * if the input is null 9124 * @deprecated use {@link StringUtils#toEncodedString(byte[], Charset)} instead of String constants in your code 9125 * @since 3.1 9126 */ 9127 @Deprecated 9128 public static String toString(final byte[] bytes, final String charsetName) throws UnsupportedEncodingException { 9129 return charsetName != null ? new String(bytes, charsetName) : new String(bytes, Charset.defaultCharset()); 9130 } 9131 9132 /** 9133 * Converts a <code>byte[]</code> to a String using the specified character encoding. 9134 * 9135 * @param bytes 9136 * the byte array to read from 9137 * @param charset 9138 * the encoding to use, if null then use the platform default 9139 * @return a new String 9140 * @throws NullPointerException 9141 * if {@code bytes} is null 9142 * @since 3.2 9143 * @since 3.3 No longer throws {@link UnsupportedEncodingException}. 9144 */ 9145 public static String toEncodedString(final byte[] bytes, final Charset charset) { 9146 return new String(bytes, charset != null ? charset : Charset.defaultCharset()); 9147 } 9148 9149 /** 9150 * <p> 9151 * Wraps a string with a char. 9152 * </p> 9153 * 9154 * <pre> 9155 * StringUtils.wrap(null, *) = null 9156 * StringUtils.wrap("", *) = "" 9157 * StringUtils.wrap("ab", '\0') = "ab" 9158 * StringUtils.wrap("ab", 'x') = "xabx" 9159 * StringUtils.wrap("ab", '\'') = "'ab'" 9160 * StringUtils.wrap("\"ab\"", '\"') = "\"\"ab\"\"" 9161 * </pre> 9162 * 9163 * @param str 9164 * the string to be wrapped, may be {@code null} 9165 * @param wrapWith 9166 * the char that will wrap {@code str} 9167 * @return the wrapped string, or {@code null} if {@code str==null} 9168 * @since 3.4 9169 */ 9170 public static String wrap(final String str, final char wrapWith) { 9171 9172 if (isEmpty(str) || wrapWith == CharUtils.NUL) { 9173 return str; 9174 } 9175 9176 return wrapWith + str + wrapWith; 9177 } 9178 9179 /** 9180 * <p> 9181 * Wraps a String with another String. 9182 * </p> 9183 * 9184 * <p> 9185 * A {@code null} input String returns {@code null}. 9186 * </p> 9187 * 9188 * <pre> 9189 * StringUtils.wrap(null, *) = null 9190 * StringUtils.wrap("", *) = "" 9191 * StringUtils.wrap("ab", null) = "ab" 9192 * StringUtils.wrap("ab", "x") = "xabx" 9193 * StringUtils.wrap("ab", "\"") = "\"ab\"" 9194 * StringUtils.wrap("\"ab\"", "\"") = "\"\"ab\"\"" 9195 * StringUtils.wrap("ab", "'") = "'ab'" 9196 * StringUtils.wrap("'abcd'", "'") = "''abcd''" 9197 * StringUtils.wrap("\"abcd\"", "'") = "'\"abcd\"'" 9198 * StringUtils.wrap("'abcd'", "\"") = "\"'abcd'\"" 9199 * </pre> 9200 * 9201 * @param str 9202 * the String to be wrapper, may be null 9203 * @param wrapWith 9204 * the String that will wrap str 9205 * @return wrapped String, {@code null} if null String input 9206 * @since 3.4 9207 */ 9208 public static String wrap(final String str, final String wrapWith) { 9209 9210 if (isEmpty(str) || isEmpty(wrapWith)) { 9211 return str; 9212 } 9213 9214 return wrapWith.concat(str).concat(wrapWith); 9215 } 9216 9217 /** 9218 * <p> 9219 * Wraps a string with a char if that char is missing from the start or end of the given string. 9220 * </p> 9221 * 9222 * <pre> 9223 * StringUtils.wrap(null, *) = null 9224 * StringUtils.wrap("", *) = "" 9225 * StringUtils.wrap("ab", '\0') = "ab" 9226 * StringUtils.wrap("ab", 'x') = "xabx" 9227 * StringUtils.wrap("ab", '\'') = "'ab'" 9228 * StringUtils.wrap("\"ab\"", '\"') = "\"ab\"" 9229 * StringUtils.wrap("/", '/') = "/" 9230 * StringUtils.wrap("a/b/c", '/') = "/a/b/c/" 9231 * StringUtils.wrap("/a/b/c", '/') = "/a/b/c/" 9232 * StringUtils.wrap("a/b/c/", '/') = "/a/b/c/" 9233 * </pre> 9234 * 9235 * @param str 9236 * the string to be wrapped, may be {@code null} 9237 * @param wrapWith 9238 * the char that will wrap {@code str} 9239 * @return the wrapped string, or {@code null} if {@code str==null} 9240 * @since 3.5 9241 */ 9242 public static String wrapIfMissing(final String str, final char wrapWith) { 9243 if (isEmpty(str) || wrapWith == CharUtils.NUL) { 9244 return str; 9245 } 9246 final StringBuilder builder = new StringBuilder(str.length() + 2); 9247 if (str.charAt(0) != wrapWith) { 9248 builder.append(wrapWith); 9249 } 9250 builder.append(str); 9251 if (str.charAt(str.length() - 1) != wrapWith) { 9252 builder.append(wrapWith); 9253 } 9254 return builder.toString(); 9255 } 9256 9257 /** 9258 * <p> 9259 * Wraps a string with a string if that string is missing from the start or end of the given string. 9260 * </p> 9261 * 9262 * <pre> 9263 * StringUtils.wrap(null, *) = null 9264 * StringUtils.wrap("", *) = "" 9265 * StringUtils.wrap("ab", null) = "ab" 9266 * StringUtils.wrap("ab", "x") = "xabx" 9267 * StringUtils.wrap("ab", "\"") = "\"ab\"" 9268 * StringUtils.wrap("\"ab\"", "\"") = "\"ab\"" 9269 * StringUtils.wrap("ab", "'") = "'ab'" 9270 * StringUtils.wrap("'abcd'", "'") = "'abcd'" 9271 * StringUtils.wrap("\"abcd\"", "'") = "'\"abcd\"'" 9272 * StringUtils.wrap("'abcd'", "\"") = "\"'abcd'\"" 9273 * StringUtils.wrap("/", "/") = "/" 9274 * StringUtils.wrap("a/b/c", "/") = "/a/b/c/" 9275 * StringUtils.wrap("/a/b/c", "/") = "/a/b/c/" 9276 * StringUtils.wrap("a/b/c/", "/") = "/a/b/c/" 9277 * </pre> 9278 * 9279 * @param str 9280 * the string to be wrapped, may be {@code null} 9281 * @param wrapWith 9282 * the char that will wrap {@code str} 9283 * @return the wrapped string, or {@code null} if {@code str==null} 9284 * @since 3.5 9285 */ 9286 public static String wrapIfMissing(final String str, final String wrapWith) { 9287 if (isEmpty(str) || isEmpty(wrapWith)) { 9288 return str; 9289 } 9290 final StringBuilder builder = new StringBuilder(str.length() + wrapWith.length() + wrapWith.length()); 9291 if (!str.startsWith(wrapWith)) { 9292 builder.append(wrapWith); 9293 } 9294 builder.append(str); 9295 if (!str.endsWith(wrapWith)) { 9296 builder.append(wrapWith); 9297 } 9298 return builder.toString(); 9299 } 9300 9301 /** 9302 * <p> 9303 * Unwraps a given string from anther string. 9304 * </p> 9305 * 9306 * <pre> 9307 * StringUtils.unwrap(null, null) = null 9308 * StringUtils.unwrap(null, "") = null 9309 * StringUtils.unwrap(null, "1") = null 9310 * StringUtils.unwrap("\'abc\'", "\'") = "abc" 9311 * StringUtils.unwrap("\"abc\"", "\"") = "abc" 9312 * StringUtils.unwrap("AABabcBAA", "AA") = "BabcB" 9313 * StringUtils.unwrap("A", "#") = "A" 9314 * StringUtils.unwrap("#A", "#") = "#A" 9315 * StringUtils.unwrap("A#", "#") = "A#" 9316 * </pre> 9317 * 9318 * @param str 9319 * the String to be unwrapped, can be null 9320 * @param wrapToken 9321 * the String used to unwrap 9322 * @return unwrapped String or the original string 9323 * if it is not quoted properly with the wrapToken 9324 * @since 3.6 9325 */ 9326 public static String unwrap(final String str, final String wrapToken) { 9327 if (isEmpty(str) || isEmpty(wrapToken)) { 9328 return str; 9329 } 9330 9331 if (startsWith(str, wrapToken) && endsWith(str, wrapToken)) { 9332 final int startIndex = str.indexOf(wrapToken); 9333 final int endIndex = str.lastIndexOf(wrapToken); 9334 final int wrapLength = wrapToken.length(); 9335 if (startIndex != -1 && endIndex != -1) { 9336 return str.substring(startIndex + wrapLength, endIndex); 9337 } 9338 } 9339 9340 return str; 9341 } 9342 9343 /** 9344 * <p> 9345 * Unwraps a given string from a character. 9346 * </p> 9347 * 9348 * <pre> 9349 * StringUtils.unwrap(null, null) = null 9350 * StringUtils.unwrap(null, '\0') = null 9351 * StringUtils.unwrap(null, '1') = null 9352 * StringUtils.unwrap("\'abc\'", '\'') = "abc" 9353 * StringUtils.unwrap("AABabcBAA", 'A') = "ABabcBA" 9354 * StringUtils.unwrap("A", '#') = "A" 9355 * StringUtils.unwrap("#A", '#') = "#A" 9356 * StringUtils.unwrap("A#", '#') = "A#" 9357 * </pre> 9358 * 9359 * @param str 9360 * the String to be unwrapped, can be null 9361 * @param wrapChar 9362 * the character used to unwrap 9363 * @return unwrapped String or the original string 9364 * if it is not quoted properly with the wrapChar 9365 * @since 3.6 9366 */ 9367 public static String unwrap(final String str, final char wrapChar) { 9368 if (isEmpty(str) || wrapChar == CharUtils.NUL) { 9369 return str; 9370 } 9371 9372 if (str.charAt(0) == wrapChar && str.charAt(str.length() - 1) == wrapChar) { 9373 final int startIndex = 0; 9374 final int endIndex = str.length() - 1; 9375 if (endIndex != -1) { 9376 return str.substring(startIndex + 1, endIndex); 9377 } 9378 } 9379 9380 return str; 9381 } 9382 9383 /** 9384 * <p>Converts a {@code CharSequence} into an array of code points.</p> 9385 * 9386 * <p>Valid pairs of surrogate code units will be converted into a single supplementary 9387 * code point. Isolated surrogate code units (i.e. a high surrogate not followed by a low surrogate or 9388 * a low surrogate not preceded by a high surrogate) will be returned as-is.</p> 9389 * 9390 * <pre> 9391 * StringUtils.toCodePoints(null) = null 9392 * StringUtils.toCodePoints("") = [] // empty array 9393 * </pre> 9394 * 9395 * @param str the character sequence to convert 9396 * @return an array of code points 9397 * @since 3.6 9398 */ 9399 public static int[] toCodePoints(final CharSequence str) { 9400 if (str == null) { 9401 return null; 9402 } 9403 if (str.length() == 0) { 9404 return ArrayUtils.EMPTY_INT_ARRAY; 9405 } 9406 9407 final String s = str.toString(); 9408 final int[] result = new int[s.codePointCount(0, s.length())]; 9409 int index = 0; 9410 for (int i = 0; i < result.length; i++) { 9411 result[i] = s.codePointAt(index); 9412 index += Character.charCount(result[i]); 9413 } 9414 return result; 9415 } 9416}