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 // Performance testing notes (JDK 1.4, Jul03, scolebourne) 119 // Whitespace: 120 // Character.isWhitespace() is faster than WHITESPACE.indexOf() 121 // where WHITESPACE is a string of all whitespace characters 122 // 123 // Character access: 124 // String.charAt(n) versus toCharArray(), then array[n] 125 // String.charAt(n) is about 15% worse for a 10K string 126 // They are about equal for a length 50 string 127 // String.charAt(n) is about 4 times better for a length 3 string 128 // String.charAt(n) is best bet overall 129 // 130 // Append: 131 // String.concat about twice as fast as StringBuffer.append 132 // (not sure who tested this) 133 134 /** 135 * A String for a space character. 136 * 137 * @since 3.2 138 */ 139 public static final String SPACE = " "; 140 141 /** 142 * The empty String {@code ""}. 143 * @since 2.0 144 */ 145 public static final String EMPTY = ""; 146 147 /** 148 * A String for linefeed LF ("\n"). 149 * 150 * @see <a href="http://docs.oracle.com/javase/specs/jls/se7/html/jls-3.html#jls-3.10.6">JLF: Escape Sequences 151 * for Character and String Literals</a> 152 * @since 3.2 153 */ 154 public static final String LF = "\n"; 155 156 /** 157 * A String for carriage return CR ("\r"). 158 * 159 * @see <a href="http://docs.oracle.com/javase/specs/jls/se7/html/jls-3.html#jls-3.10.6">JLF: Escape Sequences 160 * for Character and String Literals</a> 161 * @since 3.2 162 */ 163 public static final String CR = "\r"; 164 165 /** 166 * Represents a failed index search. 167 * @since 2.1 168 */ 169 public static final int INDEX_NOT_FOUND = -1; 170 171 /** 172 * <p>The maximum size to which the padding constant(s) can expand.</p> 173 */ 174 private static final int PAD_LIMIT = 8192; 175 176 /** 177 * <p>{@code StringUtils} instances should NOT be constructed in 178 * standard programming. Instead, the class should be used as 179 * {@code StringUtils.trim(" foo ");}.</p> 180 * 181 * <p>This constructor is public to permit tools that require a JavaBean 182 * instance to operate.</p> 183 */ 184 public StringUtils() { 185 super(); 186 } 187 188 // Empty checks 189 //----------------------------------------------------------------------- 190 /** 191 * <p>Checks if a CharSequence is empty ("") or null.</p> 192 * 193 * <pre> 194 * StringUtils.isEmpty(null) = true 195 * StringUtils.isEmpty("") = true 196 * StringUtils.isEmpty(" ") = false 197 * StringUtils.isEmpty("bob") = false 198 * StringUtils.isEmpty(" bob ") = false 199 * </pre> 200 * 201 * <p>NOTE: This method changed in Lang version 2.0. 202 * It no longer trims the CharSequence. 203 * That functionality is available in isBlank().</p> 204 * 205 * @param cs the CharSequence to check, may be null 206 * @return {@code true} if the CharSequence is empty or null 207 * @since 3.0 Changed signature from isEmpty(String) to isEmpty(CharSequence) 208 */ 209 public static boolean isEmpty(final CharSequence cs) { 210 return cs == null || cs.length() == 0; 211 } 212 213 /** 214 * <p>Checks if a CharSequence is not empty ("") and not null.</p> 215 * 216 * <pre> 217 * StringUtils.isNotEmpty(null) = false 218 * StringUtils.isNotEmpty("") = false 219 * StringUtils.isNotEmpty(" ") = true 220 * StringUtils.isNotEmpty("bob") = true 221 * StringUtils.isNotEmpty(" bob ") = true 222 * </pre> 223 * 224 * @param cs the CharSequence to check, may be null 225 * @return {@code true} if the CharSequence is not empty and not null 226 * @since 3.0 Changed signature from isNotEmpty(String) to isNotEmpty(CharSequence) 227 */ 228 public static boolean isNotEmpty(final CharSequence cs) { 229 return !isEmpty(cs); 230 } 231 232 /** 233 * <p>Checks if any of the CharSequences are empty ("") or null.</p> 234 * 235 * <pre> 236 * StringUtils.isAnyEmpty(null) = true 237 * StringUtils.isAnyEmpty(null, "foo") = true 238 * StringUtils.isAnyEmpty("", "bar") = true 239 * StringUtils.isAnyEmpty("bob", "") = true 240 * StringUtils.isAnyEmpty(" bob ", null) = true 241 * StringUtils.isAnyEmpty(" ", "bar") = false 242 * StringUtils.isAnyEmpty("foo", "bar") = false 243 * StringUtils.isAnyEmpty(new String[]{}) = false 244 * StringUtils.isAnyEmpty(new String[]{""}) = true 245 * </pre> 246 * 247 * @param css the CharSequences to check, may be null or empty 248 * @return {@code true} if any of the CharSequences are empty or null 249 * @since 3.2 250 */ 251 public static boolean isAnyEmpty(final CharSequence... css) { 252 if (ArrayUtils.isEmpty(css)) { 253 return false; 254 } 255 for (final CharSequence cs : css){ 256 if (isEmpty(cs)) { 257 return true; 258 } 259 } 260 return false; 261 } 262 263 /** 264 * <p>Checks if none of the CharSequences are empty ("") or null.</p> 265 * 266 * <pre> 267 * StringUtils.isNoneEmpty(null) = false 268 * StringUtils.isNoneEmpty(null, "foo") = false 269 * StringUtils.isNoneEmpty("", "bar") = false 270 * StringUtils.isNoneEmpty("bob", "") = false 271 * StringUtils.isNoneEmpty(" bob ", null) = false 272 * StringUtils.isNoneEmpty(new String[] {}) = true 273 * StringUtils.isNoneEmpty(new String[]{""}) = false 274 * StringUtils.isNoneEmpty(" ", "bar") = true 275 * StringUtils.isNoneEmpty("foo", "bar") = true 276 * </pre> 277 * 278 * @param css the CharSequences to check, may be null or empty 279 * @return {@code true} if none of the CharSequences are empty or null 280 * @since 3.2 281 */ 282 public static boolean isNoneEmpty(final CharSequence... css) { 283 return !isAnyEmpty(css); 284 } 285 286 /** 287 * <p>Checks if all of the CharSequences are empty ("") or null.</p> 288 * 289 * <pre> 290 * StringUtils.isAllEmpty(null) = true 291 * StringUtils.isAllEmpty(null, "") = true 292 * StringUtils.isAllEmpty(new String[] {}) = true 293 * StringUtils.isAllEmpty(null, "foo") = false 294 * StringUtils.isAllEmpty("", "bar") = false 295 * StringUtils.isAllEmpty("bob", "") = false 296 * StringUtils.isAllEmpty(" bob ", null) = false 297 * StringUtils.isAllEmpty(" ", "bar") = false 298 * StringUtils.isAllEmpty("foo", "bar") = false 299 * </pre> 300 * 301 * @param css the CharSequences to check, may be null or empty 302 * @return {@code true} if all of the CharSequences are empty or null 303 * @since 3.6 304 */ 305 public static boolean isAllEmpty(final CharSequence... css) { 306 if (ArrayUtils.isEmpty(css)) { 307 return true; 308 } 309 for (final CharSequence cs : css) { 310 if (isNotEmpty(cs)) { 311 return false; 312 } 313 } 314 return true; 315 } 316 317 /** 318 * <p>Checks if a CharSequence is empty (""), null or whitespace only.</p> 319 * 320 * <p>Whitespace is defined by {@link Character#isWhitespace(char)}.</p> 321 * 322 * <pre> 323 * StringUtils.isBlank(null) = true 324 * StringUtils.isBlank("") = true 325 * StringUtils.isBlank(" ") = true 326 * StringUtils.isBlank("bob") = false 327 * StringUtils.isBlank(" bob ") = false 328 * </pre> 329 * 330 * @param cs the CharSequence to check, may be null 331 * @return {@code true} if the CharSequence is null, empty or whitespace only 332 * @since 2.0 333 * @since 3.0 Changed signature from isBlank(String) to isBlank(CharSequence) 334 */ 335 public static boolean isBlank(final CharSequence cs) { 336 int strLen; 337 if (cs == null || (strLen = cs.length()) == 0) { 338 return true; 339 } 340 for (int i = 0; i < strLen; i++) { 341 if (!Character.isWhitespace(cs.charAt(i))) { 342 return false; 343 } 344 } 345 return true; 346 } 347 348 /** 349 * <p>Checks if a CharSequence is not empty (""), not null and not whitespace only.</p> 350 * 351 * <p>Whitespace is defined by {@link Character#isWhitespace(char)}.</p> 352 * 353 * <pre> 354 * StringUtils.isNotBlank(null) = false 355 * StringUtils.isNotBlank("") = false 356 * StringUtils.isNotBlank(" ") = false 357 * StringUtils.isNotBlank("bob") = true 358 * StringUtils.isNotBlank(" bob ") = true 359 * </pre> 360 * 361 * @param cs the CharSequence to check, may be null 362 * @return {@code true} if the CharSequence is 363 * not empty and not null and not whitespace only 364 * @since 2.0 365 * @since 3.0 Changed signature from isNotBlank(String) to isNotBlank(CharSequence) 366 */ 367 public static boolean isNotBlank(final CharSequence cs) { 368 return !isBlank(cs); 369 } 370 371 /** 372 * <p>Checks if any of the CharSequences are empty ("") or null or whitespace only.</p> 373 * 374 * <p>Whitespace is defined by {@link Character#isWhitespace(char)}.</p> 375 * 376 * <pre> 377 * StringUtils.isAnyBlank(null) = true 378 * StringUtils.isAnyBlank(null, "foo") = true 379 * StringUtils.isAnyBlank(null, null) = true 380 * StringUtils.isAnyBlank("", "bar") = true 381 * StringUtils.isAnyBlank("bob", "") = true 382 * StringUtils.isAnyBlank(" bob ", null) = true 383 * StringUtils.isAnyBlank(" ", "bar") = true 384 * StringUtils.isAnyBlank(new String[] {}) = false 385 * StringUtils.isAnyBlank(new String[]{""}) = true 386 * StringUtils.isAnyBlank("foo", "bar") = false 387 * </pre> 388 * 389 * @param css the CharSequences to check, may be null or empty 390 * @return {@code true} if any of the CharSequences are empty or null or whitespace only 391 * @since 3.2 392 */ 393 public static boolean isAnyBlank(final CharSequence... css) { 394 if (ArrayUtils.isEmpty(css)) { 395 return false; 396 } 397 for (final CharSequence cs : css){ 398 if (isBlank(cs)) { 399 return true; 400 } 401 } 402 return false; 403 } 404 405 /** 406 * <p>Checks if none of the CharSequences are empty (""), null or whitespace only.</p> 407 * 408 * <p>Whitespace is defined by {@link Character#isWhitespace(char)}.</p> 409 * 410 * <pre> 411 * StringUtils.isNoneBlank(null) = false 412 * StringUtils.isNoneBlank(null, "foo") = false 413 * StringUtils.isNoneBlank(null, null) = false 414 * StringUtils.isNoneBlank("", "bar") = false 415 * StringUtils.isNoneBlank("bob", "") = false 416 * StringUtils.isNoneBlank(" bob ", null) = false 417 * StringUtils.isNoneBlank(" ", "bar") = false 418 * StringUtils.isNoneBlank(new String[] {}) = true 419 * StringUtils.isNoneBlank(new String[]{""}) = false 420 * StringUtils.isNoneBlank("foo", "bar") = true 421 * </pre> 422 * 423 * @param css the CharSequences to check, may be null or empty 424 * @return {@code true} if none of the CharSequences are empty or null or whitespace only 425 * @since 3.2 426 */ 427 public static boolean isNoneBlank(final CharSequence... css) { 428 return !isAnyBlank(css); 429 } 430 431 /** 432 * <p>Checks if all of the CharSequences are empty (""), null or whitespace only.</p> 433 * 434 * <p>Whitespace is defined by {@link Character#isWhitespace(char)}.</p> 435 * 436 * <pre> 437 * StringUtils.isAllBlank(null) = true 438 * StringUtils.isAllBlank(null, "foo") = false 439 * StringUtils.isAllBlank(null, null) = true 440 * StringUtils.isAllBlank("", "bar") = false 441 * StringUtils.isAllBlank("bob", "") = false 442 * StringUtils.isAllBlank(" bob ", null) = false 443 * StringUtils.isAllBlank(" ", "bar") = false 444 * StringUtils.isAllBlank("foo", "bar") = false 445 * StringUtils.isAllBlank(new String[] {}) = true 446 * </pre> 447 * 448 * @param css the CharSequences to check, may be null or empty 449 * @return {@code true} if all of the CharSequences are empty or null or whitespace only 450 * @since 3.6 451 */ 452 public static boolean isAllBlank(final CharSequence... css) { 453 if (ArrayUtils.isEmpty(css)) { 454 return true; 455 } 456 for (final CharSequence cs : css) { 457 if (isNotBlank(cs)) { 458 return false; 459 } 460 } 461 return true; 462 } 463 464 // Trim 465 //----------------------------------------------------------------------- 466 /** 467 * <p>Removes control characters (char <= 32) from both 468 * ends of this String, handling {@code null} by returning 469 * {@code null}.</p> 470 * 471 * <p>The String is trimmed using {@link String#trim()}. 472 * Trim removes start and end characters <= 32. 473 * To strip whitespace use {@link #strip(String)}.</p> 474 * 475 * <p>To trim your choice of characters, use the 476 * {@link #strip(String, String)} methods.</p> 477 * 478 * <pre> 479 * StringUtils.trim(null) = null 480 * StringUtils.trim("") = "" 481 * StringUtils.trim(" ") = "" 482 * StringUtils.trim("abc") = "abc" 483 * StringUtils.trim(" abc ") = "abc" 484 * </pre> 485 * 486 * @param str the String to be trimmed, may be null 487 * @return the trimmed string, {@code null} if null String input 488 */ 489 public static String trim(final String str) { 490 return str == null ? null : str.trim(); 491 } 492 493 /** 494 * <p>Removes control characters (char <= 32) from both 495 * ends of this String returning {@code null} if the String is 496 * empty ("") after the trim or if it is {@code null}. 497 * 498 * <p>The String is trimmed using {@link String#trim()}. 499 * Trim removes start and end characters <= 32. 500 * To strip whitespace use {@link #stripToNull(String)}.</p> 501 * 502 * <pre> 503 * StringUtils.trimToNull(null) = null 504 * StringUtils.trimToNull("") = null 505 * StringUtils.trimToNull(" ") = null 506 * StringUtils.trimToNull("abc") = "abc" 507 * StringUtils.trimToNull(" abc ") = "abc" 508 * </pre> 509 * 510 * @param str the String to be trimmed, may be null 511 * @return the trimmed String, 512 * {@code null} if only chars <= 32, empty or null String input 513 * @since 2.0 514 */ 515 public static String trimToNull(final String str) { 516 final String ts = trim(str); 517 return isEmpty(ts) ? null : ts; 518 } 519 520 /** 521 * <p>Removes control characters (char <= 32) from both 522 * ends of this String returning an empty String ("") if the String 523 * is empty ("") after the trim or if it is {@code null}. 524 * 525 * <p>The String is trimmed using {@link String#trim()}. 526 * Trim removes start and end characters <= 32. 527 * To strip whitespace use {@link #stripToEmpty(String)}.</p> 528 * 529 * <pre> 530 * StringUtils.trimToEmpty(null) = "" 531 * StringUtils.trimToEmpty("") = "" 532 * StringUtils.trimToEmpty(" ") = "" 533 * StringUtils.trimToEmpty("abc") = "abc" 534 * StringUtils.trimToEmpty(" abc ") = "abc" 535 * </pre> 536 * 537 * @param str the String to be trimmed, may be null 538 * @return the trimmed String, or an empty String if {@code null} input 539 * @since 2.0 540 */ 541 public static String trimToEmpty(final String str) { 542 return str == null ? EMPTY : str.trim(); 543 } 544 545 /** 546 * <p>Truncates a String. This will turn 547 * "Now is the time for all good men" into "Now is the time for".</p> 548 * 549 * <p>Specifically:</p> 550 * <ul> 551 * <li>If {@code str} is less than {@code maxWidth} characters 552 * long, return it.</li> 553 * <li>Else truncate it to {@code substring(str, 0, maxWidth)}.</li> 554 * <li>If {@code maxWidth} is less than {@code 0}, throw an 555 * {@code IllegalArgumentException}.</li> 556 * <li>In no case will it return a String of length greater than 557 * {@code maxWidth}.</li> 558 * </ul> 559 * 560 * <pre> 561 * StringUtils.truncate(null, 0) = null 562 * StringUtils.truncate(null, 2) = null 563 * StringUtils.truncate("", 4) = "" 564 * StringUtils.truncate("abcdefg", 4) = "abcd" 565 * StringUtils.truncate("abcdefg", 6) = "abcdef" 566 * StringUtils.truncate("abcdefg", 7) = "abcdefg" 567 * StringUtils.truncate("abcdefg", 8) = "abcdefg" 568 * StringUtils.truncate("abcdefg", -1) = throws an IllegalArgumentException 569 * </pre> 570 * 571 * @param str the String to truncate, may be null 572 * @param maxWidth maximum length of result String, must be positive 573 * @return truncated String, {@code null} if null String input 574 * @since 3.5 575 */ 576 public static String truncate(final String str, final int maxWidth) { 577 return truncate(str, 0, maxWidth); 578 } 579 580 /** 581 * <p>Truncates a String. This will turn 582 * "Now is the time for all good men" into "is the time for all".</p> 583 * 584 * <p>Works like {@code truncate(String, int)}, but allows you to specify 585 * a "left edge" offset. 586 * 587 * <p>Specifically:</p> 588 * <ul> 589 * <li>If {@code str} is less than {@code maxWidth} characters 590 * long, return it.</li> 591 * <li>Else truncate it to {@code substring(str, offset, maxWidth)}.</li> 592 * <li>If {@code maxWidth} is less than {@code 0}, throw an 593 * {@code IllegalArgumentException}.</li> 594 * <li>If {@code offset} is less than {@code 0}, throw an 595 * {@code IllegalArgumentException}.</li> 596 * <li>In no case will it return a String of length greater than 597 * {@code maxWidth}.</li> 598 * </ul> 599 * 600 * <pre> 601 * StringUtils.truncate(null, 0, 0) = null 602 * StringUtils.truncate(null, 2, 4) = null 603 * StringUtils.truncate("", 0, 10) = "" 604 * StringUtils.truncate("", 2, 10) = "" 605 * StringUtils.truncate("abcdefghij", 0, 3) = "abc" 606 * StringUtils.truncate("abcdefghij", 5, 6) = "fghij" 607 * StringUtils.truncate("raspberry peach", 10, 15) = "peach" 608 * StringUtils.truncate("abcdefghijklmno", 0, 10) = "abcdefghij" 609 * StringUtils.truncate("abcdefghijklmno", -1, 10) = throws an IllegalArgumentException 610 * StringUtils.truncate("abcdefghijklmno", Integer.MIN_VALUE, 10) = "abcdefghij" 611 * StringUtils.truncate("abcdefghijklmno", Integer.MIN_VALUE, Integer.MAX_VALUE) = "abcdefghijklmno" 612 * StringUtils.truncate("abcdefghijklmno", 0, Integer.MAX_VALUE) = "abcdefghijklmno" 613 * StringUtils.truncate("abcdefghijklmno", 1, 10) = "bcdefghijk" 614 * StringUtils.truncate("abcdefghijklmno", 2, 10) = "cdefghijkl" 615 * StringUtils.truncate("abcdefghijklmno", 3, 10) = "defghijklm" 616 * StringUtils.truncate("abcdefghijklmno", 4, 10) = "efghijklmn" 617 * StringUtils.truncate("abcdefghijklmno", 5, 10) = "fghijklmno" 618 * StringUtils.truncate("abcdefghijklmno", 5, 5) = "fghij" 619 * StringUtils.truncate("abcdefghijklmno", 5, 3) = "fgh" 620 * StringUtils.truncate("abcdefghijklmno", 10, 3) = "klm" 621 * StringUtils.truncate("abcdefghijklmno", 10, Integer.MAX_VALUE) = "klmno" 622 * StringUtils.truncate("abcdefghijklmno", 13, 1) = "n" 623 * StringUtils.truncate("abcdefghijklmno", 13, Integer.MAX_VALUE) = "no" 624 * StringUtils.truncate("abcdefghijklmno", 14, 1) = "o" 625 * StringUtils.truncate("abcdefghijklmno", 14, Integer.MAX_VALUE) = "o" 626 * StringUtils.truncate("abcdefghijklmno", 15, 1) = "" 627 * StringUtils.truncate("abcdefghijklmno", 15, Integer.MAX_VALUE) = "" 628 * StringUtils.truncate("abcdefghijklmno", Integer.MAX_VALUE, Integer.MAX_VALUE) = "" 629 * StringUtils.truncate("abcdefghij", 3, -1) = throws an IllegalArgumentException 630 * StringUtils.truncate("abcdefghij", -2, 4) = throws an IllegalArgumentException 631 * </pre> 632 * 633 * @param str the String to check, may be null 634 * @param offset left edge of source String 635 * @param maxWidth maximum length of result String, must be positive 636 * @return truncated String, {@code null} if null String input 637 * @since 3.5 638 */ 639 public static String truncate(final String str, final int offset, final int maxWidth) { 640 if (offset < 0) { 641 throw new IllegalArgumentException("offset cannot be negative"); 642 } 643 if (maxWidth < 0) { 644 throw new IllegalArgumentException("maxWith cannot be negative"); 645 } 646 if (str == null) { 647 return null; 648 } 649 if (offset > str.length()) { 650 return EMPTY; 651 } 652 if (str.length() > maxWidth) { 653 final int ix = offset + maxWidth > str.length() ? str.length() : offset + maxWidth; 654 return str.substring(offset, ix); 655 } 656 return str.substring(offset); 657 } 658 659 // Stripping 660 //----------------------------------------------------------------------- 661 /** 662 * <p>Strips whitespace from the start and end of a String.</p> 663 * 664 * <p>This is similar to {@link #trim(String)} but removes whitespace. 665 * Whitespace is defined by {@link Character#isWhitespace(char)}.</p> 666 * 667 * <p>A {@code null} input String returns {@code null}.</p> 668 * 669 * <pre> 670 * StringUtils.strip(null) = null 671 * StringUtils.strip("") = "" 672 * StringUtils.strip(" ") = "" 673 * StringUtils.strip("abc") = "abc" 674 * StringUtils.strip(" abc") = "abc" 675 * StringUtils.strip("abc ") = "abc" 676 * StringUtils.strip(" abc ") = "abc" 677 * StringUtils.strip(" ab c ") = "ab c" 678 * </pre> 679 * 680 * @param str the String to remove whitespace from, may be null 681 * @return the stripped String, {@code null} if null String input 682 */ 683 public static String strip(final String str) { 684 return strip(str, null); 685 } 686 687 /** 688 * <p>Strips whitespace from the start and end of a String returning 689 * {@code null} if the String is empty ("") after the strip.</p> 690 * 691 * <p>This is similar to {@link #trimToNull(String)} but removes whitespace. 692 * Whitespace is defined by {@link Character#isWhitespace(char)}.</p> 693 * 694 * <pre> 695 * StringUtils.stripToNull(null) = null 696 * StringUtils.stripToNull("") = null 697 * StringUtils.stripToNull(" ") = null 698 * StringUtils.stripToNull("abc") = "abc" 699 * StringUtils.stripToNull(" abc") = "abc" 700 * StringUtils.stripToNull("abc ") = "abc" 701 * StringUtils.stripToNull(" abc ") = "abc" 702 * StringUtils.stripToNull(" ab c ") = "ab c" 703 * </pre> 704 * 705 * @param str the String to be stripped, may be null 706 * @return the stripped String, 707 * {@code null} if whitespace, empty or null String input 708 * @since 2.0 709 */ 710 public static String stripToNull(String str) { 711 if (str == null) { 712 return null; 713 } 714 str = strip(str, null); 715 return str.isEmpty() ? null : str; 716 } 717 718 /** 719 * <p>Strips whitespace from the start and end of a String returning 720 * an empty String if {@code null} input.</p> 721 * 722 * <p>This is similar to {@link #trimToEmpty(String)} but removes whitespace. 723 * Whitespace is defined by {@link Character#isWhitespace(char)}.</p> 724 * 725 * <pre> 726 * StringUtils.stripToEmpty(null) = "" 727 * StringUtils.stripToEmpty("") = "" 728 * StringUtils.stripToEmpty(" ") = "" 729 * StringUtils.stripToEmpty("abc") = "abc" 730 * StringUtils.stripToEmpty(" abc") = "abc" 731 * StringUtils.stripToEmpty("abc ") = "abc" 732 * StringUtils.stripToEmpty(" abc ") = "abc" 733 * StringUtils.stripToEmpty(" ab c ") = "ab c" 734 * </pre> 735 * 736 * @param str the String to be stripped, may be null 737 * @return the trimmed String, or an empty String if {@code null} input 738 * @since 2.0 739 */ 740 public static String stripToEmpty(final String str) { 741 return str == null ? EMPTY : strip(str, null); 742 } 743 744 /** 745 * <p>Strips any of a set of characters from the start and end of a String. 746 * This is similar to {@link String#trim()} but allows the characters 747 * to be stripped to be controlled.</p> 748 * 749 * <p>A {@code null} input String returns {@code null}. 750 * An empty string ("") input returns the empty string.</p> 751 * 752 * <p>If the stripChars String is {@code null}, whitespace is 753 * stripped as defined by {@link Character#isWhitespace(char)}. 754 * Alternatively use {@link #strip(String)}.</p> 755 * 756 * <pre> 757 * StringUtils.strip(null, *) = null 758 * StringUtils.strip("", *) = "" 759 * StringUtils.strip("abc", null) = "abc" 760 * StringUtils.strip(" abc", null) = "abc" 761 * StringUtils.strip("abc ", null) = "abc" 762 * StringUtils.strip(" abc ", null) = "abc" 763 * StringUtils.strip(" abcyx", "xyz") = " abc" 764 * </pre> 765 * 766 * @param str the String to remove characters from, may be null 767 * @param stripChars the characters to remove, null treated as whitespace 768 * @return the stripped String, {@code null} if null String input 769 */ 770 public static String strip(String str, final String stripChars) { 771 if (isEmpty(str)) { 772 return str; 773 } 774 str = stripStart(str, stripChars); 775 return stripEnd(str, stripChars); 776 } 777 778 /** 779 * <p>Strips any of a set of characters from the start of a String.</p> 780 * 781 * <p>A {@code null} input String returns {@code null}. 782 * An empty string ("") input returns the empty string.</p> 783 * 784 * <p>If the stripChars String is {@code null}, whitespace is 785 * stripped as defined by {@link Character#isWhitespace(char)}.</p> 786 * 787 * <pre> 788 * StringUtils.stripStart(null, *) = null 789 * StringUtils.stripStart("", *) = "" 790 * StringUtils.stripStart("abc", "") = "abc" 791 * StringUtils.stripStart("abc", null) = "abc" 792 * StringUtils.stripStart(" abc", null) = "abc" 793 * StringUtils.stripStart("abc ", null) = "abc " 794 * StringUtils.stripStart(" abc ", null) = "abc " 795 * StringUtils.stripStart("yxabc ", "xyz") = "abc " 796 * </pre> 797 * 798 * @param str the String to remove characters from, may be null 799 * @param stripChars the characters to remove, null treated as whitespace 800 * @return the stripped String, {@code null} if null String input 801 */ 802 public static String stripStart(final String str, final String stripChars) { 803 int strLen; 804 if (str == null || (strLen = str.length()) == 0) { 805 return str; 806 } 807 int start = 0; 808 if (stripChars == null) { 809 while (start != strLen && Character.isWhitespace(str.charAt(start))) { 810 start++; 811 } 812 } else if (stripChars.isEmpty()) { 813 return str; 814 } else { 815 while (start != strLen && stripChars.indexOf(str.charAt(start)) != INDEX_NOT_FOUND) { 816 start++; 817 } 818 } 819 return str.substring(start); 820 } 821 822 /** 823 * <p>Strips any of a set of characters from the end of a String.</p> 824 * 825 * <p>A {@code null} input String returns {@code null}. 826 * An empty string ("") input returns the empty string.</p> 827 * 828 * <p>If the stripChars String is {@code null}, whitespace is 829 * stripped as defined by {@link Character#isWhitespace(char)}.</p> 830 * 831 * <pre> 832 * StringUtils.stripEnd(null, *) = null 833 * StringUtils.stripEnd("", *) = "" 834 * StringUtils.stripEnd("abc", "") = "abc" 835 * StringUtils.stripEnd("abc", null) = "abc" 836 * StringUtils.stripEnd(" abc", null) = " abc" 837 * StringUtils.stripEnd("abc ", null) = "abc" 838 * StringUtils.stripEnd(" abc ", null) = " abc" 839 * StringUtils.stripEnd(" abcyx", "xyz") = " abc" 840 * StringUtils.stripEnd("120.00", ".0") = "12" 841 * </pre> 842 * 843 * @param str the String to remove characters from, may be null 844 * @param stripChars the set of characters to remove, null treated as whitespace 845 * @return the stripped String, {@code null} if null String input 846 */ 847 public static String stripEnd(final String str, final String stripChars) { 848 int end; 849 if (str == null || (end = str.length()) == 0) { 850 return str; 851 } 852 853 if (stripChars == null) { 854 while (end != 0 && Character.isWhitespace(str.charAt(end - 1))) { 855 end--; 856 } 857 } else if (stripChars.isEmpty()) { 858 return str; 859 } else { 860 while (end != 0 && stripChars.indexOf(str.charAt(end - 1)) != INDEX_NOT_FOUND) { 861 end--; 862 } 863 } 864 return str.substring(0, end); 865 } 866 867 // StripAll 868 //----------------------------------------------------------------------- 869 /** 870 * <p>Strips whitespace from the start and end of every String in an array. 871 * Whitespace is defined by {@link Character#isWhitespace(char)}.</p> 872 * 873 * <p>A new array is returned each time, except for length zero. 874 * A {@code null} array will return {@code null}. 875 * An empty array will return itself. 876 * A {@code null} array entry will be ignored.</p> 877 * 878 * <pre> 879 * StringUtils.stripAll(null) = null 880 * StringUtils.stripAll([]) = [] 881 * StringUtils.stripAll(["abc", " abc"]) = ["abc", "abc"] 882 * StringUtils.stripAll(["abc ", null]) = ["abc", null] 883 * </pre> 884 * 885 * @param strs the array to remove whitespace from, may be null 886 * @return the stripped Strings, {@code null} if null array input 887 */ 888 public static String[] stripAll(final String... strs) { 889 return stripAll(strs, null); 890 } 891 892 /** 893 * <p>Strips any of a set of characters from the start and end of every 894 * String in an array.</p> 895 * <p>Whitespace is defined by {@link Character#isWhitespace(char)}.</p> 896 * 897 * <p>A new array is returned each time, except for length zero. 898 * A {@code null} array will return {@code null}. 899 * An empty array will return itself. 900 * A {@code null} array entry will be ignored. 901 * A {@code null} stripChars will strip whitespace as defined by 902 * {@link Character#isWhitespace(char)}.</p> 903 * 904 * <pre> 905 * StringUtils.stripAll(null, *) = null 906 * StringUtils.stripAll([], *) = [] 907 * StringUtils.stripAll(["abc", " abc"], null) = ["abc", "abc"] 908 * StringUtils.stripAll(["abc ", null], null) = ["abc", null] 909 * StringUtils.stripAll(["abc ", null], "yz") = ["abc ", null] 910 * StringUtils.stripAll(["yabcz", null], "yz") = ["abc", null] 911 * </pre> 912 * 913 * @param strs the array to remove characters from, may be null 914 * @param stripChars the characters to remove, null treated as whitespace 915 * @return the stripped Strings, {@code null} if null array input 916 */ 917 public static String[] stripAll(final String[] strs, final String stripChars) { 918 int strsLen; 919 if (strs == null || (strsLen = strs.length) == 0) { 920 return strs; 921 } 922 final String[] newArr = new String[strsLen]; 923 for (int i = 0; i < strsLen; i++) { 924 newArr[i] = strip(strs[i], stripChars); 925 } 926 return newArr; 927 } 928 929 /** 930 * <p>Removes diacritics (~= accents) from a string. The case will not be altered.</p> 931 * <p>For instance, 'à' will be replaced by 'a'.</p> 932 * <p>Note that ligatures will be left as is.</p> 933 * 934 * <pre> 935 * StringUtils.stripAccents(null) = null 936 * StringUtils.stripAccents("") = "" 937 * StringUtils.stripAccents("control") = "control" 938 * StringUtils.stripAccents("éclair") = "eclair" 939 * </pre> 940 * 941 * @param input String to be stripped 942 * @return input text with diacritics removed 943 * 944 * @since 3.0 945 */ 946 // 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). 947 public static String stripAccents(final String input) { 948 if(input == null) { 949 return null; 950 } 951 final Pattern pattern = Pattern.compile("\\p{InCombiningDiacriticalMarks}+");//$NON-NLS-1$ 952 final StringBuilder decomposed = new StringBuilder(Normalizer.normalize(input, Normalizer.Form.NFD)); 953 convertRemainingAccentCharacters(decomposed); 954 // Note that this doesn't correctly remove ligatures... 955 return pattern.matcher(decomposed).replaceAll(StringUtils.EMPTY); 956 } 957 958 private static void convertRemainingAccentCharacters(final StringBuilder decomposed) { 959 for (int i = 0; i < decomposed.length(); i++) { 960 if (decomposed.charAt(i) == '\u0141') { 961 decomposed.deleteCharAt(i); 962 decomposed.insert(i, 'L'); 963 } else if (decomposed.charAt(i) == '\u0142') { 964 decomposed.deleteCharAt(i); 965 decomposed.insert(i, 'l'); 966 } 967 } 968 } 969 970 // Equals 971 //----------------------------------------------------------------------- 972 /** 973 * <p>Compares two CharSequences, returning {@code true} if they represent 974 * equal sequences of characters.</p> 975 * 976 * <p>{@code null}s are handled without exceptions. Two {@code null} 977 * references are considered to be equal. The comparison is case sensitive.</p> 978 * 979 * <pre> 980 * StringUtils.equals(null, null) = true 981 * StringUtils.equals(null, "abc") = false 982 * StringUtils.equals("abc", null) = false 983 * StringUtils.equals("abc", "abc") = true 984 * StringUtils.equals("abc", "ABC") = false 985 * </pre> 986 * 987 * @see Object#equals(Object) 988 * @param cs1 the first CharSequence, may be {@code null} 989 * @param cs2 the second CharSequence, may be {@code null} 990 * @return {@code true} if the CharSequences are equal (case-sensitive), or both {@code null} 991 * @since 3.0 Changed signature from equals(String, String) to equals(CharSequence, CharSequence) 992 */ 993 public static boolean equals(final CharSequence cs1, final CharSequence cs2) { 994 if (cs1 == cs2) { 995 return true; 996 } 997 if (cs1 == null || cs2 == null) { 998 return false; 999 } 1000 if (cs1.length() != cs2.length()) { 1001 return false; 1002 } 1003 if (cs1 instanceof String && cs2 instanceof String) { 1004 return cs1.equals(cs2); 1005 } 1006 return CharSequenceUtils.regionMatches(cs1, false, 0, cs2, 0, cs1.length()); 1007 } 1008 1009 /** 1010 * <p>Compares two CharSequences, returning {@code true} if they represent 1011 * equal sequences of characters, ignoring case.</p> 1012 * 1013 * <p>{@code null}s are handled without exceptions. Two {@code null} 1014 * references are considered equal. Comparison is case insensitive.</p> 1015 * 1016 * <pre> 1017 * StringUtils.equalsIgnoreCase(null, null) = true 1018 * StringUtils.equalsIgnoreCase(null, "abc") = false 1019 * StringUtils.equalsIgnoreCase("abc", null) = false 1020 * StringUtils.equalsIgnoreCase("abc", "abc") = true 1021 * StringUtils.equalsIgnoreCase("abc", "ABC") = true 1022 * </pre> 1023 * 1024 * @param str1 the first CharSequence, may be null 1025 * @param str2 the second CharSequence, may be null 1026 * @return {@code true} if the CharSequence are equal, case insensitive, or 1027 * both {@code null} 1028 * @since 3.0 Changed signature from equalsIgnoreCase(String, String) to equalsIgnoreCase(CharSequence, CharSequence) 1029 */ 1030 public static boolean equalsIgnoreCase(final CharSequence str1, final CharSequence str2) { 1031 if (str1 == null || str2 == null) { 1032 return str1 == str2; 1033 } else if (str1 == str2) { 1034 return true; 1035 } else if (str1.length() != str2.length()) { 1036 return false; 1037 } else { 1038 return CharSequenceUtils.regionMatches(str1, true, 0, str2, 0, str1.length()); 1039 } 1040 } 1041 1042 // Compare 1043 //----------------------------------------------------------------------- 1044 /** 1045 * <p>Compare two Strings lexicographically, as per {@link String#compareTo(String)}, returning :</p> 1046 * <ul> 1047 * <li>{@code int = 0}, if {@code str1} is equal to {@code str2} (or both {@code null})</li> 1048 * <li>{@code int < 0}, if {@code str1} is less than {@code str2}</li> 1049 * <li>{@code int > 0}, if {@code str1} is greater than {@code str2}</li> 1050 * </ul> 1051 * 1052 * <p>This is a {@code null} safe version of :</p> 1053 * <blockquote><pre>str1.compareTo(str2)</pre></blockquote> 1054 * 1055 * <p>{@code null} value is considered less than non-{@code null} value. 1056 * Two {@code null} references are considered equal.</p> 1057 * 1058 * <pre> 1059 * StringUtils.compare(null, null) = 0 1060 * StringUtils.compare(null , "a") < 0 1061 * StringUtils.compare("a", null) > 0 1062 * StringUtils.compare("abc", "abc") = 0 1063 * StringUtils.compare("a", "b") < 0 1064 * StringUtils.compare("b", "a") > 0 1065 * StringUtils.compare("a", "B") > 0 1066 * StringUtils.compare("ab", "abc") < 0 1067 * </pre> 1068 * 1069 * @see #compare(String, String, boolean) 1070 * @see String#compareTo(String) 1071 * @param str1 the String to compare from 1072 * @param str2 the String to compare to 1073 * @return < 0, 0, > 0, if {@code str1} is respectively less, equal or greater than {@code str2} 1074 * @since 3.5 1075 */ 1076 public static int compare(final String str1, final String str2) { 1077 return compare(str1, str2, true); 1078 } 1079 1080 /** 1081 * <p>Compare two Strings lexicographically, as per {@link String#compareTo(String)}, returning :</p> 1082 * <ul> 1083 * <li>{@code int = 0}, if {@code str1} is equal to {@code str2} (or both {@code null})</li> 1084 * <li>{@code int < 0}, if {@code str1} is less than {@code str2}</li> 1085 * <li>{@code int > 0}, if {@code str1} is greater than {@code str2}</li> 1086 * </ul> 1087 * 1088 * <p>This is a {@code null} safe version of :</p> 1089 * <blockquote><pre>str1.compareTo(str2)</pre></blockquote> 1090 * 1091 * <p>{@code null} inputs are handled according to the {@code nullIsLess} parameter. 1092 * Two {@code null} references are considered equal.</p> 1093 * 1094 * <pre> 1095 * StringUtils.compare(null, null, *) = 0 1096 * StringUtils.compare(null , "a", true) < 0 1097 * StringUtils.compare(null , "a", false) > 0 1098 * StringUtils.compare("a", null, true) > 0 1099 * StringUtils.compare("a", null, false) < 0 1100 * StringUtils.compare("abc", "abc", *) = 0 1101 * StringUtils.compare("a", "b", *) < 0 1102 * StringUtils.compare("b", "a", *) > 0 1103 * StringUtils.compare("a", "B", *) > 0 1104 * StringUtils.compare("ab", "abc", *) < 0 1105 * </pre> 1106 * 1107 * @see String#compareTo(String) 1108 * @param str1 the String to compare from 1109 * @param str2 the String to compare to 1110 * @param nullIsLess whether consider {@code null} value less than non-{@code null} value 1111 * @return < 0, 0, > 0, if {@code str1} is respectively less, equal ou greater than {@code str2} 1112 * @since 3.5 1113 */ 1114 public static int compare(final String str1, final String str2, final boolean nullIsLess) { 1115 if (str1 == str2) { 1116 return 0; 1117 } 1118 if (str1 == null) { 1119 return nullIsLess ? -1 : 1; 1120 } 1121 if (str2 == null) { 1122 return nullIsLess ? 1 : - 1; 1123 } 1124 return str1.compareTo(str2); 1125 } 1126 1127 /** 1128 * <p>Compare two Strings lexicographically, ignoring case differences, 1129 * as per {@link String#compareToIgnoreCase(String)}, returning :</p> 1130 * <ul> 1131 * <li>{@code int = 0}, if {@code str1} is equal to {@code str2} (or both {@code null})</li> 1132 * <li>{@code int < 0}, if {@code str1} is less than {@code str2}</li> 1133 * <li>{@code int > 0}, if {@code str1} is greater than {@code str2}</li> 1134 * </ul> 1135 * 1136 * <p>This is a {@code null} safe version of :</p> 1137 * <blockquote><pre>str1.compareToIgnoreCase(str2)</pre></blockquote> 1138 * 1139 * <p>{@code null} value is considered less than non-{@code null} value. 1140 * Two {@code null} references are considered equal. 1141 * Comparison is case insensitive.</p> 1142 * 1143 * <pre> 1144 * StringUtils.compareIgnoreCase(null, null) = 0 1145 * StringUtils.compareIgnoreCase(null , "a") < 0 1146 * StringUtils.compareIgnoreCase("a", null) > 0 1147 * StringUtils.compareIgnoreCase("abc", "abc") = 0 1148 * StringUtils.compareIgnoreCase("abc", "ABC") = 0 1149 * StringUtils.compareIgnoreCase("a", "b") < 0 1150 * StringUtils.compareIgnoreCase("b", "a") > 0 1151 * StringUtils.compareIgnoreCase("a", "B") < 0 1152 * StringUtils.compareIgnoreCase("A", "b") < 0 1153 * StringUtils.compareIgnoreCase("ab", "ABC") < 0 1154 * </pre> 1155 * 1156 * @see #compareIgnoreCase(String, String, boolean) 1157 * @see String#compareToIgnoreCase(String) 1158 * @param str1 the String to compare from 1159 * @param str2 the String to compare to 1160 * @return < 0, 0, > 0, if {@code str1} is respectively less, equal ou greater than {@code str2}, 1161 * ignoring case differences. 1162 * @since 3.5 1163 */ 1164 public static int compareIgnoreCase(final String str1, final String str2) { 1165 return compareIgnoreCase(str1, str2, true); 1166 } 1167 1168 /** 1169 * <p>Compare two Strings lexicographically, ignoring case differences, 1170 * as per {@link String#compareToIgnoreCase(String)}, returning :</p> 1171 * <ul> 1172 * <li>{@code int = 0}, if {@code str1} is equal to {@code str2} (or both {@code null})</li> 1173 * <li>{@code int < 0}, if {@code str1} is less than {@code str2}</li> 1174 * <li>{@code int > 0}, if {@code str1} is greater than {@code str2}</li> 1175 * </ul> 1176 * 1177 * <p>This is a {@code null} safe version of :</p> 1178 * <blockquote><pre>str1.compareToIgnoreCase(str2)</pre></blockquote> 1179 * 1180 * <p>{@code null} inputs are handled according to the {@code nullIsLess} parameter. 1181 * Two {@code null} references are considered equal. 1182 * Comparison is case insensitive.</p> 1183 * 1184 * <pre> 1185 * StringUtils.compareIgnoreCase(null, null, *) = 0 1186 * StringUtils.compareIgnoreCase(null , "a", true) < 0 1187 * StringUtils.compareIgnoreCase(null , "a", false) > 0 1188 * StringUtils.compareIgnoreCase("a", null, true) > 0 1189 * StringUtils.compareIgnoreCase("a", null, false) < 0 1190 * StringUtils.compareIgnoreCase("abc", "abc", *) = 0 1191 * StringUtils.compareIgnoreCase("abc", "ABC", *) = 0 1192 * StringUtils.compareIgnoreCase("a", "b", *) < 0 1193 * StringUtils.compareIgnoreCase("b", "a", *) > 0 1194 * StringUtils.compareIgnoreCase("a", "B", *) < 0 1195 * StringUtils.compareIgnoreCase("A", "b", *) < 0 1196 * StringUtils.compareIgnoreCase("ab", "abc", *) < 0 1197 * </pre> 1198 * 1199 * @see String#compareToIgnoreCase(String) 1200 * @param str1 the String to compare from 1201 * @param str2 the String to compare to 1202 * @param nullIsLess whether consider {@code null} value less than non-{@code null} value 1203 * @return < 0, 0, > 0, if {@code str1} is respectively less, equal ou greater than {@code str2}, 1204 * ignoring case differences. 1205 * @since 3.5 1206 */ 1207 public static int compareIgnoreCase(final String str1, final String str2, final boolean nullIsLess) { 1208 if (str1 == str2) { 1209 return 0; 1210 } 1211 if (str1 == null) { 1212 return nullIsLess ? -1 : 1; 1213 } 1214 if (str2 == null) { 1215 return nullIsLess ? 1 : - 1; 1216 } 1217 return str1.compareToIgnoreCase(str2); 1218 } 1219 1220 /** 1221 * <p>Compares given <code>string</code> to a CharSequences vararg of <code>searchStrings</code>, 1222 * returning {@code true} if the <code>string</code> is equal to any of the <code>searchStrings</code>.</p> 1223 * 1224 * <pre> 1225 * StringUtils.equalsAny(null, (CharSequence[]) null) = false 1226 * StringUtils.equalsAny(null, null, null) = true 1227 * StringUtils.equalsAny(null, "abc", "def") = false 1228 * StringUtils.equalsAny("abc", null, "def") = false 1229 * StringUtils.equalsAny("abc", "abc", "def") = true 1230 * StringUtils.equalsAny("abc", "ABC", "DEF") = false 1231 * </pre> 1232 * 1233 * @param string to compare, may be {@code null}. 1234 * @param searchStrings a vararg of strings, may be {@code null}. 1235 * @return {@code true} if the string is equal (case-sensitive) to any other element of <code>searchStrings</code>; 1236 * {@code false} if <code>searchStrings</code> is null or contains no matches. 1237 * @since 3.5 1238 */ 1239 public static boolean equalsAny(final CharSequence string, final CharSequence... searchStrings) { 1240 if (ArrayUtils.isNotEmpty(searchStrings)) { 1241 for (final CharSequence next : searchStrings) { 1242 if (equals(string, next)) { 1243 return true; 1244 } 1245 } 1246 } 1247 return false; 1248 } 1249 1250 1251 /** 1252 * <p>Compares given <code>string</code> to a CharSequences vararg of <code>searchStrings</code>, 1253 * returning {@code true} if the <code>string</code> is equal to any of the <code>searchStrings</code>, ignoring case.</p> 1254 * 1255 * <pre> 1256 * StringUtils.equalsAnyIgnoreCase(null, (CharSequence[]) null) = false 1257 * StringUtils.equalsAnyIgnoreCase(null, null, null) = true 1258 * StringUtils.equalsAnyIgnoreCase(null, "abc", "def") = false 1259 * StringUtils.equalsAnyIgnoreCase("abc", null, "def") = false 1260 * StringUtils.equalsAnyIgnoreCase("abc", "abc", "def") = true 1261 * StringUtils.equalsAnyIgnoreCase("abc", "ABC", "DEF") = true 1262 * </pre> 1263 * 1264 * @param string to compare, may be {@code null}. 1265 * @param searchStrings a vararg of strings, may be {@code null}. 1266 * @return {@code true} if the string is equal (case-insensitive) to any other element of <code>searchStrings</code>; 1267 * {@code false} if <code>searchStrings</code> is null or contains no matches. 1268 * @since 3.5 1269 */ 1270 public static boolean equalsAnyIgnoreCase(final CharSequence string, final CharSequence...searchStrings) { 1271 if (ArrayUtils.isNotEmpty(searchStrings)) { 1272 for (final CharSequence next : searchStrings) { 1273 if (equalsIgnoreCase(string, next)) { 1274 return true; 1275 } 1276 } 1277 } 1278 return false; 1279 } 1280 1281 // IndexOf 1282 //----------------------------------------------------------------------- 1283 /** 1284 * Returns the index within <code>seq</code> of the first occurrence of 1285 * the specified character. If a character with value 1286 * <code>searchChar</code> occurs in the character sequence represented by 1287 * <code>seq</code> <code>CharSequence</code> object, then the index (in Unicode 1288 * code units) of the first such occurrence is returned. For 1289 * values of <code>searchChar</code> in the range from 0 to 0xFFFF 1290 * (inclusive), this is the smallest value <i>k</i> such that: 1291 * <blockquote><pre> 1292 * this.charAt(<i>k</i>) == searchChar 1293 * </pre></blockquote> 1294 * is true. For other values of <code>searchChar</code>, it is the 1295 * smallest value <i>k</i> such that: 1296 * <blockquote><pre> 1297 * this.codePointAt(<i>k</i>) == searchChar 1298 * </pre></blockquote> 1299 * is true. In either case, if no such character occurs in <code>seq</code>, 1300 * then {@code INDEX_NOT_FOUND (-1)} is returned. 1301 * 1302 * <p>Furthermore, a {@code null} or empty ("") CharSequence will 1303 * return {@code INDEX_NOT_FOUND (-1)}.</p> 1304 * 1305 * <pre> 1306 * StringUtils.indexOf(null, *) = -1 1307 * StringUtils.indexOf("", *) = -1 1308 * StringUtils.indexOf("aabaabaa", 'a') = 0 1309 * StringUtils.indexOf("aabaabaa", 'b') = 2 1310 * </pre> 1311 * 1312 * @param seq the CharSequence to check, may be null 1313 * @param searchChar the character to find 1314 * @return the first index of the search character, 1315 * -1 if no match or {@code null} string input 1316 * @since 2.0 1317 * @since 3.0 Changed signature from indexOf(String, int) to indexOf(CharSequence, int) 1318 * @since 3.6 Updated {@link CharSequenceUtils} call to behave more like <code>String</code> 1319 */ 1320 public static int indexOf(final CharSequence seq, final int searchChar) { 1321 if (isEmpty(seq)) { 1322 return INDEX_NOT_FOUND; 1323 } 1324 return CharSequenceUtils.indexOf(seq, searchChar, 0); 1325 } 1326 1327 /** 1328 * 1329 * Returns the index within <code>seq</code> of the first occurrence of the 1330 * specified character, starting the search at the specified index. 1331 * <p> 1332 * If a character with value <code>searchChar</code> occurs in the 1333 * character sequence represented by the <code>seq</code> <code>CharSequence</code> 1334 * object at an index no smaller than <code>startPos</code>, then 1335 * the index of the first such occurrence is returned. For values 1336 * of <code>searchChar</code> in the range from 0 to 0xFFFF (inclusive), 1337 * this is the smallest value <i>k</i> such that: 1338 * <blockquote><pre> 1339 * (this.charAt(<i>k</i>) == searchChar) && (<i>k</i> >= startPos) 1340 * </pre></blockquote> 1341 * is true. For other values of <code>searchChar</code>, it is the 1342 * smallest value <i>k</i> such that: 1343 * <blockquote><pre> 1344 * (this.codePointAt(<i>k</i>) == searchChar) && (<i>k</i> >= startPos) 1345 * </pre></blockquote> 1346 * is true. In either case, if no such character occurs in <code>seq</code> 1347 * at or after position <code>startPos</code>, then 1348 * <code>-1</code> is returned. 1349 * 1350 * <p> 1351 * There is no restriction on the value of <code>startPos</code>. If it 1352 * is negative, it has the same effect as if it were zero: this entire 1353 * string may be searched. If it is greater than the length of this 1354 * string, it has the same effect as if it were equal to the length of 1355 * this string: {@code (INDEX_NOT_FOUND) -1} is returned. Furthermore, a 1356 * {@code null} or empty ("") CharSequence will 1357 * return {@code (INDEX_NOT_FOUND) -1}. 1358 * 1359 * <p>All indices are specified in <code>char</code> values 1360 * (Unicode code units). 1361 * 1362 * <pre> 1363 * StringUtils.indexOf(null, *, *) = -1 1364 * StringUtils.indexOf("", *, *) = -1 1365 * StringUtils.indexOf("aabaabaa", 'b', 0) = 2 1366 * StringUtils.indexOf("aabaabaa", 'b', 3) = 5 1367 * StringUtils.indexOf("aabaabaa", 'b', 9) = -1 1368 * StringUtils.indexOf("aabaabaa", 'b', -1) = 2 1369 * </pre> 1370 * 1371 * @param seq the CharSequence to check, may be null 1372 * @param searchChar the character to find 1373 * @param startPos the start position, negative treated as zero 1374 * @return the first index of the search character (always ≥ startPos), 1375 * -1 if no match or {@code null} string input 1376 * @since 2.0 1377 * @since 3.0 Changed signature from indexOf(String, int, int) to indexOf(CharSequence, int, int) 1378 * @since 3.6 Updated {@link CharSequenceUtils} call to behave more like <code>String</code> 1379 */ 1380 public static int indexOf(final CharSequence seq, final int searchChar, final int startPos) { 1381 if (isEmpty(seq)) { 1382 return INDEX_NOT_FOUND; 1383 } 1384 return CharSequenceUtils.indexOf(seq, searchChar, startPos); 1385 } 1386 1387 /** 1388 * <p>Finds the first index within a CharSequence, handling {@code null}. 1389 * This method uses {@link String#indexOf(String, int)} if possible.</p> 1390 * 1391 * <p>A {@code null} CharSequence will return {@code -1}.</p> 1392 * 1393 * <pre> 1394 * StringUtils.indexOf(null, *) = -1 1395 * StringUtils.indexOf(*, null) = -1 1396 * StringUtils.indexOf("", "") = 0 1397 * StringUtils.indexOf("", *) = -1 (except when * = "") 1398 * StringUtils.indexOf("aabaabaa", "a") = 0 1399 * StringUtils.indexOf("aabaabaa", "b") = 2 1400 * StringUtils.indexOf("aabaabaa", "ab") = 1 1401 * StringUtils.indexOf("aabaabaa", "") = 0 1402 * </pre> 1403 * 1404 * @param seq the CharSequence to check, may be null 1405 * @param searchSeq the CharSequence to find, may be null 1406 * @return the first index of the search CharSequence, 1407 * -1 if no match or {@code null} string input 1408 * @since 2.0 1409 * @since 3.0 Changed signature from indexOf(String, String) to indexOf(CharSequence, CharSequence) 1410 */ 1411 public static int indexOf(final CharSequence seq, final CharSequence searchSeq) { 1412 if (seq == null || searchSeq == null) { 1413 return INDEX_NOT_FOUND; 1414 } 1415 return CharSequenceUtils.indexOf(seq, searchSeq, 0); 1416 } 1417 1418 /** 1419 * <p>Finds the first index within a CharSequence, handling {@code null}. 1420 * This method uses {@link String#indexOf(String, int)} if possible.</p> 1421 * 1422 * <p>A {@code null} CharSequence will return {@code -1}. 1423 * A negative start position is treated as zero. 1424 * An empty ("") search CharSequence always matches. 1425 * A start position greater than the string length only matches 1426 * an empty search CharSequence.</p> 1427 * 1428 * <pre> 1429 * StringUtils.indexOf(null, *, *) = -1 1430 * StringUtils.indexOf(*, null, *) = -1 1431 * StringUtils.indexOf("", "", 0) = 0 1432 * StringUtils.indexOf("", *, 0) = -1 (except when * = "") 1433 * StringUtils.indexOf("aabaabaa", "a", 0) = 0 1434 * StringUtils.indexOf("aabaabaa", "b", 0) = 2 1435 * StringUtils.indexOf("aabaabaa", "ab", 0) = 1 1436 * StringUtils.indexOf("aabaabaa", "b", 3) = 5 1437 * StringUtils.indexOf("aabaabaa", "b", 9) = -1 1438 * StringUtils.indexOf("aabaabaa", "b", -1) = 2 1439 * StringUtils.indexOf("aabaabaa", "", 2) = 2 1440 * StringUtils.indexOf("abc", "", 9) = 3 1441 * </pre> 1442 * 1443 * @param seq the CharSequence to check, may be null 1444 * @param searchSeq the CharSequence to find, may be null 1445 * @param startPos the start position, negative treated as zero 1446 * @return the first index of the search CharSequence (always ≥ startPos), 1447 * -1 if no match or {@code null} string input 1448 * @since 2.0 1449 * @since 3.0 Changed signature from indexOf(String, String, int) to indexOf(CharSequence, CharSequence, int) 1450 */ 1451 public static int indexOf(final CharSequence seq, final CharSequence searchSeq, final int startPos) { 1452 if (seq == null || searchSeq == null) { 1453 return INDEX_NOT_FOUND; 1454 } 1455 return CharSequenceUtils.indexOf(seq, searchSeq, startPos); 1456 } 1457 1458 /** 1459 * <p>Finds the n-th index within a CharSequence, handling {@code null}. 1460 * This method uses {@link String#indexOf(String)} if possible.</p> 1461 * <p><b>Note:</b> The code starts looking for a match at the start of the target, 1462 * incrementing the starting index by one after each successful match 1463 * (unless {@code searchStr} is an empty string in which case the position 1464 * is never incremented and {@code 0} is returned immediately). 1465 * This means that matches may overlap.</p> 1466 * <p>A {@code null} CharSequence will return {@code -1}.</p> 1467 * 1468 * <pre> 1469 * StringUtils.ordinalIndexOf(null, *, *) = -1 1470 * StringUtils.ordinalIndexOf(*, null, *) = -1 1471 * StringUtils.ordinalIndexOf("", "", *) = 0 1472 * StringUtils.ordinalIndexOf("aabaabaa", "a", 1) = 0 1473 * StringUtils.ordinalIndexOf("aabaabaa", "a", 2) = 1 1474 * StringUtils.ordinalIndexOf("aabaabaa", "b", 1) = 2 1475 * StringUtils.ordinalIndexOf("aabaabaa", "b", 2) = 5 1476 * StringUtils.ordinalIndexOf("aabaabaa", "ab", 1) = 1 1477 * StringUtils.ordinalIndexOf("aabaabaa", "ab", 2) = 4 1478 * StringUtils.ordinalIndexOf("aabaabaa", "", 1) = 0 1479 * StringUtils.ordinalIndexOf("aabaabaa", "", 2) = 0 1480 * </pre> 1481 * 1482 * <p>Matches may overlap:</p> 1483 * <pre> 1484 * StringUtils.ordinalIndexOf("ababab","aba", 1) = 0 1485 * StringUtils.ordinalIndexOf("ababab","aba", 2) = 2 1486 * StringUtils.ordinalIndexOf("ababab","aba", 3) = -1 1487 * 1488 * StringUtils.ordinalIndexOf("abababab", "abab", 1) = 0 1489 * StringUtils.ordinalIndexOf("abababab", "abab", 2) = 2 1490 * StringUtils.ordinalIndexOf("abababab", "abab", 3) = 4 1491 * StringUtils.ordinalIndexOf("abababab", "abab", 4) = -1 1492 * </pre> 1493 * 1494 * <p>Note that 'head(CharSequence str, int n)' may be implemented as: </p> 1495 * 1496 * <pre> 1497 * str.substring(0, lastOrdinalIndexOf(str, "\n", n)) 1498 * </pre> 1499 * 1500 * @param str the CharSequence to check, may be null 1501 * @param searchStr the CharSequence to find, may be null 1502 * @param ordinal the n-th {@code searchStr} to find 1503 * @return the n-th index of the search CharSequence, 1504 * {@code -1} ({@code INDEX_NOT_FOUND}) if no match or {@code null} string input 1505 * @since 2.1 1506 * @since 3.0 Changed signature from ordinalIndexOf(String, String, int) to ordinalIndexOf(CharSequence, CharSequence, int) 1507 */ 1508 public static int ordinalIndexOf(final CharSequence str, final CharSequence searchStr, final int ordinal) { 1509 return ordinalIndexOf(str, searchStr, ordinal, false); 1510 } 1511 1512 /** 1513 * <p>Finds the n-th index within a String, handling {@code null}. 1514 * This method uses {@link String#indexOf(String)} if possible.</p> 1515 * <p>Note that matches may overlap<p> 1516 * 1517 * <p>A {@code null} CharSequence will return {@code -1}.</p> 1518 * 1519 * @param str the CharSequence to check, may be null 1520 * @param searchStr the CharSequence to find, may be null 1521 * @param ordinal the n-th {@code searchStr} to find, overlapping matches are allowed. 1522 * @param lastIndex true if lastOrdinalIndexOf() otherwise false if ordinalIndexOf() 1523 * @return the n-th index of the search CharSequence, 1524 * {@code -1} ({@code INDEX_NOT_FOUND}) if no match or {@code null} string input 1525 */ 1526 // Shared code between ordinalIndexOf(String,String,int) and lastOrdinalIndexOf(String,String,int) 1527 private static int ordinalIndexOf(final CharSequence str, final CharSequence searchStr, final int ordinal, final boolean lastIndex) { 1528 if (str == null || searchStr == null || ordinal <= 0) { 1529 return INDEX_NOT_FOUND; 1530 } 1531 if (searchStr.length() == 0) { 1532 return lastIndex ? str.length() : 0; 1533 } 1534 int found = 0; 1535 // set the initial index beyond the end of the string 1536 // this is to allow for the initial index decrement/increment 1537 int index = lastIndex ? str.length() : INDEX_NOT_FOUND; 1538 do { 1539 if (lastIndex) { 1540 index = CharSequenceUtils.lastIndexOf(str, searchStr, index - 1); // step backwards thru string 1541 } else { 1542 index = CharSequenceUtils.indexOf(str, searchStr, index + 1); // step forwards through string 1543 } 1544 if (index < 0) { 1545 return index; 1546 } 1547 found++; 1548 } while (found < ordinal); 1549 return index; 1550 } 1551 1552 /** 1553 * <p>Case in-sensitive find of the first index within a CharSequence.</p> 1554 * 1555 * <p>A {@code null} CharSequence will return {@code -1}. 1556 * A negative start position is treated as zero. 1557 * An empty ("") search CharSequence always matches. 1558 * A start position greater than the string length only matches 1559 * an empty search CharSequence.</p> 1560 * 1561 * <pre> 1562 * StringUtils.indexOfIgnoreCase(null, *) = -1 1563 * StringUtils.indexOfIgnoreCase(*, null) = -1 1564 * StringUtils.indexOfIgnoreCase("", "") = 0 1565 * StringUtils.indexOfIgnoreCase("aabaabaa", "a") = 0 1566 * StringUtils.indexOfIgnoreCase("aabaabaa", "b") = 2 1567 * StringUtils.indexOfIgnoreCase("aabaabaa", "ab") = 1 1568 * </pre> 1569 * 1570 * @param str the CharSequence to check, may be null 1571 * @param searchStr the CharSequence to find, may be null 1572 * @return the first index of the search CharSequence, 1573 * -1 if no match or {@code null} string input 1574 * @since 2.5 1575 * @since 3.0 Changed signature from indexOfIgnoreCase(String, String) to indexOfIgnoreCase(CharSequence, CharSequence) 1576 */ 1577 public static int indexOfIgnoreCase(final CharSequence str, final CharSequence searchStr) { 1578 return indexOfIgnoreCase(str, searchStr, 0); 1579 } 1580 1581 /** 1582 * <p>Case in-sensitive find of the first index within a CharSequence 1583 * from the specified position.</p> 1584 * 1585 * <p>A {@code null} CharSequence will return {@code -1}. 1586 * A negative start position is treated as zero. 1587 * An empty ("") search CharSequence always matches. 1588 * A start position greater than the string length only matches 1589 * an empty search CharSequence.</p> 1590 * 1591 * <pre> 1592 * StringUtils.indexOfIgnoreCase(null, *, *) = -1 1593 * StringUtils.indexOfIgnoreCase(*, null, *) = -1 1594 * StringUtils.indexOfIgnoreCase("", "", 0) = 0 1595 * StringUtils.indexOfIgnoreCase("aabaabaa", "A", 0) = 0 1596 * StringUtils.indexOfIgnoreCase("aabaabaa", "B", 0) = 2 1597 * StringUtils.indexOfIgnoreCase("aabaabaa", "AB", 0) = 1 1598 * StringUtils.indexOfIgnoreCase("aabaabaa", "B", 3) = 5 1599 * StringUtils.indexOfIgnoreCase("aabaabaa", "B", 9) = -1 1600 * StringUtils.indexOfIgnoreCase("aabaabaa", "B", -1) = 2 1601 * StringUtils.indexOfIgnoreCase("aabaabaa", "", 2) = 2 1602 * StringUtils.indexOfIgnoreCase("abc", "", 9) = -1 1603 * </pre> 1604 * 1605 * @param str the CharSequence to check, may be null 1606 * @param searchStr the CharSequence to find, may be null 1607 * @param startPos the start position, negative treated as zero 1608 * @return the first index of the search CharSequence (always ≥ startPos), 1609 * -1 if no match or {@code null} string input 1610 * @since 2.5 1611 * @since 3.0 Changed signature from indexOfIgnoreCase(String, String, int) to indexOfIgnoreCase(CharSequence, CharSequence, int) 1612 */ 1613 public static int indexOfIgnoreCase(final CharSequence str, final CharSequence searchStr, int startPos) { 1614 if (str == null || searchStr == null) { 1615 return INDEX_NOT_FOUND; 1616 } 1617 if (startPos < 0) { 1618 startPos = 0; 1619 } 1620 final int endLimit = str.length() - searchStr.length() + 1; 1621 if (startPos > endLimit) { 1622 return INDEX_NOT_FOUND; 1623 } 1624 if (searchStr.length() == 0) { 1625 return startPos; 1626 } 1627 for (int i = startPos; i < endLimit; i++) { 1628 if (CharSequenceUtils.regionMatches(str, true, i, searchStr, 0, searchStr.length())) { 1629 return i; 1630 } 1631 } 1632 return INDEX_NOT_FOUND; 1633 } 1634 1635 // LastIndexOf 1636 //----------------------------------------------------------------------- 1637 /** 1638 * Returns the index within <code>seq</code> of the last occurrence of 1639 * the specified character. For values of <code>searchChar</code> in the 1640 * range from 0 to 0xFFFF (inclusive), the index (in Unicode code 1641 * units) returned is the largest value <i>k</i> such that: 1642 * <blockquote><pre> 1643 * this.charAt(<i>k</i>) == searchChar 1644 * </pre></blockquote> 1645 * is true. For other values of <code>searchChar</code>, it is the 1646 * largest value <i>k</i> such that: 1647 * <blockquote><pre> 1648 * this.codePointAt(<i>k</i>) == searchChar 1649 * </pre></blockquote> 1650 * is true. In either case, if no such character occurs in this 1651 * string, then <code>-1</code> is returned. Furthermore, a {@code null} or empty ("") 1652 * <code>CharSequence</code> will return {@code -1}. The 1653 * <code>seq</code> <code>CharSequence</code> object is searched backwards 1654 * starting at the last character. 1655 * 1656 * <pre> 1657 * StringUtils.lastIndexOf(null, *) = -1 1658 * StringUtils.lastIndexOf("", *) = -1 1659 * StringUtils.lastIndexOf("aabaabaa", 'a') = 7 1660 * StringUtils.lastIndexOf("aabaabaa", 'b') = 5 1661 * </pre> 1662 * 1663 * @param seq the <code>CharSequence</code> to check, may be null 1664 * @param searchChar the character to find 1665 * @return the last index of the search character, 1666 * -1 if no match or {@code null} string input 1667 * @since 2.0 1668 * @since 3.0 Changed signature from lastIndexOf(String, int) to lastIndexOf(CharSequence, int) 1669 * @since 3.6 Updated {@link CharSequenceUtils} call to behave more like <code>String</code> 1670 */ 1671 public static int lastIndexOf(final CharSequence seq, final int searchChar) { 1672 if (isEmpty(seq)) { 1673 return INDEX_NOT_FOUND; 1674 } 1675 return CharSequenceUtils.lastIndexOf(seq, searchChar, seq.length()); 1676 } 1677 1678 /** 1679 * Returns the index within <code>seq</code> of the last occurrence of 1680 * the specified character, searching backward starting at the 1681 * specified index. For values of <code>searchChar</code> in the range 1682 * from 0 to 0xFFFF (inclusive), the index returned is the largest 1683 * value <i>k</i> such that: 1684 * <blockquote><pre> 1685 * (this.charAt(<i>k</i>) == searchChar) && (<i>k</i> <= startPos) 1686 * </pre></blockquote> 1687 * is true. For other values of <code>searchChar</code>, it is the 1688 * largest value <i>k</i> such that: 1689 * <blockquote><pre> 1690 * (this.codePointAt(<i>k</i>) == searchChar) && (<i>k</i> <= startPos) 1691 * </pre></blockquote> 1692 * is true. In either case, if no such character occurs in <code>seq</code> 1693 * at or before position <code>startPos</code>, then 1694 * <code>-1</code> is returned. Furthermore, a {@code null} or empty ("") 1695 * <code>CharSequence</code> will return {@code -1}. A start position greater 1696 * than the string length searches the whole string. 1697 * The search starts at the <code>startPos</code> and works backwards; 1698 * matches starting after the start position are ignored. 1699 * 1700 * <p>All indices are specified in <code>char</code> values 1701 * (Unicode code units). 1702 * 1703 * <pre> 1704 * StringUtils.lastIndexOf(null, *, *) = -1 1705 * StringUtils.lastIndexOf("", *, *) = -1 1706 * StringUtils.lastIndexOf("aabaabaa", 'b', 8) = 5 1707 * StringUtils.lastIndexOf("aabaabaa", 'b', 4) = 2 1708 * StringUtils.lastIndexOf("aabaabaa", 'b', 0) = -1 1709 * StringUtils.lastIndexOf("aabaabaa", 'b', 9) = 5 1710 * StringUtils.lastIndexOf("aabaabaa", 'b', -1) = -1 1711 * StringUtils.lastIndexOf("aabaabaa", 'a', 0) = 0 1712 * </pre> 1713 * 1714 * @param seq the CharSequence to check, may be null 1715 * @param searchChar the character to find 1716 * @param startPos the start position 1717 * @return the last index of the search character (always ≤ startPos), 1718 * -1 if no match or {@code null} string input 1719 * @since 2.0 1720 * @since 3.0 Changed signature from lastIndexOf(String, int, int) to lastIndexOf(CharSequence, int, int) 1721 */ 1722 public static int lastIndexOf(final CharSequence seq, final int searchChar, final int startPos) { 1723 if (isEmpty(seq)) { 1724 return INDEX_NOT_FOUND; 1725 } 1726 return CharSequenceUtils.lastIndexOf(seq, searchChar, startPos); 1727 } 1728 1729 /** 1730 * <p>Finds the last index within a CharSequence, handling {@code null}. 1731 * This method uses {@link String#lastIndexOf(String)} if possible.</p> 1732 * 1733 * <p>A {@code null} CharSequence will return {@code -1}.</p> 1734 * 1735 * <pre> 1736 * StringUtils.lastIndexOf(null, *) = -1 1737 * StringUtils.lastIndexOf(*, null) = -1 1738 * StringUtils.lastIndexOf("", "") = 0 1739 * StringUtils.lastIndexOf("aabaabaa", "a") = 7 1740 * StringUtils.lastIndexOf("aabaabaa", "b") = 5 1741 * StringUtils.lastIndexOf("aabaabaa", "ab") = 4 1742 * StringUtils.lastIndexOf("aabaabaa", "") = 8 1743 * </pre> 1744 * 1745 * @param seq the CharSequence to check, may be null 1746 * @param searchSeq the CharSequence to find, may be null 1747 * @return the last index of the search String, 1748 * -1 if no match or {@code null} string input 1749 * @since 2.0 1750 * @since 3.0 Changed signature from lastIndexOf(String, String) to lastIndexOf(CharSequence, CharSequence) 1751 */ 1752 public static int lastIndexOf(final CharSequence seq, final CharSequence searchSeq) { 1753 if (seq == null || searchSeq == null) { 1754 return INDEX_NOT_FOUND; 1755 } 1756 return CharSequenceUtils.lastIndexOf(seq, searchSeq, seq.length()); 1757 } 1758 1759 /** 1760 * <p>Finds the n-th last index within a String, handling {@code null}. 1761 * This method uses {@link String#lastIndexOf(String)}.</p> 1762 * 1763 * <p>A {@code null} String will return {@code -1}.</p> 1764 * 1765 * <pre> 1766 * StringUtils.lastOrdinalIndexOf(null, *, *) = -1 1767 * StringUtils.lastOrdinalIndexOf(*, null, *) = -1 1768 * StringUtils.lastOrdinalIndexOf("", "", *) = 0 1769 * StringUtils.lastOrdinalIndexOf("aabaabaa", "a", 1) = 7 1770 * StringUtils.lastOrdinalIndexOf("aabaabaa", "a", 2) = 6 1771 * StringUtils.lastOrdinalIndexOf("aabaabaa", "b", 1) = 5 1772 * StringUtils.lastOrdinalIndexOf("aabaabaa", "b", 2) = 2 1773 * StringUtils.lastOrdinalIndexOf("aabaabaa", "ab", 1) = 4 1774 * StringUtils.lastOrdinalIndexOf("aabaabaa", "ab", 2) = 1 1775 * StringUtils.lastOrdinalIndexOf("aabaabaa", "", 1) = 8 1776 * StringUtils.lastOrdinalIndexOf("aabaabaa", "", 2) = 8 1777 * </pre> 1778 * 1779 * <p>Note that 'tail(CharSequence str, int n)' may be implemented as: </p> 1780 * 1781 * <pre> 1782 * str.substring(lastOrdinalIndexOf(str, "\n", n) + 1) 1783 * </pre> 1784 * 1785 * @param str the CharSequence to check, may be null 1786 * @param searchStr the CharSequence to find, may be null 1787 * @param ordinal the n-th last {@code searchStr} to find 1788 * @return the n-th last index of the search CharSequence, 1789 * {@code -1} ({@code INDEX_NOT_FOUND}) if no match or {@code null} string input 1790 * @since 2.5 1791 * @since 3.0 Changed signature from lastOrdinalIndexOf(String, String, int) to lastOrdinalIndexOf(CharSequence, CharSequence, int) 1792 */ 1793 public static int lastOrdinalIndexOf(final CharSequence str, final CharSequence searchStr, final int ordinal) { 1794 return ordinalIndexOf(str, searchStr, ordinal, true); 1795 } 1796 1797 /** 1798 * <p>Finds the last index within a CharSequence, handling {@code null}. 1799 * This method uses {@link String#lastIndexOf(String, int)} if possible.</p> 1800 * 1801 * <p>A {@code null} CharSequence will return {@code -1}. 1802 * A negative start position returns {@code -1}. 1803 * An empty ("") search CharSequence always matches unless the start position is negative. 1804 * A start position greater than the string length searches the whole string. 1805 * The search starts at the startPos and works backwards; matches starting after the start 1806 * position are ignored. 1807 * </p> 1808 * 1809 * <pre> 1810 * StringUtils.lastIndexOf(null, *, *) = -1 1811 * StringUtils.lastIndexOf(*, null, *) = -1 1812 * StringUtils.lastIndexOf("aabaabaa", "a", 8) = 7 1813 * StringUtils.lastIndexOf("aabaabaa", "b", 8) = 5 1814 * StringUtils.lastIndexOf("aabaabaa", "ab", 8) = 4 1815 * StringUtils.lastIndexOf("aabaabaa", "b", 9) = 5 1816 * StringUtils.lastIndexOf("aabaabaa", "b", -1) = -1 1817 * StringUtils.lastIndexOf("aabaabaa", "a", 0) = 0 1818 * StringUtils.lastIndexOf("aabaabaa", "b", 0) = -1 1819 * StringUtils.lastIndexOf("aabaabaa", "b", 1) = -1 1820 * StringUtils.lastIndexOf("aabaabaa", "b", 2) = 2 1821 * StringUtils.lastIndexOf("aabaabaa", "ba", 2) = -1 1822 * StringUtils.lastIndexOf("aabaabaa", "ba", 2) = 2 1823 * </pre> 1824 * 1825 * @param seq the CharSequence to check, may be null 1826 * @param searchSeq the CharSequence to find, may be null 1827 * @param startPos the start position, negative treated as zero 1828 * @return the last index of the search CharSequence (always ≤ startPos), 1829 * -1 if no match or {@code null} string input 1830 * @since 2.0 1831 * @since 3.0 Changed signature from lastIndexOf(String, String, int) to lastIndexOf(CharSequence, CharSequence, int) 1832 */ 1833 public static int lastIndexOf(final CharSequence seq, final CharSequence searchSeq, final int startPos) { 1834 if (seq == null || searchSeq == null) { 1835 return INDEX_NOT_FOUND; 1836 } 1837 return CharSequenceUtils.lastIndexOf(seq, searchSeq, startPos); 1838 } 1839 1840 /** 1841 * <p>Case in-sensitive find of the last index within a CharSequence.</p> 1842 * 1843 * <p>A {@code null} CharSequence will return {@code -1}. 1844 * A negative start position returns {@code -1}. 1845 * An empty ("") search CharSequence always matches unless the start position is negative. 1846 * A start position greater than the string length searches the whole string.</p> 1847 * 1848 * <pre> 1849 * StringUtils.lastIndexOfIgnoreCase(null, *) = -1 1850 * StringUtils.lastIndexOfIgnoreCase(*, null) = -1 1851 * StringUtils.lastIndexOfIgnoreCase("aabaabaa", "A") = 7 1852 * StringUtils.lastIndexOfIgnoreCase("aabaabaa", "B") = 5 1853 * StringUtils.lastIndexOfIgnoreCase("aabaabaa", "AB") = 4 1854 * </pre> 1855 * 1856 * @param str the CharSequence to check, may be null 1857 * @param searchStr the CharSequence to find, may be null 1858 * @return the first index of the search CharSequence, 1859 * -1 if no match or {@code null} string input 1860 * @since 2.5 1861 * @since 3.0 Changed signature from lastIndexOfIgnoreCase(String, String) to lastIndexOfIgnoreCase(CharSequence, CharSequence) 1862 */ 1863 public static int lastIndexOfIgnoreCase(final CharSequence str, final CharSequence searchStr) { 1864 if (str == null || searchStr == null) { 1865 return INDEX_NOT_FOUND; 1866 } 1867 return lastIndexOfIgnoreCase(str, searchStr, str.length()); 1868 } 1869 1870 /** 1871 * <p>Case in-sensitive find of the last index within a CharSequence 1872 * from the specified position.</p> 1873 * 1874 * <p>A {@code null} CharSequence will return {@code -1}. 1875 * A negative start position returns {@code -1}. 1876 * An empty ("") search CharSequence always matches unless the start position is negative. 1877 * A start position greater than the string length searches the whole string. 1878 * The search starts at the startPos and works backwards; matches starting after the start 1879 * position are ignored. 1880 * </p> 1881 * 1882 * <pre> 1883 * StringUtils.lastIndexOfIgnoreCase(null, *, *) = -1 1884 * StringUtils.lastIndexOfIgnoreCase(*, null, *) = -1 1885 * StringUtils.lastIndexOfIgnoreCase("aabaabaa", "A", 8) = 7 1886 * StringUtils.lastIndexOfIgnoreCase("aabaabaa", "B", 8) = 5 1887 * StringUtils.lastIndexOfIgnoreCase("aabaabaa", "AB", 8) = 4 1888 * StringUtils.lastIndexOfIgnoreCase("aabaabaa", "B", 9) = 5 1889 * StringUtils.lastIndexOfIgnoreCase("aabaabaa", "B", -1) = -1 1890 * StringUtils.lastIndexOfIgnoreCase("aabaabaa", "A", 0) = 0 1891 * StringUtils.lastIndexOfIgnoreCase("aabaabaa", "B", 0) = -1 1892 * </pre> 1893 * 1894 * @param str the CharSequence to check, may be null 1895 * @param searchStr the CharSequence to find, may be null 1896 * @param startPos the start position 1897 * @return the last index of the search CharSequence (always ≤ startPos), 1898 * -1 if no match or {@code null} input 1899 * @since 2.5 1900 * @since 3.0 Changed signature from lastIndexOfIgnoreCase(String, String, int) to lastIndexOfIgnoreCase(CharSequence, CharSequence, int) 1901 */ 1902 public static int lastIndexOfIgnoreCase(final CharSequence str, final CharSequence searchStr, int startPos) { 1903 if (str == null || searchStr == null) { 1904 return INDEX_NOT_FOUND; 1905 } 1906 if (startPos > str.length() - searchStr.length()) { 1907 startPos = str.length() - searchStr.length(); 1908 } 1909 if (startPos < 0) { 1910 return INDEX_NOT_FOUND; 1911 } 1912 if (searchStr.length() == 0) { 1913 return startPos; 1914 } 1915 1916 for (int i = startPos; i >= 0; i--) { 1917 if (CharSequenceUtils.regionMatches(str, true, i, searchStr, 0, searchStr.length())) { 1918 return i; 1919 } 1920 } 1921 return INDEX_NOT_FOUND; 1922 } 1923 1924 // Contains 1925 //----------------------------------------------------------------------- 1926 /** 1927 * <p>Checks if CharSequence contains a search character, handling {@code null}. 1928 * This method uses {@link String#indexOf(int)} if possible.</p> 1929 * 1930 * <p>A {@code null} or empty ("") CharSequence will return {@code false}.</p> 1931 * 1932 * <pre> 1933 * StringUtils.contains(null, *) = false 1934 * StringUtils.contains("", *) = false 1935 * StringUtils.contains("abc", 'a') = true 1936 * StringUtils.contains("abc", 'z') = false 1937 * </pre> 1938 * 1939 * @param seq the CharSequence to check, may be null 1940 * @param searchChar the character to find 1941 * @return true if the CharSequence contains the search character, 1942 * false if not or {@code null} string input 1943 * @since 2.0 1944 * @since 3.0 Changed signature from contains(String, int) to contains(CharSequence, int) 1945 */ 1946 public static boolean contains(final CharSequence seq, final int searchChar) { 1947 if (isEmpty(seq)) { 1948 return false; 1949 } 1950 return CharSequenceUtils.indexOf(seq, searchChar, 0) >= 0; 1951 } 1952 1953 /** 1954 * <p>Checks if CharSequence contains a search CharSequence, handling {@code null}. 1955 * This method uses {@link String#indexOf(String)} if possible.</p> 1956 * 1957 * <p>A {@code null} CharSequence will return {@code false}.</p> 1958 * 1959 * <pre> 1960 * StringUtils.contains(null, *) = false 1961 * StringUtils.contains(*, null) = false 1962 * StringUtils.contains("", "") = true 1963 * StringUtils.contains("abc", "") = true 1964 * StringUtils.contains("abc", "a") = true 1965 * StringUtils.contains("abc", "z") = false 1966 * </pre> 1967 * 1968 * @param seq the CharSequence to check, may be null 1969 * @param searchSeq the CharSequence to find, may be null 1970 * @return true if the CharSequence contains the search CharSequence, 1971 * false if not or {@code null} string input 1972 * @since 2.0 1973 * @since 3.0 Changed signature from contains(String, String) to contains(CharSequence, CharSequence) 1974 */ 1975 public static boolean contains(final CharSequence seq, final CharSequence searchSeq) { 1976 if (seq == null || searchSeq == null) { 1977 return false; 1978 } 1979 return CharSequenceUtils.indexOf(seq, searchSeq, 0) >= 0; 1980 } 1981 1982 /** 1983 * <p>Checks if CharSequence contains a search CharSequence irrespective of case, 1984 * handling {@code null}. Case-insensitivity is defined as by 1985 * {@link String#equalsIgnoreCase(String)}. 1986 * 1987 * <p>A {@code null} CharSequence will return {@code false}.</p> 1988 * 1989 * <pre> 1990 * StringUtils.containsIgnoreCase(null, *) = false 1991 * StringUtils.containsIgnoreCase(*, null) = false 1992 * StringUtils.containsIgnoreCase("", "") = true 1993 * StringUtils.containsIgnoreCase("abc", "") = true 1994 * StringUtils.containsIgnoreCase("abc", "a") = true 1995 * StringUtils.containsIgnoreCase("abc", "z") = false 1996 * StringUtils.containsIgnoreCase("abc", "A") = true 1997 * StringUtils.containsIgnoreCase("abc", "Z") = false 1998 * </pre> 1999 * 2000 * @param str the CharSequence to check, may be null 2001 * @param searchStr the CharSequence to find, may be null 2002 * @return true if the CharSequence contains the search CharSequence irrespective of 2003 * case or false if not or {@code null} string input 2004 * @since 3.0 Changed signature from containsIgnoreCase(String, String) to containsIgnoreCase(CharSequence, CharSequence) 2005 */ 2006 public static boolean containsIgnoreCase(final CharSequence str, final CharSequence searchStr) { 2007 if (str == null || searchStr == null) { 2008 return false; 2009 } 2010 final int len = searchStr.length(); 2011 final int max = str.length() - len; 2012 for (int i = 0; i <= max; i++) { 2013 if (CharSequenceUtils.regionMatches(str, true, i, searchStr, 0, len)) { 2014 return true; 2015 } 2016 } 2017 return false; 2018 } 2019 2020 /** 2021 * <p>Check whether the given CharSequence contains any whitespace characters.</p> 2022 * 2023 * <p>Whitespace is defined by {@link Character#isWhitespace(char)}.</p> 2024 * 2025 * @param seq the CharSequence to check (may be {@code null}) 2026 * @return {@code true} if the CharSequence is not empty and 2027 * contains at least 1 (breaking) whitespace character 2028 * @since 3.0 2029 */ 2030 // From org.springframework.util.StringUtils, under Apache License 2.0 2031 public static boolean containsWhitespace(final CharSequence seq) { 2032 if (isEmpty(seq)) { 2033 return false; 2034 } 2035 final int strLen = seq.length(); 2036 for (int i = 0; i < strLen; i++) { 2037 if (Character.isWhitespace(seq.charAt(i))) { 2038 return true; 2039 } 2040 } 2041 return false; 2042 } 2043 2044 // IndexOfAny chars 2045 //----------------------------------------------------------------------- 2046 /** 2047 * <p>Search a CharSequence to find the first index of any 2048 * character in the given set of characters.</p> 2049 * 2050 * <p>A {@code null} String will return {@code -1}. 2051 * A {@code null} or zero length search array will return {@code -1}.</p> 2052 * 2053 * <pre> 2054 * StringUtils.indexOfAny(null, *) = -1 2055 * StringUtils.indexOfAny("", *) = -1 2056 * StringUtils.indexOfAny(*, null) = -1 2057 * StringUtils.indexOfAny(*, []) = -1 2058 * StringUtils.indexOfAny("zzabyycdxx",['z','a']) = 0 2059 * StringUtils.indexOfAny("zzabyycdxx",['b','y']) = 3 2060 * StringUtils.indexOfAny("aba", ['z']) = -1 2061 * </pre> 2062 * 2063 * @param cs the CharSequence to check, may be null 2064 * @param searchChars the chars to search for, may be null 2065 * @return the index of any of the chars, -1 if no match or null input 2066 * @since 2.0 2067 * @since 3.0 Changed signature from indexOfAny(String, char[]) to indexOfAny(CharSequence, char...) 2068 */ 2069 public static int indexOfAny(final CharSequence cs, final char... searchChars) { 2070 if (isEmpty(cs) || ArrayUtils.isEmpty(searchChars)) { 2071 return INDEX_NOT_FOUND; 2072 } 2073 final int csLen = cs.length(); 2074 final int csLast = csLen - 1; 2075 final int searchLen = searchChars.length; 2076 final int searchLast = searchLen - 1; 2077 for (int i = 0; i < csLen; i++) { 2078 final char ch = cs.charAt(i); 2079 for (int j = 0; j < searchLen; j++) { 2080 if (searchChars[j] == ch) { 2081 if (i < csLast && j < searchLast && Character.isHighSurrogate(ch)) { 2082 // ch is a supplementary character 2083 if (searchChars[j + 1] == cs.charAt(i + 1)) { 2084 return i; 2085 } 2086 } else { 2087 return i; 2088 } 2089 } 2090 } 2091 } 2092 return INDEX_NOT_FOUND; 2093 } 2094 2095 /** 2096 * <p>Search a CharSequence to find the first index of any 2097 * character in the given set of characters.</p> 2098 * 2099 * <p>A {@code null} String will return {@code -1}. 2100 * A {@code null} search string will return {@code -1}.</p> 2101 * 2102 * <pre> 2103 * StringUtils.indexOfAny(null, *) = -1 2104 * StringUtils.indexOfAny("", *) = -1 2105 * StringUtils.indexOfAny(*, null) = -1 2106 * StringUtils.indexOfAny(*, "") = -1 2107 * StringUtils.indexOfAny("zzabyycdxx", "za") = 0 2108 * StringUtils.indexOfAny("zzabyycdxx", "by") = 3 2109 * StringUtils.indexOfAny("aba","z") = -1 2110 * </pre> 2111 * 2112 * @param cs the CharSequence to check, may be null 2113 * @param searchChars the chars to search for, may be null 2114 * @return the index of any of the chars, -1 if no match or null input 2115 * @since 2.0 2116 * @since 3.0 Changed signature from indexOfAny(String, String) to indexOfAny(CharSequence, String) 2117 */ 2118 public static int indexOfAny(final CharSequence cs, final String searchChars) { 2119 if (isEmpty(cs) || isEmpty(searchChars)) { 2120 return INDEX_NOT_FOUND; 2121 } 2122 return indexOfAny(cs, searchChars.toCharArray()); 2123 } 2124 2125 // ContainsAny 2126 //----------------------------------------------------------------------- 2127 /** 2128 * <p>Checks if the CharSequence contains any character in the given 2129 * set of characters.</p> 2130 * 2131 * <p>A {@code null} CharSequence will return {@code false}. 2132 * A {@code null} or zero length search array will return {@code false}.</p> 2133 * 2134 * <pre> 2135 * StringUtils.containsAny(null, *) = false 2136 * StringUtils.containsAny("", *) = false 2137 * StringUtils.containsAny(*, null) = false 2138 * StringUtils.containsAny(*, []) = false 2139 * StringUtils.containsAny("zzabyycdxx",['z','a']) = true 2140 * StringUtils.containsAny("zzabyycdxx",['b','y']) = true 2141 * StringUtils.containsAny("zzabyycdxx",['z','y']) = true 2142 * StringUtils.containsAny("aba", ['z']) = false 2143 * </pre> 2144 * 2145 * @param cs the CharSequence to check, may be null 2146 * @param searchChars the chars to search for, may be null 2147 * @return the {@code true} if any of the chars are found, 2148 * {@code false} if no match or null input 2149 * @since 2.4 2150 * @since 3.0 Changed signature from containsAny(String, char[]) to containsAny(CharSequence, char...) 2151 */ 2152 public static boolean containsAny(final CharSequence cs, final char... searchChars) { 2153 if (isEmpty(cs) || ArrayUtils.isEmpty(searchChars)) { 2154 return false; 2155 } 2156 final int csLength = cs.length(); 2157 final int searchLength = searchChars.length; 2158 final int csLast = csLength - 1; 2159 final int searchLast = searchLength - 1; 2160 for (int i = 0; i < csLength; i++) { 2161 final char ch = cs.charAt(i); 2162 for (int j = 0; j < searchLength; j++) { 2163 if (searchChars[j] == ch) { 2164 if (Character.isHighSurrogate(ch)) { 2165 if (j == searchLast) { 2166 // missing low surrogate, fine, like String.indexOf(String) 2167 return true; 2168 } 2169 if (i < csLast && searchChars[j + 1] == cs.charAt(i + 1)) { 2170 return true; 2171 } 2172 } else { 2173 // ch is in the Basic Multilingual Plane 2174 return true; 2175 } 2176 } 2177 } 2178 } 2179 return false; 2180 } 2181 2182 /** 2183 * <p> 2184 * Checks if the CharSequence contains any character in the given set of characters. 2185 * </p> 2186 * 2187 * <p> 2188 * A {@code null} CharSequence will return {@code false}. A {@code null} search CharSequence will return 2189 * {@code false}. 2190 * </p> 2191 * 2192 * <pre> 2193 * StringUtils.containsAny(null, *) = false 2194 * StringUtils.containsAny("", *) = false 2195 * StringUtils.containsAny(*, null) = false 2196 * StringUtils.containsAny(*, "") = false 2197 * StringUtils.containsAny("zzabyycdxx", "za") = true 2198 * StringUtils.containsAny("zzabyycdxx", "by") = true 2199 * StringUtils.containsAny("zzabyycdxx", "zy") = true 2200 * StringUtils.containsAny("zzabyycdxx", "\tx") = true 2201 * StringUtils.containsAny("zzabyycdxx", "$.#yF") = true 2202 * StringUtils.containsAny("aba","z") = false 2203 * </pre> 2204 * 2205 * @param cs 2206 * the CharSequence to check, may be null 2207 * @param searchChars 2208 * the chars to search for, may be null 2209 * @return the {@code true} if any of the chars are found, {@code false} if no match or null input 2210 * @since 2.4 2211 * @since 3.0 Changed signature from containsAny(String, String) to containsAny(CharSequence, CharSequence) 2212 */ 2213 public static boolean containsAny(final CharSequence cs, final CharSequence searchChars) { 2214 if (searchChars == null) { 2215 return false; 2216 } 2217 return containsAny(cs, CharSequenceUtils.toCharArray(searchChars)); 2218 } 2219 2220 /** 2221 * <p>Checks if the CharSequence contains any of the CharSequences in the given array.</p> 2222 * 2223 * <p> 2224 * A {@code null} {@code cs} CharSequence will return {@code false}. A {@code null} or zero 2225 * length search array will return {@code false}. 2226 * </p> 2227 * 2228 * <pre> 2229 * StringUtils.containsAny(null, *) = false 2230 * StringUtils.containsAny("", *) = false 2231 * StringUtils.containsAny(*, null) = false 2232 * StringUtils.containsAny(*, []) = false 2233 * StringUtils.containsAny("abcd", "ab", null) = true 2234 * StringUtils.containsAny("abcd", "ab", "cd") = true 2235 * StringUtils.containsAny("abc", "d", "abc") = true 2236 * </pre> 2237 * 2238 * 2239 * @param cs The CharSequence to check, may be null 2240 * @param searchCharSequences The array of CharSequences to search for, may be null. 2241 * Individual CharSequences may be null as well. 2242 * @return {@code true} if any of the search CharSequences are found, {@code false} otherwise 2243 * @since 3.4 2244 */ 2245 public static boolean containsAny(final CharSequence cs, final CharSequence... searchCharSequences) { 2246 if (isEmpty(cs) || ArrayUtils.isEmpty(searchCharSequences)) { 2247 return false; 2248 } 2249 for (final CharSequence searchCharSequence : searchCharSequences) { 2250 if (contains(cs, searchCharSequence)) { 2251 return true; 2252 } 2253 } 2254 return false; 2255 } 2256 2257 // IndexOfAnyBut chars 2258 //----------------------------------------------------------------------- 2259 /** 2260 * <p>Searches a CharSequence to find the first index of any 2261 * character not in the given set of characters.</p> 2262 * 2263 * <p>A {@code null} CharSequence will return {@code -1}. 2264 * A {@code null} or zero length search array will return {@code -1}.</p> 2265 * 2266 * <pre> 2267 * StringUtils.indexOfAnyBut(null, *) = -1 2268 * StringUtils.indexOfAnyBut("", *) = -1 2269 * StringUtils.indexOfAnyBut(*, null) = -1 2270 * StringUtils.indexOfAnyBut(*, []) = -1 2271 * StringUtils.indexOfAnyBut("zzabyycdxx", new char[] {'z', 'a'} ) = 3 2272 * StringUtils.indexOfAnyBut("aba", new char[] {'z'} ) = 0 2273 * StringUtils.indexOfAnyBut("aba", new char[] {'a', 'b'} ) = -1 2274 2275 * </pre> 2276 * 2277 * @param cs the CharSequence to check, may be null 2278 * @param searchChars the chars to search for, may be null 2279 * @return the index of any of the chars, -1 if no match or null input 2280 * @since 2.0 2281 * @since 3.0 Changed signature from indexOfAnyBut(String, char[]) to indexOfAnyBut(CharSequence, char...) 2282 */ 2283 public static int indexOfAnyBut(final CharSequence cs, final char... searchChars) { 2284 if (isEmpty(cs) || ArrayUtils.isEmpty(searchChars)) { 2285 return INDEX_NOT_FOUND; 2286 } 2287 final int csLen = cs.length(); 2288 final int csLast = csLen - 1; 2289 final int searchLen = searchChars.length; 2290 final int searchLast = searchLen - 1; 2291 outer: 2292 for (int i = 0; i < csLen; i++) { 2293 final char ch = cs.charAt(i); 2294 for (int j = 0; j < searchLen; j++) { 2295 if (searchChars[j] == ch) { 2296 if (i < csLast && j < searchLast && Character.isHighSurrogate(ch)) { 2297 if (searchChars[j + 1] == cs.charAt(i + 1)) { 2298 continue outer; 2299 } 2300 } else { 2301 continue outer; 2302 } 2303 } 2304 } 2305 return i; 2306 } 2307 return INDEX_NOT_FOUND; 2308 } 2309 2310 /** 2311 * <p>Search a CharSequence to find the first index of any 2312 * character not in the given set of characters.</p> 2313 * 2314 * <p>A {@code null} CharSequence will return {@code -1}. 2315 * A {@code null} or empty search string will return {@code -1}.</p> 2316 * 2317 * <pre> 2318 * StringUtils.indexOfAnyBut(null, *) = -1 2319 * StringUtils.indexOfAnyBut("", *) = -1 2320 * StringUtils.indexOfAnyBut(*, null) = -1 2321 * StringUtils.indexOfAnyBut(*, "") = -1 2322 * StringUtils.indexOfAnyBut("zzabyycdxx", "za") = 3 2323 * StringUtils.indexOfAnyBut("zzabyycdxx", "") = -1 2324 * StringUtils.indexOfAnyBut("aba","ab") = -1 2325 * </pre> 2326 * 2327 * @param seq the CharSequence to check, may be null 2328 * @param searchChars the chars to search for, may be null 2329 * @return the index of any of the chars, -1 if no match or null input 2330 * @since 2.0 2331 * @since 3.0 Changed signature from indexOfAnyBut(String, String) to indexOfAnyBut(CharSequence, CharSequence) 2332 */ 2333 public static int indexOfAnyBut(final CharSequence seq, final CharSequence searchChars) { 2334 if (isEmpty(seq) || isEmpty(searchChars)) { 2335 return INDEX_NOT_FOUND; 2336 } 2337 final int strLen = seq.length(); 2338 for (int i = 0; i < strLen; i++) { 2339 final char ch = seq.charAt(i); 2340 final boolean chFound = CharSequenceUtils.indexOf(searchChars, ch, 0) >= 0; 2341 if (i + 1 < strLen && Character.isHighSurrogate(ch)) { 2342 final char ch2 = seq.charAt(i + 1); 2343 if (chFound && CharSequenceUtils.indexOf(searchChars, ch2, 0) < 0) { 2344 return i; 2345 } 2346 } else { 2347 if (!chFound) { 2348 return i; 2349 } 2350 } 2351 } 2352 return INDEX_NOT_FOUND; 2353 } 2354 2355 // ContainsOnly 2356 //----------------------------------------------------------------------- 2357 /** 2358 * <p>Checks if the CharSequence contains only certain characters.</p> 2359 * 2360 * <p>A {@code null} CharSequence will return {@code false}. 2361 * A {@code null} valid character array will return {@code false}. 2362 * An empty CharSequence (length()=0) always returns {@code true}.</p> 2363 * 2364 * <pre> 2365 * StringUtils.containsOnly(null, *) = false 2366 * StringUtils.containsOnly(*, null) = false 2367 * StringUtils.containsOnly("", *) = true 2368 * StringUtils.containsOnly("ab", '') = false 2369 * StringUtils.containsOnly("abab", 'abc') = true 2370 * StringUtils.containsOnly("ab1", 'abc') = false 2371 * StringUtils.containsOnly("abz", 'abc') = false 2372 * </pre> 2373 * 2374 * @param cs the String to check, may be null 2375 * @param valid an array of valid chars, may be null 2376 * @return true if it only contains valid chars and is non-null 2377 * @since 3.0 Changed signature from containsOnly(String, char[]) to containsOnly(CharSequence, char...) 2378 */ 2379 public static boolean containsOnly(final CharSequence cs, final char... valid) { 2380 // All these pre-checks are to maintain API with an older version 2381 if (valid == null || cs == null) { 2382 return false; 2383 } 2384 if (cs.length() == 0) { 2385 return true; 2386 } 2387 if (valid.length == 0) { 2388 return false; 2389 } 2390 return indexOfAnyBut(cs, valid) == INDEX_NOT_FOUND; 2391 } 2392 2393 /** 2394 * <p>Checks if the CharSequence contains only certain characters.</p> 2395 * 2396 * <p>A {@code null} CharSequence will return {@code false}. 2397 * A {@code null} valid character String will return {@code false}. 2398 * An empty String (length()=0) always returns {@code true}.</p> 2399 * 2400 * <pre> 2401 * StringUtils.containsOnly(null, *) = false 2402 * StringUtils.containsOnly(*, null) = false 2403 * StringUtils.containsOnly("", *) = true 2404 * StringUtils.containsOnly("ab", "") = false 2405 * StringUtils.containsOnly("abab", "abc") = true 2406 * StringUtils.containsOnly("ab1", "abc") = false 2407 * StringUtils.containsOnly("abz", "abc") = false 2408 * </pre> 2409 * 2410 * @param cs the CharSequence to check, may be null 2411 * @param validChars a String of valid chars, may be null 2412 * @return true if it only contains valid chars and is non-null 2413 * @since 2.0 2414 * @since 3.0 Changed signature from containsOnly(String, String) to containsOnly(CharSequence, String) 2415 */ 2416 public static boolean containsOnly(final CharSequence cs, final String validChars) { 2417 if (cs == null || validChars == null) { 2418 return false; 2419 } 2420 return containsOnly(cs, validChars.toCharArray()); 2421 } 2422 2423 // ContainsNone 2424 //----------------------------------------------------------------------- 2425 /** 2426 * <p>Checks that the CharSequence does not contain certain characters.</p> 2427 * 2428 * <p>A {@code null} CharSequence will return {@code true}. 2429 * A {@code null} invalid character array will return {@code true}. 2430 * An empty CharSequence (length()=0) always returns true.</p> 2431 * 2432 * <pre> 2433 * StringUtils.containsNone(null, *) = true 2434 * StringUtils.containsNone(*, null) = true 2435 * StringUtils.containsNone("", *) = true 2436 * StringUtils.containsNone("ab", '') = true 2437 * StringUtils.containsNone("abab", 'xyz') = true 2438 * StringUtils.containsNone("ab1", 'xyz') = true 2439 * StringUtils.containsNone("abz", 'xyz') = false 2440 * </pre> 2441 * 2442 * @param cs the CharSequence to check, may be null 2443 * @param searchChars an array of invalid chars, may be null 2444 * @return true if it contains none of the invalid chars, or is null 2445 * @since 2.0 2446 * @since 3.0 Changed signature from containsNone(String, char[]) to containsNone(CharSequence, char...) 2447 */ 2448 public static boolean containsNone(final CharSequence cs, final char... searchChars) { 2449 if (cs == null || searchChars == null) { 2450 return true; 2451 } 2452 final int csLen = cs.length(); 2453 final int csLast = csLen - 1; 2454 final int searchLen = searchChars.length; 2455 final int searchLast = searchLen - 1; 2456 for (int i = 0; i < csLen; i++) { 2457 final char ch = cs.charAt(i); 2458 for (int j = 0; j < searchLen; j++) { 2459 if (searchChars[j] == ch) { 2460 if (Character.isHighSurrogate(ch)) { 2461 if (j == searchLast) { 2462 // missing low surrogate, fine, like String.indexOf(String) 2463 return false; 2464 } 2465 if (i < csLast && searchChars[j + 1] == cs.charAt(i + 1)) { 2466 return false; 2467 } 2468 } else { 2469 // ch is in the Basic Multilingual Plane 2470 return false; 2471 } 2472 } 2473 } 2474 } 2475 return true; 2476 } 2477 2478 /** 2479 * <p>Checks that the CharSequence does not contain certain characters.</p> 2480 * 2481 * <p>A {@code null} CharSequence will return {@code true}. 2482 * A {@code null} invalid character array will return {@code true}. 2483 * An empty String ("") always returns true.</p> 2484 * 2485 * <pre> 2486 * StringUtils.containsNone(null, *) = true 2487 * StringUtils.containsNone(*, null) = true 2488 * StringUtils.containsNone("", *) = true 2489 * StringUtils.containsNone("ab", "") = true 2490 * StringUtils.containsNone("abab", "xyz") = true 2491 * StringUtils.containsNone("ab1", "xyz") = true 2492 * StringUtils.containsNone("abz", "xyz") = false 2493 * </pre> 2494 * 2495 * @param cs the CharSequence to check, may be null 2496 * @param invalidChars a String of invalid chars, may be null 2497 * @return true if it contains none of the invalid chars, or is null 2498 * @since 2.0 2499 * @since 3.0 Changed signature from containsNone(String, String) to containsNone(CharSequence, String) 2500 */ 2501 public static boolean containsNone(final CharSequence cs, final String invalidChars) { 2502 if (cs == null || invalidChars == null) { 2503 return true; 2504 } 2505 return containsNone(cs, invalidChars.toCharArray()); 2506 } 2507 2508 // IndexOfAny strings 2509 //----------------------------------------------------------------------- 2510 /** 2511 * <p>Find the first index of any of a set of potential substrings.</p> 2512 * 2513 * <p>A {@code null} CharSequence will return {@code -1}. 2514 * A {@code null} or zero length search array will return {@code -1}. 2515 * A {@code null} search array entry will be ignored, but a search 2516 * array containing "" will return {@code 0} if {@code str} is not 2517 * null. This method uses {@link String#indexOf(String)} if possible.</p> 2518 * 2519 * <pre> 2520 * StringUtils.indexOfAny(null, *) = -1 2521 * StringUtils.indexOfAny(*, null) = -1 2522 * StringUtils.indexOfAny(*, []) = -1 2523 * StringUtils.indexOfAny("zzabyycdxx", ["ab","cd"]) = 2 2524 * StringUtils.indexOfAny("zzabyycdxx", ["cd","ab"]) = 2 2525 * StringUtils.indexOfAny("zzabyycdxx", ["mn","op"]) = -1 2526 * StringUtils.indexOfAny("zzabyycdxx", ["zab","aby"]) = 1 2527 * StringUtils.indexOfAny("zzabyycdxx", [""]) = 0 2528 * StringUtils.indexOfAny("", [""]) = 0 2529 * StringUtils.indexOfAny("", ["a"]) = -1 2530 * </pre> 2531 * 2532 * @param str the CharSequence to check, may be null 2533 * @param searchStrs the CharSequences to search for, may be null 2534 * @return the first index of any of the searchStrs in str, -1 if no match 2535 * @since 3.0 Changed signature from indexOfAny(String, String[]) to indexOfAny(CharSequence, CharSequence...) 2536 */ 2537 public static int indexOfAny(final CharSequence str, final CharSequence... searchStrs) { 2538 if (str == null || searchStrs == null) { 2539 return INDEX_NOT_FOUND; 2540 } 2541 2542 // String's can't have a MAX_VALUEth index. 2543 int ret = Integer.MAX_VALUE; 2544 2545 int tmp = 0; 2546 for (final CharSequence search : searchStrs) { 2547 if (search == null) { 2548 continue; 2549 } 2550 tmp = CharSequenceUtils.indexOf(str, search, 0); 2551 if (tmp == INDEX_NOT_FOUND) { 2552 continue; 2553 } 2554 2555 if (tmp < ret) { 2556 ret = tmp; 2557 } 2558 } 2559 2560 return ret == Integer.MAX_VALUE ? INDEX_NOT_FOUND : ret; 2561 } 2562 2563 /** 2564 * <p>Find the latest index of any of a set of potential substrings.</p> 2565 * 2566 * <p>A {@code null} CharSequence will return {@code -1}. 2567 * A {@code null} search array will return {@code -1}. 2568 * A {@code null} or zero length search array entry will be ignored, 2569 * but a search array containing "" will return the length of {@code str} 2570 * if {@code str} is not null. This method uses {@link String#indexOf(String)} if possible</p> 2571 * 2572 * <pre> 2573 * StringUtils.lastIndexOfAny(null, *) = -1 2574 * StringUtils.lastIndexOfAny(*, null) = -1 2575 * StringUtils.lastIndexOfAny(*, []) = -1 2576 * StringUtils.lastIndexOfAny(*, [null]) = -1 2577 * StringUtils.lastIndexOfAny("zzabyycdxx", ["ab","cd"]) = 6 2578 * StringUtils.lastIndexOfAny("zzabyycdxx", ["cd","ab"]) = 6 2579 * StringUtils.lastIndexOfAny("zzabyycdxx", ["mn","op"]) = -1 2580 * StringUtils.lastIndexOfAny("zzabyycdxx", ["mn","op"]) = -1 2581 * StringUtils.lastIndexOfAny("zzabyycdxx", ["mn",""]) = 10 2582 * </pre> 2583 * 2584 * @param str the CharSequence to check, may be null 2585 * @param searchStrs the CharSequences to search for, may be null 2586 * @return the last index of any of the CharSequences, -1 if no match 2587 * @since 3.0 Changed signature from lastIndexOfAny(String, String[]) to lastIndexOfAny(CharSequence, CharSequence) 2588 */ 2589 public static int lastIndexOfAny(final CharSequence str, final CharSequence... searchStrs) { 2590 if (str == null || searchStrs == null) { 2591 return INDEX_NOT_FOUND; 2592 } 2593 int ret = INDEX_NOT_FOUND; 2594 int tmp = 0; 2595 for (final CharSequence search : searchStrs) { 2596 if (search == null) { 2597 continue; 2598 } 2599 tmp = CharSequenceUtils.lastIndexOf(str, search, str.length()); 2600 if (tmp > ret) { 2601 ret = tmp; 2602 } 2603 } 2604 return ret; 2605 } 2606 2607 // Substring 2608 //----------------------------------------------------------------------- 2609 /** 2610 * <p>Gets a substring from the specified String avoiding exceptions.</p> 2611 * 2612 * <p>A negative start position can be used to start {@code n} 2613 * characters from the end of the String.</p> 2614 * 2615 * <p>A {@code null} String will return {@code null}. 2616 * An empty ("") String will return "".</p> 2617 * 2618 * <pre> 2619 * StringUtils.substring(null, *) = null 2620 * StringUtils.substring("", *) = "" 2621 * StringUtils.substring("abc", 0) = "abc" 2622 * StringUtils.substring("abc", 2) = "c" 2623 * StringUtils.substring("abc", 4) = "" 2624 * StringUtils.substring("abc", -2) = "bc" 2625 * StringUtils.substring("abc", -4) = "abc" 2626 * </pre> 2627 * 2628 * @param str the String to get the substring from, may be null 2629 * @param start the position to start from, negative means 2630 * count back from the end of the String by this many characters 2631 * @return substring from start position, {@code null} if null String input 2632 */ 2633 public static String substring(final String str, int start) { 2634 if (str == null) { 2635 return null; 2636 } 2637 2638 // handle negatives, which means last n characters 2639 if (start < 0) { 2640 start = str.length() + start; // remember start is negative 2641 } 2642 2643 if (start < 0) { 2644 start = 0; 2645 } 2646 if (start > str.length()) { 2647 return EMPTY; 2648 } 2649 2650 return str.substring(start); 2651 } 2652 2653 /** 2654 * <p>Gets a substring from the specified String avoiding exceptions.</p> 2655 * 2656 * <p>A negative start position can be used to start/end {@code n} 2657 * characters from the end of the String.</p> 2658 * 2659 * <p>The returned substring starts with the character in the {@code start} 2660 * position and ends before the {@code end} position. All position counting is 2661 * zero-based -- i.e., to start at the beginning of the string use 2662 * {@code start = 0}. Negative start and end positions can be used to 2663 * specify offsets relative to the end of the String.</p> 2664 * 2665 * <p>If {@code start} is not strictly to the left of {@code end}, "" 2666 * is returned.</p> 2667 * 2668 * <pre> 2669 * StringUtils.substring(null, *, *) = null 2670 * StringUtils.substring("", * , *) = ""; 2671 * StringUtils.substring("abc", 0, 2) = "ab" 2672 * StringUtils.substring("abc", 2, 0) = "" 2673 * StringUtils.substring("abc", 2, 4) = "c" 2674 * StringUtils.substring("abc", 4, 6) = "" 2675 * StringUtils.substring("abc", 2, 2) = "" 2676 * StringUtils.substring("abc", -2, -1) = "b" 2677 * StringUtils.substring("abc", -4, 2) = "ab" 2678 * </pre> 2679 * 2680 * @param str the String to get the substring from, may be null 2681 * @param start the position to start from, negative means 2682 * count back from the end of the String by this many characters 2683 * @param end the position to end at (exclusive), negative means 2684 * count back from the end of the String by this many characters 2685 * @return substring from start position to end position, 2686 * {@code null} if null String input 2687 */ 2688 public static String substring(final String str, int start, int end) { 2689 if (str == null) { 2690 return null; 2691 } 2692 2693 // handle negatives 2694 if (end < 0) { 2695 end = str.length() + end; // remember end is negative 2696 } 2697 if (start < 0) { 2698 start = str.length() + start; // remember start is negative 2699 } 2700 2701 // check length next 2702 if (end > str.length()) { 2703 end = str.length(); 2704 } 2705 2706 // if start is greater than end, return "" 2707 if (start > end) { 2708 return EMPTY; 2709 } 2710 2711 if (start < 0) { 2712 start = 0; 2713 } 2714 if (end < 0) { 2715 end = 0; 2716 } 2717 2718 return str.substring(start, end); 2719 } 2720 2721 // Left/Right/Mid 2722 //----------------------------------------------------------------------- 2723 /** 2724 * <p>Gets the leftmost {@code len} characters of a String.</p> 2725 * 2726 * <p>If {@code len} characters are not available, or the 2727 * String is {@code null}, the String will be returned without 2728 * an exception. An empty String is returned if len is negative.</p> 2729 * 2730 * <pre> 2731 * StringUtils.left(null, *) = null 2732 * StringUtils.left(*, -ve) = "" 2733 * StringUtils.left("", *) = "" 2734 * StringUtils.left("abc", 0) = "" 2735 * StringUtils.left("abc", 2) = "ab" 2736 * StringUtils.left("abc", 4) = "abc" 2737 * </pre> 2738 * 2739 * @param str the String to get the leftmost characters from, may be null 2740 * @param len the length of the required String 2741 * @return the leftmost characters, {@code null} if null String input 2742 */ 2743 public static String left(final String str, final int len) { 2744 if (str == null) { 2745 return null; 2746 } 2747 if (len < 0) { 2748 return EMPTY; 2749 } 2750 if (str.length() <= len) { 2751 return str; 2752 } 2753 return str.substring(0, len); 2754 } 2755 2756 /** 2757 * <p>Gets the rightmost {@code len} characters of a String.</p> 2758 * 2759 * <p>If {@code len} characters are not available, or the String 2760 * is {@code null}, the String will be returned without an 2761 * an exception. An empty String is returned if len is negative.</p> 2762 * 2763 * <pre> 2764 * StringUtils.right(null, *) = null 2765 * StringUtils.right(*, -ve) = "" 2766 * StringUtils.right("", *) = "" 2767 * StringUtils.right("abc", 0) = "" 2768 * StringUtils.right("abc", 2) = "bc" 2769 * StringUtils.right("abc", 4) = "abc" 2770 * </pre> 2771 * 2772 * @param str the String to get the rightmost characters from, may be null 2773 * @param len the length of the required String 2774 * @return the rightmost characters, {@code null} if null String input 2775 */ 2776 public static String right(final String str, final int len) { 2777 if (str == null) { 2778 return null; 2779 } 2780 if (len < 0) { 2781 return EMPTY; 2782 } 2783 if (str.length() <= len) { 2784 return str; 2785 } 2786 return str.substring(str.length() - len); 2787 } 2788 2789 /** 2790 * <p>Gets {@code len} characters from the middle of a String.</p> 2791 * 2792 * <p>If {@code len} characters are not available, the remainder 2793 * of the String will be returned without an exception. If the 2794 * String is {@code null}, {@code null} will be returned. 2795 * An empty String is returned if len is negative or exceeds the 2796 * length of {@code str}.</p> 2797 * 2798 * <pre> 2799 * StringUtils.mid(null, *, *) = null 2800 * StringUtils.mid(*, *, -ve) = "" 2801 * StringUtils.mid("", 0, *) = "" 2802 * StringUtils.mid("abc", 0, 2) = "ab" 2803 * StringUtils.mid("abc", 0, 4) = "abc" 2804 * StringUtils.mid("abc", 2, 4) = "c" 2805 * StringUtils.mid("abc", 4, 2) = "" 2806 * StringUtils.mid("abc", -2, 2) = "ab" 2807 * </pre> 2808 * 2809 * @param str the String to get the characters from, may be null 2810 * @param pos the position to start from, negative treated as zero 2811 * @param len the length of the required String 2812 * @return the middle characters, {@code null} if null String input 2813 */ 2814 public static String mid(final String str, int pos, final int len) { 2815 if (str == null) { 2816 return null; 2817 } 2818 if (len < 0 || pos > str.length()) { 2819 return EMPTY; 2820 } 2821 if (pos < 0) { 2822 pos = 0; 2823 } 2824 if (str.length() <= pos + len) { 2825 return str.substring(pos); 2826 } 2827 return str.substring(pos, pos + len); 2828 } 2829 2830 // SubStringAfter/SubStringBefore 2831 //----------------------------------------------------------------------- 2832 /** 2833 * <p>Gets the substring before the first occurrence of a separator. 2834 * The separator is not returned.</p> 2835 * 2836 * <p>A {@code null} string input will return {@code null}. 2837 * An empty ("") string input will return the empty string. 2838 * A {@code null} separator will return the input string.</p> 2839 * 2840 * <p>If nothing is found, the string input is returned.</p> 2841 * 2842 * <pre> 2843 * StringUtils.substringBefore(null, *) = null 2844 * StringUtils.substringBefore("", *) = "" 2845 * StringUtils.substringBefore("abc", "a") = "" 2846 * StringUtils.substringBefore("abcba", "b") = "a" 2847 * StringUtils.substringBefore("abc", "c") = "ab" 2848 * StringUtils.substringBefore("abc", "d") = "abc" 2849 * StringUtils.substringBefore("abc", "") = "" 2850 * StringUtils.substringBefore("abc", null) = "abc" 2851 * </pre> 2852 * 2853 * @param str the String to get a substring from, may be null 2854 * @param separator the String to search for, may be null 2855 * @return the substring before the first occurrence of the separator, 2856 * {@code null} if null String input 2857 * @since 2.0 2858 */ 2859 public static String substringBefore(final String str, final String separator) { 2860 if (isEmpty(str) || separator == null) { 2861 return str; 2862 } 2863 if (separator.isEmpty()) { 2864 return EMPTY; 2865 } 2866 final int pos = str.indexOf(separator); 2867 if (pos == INDEX_NOT_FOUND) { 2868 return str; 2869 } 2870 return str.substring(0, pos); 2871 } 2872 2873 /** 2874 * <p>Gets the substring after the first occurrence of a separator. 2875 * The separator is not returned.</p> 2876 * 2877 * <p>A {@code null} string input will return {@code null}. 2878 * An empty ("") string input will return the empty string. 2879 * A {@code null} separator will return the empty string if the 2880 * input string is not {@code null}.</p> 2881 * 2882 * <p>If nothing is found, the empty string is returned.</p> 2883 * 2884 * <pre> 2885 * StringUtils.substringAfter(null, *) = null 2886 * StringUtils.substringAfter("", *) = "" 2887 * StringUtils.substringAfter(*, null) = "" 2888 * StringUtils.substringAfter("abc", "a") = "bc" 2889 * StringUtils.substringAfter("abcba", "b") = "cba" 2890 * StringUtils.substringAfter("abc", "c") = "" 2891 * StringUtils.substringAfter("abc", "d") = "" 2892 * StringUtils.substringAfter("abc", "") = "abc" 2893 * </pre> 2894 * 2895 * @param str the String to get a substring from, may be null 2896 * @param separator the String to search for, may be null 2897 * @return the substring after the first occurrence of the separator, 2898 * {@code null} if null String input 2899 * @since 2.0 2900 */ 2901 public static String substringAfter(final String str, final String separator) { 2902 if (isEmpty(str)) { 2903 return str; 2904 } 2905 if (separator == null) { 2906 return EMPTY; 2907 } 2908 final int pos = str.indexOf(separator); 2909 if (pos == INDEX_NOT_FOUND) { 2910 return EMPTY; 2911 } 2912 return str.substring(pos + separator.length()); 2913 } 2914 2915 /** 2916 * <p>Gets the substring before the last occurrence of a separator. 2917 * The separator is not returned.</p> 2918 * 2919 * <p>A {@code null} string input will return {@code null}. 2920 * An empty ("") string input will return the empty string. 2921 * An empty or {@code null} separator will return the input string.</p> 2922 * 2923 * <p>If nothing is found, the string input is returned.</p> 2924 * 2925 * <pre> 2926 * StringUtils.substringBeforeLast(null, *) = null 2927 * StringUtils.substringBeforeLast("", *) = "" 2928 * StringUtils.substringBeforeLast("abcba", "b") = "abc" 2929 * StringUtils.substringBeforeLast("abc", "c") = "ab" 2930 * StringUtils.substringBeforeLast("a", "a") = "" 2931 * StringUtils.substringBeforeLast("a", "z") = "a" 2932 * StringUtils.substringBeforeLast("a", null) = "a" 2933 * StringUtils.substringBeforeLast("a", "") = "a" 2934 * </pre> 2935 * 2936 * @param str the String to get a substring from, may be null 2937 * @param separator the String to search for, may be null 2938 * @return the substring before the last occurrence of the separator, 2939 * {@code null} if null String input 2940 * @since 2.0 2941 */ 2942 public static String substringBeforeLast(final String str, final String separator) { 2943 if (isEmpty(str) || isEmpty(separator)) { 2944 return str; 2945 } 2946 final int pos = str.lastIndexOf(separator); 2947 if (pos == INDEX_NOT_FOUND) { 2948 return str; 2949 } 2950 return str.substring(0, pos); 2951 } 2952 2953 /** 2954 * <p>Gets the substring after the last occurrence of a separator. 2955 * The separator is not returned.</p> 2956 * 2957 * <p>A {@code null} string input will return {@code null}. 2958 * An empty ("") string input will return the empty string. 2959 * An empty or {@code null} separator will return the empty string if 2960 * the input string is not {@code null}.</p> 2961 * 2962 * <p>If nothing is found, the empty string is returned.</p> 2963 * 2964 * <pre> 2965 * StringUtils.substringAfterLast(null, *) = null 2966 * StringUtils.substringAfterLast("", *) = "" 2967 * StringUtils.substringAfterLast(*, "") = "" 2968 * StringUtils.substringAfterLast(*, null) = "" 2969 * StringUtils.substringAfterLast("abc", "a") = "bc" 2970 * StringUtils.substringAfterLast("abcba", "b") = "a" 2971 * StringUtils.substringAfterLast("abc", "c") = "" 2972 * StringUtils.substringAfterLast("a", "a") = "" 2973 * StringUtils.substringAfterLast("a", "z") = "" 2974 * </pre> 2975 * 2976 * @param str the String to get a substring from, may be null 2977 * @param separator the String to search for, may be null 2978 * @return the substring after the last occurrence of the separator, 2979 * {@code null} if null String input 2980 * @since 2.0 2981 */ 2982 public static String substringAfterLast(final String str, final String separator) { 2983 if (isEmpty(str)) { 2984 return str; 2985 } 2986 if (isEmpty(separator)) { 2987 return EMPTY; 2988 } 2989 final int pos = str.lastIndexOf(separator); 2990 if (pos == INDEX_NOT_FOUND || pos == str.length() - separator.length()) { 2991 return EMPTY; 2992 } 2993 return str.substring(pos + separator.length()); 2994 } 2995 2996 // Substring between 2997 //----------------------------------------------------------------------- 2998 /** 2999 * <p>Gets the String that is nested in between two instances of the 3000 * same String.</p> 3001 * 3002 * <p>A {@code null} input String returns {@code null}. 3003 * A {@code null} tag returns {@code null}.</p> 3004 * 3005 * <pre> 3006 * StringUtils.substringBetween(null, *) = null 3007 * StringUtils.substringBetween("", "") = "" 3008 * StringUtils.substringBetween("", "tag") = null 3009 * StringUtils.substringBetween("tagabctag", null) = null 3010 * StringUtils.substringBetween("tagabctag", "") = "" 3011 * StringUtils.substringBetween("tagabctag", "tag") = "abc" 3012 * </pre> 3013 * 3014 * @param str the String containing the substring, may be null 3015 * @param tag the String before and after the substring, may be null 3016 * @return the substring, {@code null} if no match 3017 * @since 2.0 3018 */ 3019 public static String substringBetween(final String str, final String tag) { 3020 return substringBetween(str, tag, tag); 3021 } 3022 3023 /** 3024 * <p>Gets the String that is nested in between two Strings. 3025 * Only the first match is returned.</p> 3026 * 3027 * <p>A {@code null} input String returns {@code null}. 3028 * A {@code null} open/close returns {@code null} (no match). 3029 * An empty ("") open and close returns an empty string.</p> 3030 * 3031 * <pre> 3032 * StringUtils.substringBetween("wx[b]yz", "[", "]") = "b" 3033 * StringUtils.substringBetween(null, *, *) = null 3034 * StringUtils.substringBetween(*, null, *) = null 3035 * StringUtils.substringBetween(*, *, null) = null 3036 * StringUtils.substringBetween("", "", "") = "" 3037 * StringUtils.substringBetween("", "", "]") = null 3038 * StringUtils.substringBetween("", "[", "]") = null 3039 * StringUtils.substringBetween("yabcz", "", "") = "" 3040 * StringUtils.substringBetween("yabcz", "y", "z") = "abc" 3041 * StringUtils.substringBetween("yabczyabcz", "y", "z") = "abc" 3042 * </pre> 3043 * 3044 * @param str the String containing the substring, may be null 3045 * @param open the String before the substring, may be null 3046 * @param close the String after the substring, may be null 3047 * @return the substring, {@code null} if no match 3048 * @since 2.0 3049 */ 3050 public static String substringBetween(final String str, final String open, final String close) { 3051 if (str == null || open == null || close == null) { 3052 return null; 3053 } 3054 final int start = str.indexOf(open); 3055 if (start != INDEX_NOT_FOUND) { 3056 final int end = str.indexOf(close, start + open.length()); 3057 if (end != INDEX_NOT_FOUND) { 3058 return str.substring(start + open.length(), end); 3059 } 3060 } 3061 return null; 3062 } 3063 3064 /** 3065 * <p>Searches a String for substrings delimited by a start and end tag, 3066 * returning all matching substrings in an array.</p> 3067 * 3068 * <p>A {@code null} input String returns {@code null}. 3069 * A {@code null} open/close returns {@code null} (no match). 3070 * An empty ("") open/close returns {@code null} (no match).</p> 3071 * 3072 * <pre> 3073 * StringUtils.substringsBetween("[a][b][c]", "[", "]") = ["a","b","c"] 3074 * StringUtils.substringsBetween(null, *, *) = null 3075 * StringUtils.substringsBetween(*, null, *) = null 3076 * StringUtils.substringsBetween(*, *, null) = null 3077 * StringUtils.substringsBetween("", "[", "]") = [] 3078 * </pre> 3079 * 3080 * @param str the String containing the substrings, null returns null, empty returns empty 3081 * @param open the String identifying the start of the substring, empty returns null 3082 * @param close the String identifying the end of the substring, empty returns null 3083 * @return a String Array of substrings, or {@code null} if no match 3084 * @since 2.3 3085 */ 3086 public static String[] substringsBetween(final String str, final String open, final String close) { 3087 if (str == null || isEmpty(open) || isEmpty(close)) { 3088 return null; 3089 } 3090 final int strLen = str.length(); 3091 if (strLen == 0) { 3092 return ArrayUtils.EMPTY_STRING_ARRAY; 3093 } 3094 final int closeLen = close.length(); 3095 final int openLen = open.length(); 3096 final List<String> list = new ArrayList<>(); 3097 int pos = 0; 3098 while (pos < strLen - closeLen) { 3099 int start = str.indexOf(open, pos); 3100 if (start < 0) { 3101 break; 3102 } 3103 start += openLen; 3104 final int end = str.indexOf(close, start); 3105 if (end < 0) { 3106 break; 3107 } 3108 list.add(str.substring(start, end)); 3109 pos = end + closeLen; 3110 } 3111 if (list.isEmpty()) { 3112 return null; 3113 } 3114 return list.toArray(new String [list.size()]); 3115 } 3116 3117 // Nested extraction 3118 //----------------------------------------------------------------------- 3119 3120 // Splitting 3121 //----------------------------------------------------------------------- 3122 /** 3123 * <p>Splits the provided text into an array, using whitespace as the 3124 * separator. 3125 * Whitespace is defined by {@link Character#isWhitespace(char)}.</p> 3126 * 3127 * <p>The separator is not included in the returned String array. 3128 * Adjacent separators are treated as one separator. 3129 * For more control over the split use the StrTokenizer class.</p> 3130 * 3131 * <p>A {@code null} input String returns {@code null}.</p> 3132 * 3133 * <pre> 3134 * StringUtils.split(null) = null 3135 * StringUtils.split("") = [] 3136 * StringUtils.split("abc def") = ["abc", "def"] 3137 * StringUtils.split("abc def") = ["abc", "def"] 3138 * StringUtils.split(" abc ") = ["abc"] 3139 * </pre> 3140 * 3141 * @param str the String to parse, may be null 3142 * @return an array of parsed Strings, {@code null} if null String input 3143 */ 3144 public static String[] split(final String str) { 3145 return split(str, null, -1); 3146 } 3147 3148 /** 3149 * <p>Splits the provided text into an array, separator specified. 3150 * This is an alternative to using StringTokenizer.</p> 3151 * 3152 * <p>The separator is not included in the returned String array. 3153 * Adjacent separators are treated as one separator. 3154 * For more control over the split use the StrTokenizer class.</p> 3155 * 3156 * <p>A {@code null} input String returns {@code null}.</p> 3157 * 3158 * <pre> 3159 * StringUtils.split(null, *) = null 3160 * StringUtils.split("", *) = [] 3161 * StringUtils.split("a.b.c", '.') = ["a", "b", "c"] 3162 * StringUtils.split("a..b.c", '.') = ["a", "b", "c"] 3163 * StringUtils.split("a:b:c", '.') = ["a:b:c"] 3164 * StringUtils.split("a b c", ' ') = ["a", "b", "c"] 3165 * </pre> 3166 * 3167 * @param str the String to parse, may be null 3168 * @param separatorChar the character used as the delimiter 3169 * @return an array of parsed Strings, {@code null} if null String input 3170 * @since 2.0 3171 */ 3172 public static String[] split(final String str, final char separatorChar) { 3173 return splitWorker(str, separatorChar, false); 3174 } 3175 3176 /** 3177 * <p>Splits the provided text into an array, separators specified. 3178 * This is an alternative to using StringTokenizer.</p> 3179 * 3180 * <p>The separator is not included in the returned String array. 3181 * Adjacent separators are treated as one separator. 3182 * For more control over the split use the StrTokenizer class.</p> 3183 * 3184 * <p>A {@code null} input String returns {@code null}. 3185 * A {@code null} separatorChars splits on whitespace.</p> 3186 * 3187 * <pre> 3188 * StringUtils.split(null, *) = null 3189 * StringUtils.split("", *) = [] 3190 * StringUtils.split("abc def", null) = ["abc", "def"] 3191 * StringUtils.split("abc def", " ") = ["abc", "def"] 3192 * StringUtils.split("abc def", " ") = ["abc", "def"] 3193 * StringUtils.split("ab:cd:ef", ":") = ["ab", "cd", "ef"] 3194 * </pre> 3195 * 3196 * @param str the String to parse, may be null 3197 * @param separatorChars the characters used as the delimiters, 3198 * {@code null} splits on whitespace 3199 * @return an array of parsed Strings, {@code null} if null String input 3200 */ 3201 public static String[] split(final String str, final String separatorChars) { 3202 return splitWorker(str, separatorChars, -1, false); 3203 } 3204 3205 /** 3206 * <p>Splits the provided text into an array with a maximum length, 3207 * separators specified.</p> 3208 * 3209 * <p>The separator is not included in the returned String array. 3210 * Adjacent separators are treated as one separator.</p> 3211 * 3212 * <p>A {@code null} input String returns {@code null}. 3213 * A {@code null} separatorChars splits on whitespace.</p> 3214 * 3215 * <p>If more than {@code max} delimited substrings are found, the last 3216 * returned string includes all characters after the first {@code max - 1} 3217 * returned strings (including separator characters).</p> 3218 * 3219 * <pre> 3220 * StringUtils.split(null, *, *) = null 3221 * StringUtils.split("", *, *) = [] 3222 * StringUtils.split("ab cd ef", null, 0) = ["ab", "cd", "ef"] 3223 * StringUtils.split("ab cd ef", null, 0) = ["ab", "cd", "ef"] 3224 * StringUtils.split("ab:cd:ef", ":", 0) = ["ab", "cd", "ef"] 3225 * StringUtils.split("ab:cd:ef", ":", 2) = ["ab", "cd:ef"] 3226 * </pre> 3227 * 3228 * @param str the String to parse, may be null 3229 * @param separatorChars the characters used as the delimiters, 3230 * {@code null} splits on whitespace 3231 * @param max the maximum number of elements to include in the 3232 * array. A zero or negative value implies no limit 3233 * @return an array of parsed Strings, {@code null} if null String input 3234 */ 3235 public static String[] split(final String str, final String separatorChars, final int max) { 3236 return splitWorker(str, separatorChars, max, false); 3237 } 3238 3239 /** 3240 * <p>Splits the provided text into an array, separator string specified.</p> 3241 * 3242 * <p>The separator(s) will not be included in the returned String array. 3243 * Adjacent separators are treated as one separator.</p> 3244 * 3245 * <p>A {@code null} input String returns {@code null}. 3246 * A {@code null} separator splits on whitespace.</p> 3247 * 3248 * <pre> 3249 * StringUtils.splitByWholeSeparator(null, *) = null 3250 * StringUtils.splitByWholeSeparator("", *) = [] 3251 * StringUtils.splitByWholeSeparator("ab de fg", null) = ["ab", "de", "fg"] 3252 * StringUtils.splitByWholeSeparator("ab de fg", null) = ["ab", "de", "fg"] 3253 * StringUtils.splitByWholeSeparator("ab:cd:ef", ":") = ["ab", "cd", "ef"] 3254 * StringUtils.splitByWholeSeparator("ab-!-cd-!-ef", "-!-") = ["ab", "cd", "ef"] 3255 * </pre> 3256 * 3257 * @param str the String to parse, may be null 3258 * @param separator String containing the String to be used as a delimiter, 3259 * {@code null} splits on whitespace 3260 * @return an array of parsed Strings, {@code null} if null String was input 3261 */ 3262 public static String[] splitByWholeSeparator(final String str, final String separator) { 3263 return splitByWholeSeparatorWorker( str, separator, -1, false ) ; 3264 } 3265 3266 /** 3267 * <p>Splits the provided text into an array, separator string specified. 3268 * Returns a maximum of {@code max} substrings.</p> 3269 * 3270 * <p>The separator(s) will not be included in the returned String array. 3271 * Adjacent separators are treated as one separator.</p> 3272 * 3273 * <p>A {@code null} input String returns {@code null}. 3274 * A {@code null} separator splits on whitespace.</p> 3275 * 3276 * <pre> 3277 * StringUtils.splitByWholeSeparator(null, *, *) = null 3278 * StringUtils.splitByWholeSeparator("", *, *) = [] 3279 * StringUtils.splitByWholeSeparator("ab de fg", null, 0) = ["ab", "de", "fg"] 3280 * StringUtils.splitByWholeSeparator("ab de fg", null, 0) = ["ab", "de", "fg"] 3281 * StringUtils.splitByWholeSeparator("ab:cd:ef", ":", 2) = ["ab", "cd:ef"] 3282 * StringUtils.splitByWholeSeparator("ab-!-cd-!-ef", "-!-", 5) = ["ab", "cd", "ef"] 3283 * StringUtils.splitByWholeSeparator("ab-!-cd-!-ef", "-!-", 2) = ["ab", "cd-!-ef"] 3284 * </pre> 3285 * 3286 * @param str the String to parse, may be null 3287 * @param separator String containing the String to be used as a delimiter, 3288 * {@code null} splits on whitespace 3289 * @param max the maximum number of elements to include in the returned 3290 * array. A zero or negative value implies no limit. 3291 * @return an array of parsed Strings, {@code null} if null String was input 3292 */ 3293 public static String[] splitByWholeSeparator( final String str, final String separator, final int max) { 3294 return splitByWholeSeparatorWorker(str, separator, max, false); 3295 } 3296 3297 /** 3298 * <p>Splits the provided text into an array, separator string specified. </p> 3299 * 3300 * <p>The separator is not included in the returned String array. 3301 * Adjacent separators are treated as separators for empty tokens. 3302 * For more control over the split use the StrTokenizer class.</p> 3303 * 3304 * <p>A {@code null} input String returns {@code null}. 3305 * A {@code null} separator splits on whitespace.</p> 3306 * 3307 * <pre> 3308 * StringUtils.splitByWholeSeparatorPreserveAllTokens(null, *) = null 3309 * StringUtils.splitByWholeSeparatorPreserveAllTokens("", *) = [] 3310 * StringUtils.splitByWholeSeparatorPreserveAllTokens("ab de fg", null) = ["ab", "de", "fg"] 3311 * StringUtils.splitByWholeSeparatorPreserveAllTokens("ab de fg", null) = ["ab", "", "", "de", "fg"] 3312 * StringUtils.splitByWholeSeparatorPreserveAllTokens("ab:cd:ef", ":") = ["ab", "cd", "ef"] 3313 * StringUtils.splitByWholeSeparatorPreserveAllTokens("ab-!-cd-!-ef", "-!-") = ["ab", "cd", "ef"] 3314 * </pre> 3315 * 3316 * @param str the String to parse, may be null 3317 * @param separator String containing the String to be used as a delimiter, 3318 * {@code null} splits on whitespace 3319 * @return an array of parsed Strings, {@code null} if null String was input 3320 * @since 2.4 3321 */ 3322 public static String[] splitByWholeSeparatorPreserveAllTokens(final String str, final String separator) { 3323 return splitByWholeSeparatorWorker(str, separator, -1, true); 3324 } 3325 3326 /** 3327 * <p>Splits the provided text into an array, separator string specified. 3328 * Returns a maximum of {@code max} substrings.</p> 3329 * 3330 * <p>The separator is not included in the returned String array. 3331 * Adjacent separators are treated as separators for empty tokens. 3332 * For more control over the split use the StrTokenizer class.</p> 3333 * 3334 * <p>A {@code null} input String returns {@code null}. 3335 * A {@code null} separator splits on whitespace.</p> 3336 * 3337 * <pre> 3338 * StringUtils.splitByWholeSeparatorPreserveAllTokens(null, *, *) = null 3339 * StringUtils.splitByWholeSeparatorPreserveAllTokens("", *, *) = [] 3340 * StringUtils.splitByWholeSeparatorPreserveAllTokens("ab de fg", null, 0) = ["ab", "de", "fg"] 3341 * StringUtils.splitByWholeSeparatorPreserveAllTokens("ab de fg", null, 0) = ["ab", "", "", "de", "fg"] 3342 * StringUtils.splitByWholeSeparatorPreserveAllTokens("ab:cd:ef", ":", 2) = ["ab", "cd:ef"] 3343 * StringUtils.splitByWholeSeparatorPreserveAllTokens("ab-!-cd-!-ef", "-!-", 5) = ["ab", "cd", "ef"] 3344 * StringUtils.splitByWholeSeparatorPreserveAllTokens("ab-!-cd-!-ef", "-!-", 2) = ["ab", "cd-!-ef"] 3345 * </pre> 3346 * 3347 * @param str the String to parse, may be null 3348 * @param separator String containing the String to be used as a delimiter, 3349 * {@code null} splits on whitespace 3350 * @param max the maximum number of elements to include in the returned 3351 * array. A zero or negative value implies no limit. 3352 * @return an array of parsed Strings, {@code null} if null String was input 3353 * @since 2.4 3354 */ 3355 public static String[] splitByWholeSeparatorPreserveAllTokens(final String str, final String separator, final int max) { 3356 return splitByWholeSeparatorWorker(str, separator, max, true); 3357 } 3358 3359 /** 3360 * Performs the logic for the {@code splitByWholeSeparatorPreserveAllTokens} methods. 3361 * 3362 * @param str the String to parse, may be {@code null} 3363 * @param separator String containing the String to be used as a delimiter, 3364 * {@code null} splits on whitespace 3365 * @param max the maximum number of elements to include in the returned 3366 * array. A zero or negative value implies no limit. 3367 * @param preserveAllTokens if {@code true}, adjacent separators are 3368 * treated as empty token separators; if {@code false}, adjacent 3369 * separators are treated as one separator. 3370 * @return an array of parsed Strings, {@code null} if null String input 3371 * @since 2.4 3372 */ 3373 private static String[] splitByWholeSeparatorWorker( 3374 final String str, final String separator, final int max, final boolean preserveAllTokens) { 3375 if (str == null) { 3376 return null; 3377 } 3378 3379 final int len = str.length(); 3380 3381 if (len == 0) { 3382 return ArrayUtils.EMPTY_STRING_ARRAY; 3383 } 3384 3385 if (separator == null || EMPTY.equals(separator)) { 3386 // Split on whitespace. 3387 return splitWorker(str, null, max, preserveAllTokens); 3388 } 3389 3390 final int separatorLength = separator.length(); 3391 3392 final ArrayList<String> substrings = new ArrayList<>(); 3393 int numberOfSubstrings = 0; 3394 int beg = 0; 3395 int end = 0; 3396 while (end < len) { 3397 end = str.indexOf(separator, beg); 3398 3399 if (end > -1) { 3400 if (end > beg) { 3401 numberOfSubstrings += 1; 3402 3403 if (numberOfSubstrings == max) { 3404 end = len; 3405 substrings.add(str.substring(beg)); 3406 } else { 3407 // The following is OK, because String.substring( beg, end ) excludes 3408 // the character at the position 'end'. 3409 substrings.add(str.substring(beg, end)); 3410 3411 // Set the starting point for the next search. 3412 // The following is equivalent to beg = end + (separatorLength - 1) + 1, 3413 // which is the right calculation: 3414 beg = end + separatorLength; 3415 } 3416 } else { 3417 // We found a consecutive occurrence of the separator, so skip it. 3418 if (preserveAllTokens) { 3419 numberOfSubstrings += 1; 3420 if (numberOfSubstrings == max) { 3421 end = len; 3422 substrings.add(str.substring(beg)); 3423 } else { 3424 substrings.add(EMPTY); 3425 } 3426 } 3427 beg = end + separatorLength; 3428 } 3429 } else { 3430 // String.substring( beg ) goes from 'beg' to the end of the String. 3431 substrings.add(str.substring(beg)); 3432 end = len; 3433 } 3434 } 3435 3436 return substrings.toArray(new String[substrings.size()]); 3437 } 3438 3439 // ----------------------------------------------------------------------- 3440 /** 3441 * <p>Splits the provided text into an array, using whitespace as the 3442 * separator, preserving all tokens, including empty tokens created by 3443 * adjacent separators. This is an alternative to using StringTokenizer. 3444 * Whitespace is defined by {@link Character#isWhitespace(char)}.</p> 3445 * 3446 * <p>The separator is not included in the returned String array. 3447 * Adjacent separators are treated as separators for empty tokens. 3448 * For more control over the split use the StrTokenizer class.</p> 3449 * 3450 * <p>A {@code null} input String returns {@code null}.</p> 3451 * 3452 * <pre> 3453 * StringUtils.splitPreserveAllTokens(null) = null 3454 * StringUtils.splitPreserveAllTokens("") = [] 3455 * StringUtils.splitPreserveAllTokens("abc def") = ["abc", "def"] 3456 * StringUtils.splitPreserveAllTokens("abc def") = ["abc", "", "def"] 3457 * StringUtils.splitPreserveAllTokens(" abc ") = ["", "abc", ""] 3458 * </pre> 3459 * 3460 * @param str the String to parse, may be {@code null} 3461 * @return an array of parsed Strings, {@code null} if null String input 3462 * @since 2.1 3463 */ 3464 public static String[] splitPreserveAllTokens(final String str) { 3465 return splitWorker(str, null, -1, true); 3466 } 3467 3468 /** 3469 * <p>Splits the provided text into an array, separator specified, 3470 * preserving all tokens, including empty tokens created by adjacent 3471 * separators. This is an alternative to using StringTokenizer.</p> 3472 * 3473 * <p>The separator is not included in the returned String array. 3474 * Adjacent separators are treated as separators for empty tokens. 3475 * For more control over the split use the StrTokenizer class.</p> 3476 * 3477 * <p>A {@code null} input String returns {@code null}.</p> 3478 * 3479 * <pre> 3480 * StringUtils.splitPreserveAllTokens(null, *) = null 3481 * StringUtils.splitPreserveAllTokens("", *) = [] 3482 * StringUtils.splitPreserveAllTokens("a.b.c", '.') = ["a", "b", "c"] 3483 * StringUtils.splitPreserveAllTokens("a..b.c", '.') = ["a", "", "b", "c"] 3484 * StringUtils.splitPreserveAllTokens("a:b:c", '.') = ["a:b:c"] 3485 * StringUtils.splitPreserveAllTokens("a\tb\nc", null) = ["a", "b", "c"] 3486 * StringUtils.splitPreserveAllTokens("a b c", ' ') = ["a", "b", "c"] 3487 * StringUtils.splitPreserveAllTokens("a b c ", ' ') = ["a", "b", "c", ""] 3488 * StringUtils.splitPreserveAllTokens("a b c ", ' ') = ["a", "b", "c", "", ""] 3489 * StringUtils.splitPreserveAllTokens(" a b c", ' ') = ["", a", "b", "c"] 3490 * StringUtils.splitPreserveAllTokens(" a b c", ' ') = ["", "", a", "b", "c"] 3491 * StringUtils.splitPreserveAllTokens(" a b c ", ' ') = ["", a", "b", "c", ""] 3492 * </pre> 3493 * 3494 * @param str the String to parse, may be {@code null} 3495 * @param separatorChar the character used as the delimiter, 3496 * {@code null} splits on whitespace 3497 * @return an array of parsed Strings, {@code null} if null String input 3498 * @since 2.1 3499 */ 3500 public static String[] splitPreserveAllTokens(final String str, final char separatorChar) { 3501 return splitWorker(str, separatorChar, true); 3502 } 3503 3504 /** 3505 * Performs the logic for the {@code split} and 3506 * {@code splitPreserveAllTokens} methods that do not return a 3507 * maximum array length. 3508 * 3509 * @param str the String to parse, may be {@code null} 3510 * @param separatorChar the separate character 3511 * @param preserveAllTokens if {@code true}, adjacent separators are 3512 * treated as empty token separators; if {@code false}, adjacent 3513 * separators are treated as one separator. 3514 * @return an array of parsed Strings, {@code null} if null String input 3515 */ 3516 private static String[] splitWorker(final String str, final char separatorChar, final boolean preserveAllTokens) { 3517 // Performance tuned for 2.0 (JDK1.4) 3518 3519 if (str == null) { 3520 return null; 3521 } 3522 final int len = str.length(); 3523 if (len == 0) { 3524 return ArrayUtils.EMPTY_STRING_ARRAY; 3525 } 3526 final List<String> list = new ArrayList<>(); 3527 int i = 0, start = 0; 3528 boolean match = false; 3529 boolean lastMatch = false; 3530 while (i < len) { 3531 if (str.charAt(i) == separatorChar) { 3532 if (match || preserveAllTokens) { 3533 list.add(str.substring(start, i)); 3534 match = false; 3535 lastMatch = true; 3536 } 3537 start = ++i; 3538 continue; 3539 } 3540 lastMatch = false; 3541 match = true; 3542 i++; 3543 } 3544 if (match || preserveAllTokens && lastMatch) { 3545 list.add(str.substring(start, i)); 3546 } 3547 return list.toArray(new String[list.size()]); 3548 } 3549 3550 /** 3551 * <p>Splits the provided text into an array, separators specified, 3552 * preserving all tokens, including empty tokens created by adjacent 3553 * separators. This is an alternative to using StringTokenizer.</p> 3554 * 3555 * <p>The separator is not included in the returned String array. 3556 * Adjacent separators are treated as separators for empty tokens. 3557 * For more control over the split use the StrTokenizer class.</p> 3558 * 3559 * <p>A {@code null} input String returns {@code null}. 3560 * A {@code null} separatorChars splits on whitespace.</p> 3561 * 3562 * <pre> 3563 * StringUtils.splitPreserveAllTokens(null, *) = null 3564 * StringUtils.splitPreserveAllTokens("", *) = [] 3565 * StringUtils.splitPreserveAllTokens("abc def", null) = ["abc", "def"] 3566 * StringUtils.splitPreserveAllTokens("abc def", " ") = ["abc", "def"] 3567 * StringUtils.splitPreserveAllTokens("abc def", " ") = ["abc", "", def"] 3568 * StringUtils.splitPreserveAllTokens("ab:cd:ef", ":") = ["ab", "cd", "ef"] 3569 * StringUtils.splitPreserveAllTokens("ab:cd:ef:", ":") = ["ab", "cd", "ef", ""] 3570 * StringUtils.splitPreserveAllTokens("ab:cd:ef::", ":") = ["ab", "cd", "ef", "", ""] 3571 * StringUtils.splitPreserveAllTokens("ab::cd:ef", ":") = ["ab", "", cd", "ef"] 3572 * StringUtils.splitPreserveAllTokens(":cd:ef", ":") = ["", cd", "ef"] 3573 * StringUtils.splitPreserveAllTokens("::cd:ef", ":") = ["", "", cd", "ef"] 3574 * StringUtils.splitPreserveAllTokens(":cd:ef:", ":") = ["", cd", "ef", ""] 3575 * </pre> 3576 * 3577 * @param str the String to parse, may be {@code null} 3578 * @param separatorChars the characters used as the delimiters, 3579 * {@code null} splits on whitespace 3580 * @return an array of parsed Strings, {@code null} if null String input 3581 * @since 2.1 3582 */ 3583 public static String[] splitPreserveAllTokens(final String str, final String separatorChars) { 3584 return splitWorker(str, separatorChars, -1, true); 3585 } 3586 3587 /** 3588 * <p>Splits the provided text into an array with a maximum length, 3589 * separators specified, preserving all tokens, including empty tokens 3590 * created by adjacent separators.</p> 3591 * 3592 * <p>The separator is not included in the returned String array. 3593 * Adjacent separators are treated as separators for empty tokens. 3594 * Adjacent separators are treated as one separator.</p> 3595 * 3596 * <p>A {@code null} input String returns {@code null}. 3597 * A {@code null} separatorChars splits on whitespace.</p> 3598 * 3599 * <p>If more than {@code max} delimited substrings are found, the last 3600 * returned string includes all characters after the first {@code max - 1} 3601 * returned strings (including separator characters).</p> 3602 * 3603 * <pre> 3604 * StringUtils.splitPreserveAllTokens(null, *, *) = null 3605 * StringUtils.splitPreserveAllTokens("", *, *) = [] 3606 * StringUtils.splitPreserveAllTokens("ab de fg", null, 0) = ["ab", "cd", "ef"] 3607 * StringUtils.splitPreserveAllTokens("ab de fg", null, 0) = ["ab", "cd", "ef"] 3608 * StringUtils.splitPreserveAllTokens("ab:cd:ef", ":", 0) = ["ab", "cd", "ef"] 3609 * StringUtils.splitPreserveAllTokens("ab:cd:ef", ":", 2) = ["ab", "cd:ef"] 3610 * StringUtils.splitPreserveAllTokens("ab de fg", null, 2) = ["ab", " de fg"] 3611 * StringUtils.splitPreserveAllTokens("ab de fg", null, 3) = ["ab", "", " de fg"] 3612 * StringUtils.splitPreserveAllTokens("ab de fg", null, 4) = ["ab", "", "", "de fg"] 3613 * </pre> 3614 * 3615 * @param str the String to parse, may be {@code null} 3616 * @param separatorChars the characters used as the delimiters, 3617 * {@code null} splits on whitespace 3618 * @param max the maximum number of elements to include in the 3619 * array. A zero or negative value implies no limit 3620 * @return an array of parsed Strings, {@code null} if null String input 3621 * @since 2.1 3622 */ 3623 public static String[] splitPreserveAllTokens(final String str, final String separatorChars, final int max) { 3624 return splitWorker(str, separatorChars, max, true); 3625 } 3626 3627 /** 3628 * Performs the logic for the {@code split} and 3629 * {@code splitPreserveAllTokens} methods that return a maximum array 3630 * length. 3631 * 3632 * @param str the String to parse, may be {@code null} 3633 * @param separatorChars the separate character 3634 * @param max the maximum number of elements to include in the 3635 * array. A zero or negative value implies no limit. 3636 * @param preserveAllTokens if {@code true}, adjacent separators are 3637 * treated as empty token separators; if {@code false}, adjacent 3638 * separators are treated as one separator. 3639 * @return an array of parsed Strings, {@code null} if null String input 3640 */ 3641 private static String[] splitWorker(final String str, final String separatorChars, final int max, final boolean preserveAllTokens) { 3642 // Performance tuned for 2.0 (JDK1.4) 3643 // Direct code is quicker than StringTokenizer. 3644 // Also, StringTokenizer uses isSpace() not isWhitespace() 3645 3646 if (str == null) { 3647 return null; 3648 } 3649 final int len = str.length(); 3650 if (len == 0) { 3651 return ArrayUtils.EMPTY_STRING_ARRAY; 3652 } 3653 final List<String> list = new ArrayList<>(); 3654 int sizePlus1 = 1; 3655 int i = 0, start = 0; 3656 boolean match = false; 3657 boolean lastMatch = false; 3658 if (separatorChars == null) { 3659 // Null separator means use whitespace 3660 while (i < len) { 3661 if (Character.isWhitespace(str.charAt(i))) { 3662 if (match || preserveAllTokens) { 3663 lastMatch = true; 3664 if (sizePlus1++ == max) { 3665 i = len; 3666 lastMatch = false; 3667 } 3668 list.add(str.substring(start, i)); 3669 match = false; 3670 } 3671 start = ++i; 3672 continue; 3673 } 3674 lastMatch = false; 3675 match = true; 3676 i++; 3677 } 3678 } else if (separatorChars.length() == 1) { 3679 // Optimise 1 character case 3680 final char sep = separatorChars.charAt(0); 3681 while (i < len) { 3682 if (str.charAt(i) == sep) { 3683 if (match || preserveAllTokens) { 3684 lastMatch = true; 3685 if (sizePlus1++ == max) { 3686 i = len; 3687 lastMatch = false; 3688 } 3689 list.add(str.substring(start, i)); 3690 match = false; 3691 } 3692 start = ++i; 3693 continue; 3694 } 3695 lastMatch = false; 3696 match = true; 3697 i++; 3698 } 3699 } else { 3700 // standard case 3701 while (i < len) { 3702 if (separatorChars.indexOf(str.charAt(i)) >= 0) { 3703 if (match || preserveAllTokens) { 3704 lastMatch = true; 3705 if (sizePlus1++ == max) { 3706 i = len; 3707 lastMatch = false; 3708 } 3709 list.add(str.substring(start, i)); 3710 match = false; 3711 } 3712 start = ++i; 3713 continue; 3714 } 3715 lastMatch = false; 3716 match = true; 3717 i++; 3718 } 3719 } 3720 if (match || preserveAllTokens && lastMatch) { 3721 list.add(str.substring(start, i)); 3722 } 3723 return list.toArray(new String[list.size()]); 3724 } 3725 3726 /** 3727 * <p>Splits a String by Character type as returned by 3728 * {@code java.lang.Character.getType(char)}. Groups of contiguous 3729 * characters of the same type are returned as complete tokens. 3730 * <pre> 3731 * StringUtils.splitByCharacterType(null) = null 3732 * StringUtils.splitByCharacterType("") = [] 3733 * StringUtils.splitByCharacterType("ab de fg") = ["ab", " ", "de", " ", "fg"] 3734 * StringUtils.splitByCharacterType("ab de fg") = ["ab", " ", "de", " ", "fg"] 3735 * StringUtils.splitByCharacterType("ab:cd:ef") = ["ab", ":", "cd", ":", "ef"] 3736 * StringUtils.splitByCharacterType("number5") = ["number", "5"] 3737 * StringUtils.splitByCharacterType("fooBar") = ["foo", "B", "ar"] 3738 * StringUtils.splitByCharacterType("foo200Bar") = ["foo", "200", "B", "ar"] 3739 * StringUtils.splitByCharacterType("ASFRules") = ["ASFR", "ules"] 3740 * </pre> 3741 * @param str the String to split, may be {@code null} 3742 * @return an array of parsed Strings, {@code null} if null String input 3743 * @since 2.4 3744 */ 3745 public static String[] splitByCharacterType(final String str) { 3746 return splitByCharacterType(str, false); 3747 } 3748 3749 /** 3750 * <p>Splits a String by Character type as returned by 3751 * {@code java.lang.Character.getType(char)}. Groups of contiguous 3752 * characters of the same type are returned as complete tokens, with the 3753 * following exception: the character of type 3754 * {@code Character.UPPERCASE_LETTER}, if any, immediately 3755 * preceding a token of type {@code Character.LOWERCASE_LETTER} 3756 * will belong to the following token rather than to the preceding, if any, 3757 * {@code Character.UPPERCASE_LETTER} token. 3758 * <pre> 3759 * StringUtils.splitByCharacterTypeCamelCase(null) = null 3760 * StringUtils.splitByCharacterTypeCamelCase("") = [] 3761 * StringUtils.splitByCharacterTypeCamelCase("ab de fg") = ["ab", " ", "de", " ", "fg"] 3762 * StringUtils.splitByCharacterTypeCamelCase("ab de fg") = ["ab", " ", "de", " ", "fg"] 3763 * StringUtils.splitByCharacterTypeCamelCase("ab:cd:ef") = ["ab", ":", "cd", ":", "ef"] 3764 * StringUtils.splitByCharacterTypeCamelCase("number5") = ["number", "5"] 3765 * StringUtils.splitByCharacterTypeCamelCase("fooBar") = ["foo", "Bar"] 3766 * StringUtils.splitByCharacterTypeCamelCase("foo200Bar") = ["foo", "200", "Bar"] 3767 * StringUtils.splitByCharacterTypeCamelCase("ASFRules") = ["ASF", "Rules"] 3768 * </pre> 3769 * @param str the String to split, may be {@code null} 3770 * @return an array of parsed Strings, {@code null} if null String input 3771 * @since 2.4 3772 */ 3773 public static String[] splitByCharacterTypeCamelCase(final String str) { 3774 return splitByCharacterType(str, true); 3775 } 3776 3777 /** 3778 * <p>Splits a String by Character type as returned by 3779 * {@code java.lang.Character.getType(char)}. Groups of contiguous 3780 * characters of the same type are returned as complete tokens, with the 3781 * following exception: if {@code camelCase} is {@code true}, 3782 * the character of type {@code Character.UPPERCASE_LETTER}, if any, 3783 * immediately preceding a token of type {@code Character.LOWERCASE_LETTER} 3784 * will belong to the following token rather than to the preceding, if any, 3785 * {@code Character.UPPERCASE_LETTER} token. 3786 * @param str the String to split, may be {@code null} 3787 * @param camelCase whether to use so-called "camel-case" for letter types 3788 * @return an array of parsed Strings, {@code null} if null String input 3789 * @since 2.4 3790 */ 3791 private static String[] splitByCharacterType(final String str, final boolean camelCase) { 3792 if (str == null) { 3793 return null; 3794 } 3795 if (str.isEmpty()) { 3796 return ArrayUtils.EMPTY_STRING_ARRAY; 3797 } 3798 final char[] c = str.toCharArray(); 3799 final List<String> list = new ArrayList<>(); 3800 int tokenStart = 0; 3801 int currentType = Character.getType(c[tokenStart]); 3802 for (int pos = tokenStart + 1; pos < c.length; pos++) { 3803 final int type = Character.getType(c[pos]); 3804 if (type == currentType) { 3805 continue; 3806 } 3807 if (camelCase && type == Character.LOWERCASE_LETTER && currentType == Character.UPPERCASE_LETTER) { 3808 final int newTokenStart = pos - 1; 3809 if (newTokenStart != tokenStart) { 3810 list.add(new String(c, tokenStart, newTokenStart - tokenStart)); 3811 tokenStart = newTokenStart; 3812 } 3813 } else { 3814 list.add(new String(c, tokenStart, pos - tokenStart)); 3815 tokenStart = pos; 3816 } 3817 currentType = type; 3818 } 3819 list.add(new String(c, tokenStart, c.length - tokenStart)); 3820 return list.toArray(new String[list.size()]); 3821 } 3822 3823 // Joining 3824 //----------------------------------------------------------------------- 3825 /** 3826 * <p>Joins the elements of the provided array into a single String 3827 * containing the provided list of elements.</p> 3828 * 3829 * <p>No separator is added to the joined String. 3830 * Null objects or empty strings within the array are represented by 3831 * empty strings.</p> 3832 * 3833 * <pre> 3834 * StringUtils.join(null) = null 3835 * StringUtils.join([]) = "" 3836 * StringUtils.join([null]) = "" 3837 * StringUtils.join(["a", "b", "c"]) = "abc" 3838 * StringUtils.join([null, "", "a"]) = "a" 3839 * </pre> 3840 * 3841 * @param <T> the specific type of values to join together 3842 * @param elements the values to join together, may be null 3843 * @return the joined String, {@code null} if null array input 3844 * @since 2.0 3845 * @since 3.0 Changed signature to use varargs 3846 */ 3847 @SafeVarargs 3848 public static <T> String join(final T... elements) { 3849 return join(elements, null); 3850 } 3851 3852 /** 3853 * <p>Joins the elements of the provided array into a single String 3854 * containing the provided list of elements.</p> 3855 * 3856 * <p>No delimiter is added before or after the list. 3857 * Null objects or empty strings within the array are represented by 3858 * empty strings.</p> 3859 * 3860 * <pre> 3861 * StringUtils.join(null, *) = null 3862 * StringUtils.join([], *) = "" 3863 * StringUtils.join([null], *) = "" 3864 * StringUtils.join(["a", "b", "c"], ';') = "a;b;c" 3865 * StringUtils.join(["a", "b", "c"], null) = "abc" 3866 * StringUtils.join([null, "", "a"], ';') = ";;a" 3867 * </pre> 3868 * 3869 * @param array the array of values to join together, may be null 3870 * @param separator the separator character to use 3871 * @return the joined String, {@code null} if null array input 3872 * @since 2.0 3873 */ 3874 public static String join(final Object[] array, final char separator) { 3875 if (array == null) { 3876 return null; 3877 } 3878 return join(array, separator, 0, array.length); 3879 } 3880 3881 /** 3882 * <p> 3883 * Joins the elements of the provided array into a single String containing the provided list of elements. 3884 * </p> 3885 * 3886 * <p> 3887 * No delimiter is added before or after the list. Null objects or empty strings within the array are represented 3888 * by empty strings. 3889 * </p> 3890 * 3891 * <pre> 3892 * StringUtils.join(null, *) = null 3893 * StringUtils.join([], *) = "" 3894 * StringUtils.join([null], *) = "" 3895 * StringUtils.join([1, 2, 3], ';') = "1;2;3" 3896 * StringUtils.join([1, 2, 3], null) = "123" 3897 * </pre> 3898 * 3899 * @param array 3900 * the array of values to join together, may be null 3901 * @param separator 3902 * the separator character to use 3903 * @return the joined String, {@code null} if null array input 3904 * @since 3.2 3905 */ 3906 public static String join(final long[] array, final char separator) { 3907 if (array == null) { 3908 return null; 3909 } 3910 return join(array, separator, 0, array.length); 3911 } 3912 3913 /** 3914 * <p> 3915 * Joins the elements of the provided array into a single String containing the provided list of elements. 3916 * </p> 3917 * 3918 * <p> 3919 * No delimiter is added before or after the list. Null objects or empty strings within the array are represented 3920 * by empty strings. 3921 * </p> 3922 * 3923 * <pre> 3924 * StringUtils.join(null, *) = null 3925 * StringUtils.join([], *) = "" 3926 * StringUtils.join([null], *) = "" 3927 * StringUtils.join([1, 2, 3], ';') = "1;2;3" 3928 * StringUtils.join([1, 2, 3], null) = "123" 3929 * </pre> 3930 * 3931 * @param array 3932 * the array of values to join together, may be null 3933 * @param separator 3934 * the separator character to use 3935 * @return the joined String, {@code null} if null array input 3936 * @since 3.2 3937 */ 3938 public static String join(final int[] array, final char separator) { 3939 if (array == null) { 3940 return null; 3941 } 3942 return join(array, separator, 0, array.length); 3943 } 3944 3945 /** 3946 * <p> 3947 * Joins the elements of the provided array into a single String containing the provided list of elements. 3948 * </p> 3949 * 3950 * <p> 3951 * No delimiter is added before or after the list. Null objects or empty strings within the array are represented 3952 * by empty strings. 3953 * </p> 3954 * 3955 * <pre> 3956 * StringUtils.join(null, *) = null 3957 * StringUtils.join([], *) = "" 3958 * StringUtils.join([null], *) = "" 3959 * StringUtils.join([1, 2, 3], ';') = "1;2;3" 3960 * StringUtils.join([1, 2, 3], null) = "123" 3961 * </pre> 3962 * 3963 * @param array 3964 * the array of values to join together, may be null 3965 * @param separator 3966 * the separator character to use 3967 * @return the joined String, {@code null} if null array input 3968 * @since 3.2 3969 */ 3970 public static String join(final short[] array, final char separator) { 3971 if (array == null) { 3972 return null; 3973 } 3974 return join(array, separator, 0, array.length); 3975 } 3976 3977 /** 3978 * <p> 3979 * Joins the elements of the provided array into a single String containing the provided list of elements. 3980 * </p> 3981 * 3982 * <p> 3983 * No delimiter is added before or after the list. Null objects or empty strings within the array are represented 3984 * by empty strings. 3985 * </p> 3986 * 3987 * <pre> 3988 * StringUtils.join(null, *) = null 3989 * StringUtils.join([], *) = "" 3990 * StringUtils.join([null], *) = "" 3991 * StringUtils.join([1, 2, 3], ';') = "1;2;3" 3992 * StringUtils.join([1, 2, 3], null) = "123" 3993 * </pre> 3994 * 3995 * @param array 3996 * the array of values to join together, may be null 3997 * @param separator 3998 * the separator character to use 3999 * @return the joined String, {@code null} if null array input 4000 * @since 3.2 4001 */ 4002 public static String join(final byte[] array, final char separator) { 4003 if (array == null) { 4004 return null; 4005 } 4006 return join(array, separator, 0, array.length); 4007 } 4008 4009 /** 4010 * <p> 4011 * Joins the elements of the provided array into a single String containing the provided list of elements. 4012 * </p> 4013 * 4014 * <p> 4015 * No delimiter is added before or after the list. Null objects or empty strings within the array are represented 4016 * by empty strings. 4017 * </p> 4018 * 4019 * <pre> 4020 * StringUtils.join(null, *) = null 4021 * StringUtils.join([], *) = "" 4022 * StringUtils.join([null], *) = "" 4023 * StringUtils.join([1, 2, 3], ';') = "1;2;3" 4024 * StringUtils.join([1, 2, 3], null) = "123" 4025 * </pre> 4026 * 4027 * @param array 4028 * the array of values to join together, may be null 4029 * @param separator 4030 * the separator character to use 4031 * @return the joined String, {@code null} if null array input 4032 * @since 3.2 4033 */ 4034 public static String join(final char[] array, final char separator) { 4035 if (array == null) { 4036 return null; 4037 } 4038 return join(array, separator, 0, array.length); 4039 } 4040 4041 /** 4042 * <p> 4043 * Joins the elements of the provided array into a single String containing the provided list of elements. 4044 * </p> 4045 * 4046 * <p> 4047 * No delimiter is added before or after the list. Null objects or empty strings within the array are represented 4048 * by empty strings. 4049 * </p> 4050 * 4051 * <pre> 4052 * StringUtils.join(null, *) = null 4053 * StringUtils.join([], *) = "" 4054 * StringUtils.join([null], *) = "" 4055 * StringUtils.join([1, 2, 3], ';') = "1;2;3" 4056 * StringUtils.join([1, 2, 3], null) = "123" 4057 * </pre> 4058 * 4059 * @param array 4060 * the array of values to join together, may be null 4061 * @param separator 4062 * the separator character to use 4063 * @return the joined String, {@code null} if null array input 4064 * @since 3.2 4065 */ 4066 public static String join(final float[] array, final char separator) { 4067 if (array == null) { 4068 return null; 4069 } 4070 return join(array, separator, 0, array.length); 4071 } 4072 4073 /** 4074 * <p> 4075 * Joins the elements of the provided array into a single String containing the provided list of elements. 4076 * </p> 4077 * 4078 * <p> 4079 * No delimiter is added before or after the list. Null objects or empty strings within the array are represented 4080 * by empty strings. 4081 * </p> 4082 * 4083 * <pre> 4084 * StringUtils.join(null, *) = null 4085 * StringUtils.join([], *) = "" 4086 * StringUtils.join([null], *) = "" 4087 * StringUtils.join([1, 2, 3], ';') = "1;2;3" 4088 * StringUtils.join([1, 2, 3], null) = "123" 4089 * </pre> 4090 * 4091 * @param array 4092 * the array of values to join together, may be null 4093 * @param separator 4094 * the separator character to use 4095 * @return the joined String, {@code null} if null array input 4096 * @since 3.2 4097 */ 4098 public static String join(final double[] array, final char separator) { 4099 if (array == null) { 4100 return null; 4101 } 4102 return join(array, separator, 0, array.length); 4103 } 4104 4105 4106 /** 4107 * <p>Joins the elements of the provided array into a single String 4108 * containing the provided list of elements.</p> 4109 * 4110 * <p>No delimiter is added before or after the list. 4111 * Null objects or empty strings within the array are represented by 4112 * empty strings.</p> 4113 * 4114 * <pre> 4115 * StringUtils.join(null, *) = null 4116 * StringUtils.join([], *) = "" 4117 * StringUtils.join([null], *) = "" 4118 * StringUtils.join(["a", "b", "c"], ';') = "a;b;c" 4119 * StringUtils.join(["a", "b", "c"], null) = "abc" 4120 * StringUtils.join([null, "", "a"], ';') = ";;a" 4121 * </pre> 4122 * 4123 * @param array the array of values to join together, may be null 4124 * @param separator the separator character to use 4125 * @param startIndex the first index to start joining from. It is 4126 * an error to pass in an end index past the end of the array 4127 * @param endIndex the index to stop joining from (exclusive). It is 4128 * an error to pass in an end index past the end of the array 4129 * @return the joined String, {@code null} if null array input 4130 * @since 2.0 4131 */ 4132 public static String join(final Object[] array, final char separator, final int startIndex, final int endIndex) { 4133 if (array == null) { 4134 return null; 4135 } 4136 final int noOfItems = endIndex - startIndex; 4137 if (noOfItems <= 0) { 4138 return EMPTY; 4139 } 4140 final StringBuilder buf = new StringBuilder(noOfItems * 16); 4141 for (int i = startIndex; i < endIndex; i++) { 4142 if (i > startIndex) { 4143 buf.append(separator); 4144 } 4145 if (array[i] != null) { 4146 buf.append(array[i]); 4147 } 4148 } 4149 return buf.toString(); 4150 } 4151 4152 /** 4153 * <p> 4154 * Joins the elements of the provided array into a single String containing the provided list of elements. 4155 * </p> 4156 * 4157 * <p> 4158 * No delimiter is added before or after the list. Null objects or empty strings within the array are represented 4159 * by empty strings. 4160 * </p> 4161 * 4162 * <pre> 4163 * StringUtils.join(null, *) = null 4164 * StringUtils.join([], *) = "" 4165 * StringUtils.join([null], *) = "" 4166 * StringUtils.join([1, 2, 3], ';') = "1;2;3" 4167 * StringUtils.join([1, 2, 3], null) = "123" 4168 * </pre> 4169 * 4170 * @param array 4171 * the array of values to join together, may be null 4172 * @param separator 4173 * the separator character to use 4174 * @param startIndex 4175 * the first index to start joining from. It is an error to pass in an end index past the end of the 4176 * array 4177 * @param endIndex 4178 * the index to stop joining from (exclusive). It is an error to pass in an end index past the end of 4179 * the array 4180 * @return the joined String, {@code null} if null array input 4181 * @since 3.2 4182 */ 4183 public static String join(final long[] array, final char separator, final int startIndex, final int endIndex) { 4184 if (array == null) { 4185 return null; 4186 } 4187 final int noOfItems = endIndex - startIndex; 4188 if (noOfItems <= 0) { 4189 return EMPTY; 4190 } 4191 final StringBuilder buf = new StringBuilder(noOfItems * 16); 4192 for (int i = startIndex; i < endIndex; i++) { 4193 if (i > startIndex) { 4194 buf.append(separator); 4195 } 4196 buf.append(array[i]); 4197 } 4198 return buf.toString(); 4199 } 4200 4201 /** 4202 * <p> 4203 * Joins the elements of the provided array into a single String containing the provided list of elements. 4204 * </p> 4205 * 4206 * <p> 4207 * No delimiter is added before or after the list. Null objects or empty strings within the array are represented 4208 * by empty strings. 4209 * </p> 4210 * 4211 * <pre> 4212 * StringUtils.join(null, *) = null 4213 * StringUtils.join([], *) = "" 4214 * StringUtils.join([null], *) = "" 4215 * StringUtils.join([1, 2, 3], ';') = "1;2;3" 4216 * StringUtils.join([1, 2, 3], null) = "123" 4217 * </pre> 4218 * 4219 * @param array 4220 * the array of values to join together, may be null 4221 * @param separator 4222 * the separator character to use 4223 * @param startIndex 4224 * the first index to start joining from. It is an error to pass in an end index past the end of the 4225 * array 4226 * @param endIndex 4227 * the index to stop joining from (exclusive). It is an error to pass in an end index past the end of 4228 * the array 4229 * @return the joined String, {@code null} if null array input 4230 * @since 3.2 4231 */ 4232 public static String join(final int[] array, final char separator, final int startIndex, final int endIndex) { 4233 if (array == null) { 4234 return null; 4235 } 4236 final int noOfItems = endIndex - startIndex; 4237 if (noOfItems <= 0) { 4238 return EMPTY; 4239 } 4240 final StringBuilder buf = new StringBuilder(noOfItems * 16); 4241 for (int i = startIndex; i < endIndex; i++) { 4242 if (i > startIndex) { 4243 buf.append(separator); 4244 } 4245 buf.append(array[i]); 4246 } 4247 return buf.toString(); 4248 } 4249 4250 /** 4251 * <p> 4252 * Joins the elements of the provided array into a single String containing the provided list of elements. 4253 * </p> 4254 * 4255 * <p> 4256 * No delimiter is added before or after the list. Null objects or empty strings within the array are represented 4257 * by empty strings. 4258 * </p> 4259 * 4260 * <pre> 4261 * StringUtils.join(null, *) = null 4262 * StringUtils.join([], *) = "" 4263 * StringUtils.join([null], *) = "" 4264 * StringUtils.join([1, 2, 3], ';') = "1;2;3" 4265 * StringUtils.join([1, 2, 3], null) = "123" 4266 * </pre> 4267 * 4268 * @param array 4269 * the array of values to join together, may be null 4270 * @param separator 4271 * the separator character to use 4272 * @param startIndex 4273 * the first index to start joining from. It is an error to pass in an end index past the end of the 4274 * array 4275 * @param endIndex 4276 * the index to stop joining from (exclusive). It is an error to pass in an end index past the end of 4277 * the array 4278 * @return the joined String, {@code null} if null array input 4279 * @since 3.2 4280 */ 4281 public static String join(final byte[] array, final char separator, final int startIndex, final int endIndex) { 4282 if (array == null) { 4283 return null; 4284 } 4285 final int noOfItems = endIndex - startIndex; 4286 if (noOfItems <= 0) { 4287 return EMPTY; 4288 } 4289 final StringBuilder buf = new StringBuilder(noOfItems * 16); 4290 for (int i = startIndex; i < endIndex; i++) { 4291 if (i > startIndex) { 4292 buf.append(separator); 4293 } 4294 buf.append(array[i]); 4295 } 4296 return buf.toString(); 4297 } 4298 4299 /** 4300 * <p> 4301 * Joins the elements of the provided array into a single String containing the provided list of elements. 4302 * </p> 4303 * 4304 * <p> 4305 * No delimiter is added before or after the list. Null objects or empty strings within the array are represented 4306 * by empty strings. 4307 * </p> 4308 * 4309 * <pre> 4310 * StringUtils.join(null, *) = null 4311 * StringUtils.join([], *) = "" 4312 * StringUtils.join([null], *) = "" 4313 * StringUtils.join([1, 2, 3], ';') = "1;2;3" 4314 * StringUtils.join([1, 2, 3], null) = "123" 4315 * </pre> 4316 * 4317 * @param array 4318 * the array of values to join together, may be null 4319 * @param separator 4320 * the separator character to use 4321 * @param startIndex 4322 * the first index to start joining from. It is an error to pass in an end index past the end of the 4323 * array 4324 * @param endIndex 4325 * the index to stop joining from (exclusive). It is an error to pass in an end index past the end of 4326 * the array 4327 * @return the joined String, {@code null} if null array input 4328 * @since 3.2 4329 */ 4330 public static String join(final short[] array, final char separator, final int startIndex, final int endIndex) { 4331 if (array == null) { 4332 return null; 4333 } 4334 final int noOfItems = endIndex - startIndex; 4335 if (noOfItems <= 0) { 4336 return EMPTY; 4337 } 4338 final StringBuilder buf = new StringBuilder(noOfItems * 16); 4339 for (int i = startIndex; i < endIndex; i++) { 4340 if (i > startIndex) { 4341 buf.append(separator); 4342 } 4343 buf.append(array[i]); 4344 } 4345 return buf.toString(); 4346 } 4347 4348 /** 4349 * <p> 4350 * Joins the elements of the provided array into a single String containing the provided list of elements. 4351 * </p> 4352 * 4353 * <p> 4354 * No delimiter is added before or after the list. Null objects or empty strings within the array are represented 4355 * by empty strings. 4356 * </p> 4357 * 4358 * <pre> 4359 * StringUtils.join(null, *) = null 4360 * StringUtils.join([], *) = "" 4361 * StringUtils.join([null], *) = "" 4362 * StringUtils.join([1, 2, 3], ';') = "1;2;3" 4363 * StringUtils.join([1, 2, 3], null) = "123" 4364 * </pre> 4365 * 4366 * @param array 4367 * the array of values to join together, may be null 4368 * @param separator 4369 * the separator character to use 4370 * @param startIndex 4371 * the first index to start joining from. It is an error to pass in an end index past the end of the 4372 * array 4373 * @param endIndex 4374 * the index to stop joining from (exclusive). It is an error to pass in an end index past the end of 4375 * the array 4376 * @return the joined String, {@code null} if null array input 4377 * @since 3.2 4378 */ 4379 public static String join(final char[] array, final char separator, final int startIndex, final int endIndex) { 4380 if (array == null) { 4381 return null; 4382 } 4383 final int noOfItems = endIndex - startIndex; 4384 if (noOfItems <= 0) { 4385 return EMPTY; 4386 } 4387 final StringBuilder buf = new StringBuilder(noOfItems * 16); 4388 for (int i = startIndex; i < endIndex; i++) { 4389 if (i > startIndex) { 4390 buf.append(separator); 4391 } 4392 buf.append(array[i]); 4393 } 4394 return buf.toString(); 4395 } 4396 4397 /** 4398 * <p> 4399 * Joins the elements of the provided array into a single String containing the provided list of elements. 4400 * </p> 4401 * 4402 * <p> 4403 * No delimiter is added before or after the list. Null objects or empty strings within the array are represented 4404 * by empty strings. 4405 * </p> 4406 * 4407 * <pre> 4408 * StringUtils.join(null, *) = null 4409 * StringUtils.join([], *) = "" 4410 * StringUtils.join([null], *) = "" 4411 * StringUtils.join([1, 2, 3], ';') = "1;2;3" 4412 * StringUtils.join([1, 2, 3], null) = "123" 4413 * </pre> 4414 * 4415 * @param array 4416 * the array of values to join together, may be null 4417 * @param separator 4418 * the separator character to use 4419 * @param startIndex 4420 * the first index to start joining from. It is an error to pass in an end index past the end of the 4421 * array 4422 * @param endIndex 4423 * the index to stop joining from (exclusive). It is an error to pass in an end index past the end of 4424 * the array 4425 * @return the joined String, {@code null} if null array input 4426 * @since 3.2 4427 */ 4428 public static String join(final double[] array, final char separator, final int startIndex, final int endIndex) { 4429 if (array == null) { 4430 return null; 4431 } 4432 final int noOfItems = endIndex - startIndex; 4433 if (noOfItems <= 0) { 4434 return EMPTY; 4435 } 4436 final StringBuilder buf = new StringBuilder(noOfItems * 16); 4437 for (int i = startIndex; i < endIndex; i++) { 4438 if (i > startIndex) { 4439 buf.append(separator); 4440 } 4441 buf.append(array[i]); 4442 } 4443 return buf.toString(); 4444 } 4445 4446 /** 4447 * <p> 4448 * Joins the elements of the provided array into a single String containing the provided list of elements. 4449 * </p> 4450 * 4451 * <p> 4452 * No delimiter is added before or after the list. Null objects or empty strings within the array are represented 4453 * by empty strings. 4454 * </p> 4455 * 4456 * <pre> 4457 * StringUtils.join(null, *) = null 4458 * StringUtils.join([], *) = "" 4459 * StringUtils.join([null], *) = "" 4460 * StringUtils.join([1, 2, 3], ';') = "1;2;3" 4461 * StringUtils.join([1, 2, 3], null) = "123" 4462 * </pre> 4463 * 4464 * @param array 4465 * the array of values to join together, may be null 4466 * @param separator 4467 * the separator character to use 4468 * @param startIndex 4469 * the first index to start joining from. It is an error to pass in an end index past the end of the 4470 * array 4471 * @param endIndex 4472 * the index to stop joining from (exclusive). It is an error to pass in an end index past the end of 4473 * the array 4474 * @return the joined String, {@code null} if null array input 4475 * @since 3.2 4476 */ 4477 public static String join(final float[] array, final char separator, final int startIndex, final int endIndex) { 4478 if (array == null) { 4479 return null; 4480 } 4481 final int noOfItems = endIndex - startIndex; 4482 if (noOfItems <= 0) { 4483 return EMPTY; 4484 } 4485 final StringBuilder buf = new StringBuilder(noOfItems * 16); 4486 for (int i = startIndex; i < endIndex; i++) { 4487 if (i > startIndex) { 4488 buf.append(separator); 4489 } 4490 buf.append(array[i]); 4491 } 4492 return buf.toString(); 4493 } 4494 4495 4496 /** 4497 * <p>Joins the elements of the provided array into a single String 4498 * containing the provided list of elements.</p> 4499 * 4500 * <p>No delimiter is added before or after the list. 4501 * A {@code null} separator is the same as an empty String (""). 4502 * Null objects or empty strings within the array are represented by 4503 * empty strings.</p> 4504 * 4505 * <pre> 4506 * StringUtils.join(null, *) = null 4507 * StringUtils.join([], *) = "" 4508 * StringUtils.join([null], *) = "" 4509 * StringUtils.join(["a", "b", "c"], "--") = "a--b--c" 4510 * StringUtils.join(["a", "b", "c"], null) = "abc" 4511 * StringUtils.join(["a", "b", "c"], "") = "abc" 4512 * StringUtils.join([null, "", "a"], ',') = ",,a" 4513 * </pre> 4514 * 4515 * @param array the array of values to join together, may be null 4516 * @param separator the separator character to use, null treated as "" 4517 * @return the joined String, {@code null} if null array input 4518 */ 4519 public static String join(final Object[] array, final String separator) { 4520 if (array == null) { 4521 return null; 4522 } 4523 return join(array, separator, 0, array.length); 4524 } 4525 4526 /** 4527 * <p>Joins the elements of the provided array into a single String 4528 * containing the provided list of elements.</p> 4529 * 4530 * <p>No delimiter is added before or after the list. 4531 * A {@code null} separator is the same as an empty String (""). 4532 * Null objects or empty strings within the array are represented by 4533 * empty strings.</p> 4534 * 4535 * <pre> 4536 * StringUtils.join(null, *, *, *) = null 4537 * StringUtils.join([], *, *, *) = "" 4538 * StringUtils.join([null], *, *, *) = "" 4539 * StringUtils.join(["a", "b", "c"], "--", 0, 3) = "a--b--c" 4540 * StringUtils.join(["a", "b", "c"], "--", 1, 3) = "b--c" 4541 * StringUtils.join(["a", "b", "c"], "--", 2, 3) = "c" 4542 * StringUtils.join(["a", "b", "c"], "--", 2, 2) = "" 4543 * StringUtils.join(["a", "b", "c"], null, 0, 3) = "abc" 4544 * StringUtils.join(["a", "b", "c"], "", 0, 3) = "abc" 4545 * StringUtils.join([null, "", "a"], ',', 0, 3) = ",,a" 4546 * </pre> 4547 * 4548 * @param array the array of values to join together, may be null 4549 * @param separator the separator character to use, null treated as "" 4550 * @param startIndex the first index to start joining from. 4551 * @param endIndex the index to stop joining from (exclusive). 4552 * @return the joined String, {@code null} if null array input; or the empty string 4553 * if {@code endIndex - startIndex <= 0}. The number of joined entries is given by 4554 * {@code endIndex - startIndex} 4555 * @throws ArrayIndexOutOfBoundsException ife<br> 4556 * {@code startIndex < 0} or <br> 4557 * {@code startIndex >= array.length()} or <br> 4558 * {@code endIndex < 0} or <br> 4559 * {@code endIndex > array.length()} 4560 */ 4561 public static String join(final Object[] array, String separator, final int startIndex, final int endIndex) { 4562 if (array == null) { 4563 return null; 4564 } 4565 if (separator == null) { 4566 separator = EMPTY; 4567 } 4568 4569 // endIndex - startIndex > 0: Len = NofStrings *(len(firstString) + len(separator)) 4570 // (Assuming that all Strings are roughly equally long) 4571 final int noOfItems = endIndex - startIndex; 4572 if (noOfItems <= 0) { 4573 return EMPTY; 4574 } 4575 4576 final StringBuilder buf = new StringBuilder(noOfItems * 16); 4577 4578 for (int i = startIndex; i < endIndex; i++) { 4579 if (i > startIndex) { 4580 buf.append(separator); 4581 } 4582 if (array[i] != null) { 4583 buf.append(array[i]); 4584 } 4585 } 4586 return buf.toString(); 4587 } 4588 4589 /** 4590 * <p>Joins the elements of the provided {@code Iterator} into 4591 * a single String containing the provided elements.</p> 4592 * 4593 * <p>No delimiter is added before or after the list. Null objects or empty 4594 * strings within the iteration are represented by empty strings.</p> 4595 * 4596 * <p>See the examples here: {@link #join(Object[],char)}. </p> 4597 * 4598 * @param iterator the {@code Iterator} of values to join together, may be null 4599 * @param separator the separator character to use 4600 * @return the joined String, {@code null} if null iterator input 4601 * @since 2.0 4602 */ 4603 public static String join(final Iterator<?> iterator, final char separator) { 4604 4605 // handle null, zero and one elements before building a buffer 4606 if (iterator == null) { 4607 return null; 4608 } 4609 if (!iterator.hasNext()) { 4610 return EMPTY; 4611 } 4612 final Object first = iterator.next(); 4613 if (!iterator.hasNext()) { 4614 return Objects.toString(first, ""); 4615 } 4616 4617 // two or more elements 4618 final StringBuilder buf = new StringBuilder(256); // Java default is 16, probably too small 4619 if (first != null) { 4620 buf.append(first); 4621 } 4622 4623 while (iterator.hasNext()) { 4624 buf.append(separator); 4625 final Object obj = iterator.next(); 4626 if (obj != null) { 4627 buf.append(obj); 4628 } 4629 } 4630 4631 return buf.toString(); 4632 } 4633 4634 /** 4635 * <p>Joins the elements of the provided {@code Iterator} into 4636 * a single String containing the provided elements.</p> 4637 * 4638 * <p>No delimiter is added before or after the list. 4639 * A {@code null} separator is the same as an empty String ("").</p> 4640 * 4641 * <p>See the examples here: {@link #join(Object[],String)}. </p> 4642 * 4643 * @param iterator the {@code Iterator} of values to join together, may be null 4644 * @param separator the separator character to use, null treated as "" 4645 * @return the joined String, {@code null} if null iterator input 4646 */ 4647 public static String join(final Iterator<?> iterator, final String separator) { 4648 4649 // handle null, zero and one elements before building a buffer 4650 if (iterator == null) { 4651 return null; 4652 } 4653 if (!iterator.hasNext()) { 4654 return EMPTY; 4655 } 4656 final Object first = iterator.next(); 4657 if (!iterator.hasNext()) { 4658 return Objects.toString(first, ""); 4659 } 4660 4661 // two or more elements 4662 final StringBuilder buf = new StringBuilder(256); // Java default is 16, probably too small 4663 if (first != null) { 4664 buf.append(first); 4665 } 4666 4667 while (iterator.hasNext()) { 4668 if (separator != null) { 4669 buf.append(separator); 4670 } 4671 final Object obj = iterator.next(); 4672 if (obj != null) { 4673 buf.append(obj); 4674 } 4675 } 4676 return buf.toString(); 4677 } 4678 4679 /** 4680 * <p>Joins the elements of the provided {@code Iterable} into 4681 * a single String containing the provided elements.</p> 4682 * 4683 * <p>No delimiter is added before or after the list. Null objects or empty 4684 * strings within the iteration are represented by empty strings.</p> 4685 * 4686 * <p>See the examples here: {@link #join(Object[],char)}. </p> 4687 * 4688 * @param iterable the {@code Iterable} providing the values to join together, may be null 4689 * @param separator the separator character to use 4690 * @return the joined String, {@code null} if null iterator input 4691 * @since 2.3 4692 */ 4693 public static String join(final Iterable<?> iterable, final char separator) { 4694 if (iterable == null) { 4695 return null; 4696 } 4697 return join(iterable.iterator(), separator); 4698 } 4699 4700 /** 4701 * <p>Joins the elements of the provided {@code Iterable} into 4702 * a single String containing the provided elements.</p> 4703 * 4704 * <p>No delimiter is added before or after the list. 4705 * A {@code null} separator is the same as an empty String ("").</p> 4706 * 4707 * <p>See the examples here: {@link #join(Object[],String)}. </p> 4708 * 4709 * @param iterable the {@code Iterable} providing the values to join together, may be null 4710 * @param separator the separator character to use, null treated as "" 4711 * @return the joined String, {@code null} if null iterator input 4712 * @since 2.3 4713 */ 4714 public static String join(final Iterable<?> iterable, final String separator) { 4715 if (iterable == null) { 4716 return null; 4717 } 4718 return join(iterable.iterator(), separator); 4719 } 4720 4721 /** 4722 * <p>Joins the elements of the provided varargs into a 4723 * single String containing the provided elements.</p> 4724 * 4725 * <p>No delimiter is added before or after the list. 4726 * {@code null} elements and separator are treated as empty Strings ("").</p> 4727 * 4728 * <pre> 4729 * StringUtils.joinWith(",", {"a", "b"}) = "a,b" 4730 * StringUtils.joinWith(",", {"a", "b",""}) = "a,b," 4731 * StringUtils.joinWith(",", {"a", null, "b"}) = "a,,b" 4732 * StringUtils.joinWith(null, {"a", "b"}) = "ab" 4733 * </pre> 4734 * 4735 * @param separator the separator character to use, null treated as "" 4736 * @param objects the varargs providing the values to join together. {@code null} elements are treated as "" 4737 * @return the joined String. 4738 * @throws java.lang.IllegalArgumentException if a null varargs is provided 4739 * @since 3.5 4740 */ 4741 public static String joinWith(final String separator, final Object... objects) { 4742 if (objects == null) { 4743 throw new IllegalArgumentException("Object varargs must not be null"); 4744 } 4745 4746 final String sanitizedSeparator = defaultString(separator, StringUtils.EMPTY); 4747 4748 final StringBuilder result = new StringBuilder(); 4749 4750 final Iterator<Object> iterator = Arrays.asList(objects).iterator(); 4751 while (iterator.hasNext()) { 4752 final String value = Objects.toString(iterator.next(), ""); 4753 result.append(value); 4754 4755 if (iterator.hasNext()) { 4756 result.append(sanitizedSeparator); 4757 } 4758 } 4759 4760 return result.toString(); 4761 } 4762 4763 // Delete 4764 //----------------------------------------------------------------------- 4765 /** 4766 * <p>Deletes all whitespaces from a String as defined by 4767 * {@link Character#isWhitespace(char)}.</p> 4768 * 4769 * <pre> 4770 * StringUtils.deleteWhitespace(null) = null 4771 * StringUtils.deleteWhitespace("") = "" 4772 * StringUtils.deleteWhitespace("abc") = "abc" 4773 * StringUtils.deleteWhitespace(" ab c ") = "abc" 4774 * </pre> 4775 * 4776 * @param str the String to delete whitespace from, may be null 4777 * @return the String without whitespaces, {@code null} if null String input 4778 */ 4779 public static String deleteWhitespace(final String str) { 4780 if (isEmpty(str)) { 4781 return str; 4782 } 4783 final int sz = str.length(); 4784 final char[] chs = new char[sz]; 4785 int count = 0; 4786 for (int i = 0; i < sz; i++) { 4787 if (!Character.isWhitespace(str.charAt(i))) { 4788 chs[count++] = str.charAt(i); 4789 } 4790 } 4791 if (count == sz) { 4792 return str; 4793 } 4794 return new String(chs, 0, count); 4795 } 4796 4797 // Remove 4798 //----------------------------------------------------------------------- 4799 /** 4800 * <p>Removes a substring only if it is at the beginning of a source string, 4801 * otherwise returns the source string.</p> 4802 * 4803 * <p>A {@code null} source string will return {@code null}. 4804 * An empty ("") source string will return the empty string. 4805 * A {@code null} search string will return the source string.</p> 4806 * 4807 * <pre> 4808 * StringUtils.removeStart(null, *) = null 4809 * StringUtils.removeStart("", *) = "" 4810 * StringUtils.removeStart(*, null) = * 4811 * StringUtils.removeStart("www.domain.com", "www.") = "domain.com" 4812 * StringUtils.removeStart("domain.com", "www.") = "domain.com" 4813 * StringUtils.removeStart("www.domain.com", "domain") = "www.domain.com" 4814 * StringUtils.removeStart("abc", "") = "abc" 4815 * </pre> 4816 * 4817 * @param str the source String to search, may be null 4818 * @param remove the String to search for and remove, may be null 4819 * @return the substring with the string removed if found, 4820 * {@code null} if null String input 4821 * @since 2.1 4822 */ 4823 public static String removeStart(final String str, final String remove) { 4824 if (isEmpty(str) || isEmpty(remove)) { 4825 return str; 4826 } 4827 if (str.startsWith(remove)){ 4828 return str.substring(remove.length()); 4829 } 4830 return str; 4831 } 4832 4833 /** 4834 * <p>Case insensitive removal of a substring if it is at the beginning of a source string, 4835 * otherwise returns the source string.</p> 4836 * 4837 * <p>A {@code null} source string will return {@code null}. 4838 * An empty ("") source string will return the empty string. 4839 * A {@code null} search string will return the source string.</p> 4840 * 4841 * <pre> 4842 * StringUtils.removeStartIgnoreCase(null, *) = null 4843 * StringUtils.removeStartIgnoreCase("", *) = "" 4844 * StringUtils.removeStartIgnoreCase(*, null) = * 4845 * StringUtils.removeStartIgnoreCase("www.domain.com", "www.") = "domain.com" 4846 * StringUtils.removeStartIgnoreCase("www.domain.com", "WWW.") = "domain.com" 4847 * StringUtils.removeStartIgnoreCase("domain.com", "www.") = "domain.com" 4848 * StringUtils.removeStartIgnoreCase("www.domain.com", "domain") = "www.domain.com" 4849 * StringUtils.removeStartIgnoreCase("abc", "") = "abc" 4850 * </pre> 4851 * 4852 * @param str the source String to search, may be null 4853 * @param remove the String to search for (case insensitive) and remove, may be null 4854 * @return the substring with the string removed if found, 4855 * {@code null} if null String input 4856 * @since 2.4 4857 */ 4858 public static String removeStartIgnoreCase(final String str, final String remove) { 4859 if (isEmpty(str) || isEmpty(remove)) { 4860 return str; 4861 } 4862 if (startsWithIgnoreCase(str, remove)) { 4863 return str.substring(remove.length()); 4864 } 4865 return str; 4866 } 4867 4868 /** 4869 * <p>Removes a substring only if it is at the end of a source string, 4870 * otherwise returns the source string.</p> 4871 * 4872 * <p>A {@code null} source string will return {@code null}. 4873 * An empty ("") source string will return the empty string. 4874 * A {@code null} search string will return the source string.</p> 4875 * 4876 * <pre> 4877 * StringUtils.removeEnd(null, *) = null 4878 * StringUtils.removeEnd("", *) = "" 4879 * StringUtils.removeEnd(*, null) = * 4880 * StringUtils.removeEnd("www.domain.com", ".com.") = "www.domain.com" 4881 * StringUtils.removeEnd("www.domain.com", ".com") = "www.domain" 4882 * StringUtils.removeEnd("www.domain.com", "domain") = "www.domain.com" 4883 * StringUtils.removeEnd("abc", "") = "abc" 4884 * </pre> 4885 * 4886 * @param str the source String to search, may be null 4887 * @param remove the String to search for and remove, may be null 4888 * @return the substring with the string removed if found, 4889 * {@code null} if null String input 4890 * @since 2.1 4891 */ 4892 public static String removeEnd(final String str, final String remove) { 4893 if (isEmpty(str) || isEmpty(remove)) { 4894 return str; 4895 } 4896 if (str.endsWith(remove)) { 4897 return str.substring(0, str.length() - remove.length()); 4898 } 4899 return str; 4900 } 4901 4902 /** 4903 * <p>Case insensitive removal of a substring if it is at the end of a source string, 4904 * otherwise returns the source string.</p> 4905 * 4906 * <p>A {@code null} source string will return {@code null}. 4907 * An empty ("") source string will return the empty string. 4908 * A {@code null} search string will return the source string.</p> 4909 * 4910 * <pre> 4911 * StringUtils.removeEndIgnoreCase(null, *) = null 4912 * StringUtils.removeEndIgnoreCase("", *) = "" 4913 * StringUtils.removeEndIgnoreCase(*, null) = * 4914 * StringUtils.removeEndIgnoreCase("www.domain.com", ".com.") = "www.domain.com" 4915 * StringUtils.removeEndIgnoreCase("www.domain.com", ".com") = "www.domain" 4916 * StringUtils.removeEndIgnoreCase("www.domain.com", "domain") = "www.domain.com" 4917 * StringUtils.removeEndIgnoreCase("abc", "") = "abc" 4918 * StringUtils.removeEndIgnoreCase("www.domain.com", ".COM") = "www.domain") 4919 * StringUtils.removeEndIgnoreCase("www.domain.COM", ".com") = "www.domain") 4920 * </pre> 4921 * 4922 * @param str the source String to search, may be null 4923 * @param remove the String to search for (case insensitive) and remove, may be null 4924 * @return the substring with the string removed if found, 4925 * {@code null} if null String input 4926 * @since 2.4 4927 */ 4928 public static String removeEndIgnoreCase(final String str, final String remove) { 4929 if (isEmpty(str) || isEmpty(remove)) { 4930 return str; 4931 } 4932 if (endsWithIgnoreCase(str, remove)) { 4933 return str.substring(0, str.length() - remove.length()); 4934 } 4935 return str; 4936 } 4937 4938 /** 4939 * <p>Removes all occurrences of a substring from within the source string.</p> 4940 * 4941 * <p>A {@code null} source string will return {@code null}. 4942 * An empty ("") source string will return the empty string. 4943 * A {@code null} remove string will return the source string. 4944 * An empty ("") remove string will return the source string.</p> 4945 * 4946 * <pre> 4947 * StringUtils.remove(null, *) = null 4948 * StringUtils.remove("", *) = "" 4949 * StringUtils.remove(*, null) = * 4950 * StringUtils.remove(*, "") = * 4951 * StringUtils.remove("queued", "ue") = "qd" 4952 * StringUtils.remove("queued", "zz") = "queued" 4953 * </pre> 4954 * 4955 * @param str the source String to search, may be null 4956 * @param remove the String to search for and remove, may be null 4957 * @return the substring with the string removed if found, 4958 * {@code null} if null String input 4959 * @since 2.1 4960 */ 4961 public static String remove(final String str, final String remove) { 4962 if (isEmpty(str) || isEmpty(remove)) { 4963 return str; 4964 } 4965 return replace(str, remove, EMPTY, -1); 4966 } 4967 4968 /** 4969 * <p> 4970 * Case insensitive removal of all occurrences of a substring from within 4971 * the source string. 4972 * </p> 4973 * 4974 * <p> 4975 * A {@code null} source string will return {@code null}. An empty ("") 4976 * source string will return the empty string. A {@code null} remove string 4977 * will return the source string. An empty ("") remove string will return 4978 * the source string. 4979 * </p> 4980 * 4981 * <pre> 4982 * StringUtils.removeIgnoreCase(null, *) = null 4983 * StringUtils.removeIgnoreCase("", *) = "" 4984 * StringUtils.removeIgnoreCase(*, null) = * 4985 * StringUtils.removeIgnoreCase(*, "") = * 4986 * StringUtils.removeIgnoreCase("queued", "ue") = "qd" 4987 * StringUtils.removeIgnoreCase("queued", "zz") = "queued" 4988 * StringUtils.removeIgnoreCase("quEUed", "UE") = "qd" 4989 * StringUtils.removeIgnoreCase("queued", "zZ") = "queued" 4990 * </pre> 4991 * 4992 * @param str 4993 * the source String to search, may be null 4994 * @param remove 4995 * the String to search for (case insensitive) and remove, may be 4996 * null 4997 * @return the substring with the string removed if found, {@code null} if 4998 * null String input 4999 * @since 3.5 5000 */ 5001 public static String removeIgnoreCase(final String str, final String remove) { 5002 if (isEmpty(str) || isEmpty(remove)) { 5003 return str; 5004 } 5005 return replaceIgnoreCase(str, remove, EMPTY, -1); 5006 } 5007 5008 /** 5009 * <p>Removes all occurrences of a character from within the source string.</p> 5010 * 5011 * <p>A {@code null} source string will return {@code null}. 5012 * An empty ("") source string will return the empty string.</p> 5013 * 5014 * <pre> 5015 * StringUtils.remove(null, *) = null 5016 * StringUtils.remove("", *) = "" 5017 * StringUtils.remove("queued", 'u') = "qeed" 5018 * StringUtils.remove("queued", 'z') = "queued" 5019 * </pre> 5020 * 5021 * @param str the source String to search, may be null 5022 * @param remove the char to search for and remove, may be null 5023 * @return the substring with the char removed if found, 5024 * {@code null} if null String input 5025 * @since 2.1 5026 */ 5027 public static String remove(final String str, final char remove) { 5028 if (isEmpty(str) || str.indexOf(remove) == INDEX_NOT_FOUND) { 5029 return str; 5030 } 5031 final char[] chars = str.toCharArray(); 5032 int pos = 0; 5033 for (int i = 0; i < chars.length; i++) { 5034 if (chars[i] != remove) { 5035 chars[pos++] = chars[i]; 5036 } 5037 } 5038 return new String(chars, 0, pos); 5039 } 5040 5041 /** 5042 * <p>Removes each substring of the text String that matches the given regular expression.</p> 5043 * 5044 * This method is a {@code null} safe equivalent to: 5045 * <ul> 5046 * <li>{@code text.replaceAll(regex, StringUtils.EMPTY)}</li> 5047 * <li>{@code Pattern.compile(regex).matcher(text).replaceAll(StringUtils.EMPTY)}</li> 5048 * </ul> 5049 * 5050 * <p>A {@code null} reference passed to this method is a no-op.</p> 5051 * 5052 * <p>Unlike in the {@link #removePattern(String, String)} method, the {@link Pattern#DOTALL} option 5053 * is NOT automatically added. 5054 * To use the DOTALL option prepend <code>"(?s)"</code> to the regex. 5055 * DOTALL is also known as single-line mode in Perl.</p> 5056 * 5057 * <pre> 5058 * StringUtils.removeAll(null, *) = null 5059 * StringUtils.removeAll("any", null) = "any" 5060 * StringUtils.removeAll("any", "") = "any" 5061 * StringUtils.removeAll("any", ".*") = "" 5062 * StringUtils.removeAll("any", ".+") = "" 5063 * StringUtils.removeAll("abc", ".?") = "" 5064 * StringUtils.removeAll("A<__>\n<__>B", "<.*>") = "A\nB" 5065 * StringUtils.removeAll("A<__>\n<__>B", "(?s)<.*>") = "AB" 5066 * StringUtils.removeAll("ABCabc123abc", "[a-z]") = "ABC123" 5067 * </pre> 5068 * 5069 * @param text text to remove from, may be null 5070 * @param regex the regular expression to which this string is to be matched 5071 * @return the text with any removes processed, 5072 * {@code null} if null String input 5073 * 5074 * @throws java.util.regex.PatternSyntaxException 5075 * if the regular expression's syntax is invalid 5076 * 5077 * @see #replaceAll(String, String, String) 5078 * @see #removePattern(String, String) 5079 * @see String#replaceAll(String, String) 5080 * @see java.util.regex.Pattern 5081 * @see java.util.regex.Pattern#DOTALL 5082 * @since 3.5 5083 */ 5084 public static String removeAll(final String text, final String regex) { 5085 return replaceAll(text, regex, StringUtils.EMPTY); 5086 } 5087 5088 /** 5089 * <p>Removes the first substring of the text string that matches the given regular expression.</p> 5090 * 5091 * This method is a {@code null} safe equivalent to: 5092 * <ul> 5093 * <li>{@code text.replaceFirst(regex, StringUtils.EMPTY)}</li> 5094 * <li>{@code Pattern.compile(regex).matcher(text).replaceFirst(StringUtils.EMPTY)}</li> 5095 * </ul> 5096 * 5097 * <p>A {@code null} reference passed to this method is a no-op.</p> 5098 * 5099 * <p>The {@link Pattern#DOTALL} option is NOT automatically added. 5100 * To use the DOTALL option prepend <code>"(?s)"</code> to the regex. 5101 * DOTALL is also known as single-line mode in Perl.</p> 5102 * 5103 * <pre> 5104 * StringUtils.removeFirst(null, *) = null 5105 * StringUtils.removeFirst("any", null) = "any" 5106 * StringUtils.removeFirst("any", "") = "any" 5107 * StringUtils.removeFirst("any", ".*") = "" 5108 * StringUtils.removeFirst("any", ".+") = "" 5109 * StringUtils.removeFirst("abc", ".?") = "bc" 5110 * StringUtils.removeFirst("A<__>\n<__>B", "<.*>") = "A\n<__>B" 5111 * StringUtils.removeFirst("A<__>\n<__>B", "(?s)<.*>") = "AB" 5112 * StringUtils.removeFirst("ABCabc123", "[a-z]") = "ABCbc123" 5113 * StringUtils.removeFirst("ABCabc123abc", "[a-z]+") = "ABC123abc" 5114 * </pre> 5115 * 5116 * @param text text to remove from, may be null 5117 * @param regex the regular expression to which this string is to be matched 5118 * @return the text with the first replacement processed, 5119 * {@code null} if null String input 5120 * 5121 * @throws java.util.regex.PatternSyntaxException 5122 * if the regular expression's syntax is invalid 5123 * 5124 * @see #replaceFirst(String, String, String) 5125 * @see String#replaceFirst(String, String) 5126 * @see java.util.regex.Pattern 5127 * @see java.util.regex.Pattern#DOTALL 5128 * @since 3.5 5129 */ 5130 public static String removeFirst(final String text, final String regex) { 5131 return replaceFirst(text, regex, StringUtils.EMPTY); 5132 } 5133 5134 // Replacing 5135 //----------------------------------------------------------------------- 5136 /** 5137 * <p>Replaces a String with another String inside a larger String, once.</p> 5138 * 5139 * <p>A {@code null} reference passed to this method is a no-op.</p> 5140 * 5141 * <pre> 5142 * StringUtils.replaceOnce(null, *, *) = null 5143 * StringUtils.replaceOnce("", *, *) = "" 5144 * StringUtils.replaceOnce("any", null, *) = "any" 5145 * StringUtils.replaceOnce("any", *, null) = "any" 5146 * StringUtils.replaceOnce("any", "", *) = "any" 5147 * StringUtils.replaceOnce("aba", "a", null) = "aba" 5148 * StringUtils.replaceOnce("aba", "a", "") = "ba" 5149 * StringUtils.replaceOnce("aba", "a", "z") = "zba" 5150 * </pre> 5151 * 5152 * @see #replace(String text, String searchString, String replacement, int max) 5153 * @param text text to search and replace in, may be null 5154 * @param searchString the String to search for, may be null 5155 * @param replacement the String to replace with, may be null 5156 * @return the text with any replacements processed, 5157 * {@code null} if null String input 5158 */ 5159 public static String replaceOnce(final String text, final String searchString, final String replacement) { 5160 return replace(text, searchString, replacement, 1); 5161 } 5162 5163 /** 5164 * <p>Case insensitively replaces a String with another String inside a larger String, once.</p> 5165 * 5166 * <p>A {@code null} reference passed to this method is a no-op.</p> 5167 * 5168 * <pre> 5169 * StringUtils.replaceOnceIgnoreCase(null, *, *) = null 5170 * StringUtils.replaceOnceIgnoreCase("", *, *) = "" 5171 * StringUtils.replaceOnceIgnoreCase("any", null, *) = "any" 5172 * StringUtils.replaceOnceIgnoreCase("any", *, null) = "any" 5173 * StringUtils.replaceOnceIgnoreCase("any", "", *) = "any" 5174 * StringUtils.replaceOnceIgnoreCase("aba", "a", null) = "aba" 5175 * StringUtils.replaceOnceIgnoreCase("aba", "a", "") = "ba" 5176 * StringUtils.replaceOnceIgnoreCase("aba", "a", "z") = "zba" 5177 * StringUtils.replaceOnceIgnoreCase("FoOFoofoo", "foo", "") = "Foofoo" 5178 * </pre> 5179 * 5180 * @see #replaceIgnoreCase(String text, String searchString, String replacement, int max) 5181 * @param text text to search and replace in, may be null 5182 * @param searchString the String to search for (case insensitive), may be null 5183 * @param replacement the String to replace with, may be null 5184 * @return the text with any replacements processed, 5185 * {@code null} if null String input 5186 * @since 3.5 5187 */ 5188 public static String replaceOnceIgnoreCase(final String text, final String searchString, final String replacement) { 5189 return replaceIgnoreCase(text, searchString, replacement, 1); 5190 } 5191 5192 /** 5193 * <p>Replaces each substring of the source String that matches the given regular expression with the given 5194 * replacement using the {@link Pattern#DOTALL} option. DOTALL is also known as single-line mode in Perl.</p> 5195 * 5196 * This call is a {@code null} safe equivalent to: 5197 * <ul> 5198 * <li>{@code source.replaceAll("(?s)" + regex, replacement)}</li> 5199 * <li>{@code Pattern.compile(regex, Pattern.DOTALL).matcher(source).replaceAll(replacement)}</li> 5200 * </ul> 5201 * 5202 * <p>A {@code null} reference passed to this method is a no-op.</p> 5203 * 5204 * <pre> 5205 * StringUtils.replacePattern(null, *, *) = null 5206 * StringUtils.replacePattern("any", null, *) = "any" 5207 * StringUtils.replacePattern("any", *, null) = "any" 5208 * StringUtils.replacePattern("", "", "zzz") = "zzz" 5209 * StringUtils.replacePattern("", ".*", "zzz") = "zzz" 5210 * StringUtils.replacePattern("", ".+", "zzz") = "" 5211 * StringUtils.replacePattern("<__>\n<__>", "<.*>", "z") = "z" 5212 * StringUtils.replacePattern("ABCabc123", "[a-z]", "_") = "ABC___123" 5213 * StringUtils.replacePattern("ABCabc123", "[^A-Z0-9]+", "_") = "ABC_123" 5214 * StringUtils.replacePattern("ABCabc123", "[^A-Z0-9]+", "") = "ABC123" 5215 * StringUtils.replacePattern("Lorem ipsum dolor sit", "( +)([a-z]+)", "_$2") = "Lorem_ipsum_dolor_sit" 5216 * </pre> 5217 * 5218 * @param source 5219 * the source string 5220 * @param regex 5221 * the regular expression to which this string is to be matched 5222 * @param replacement 5223 * the string to be substituted for each match 5224 * @return The resulting {@code String} 5225 * @see #replaceAll(String, String, String) 5226 * @see String#replaceAll(String, String) 5227 * @see Pattern#DOTALL 5228 * @since 3.2 5229 * @since 3.5 Changed {@code null} reference passed to this method is a no-op. 5230 */ 5231 public static String replacePattern(final String source, final String regex, final String replacement) { 5232 if (source == null || regex == null || replacement == null) { 5233 return source; 5234 } 5235 return Pattern.compile(regex, Pattern.DOTALL).matcher(source).replaceAll(replacement); 5236 } 5237 5238 /** 5239 * <p>Removes each substring of the source String that matches the given regular expression using the DOTALL option. 5240 * </p> 5241 * 5242 * This call is a {@code null} safe equivalent to: 5243 * <ul> 5244 * <li>{@code source.replaceAll("(?s)" + regex, StringUtils.EMPTY)}</li> 5245 * <li>{@code Pattern.compile(regex, Pattern.DOTALL).matcher(source).replaceAll(StringUtils.EMPTY)}</li> 5246 * </ul> 5247 * 5248 * <p>A {@code null} reference passed to this method is a no-op.</p> 5249 * 5250 * <pre> 5251 * StringUtils.removePattern(null, *) = null 5252 * StringUtils.removePattern("any", null) = "any" 5253 * StringUtils.removePattern("A<__>\n<__>B", "<.*>") = "AB" 5254 * StringUtils.removePattern("ABCabc123", "[a-z]") = "ABC123" 5255 * </pre> 5256 * 5257 * @param source 5258 * the source string 5259 * @param regex 5260 * the regular expression to which this string is to be matched 5261 * @return The resulting {@code String} 5262 * @see #replacePattern(String, String, String) 5263 * @see String#replaceAll(String, String) 5264 * @see Pattern#DOTALL 5265 * @since 3.2 5266 * @since 3.5 Changed {@code null} reference passed to this method is a no-op. 5267 */ 5268 public static String removePattern(final String source, final String regex) { 5269 return replacePattern(source, regex, StringUtils.EMPTY); 5270 } 5271 5272 /** 5273 * <p>Replaces each substring of the text String that matches the given regular expression 5274 * with the given replacement.</p> 5275 * 5276 * This method is a {@code null} safe equivalent to: 5277 * <ul> 5278 * <li>{@code text.replaceAll(regex, replacement)}</li> 5279 * <li>{@code Pattern.compile(regex).matcher(text).replaceAll(replacement)}</li> 5280 * </ul> 5281 * 5282 * <p>A {@code null} reference passed to this method is a no-op.</p> 5283 * 5284 * <p>Unlike in the {@link #replacePattern(String, String, String)} method, the {@link Pattern#DOTALL} option 5285 * is NOT automatically added. 5286 * To use the DOTALL option prepend <code>"(?s)"</code> to the regex. 5287 * DOTALL is also known as single-line mode in Perl.</p> 5288 * 5289 * <pre> 5290 * StringUtils.replaceAll(null, *, *) = null 5291 * StringUtils.replaceAll("any", null, *) = "any" 5292 * StringUtils.replaceAll("any", *, null) = "any" 5293 * StringUtils.replaceAll("", "", "zzz") = "zzz" 5294 * StringUtils.replaceAll("", ".*", "zzz") = "zzz" 5295 * StringUtils.replaceAll("", ".+", "zzz") = "" 5296 * StringUtils.replaceAll("abc", "", "ZZ") = "ZZaZZbZZcZZ" 5297 * StringUtils.replaceAll("<__>\n<__>", "<.*>", "z") = "z\nz" 5298 * StringUtils.replaceAll("<__>\n<__>", "(?s)<.*>", "z") = "z" 5299 * StringUtils.replaceAll("ABCabc123", "[a-z]", "_") = "ABC___123" 5300 * StringUtils.replaceAll("ABCabc123", "[^A-Z0-9]+", "_") = "ABC_123" 5301 * StringUtils.replaceAll("ABCabc123", "[^A-Z0-9]+", "") = "ABC123" 5302 * StringUtils.replaceAll("Lorem ipsum dolor sit", "( +)([a-z]+)", "_$2") = "Lorem_ipsum_dolor_sit" 5303 * </pre> 5304 * 5305 * @param text text to search and replace in, may be null 5306 * @param regex the regular expression to which this string is to be matched 5307 * @param replacement the string to be substituted for each match 5308 * @return the text with any replacements processed, 5309 * {@code null} if null String input 5310 * 5311 * @throws java.util.regex.PatternSyntaxException 5312 * if the regular expression's syntax is invalid 5313 * 5314 * @see #replacePattern(String, String, String) 5315 * @see String#replaceAll(String, String) 5316 * @see java.util.regex.Pattern 5317 * @see java.util.regex.Pattern#DOTALL 5318 * @since 3.5 5319 */ 5320 public static String replaceAll(final String text, final String regex, final String replacement) { 5321 if (text == null || regex == null|| replacement == null ) { 5322 return text; 5323 } 5324 return text.replaceAll(regex, replacement); 5325 } 5326 5327 /** 5328 * <p>Replaces the first substring of the text string that matches the given regular expression 5329 * with the given replacement.</p> 5330 * 5331 * This method is a {@code null} safe equivalent to: 5332 * <ul> 5333 * <li>{@code text.replaceFirst(regex, replacement)}</li> 5334 * <li>{@code Pattern.compile(regex).matcher(text).replaceFirst(replacement)}</li> 5335 * </ul> 5336 * 5337 * <p>A {@code null} reference passed to this method is a no-op.</p> 5338 * 5339 * <p>The {@link Pattern#DOTALL} option is NOT automatically added. 5340 * To use the DOTALL option prepend <code>"(?s)"</code> to the regex. 5341 * DOTALL is also known as single-line mode in Perl.</p> 5342 * 5343 * <pre> 5344 * StringUtils.replaceFirst(null, *, *) = null 5345 * StringUtils.replaceFirst("any", null, *) = "any" 5346 * StringUtils.replaceFirst("any", *, null) = "any" 5347 * StringUtils.replaceFirst("", "", "zzz") = "zzz" 5348 * StringUtils.replaceFirst("", ".*", "zzz") = "zzz" 5349 * StringUtils.replaceFirst("", ".+", "zzz") = "" 5350 * StringUtils.replaceFirst("abc", "", "ZZ") = "ZZabc" 5351 * StringUtils.replaceFirst("<__>\n<__>", "<.*>", "z") = "z\n<__>" 5352 * StringUtils.replaceFirst("<__>\n<__>", "(?s)<.*>", "z") = "z" 5353 * StringUtils.replaceFirst("ABCabc123", "[a-z]", "_") = "ABC_bc123" 5354 * StringUtils.replaceFirst("ABCabc123abc", "[^A-Z0-9]+", "_") = "ABC_123abc" 5355 * StringUtils.replaceFirst("ABCabc123abc", "[^A-Z0-9]+", "") = "ABC123abc" 5356 * StringUtils.replaceFirst("Lorem ipsum dolor sit", "( +)([a-z]+)", "_$2") = "Lorem_ipsum dolor sit" 5357 * </pre> 5358 * 5359 * @param text text to search and replace in, may be null 5360 * @param regex the regular expression to which this string is to be matched 5361 * @param replacement the string to be substituted for the first match 5362 * @return the text with the first replacement processed, 5363 * {@code null} if null String input 5364 * 5365 * @throws java.util.regex.PatternSyntaxException 5366 * if the regular expression's syntax is invalid 5367 * 5368 * @see String#replaceFirst(String, String) 5369 * @see java.util.regex.Pattern 5370 * @see java.util.regex.Pattern#DOTALL 5371 * @since 3.5 5372 */ 5373 public static String replaceFirst(final String text, final String regex, final String replacement) { 5374 if (text == null || regex == null|| replacement == null ) { 5375 return text; 5376 } 5377 return text.replaceFirst(regex, replacement); 5378 } 5379 5380 /** 5381 * <p>Replaces all occurrences of a String within another String.</p> 5382 * 5383 * <p>A {@code null} reference passed to this method is a no-op.</p> 5384 * 5385 * <pre> 5386 * StringUtils.replace(null, *, *) = null 5387 * StringUtils.replace("", *, *) = "" 5388 * StringUtils.replace("any", null, *) = "any" 5389 * StringUtils.replace("any", *, null) = "any" 5390 * StringUtils.replace("any", "", *) = "any" 5391 * StringUtils.replace("aba", "a", null) = "aba" 5392 * StringUtils.replace("aba", "a", "") = "b" 5393 * StringUtils.replace("aba", "a", "z") = "zbz" 5394 * </pre> 5395 * 5396 * @see #replace(String text, String searchString, String replacement, int max) 5397 * @param text text to search and replace in, may be null 5398 * @param searchString the String to search for, may be null 5399 * @param replacement the String to replace it with, may be null 5400 * @return the text with any replacements processed, 5401 * {@code null} if null String input 5402 */ 5403 public static String replace(final String text, final String searchString, final String replacement) { 5404 return replace(text, searchString, replacement, -1); 5405 } 5406 5407 /** 5408 * <p>Case insensitively replaces all occurrences of a String within another String.</p> 5409 * 5410 * <p>A {@code null} reference passed to this method is a no-op.</p> 5411 * 5412 * <pre> 5413 * StringUtils.replaceIgnoreCase(null, *, *) = null 5414 * StringUtils.replaceIgnoreCase("", *, *) = "" 5415 * StringUtils.replaceIgnoreCase("any", null, *) = "any" 5416 * StringUtils.replaceIgnoreCase("any", *, null) = "any" 5417 * StringUtils.replaceIgnoreCase("any", "", *) = "any" 5418 * StringUtils.replaceIgnoreCase("aba", "a", null) = "aba" 5419 * StringUtils.replaceIgnoreCase("abA", "A", "") = "b" 5420 * StringUtils.replaceIgnoreCase("aba", "A", "z") = "zbz" 5421 * </pre> 5422 * 5423 * @see #replaceIgnoreCase(String text, String searchString, String replacement, int max) 5424 * @param text text to search and replace in, may be null 5425 * @param searchString the String to search for (case insensitive), may be null 5426 * @param replacement the String to replace it with, may be null 5427 * @return the text with any replacements processed, 5428 * {@code null} if null String input 5429 * @since 3.5 5430 */ 5431 public static String replaceIgnoreCase(final String text, final String searchString, final String replacement) { 5432 return replaceIgnoreCase(text, searchString, replacement, -1); 5433 } 5434 5435 /** 5436 * <p>Replaces a String with another String inside a larger String, 5437 * for the first {@code max} values of the search String.</p> 5438 * 5439 * <p>A {@code null} reference passed to this method is a no-op.</p> 5440 * 5441 * <pre> 5442 * StringUtils.replace(null, *, *, *) = null 5443 * StringUtils.replace("", *, *, *) = "" 5444 * StringUtils.replace("any", null, *, *) = "any" 5445 * StringUtils.replace("any", *, null, *) = "any" 5446 * StringUtils.replace("any", "", *, *) = "any" 5447 * StringUtils.replace("any", *, *, 0) = "any" 5448 * StringUtils.replace("abaa", "a", null, -1) = "abaa" 5449 * StringUtils.replace("abaa", "a", "", -1) = "b" 5450 * StringUtils.replace("abaa", "a", "z", 0) = "abaa" 5451 * StringUtils.replace("abaa", "a", "z", 1) = "zbaa" 5452 * StringUtils.replace("abaa", "a", "z", 2) = "zbza" 5453 * StringUtils.replace("abaa", "a", "z", -1) = "zbzz" 5454 * </pre> 5455 * 5456 * @param text text to search and replace in, may be null 5457 * @param searchString the String to search for, may be null 5458 * @param replacement the String to replace it with, may be null 5459 * @param max maximum number of values to replace, or {@code -1} if no maximum 5460 * @return the text with any replacements processed, 5461 * {@code null} if null String input 5462 */ 5463 public static String replace(final String text, final String searchString, final String replacement, final int max) { 5464 return replace(text, searchString, replacement, max, false); 5465 } 5466 5467 /** 5468 * <p>Replaces a String with another String inside a larger String, 5469 * for the first {@code max} values of the search String, 5470 * case sensitively/insensisitively based on {@code ignoreCase} value.</p> 5471 * 5472 * <p>A {@code null} reference passed to this method is a no-op.</p> 5473 * 5474 * <pre> 5475 * StringUtils.replace(null, *, *, *, false) = null 5476 * StringUtils.replace("", *, *, *, false) = "" 5477 * StringUtils.replace("any", null, *, *, false) = "any" 5478 * StringUtils.replace("any", *, null, *, false) = "any" 5479 * StringUtils.replace("any", "", *, *, false) = "any" 5480 * StringUtils.replace("any", *, *, 0, false) = "any" 5481 * StringUtils.replace("abaa", "a", null, -1, false) = "abaa" 5482 * StringUtils.replace("abaa", "a", "", -1, false) = "b" 5483 * StringUtils.replace("abaa", "a", "z", 0, false) = "abaa" 5484 * StringUtils.replace("abaa", "A", "z", 1, false) = "abaa" 5485 * StringUtils.replace("abaa", "A", "z", 1, true) = "zbaa" 5486 * StringUtils.replace("abAa", "a", "z", 2, true) = "zbza" 5487 * StringUtils.replace("abAa", "a", "z", -1, true) = "zbzz" 5488 * </pre> 5489 * 5490 * @param text text to search and replace in, may be null 5491 * @param searchString the String to search for (case insensitive), may be null 5492 * @param replacement the String to replace it with, may be null 5493 * @param max maximum number of values to replace, or {@code -1} if no maximum 5494 * @param ignoreCase if true replace is case insensitive, otherwise case sensitive 5495 * @return the text with any replacements processed, 5496 * {@code null} if null String input 5497 */ 5498 private static String replace(final String text, String searchString, final String replacement, int max, final boolean ignoreCase) { 5499 if (isEmpty(text) || isEmpty(searchString) || replacement == null || max == 0) { 5500 return text; 5501 } 5502 String searchText = text; 5503 if (ignoreCase) { 5504 searchText = text.toLowerCase(); 5505 searchString = searchString.toLowerCase(); 5506 } 5507 int start = 0; 5508 int end = searchText.indexOf(searchString, start); 5509 if (end == INDEX_NOT_FOUND) { 5510 return text; 5511 } 5512 final int replLength = searchString.length(); 5513 int increase = replacement.length() - replLength; 5514 increase = increase < 0 ? 0 : increase; 5515 increase *= max < 0 ? 16 : max > 64 ? 64 : max; 5516 final StringBuilder buf = new StringBuilder(text.length() + increase); 5517 while (end != INDEX_NOT_FOUND) { 5518 buf.append(text, start, end).append(replacement); 5519 start = end + replLength; 5520 if (--max == 0) { 5521 break; 5522 } 5523 end = searchText.indexOf(searchString, start); 5524 } 5525 buf.append(text, start, text.length()); 5526 return buf.toString(); 5527 } 5528 5529 /** 5530 * <p>Case insensitively replaces a String with another String inside a larger String, 5531 * for the first {@code max} values of the search String.</p> 5532 * 5533 * <p>A {@code null} reference passed to this method is a no-op.</p> 5534 * 5535 * <pre> 5536 * StringUtils.replaceIgnoreCase(null, *, *, *) = null 5537 * StringUtils.replaceIgnoreCase("", *, *, *) = "" 5538 * StringUtils.replaceIgnoreCase("any", null, *, *) = "any" 5539 * StringUtils.replaceIgnoreCase("any", *, null, *) = "any" 5540 * StringUtils.replaceIgnoreCase("any", "", *, *) = "any" 5541 * StringUtils.replaceIgnoreCase("any", *, *, 0) = "any" 5542 * StringUtils.replaceIgnoreCase("abaa", "a", null, -1) = "abaa" 5543 * StringUtils.replaceIgnoreCase("abaa", "a", "", -1) = "b" 5544 * StringUtils.replaceIgnoreCase("abaa", "a", "z", 0) = "abaa" 5545 * StringUtils.replaceIgnoreCase("abaa", "A", "z", 1) = "zbaa" 5546 * StringUtils.replaceIgnoreCase("abAa", "a", "z", 2) = "zbza" 5547 * StringUtils.replaceIgnoreCase("abAa", "a", "z", -1) = "zbzz" 5548 * </pre> 5549 * 5550 * @param text text to search and replace in, may be null 5551 * @param searchString the String to search for (case insensitive), may be null 5552 * @param replacement the String to replace it with, may be null 5553 * @param max maximum number of values to replace, or {@code -1} if no maximum 5554 * @return the text with any replacements processed, 5555 * {@code null} if null String input 5556 * @since 3.5 5557 */ 5558 public static String replaceIgnoreCase(final String text, final String searchString, final String replacement, final int max) { 5559 return replace(text, searchString, replacement, max, true); 5560 } 5561 5562 /** 5563 * <p> 5564 * Replaces all occurrences of Strings within another String. 5565 * </p> 5566 * 5567 * <p> 5568 * A {@code null} reference passed to this method is a no-op, or if 5569 * any "search string" or "string to replace" is null, that replace will be 5570 * ignored. This will not repeat. For repeating replaces, call the 5571 * overloaded method. 5572 * </p> 5573 * 5574 * <pre> 5575 * StringUtils.replaceEach(null, *, *) = null 5576 * StringUtils.replaceEach("", *, *) = "" 5577 * StringUtils.replaceEach("aba", null, null) = "aba" 5578 * StringUtils.replaceEach("aba", new String[0], null) = "aba" 5579 * StringUtils.replaceEach("aba", null, new String[0]) = "aba" 5580 * StringUtils.replaceEach("aba", new String[]{"a"}, null) = "aba" 5581 * StringUtils.replaceEach("aba", new String[]{"a"}, new String[]{""}) = "b" 5582 * StringUtils.replaceEach("aba", new String[]{null}, new String[]{"a"}) = "aba" 5583 * StringUtils.replaceEach("abcde", new String[]{"ab", "d"}, new String[]{"w", "t"}) = "wcte" 5584 * (example of how it does not repeat) 5585 * StringUtils.replaceEach("abcde", new String[]{"ab", "d"}, new String[]{"d", "t"}) = "dcte" 5586 * </pre> 5587 * 5588 * @param text 5589 * text to search and replace in, no-op if null 5590 * @param searchList 5591 * the Strings to search for, no-op if null 5592 * @param replacementList 5593 * the Strings to replace them with, no-op if null 5594 * @return the text with any replacements processed, {@code null} if 5595 * null String input 5596 * @throws IllegalArgumentException 5597 * if the lengths of the arrays are not the same (null is ok, 5598 * and/or size 0) 5599 * @since 2.4 5600 */ 5601 public static String replaceEach(final String text, final String[] searchList, final String[] replacementList) { 5602 return replaceEach(text, searchList, replacementList, false, 0); 5603 } 5604 5605 /** 5606 * <p> 5607 * Replaces all occurrences of Strings within another String. 5608 * </p> 5609 * 5610 * <p> 5611 * A {@code null} reference passed to this method is a no-op, or if 5612 * any "search string" or "string to replace" is null, that replace will be 5613 * ignored. 5614 * </p> 5615 * 5616 * <pre> 5617 * StringUtils.replaceEachRepeatedly(null, *, *) = null 5618 * StringUtils.replaceEachRepeatedly("", *, *) = "" 5619 * StringUtils.replaceEachRepeatedly("aba", null, null) = "aba" 5620 * StringUtils.replaceEachRepeatedly("aba", new String[0], null) = "aba" 5621 * StringUtils.replaceEachRepeatedly("aba", null, new String[0]) = "aba" 5622 * StringUtils.replaceEachRepeatedly("aba", new String[]{"a"}, null) = "aba" 5623 * StringUtils.replaceEachRepeatedly("aba", new String[]{"a"}, new String[]{""}) = "b" 5624 * StringUtils.replaceEachRepeatedly("aba", new String[]{null}, new String[]{"a"}) = "aba" 5625 * StringUtils.replaceEachRepeatedly("abcde", new String[]{"ab", "d"}, new String[]{"w", "t"}) = "wcte" 5626 * (example of how it repeats) 5627 * StringUtils.replaceEachRepeatedly("abcde", new String[]{"ab", "d"}, new String[]{"d", "t"}) = "tcte" 5628 * StringUtils.replaceEachRepeatedly("abcde", new String[]{"ab", "d"}, new String[]{"d", "ab"}) = IllegalStateException 5629 * </pre> 5630 * 5631 * @param text 5632 * text to search and replace in, no-op if null 5633 * @param searchList 5634 * the Strings to search for, no-op if null 5635 * @param replacementList 5636 * the Strings to replace them with, no-op if null 5637 * @return the text with any replacements processed, {@code null} if 5638 * null String input 5639 * @throws IllegalStateException 5640 * if the search is repeating and there is an endless loop due 5641 * to outputs of one being inputs to another 5642 * @throws IllegalArgumentException 5643 * if the lengths of the arrays are not the same (null is ok, 5644 * and/or size 0) 5645 * @since 2.4 5646 */ 5647 public static String replaceEachRepeatedly(final String text, final String[] searchList, final String[] replacementList) { 5648 // timeToLive should be 0 if not used or nothing to replace, else it's 5649 // the length of the replace array 5650 final int timeToLive = searchList == null ? 0 : searchList.length; 5651 return replaceEach(text, searchList, replacementList, true, timeToLive); 5652 } 5653 5654 /** 5655 * <p> 5656 * Replace all occurrences of Strings within another String. 5657 * This is a private recursive helper method for {@link #replaceEachRepeatedly(String, String[], String[])} and 5658 * {@link #replaceEach(String, String[], String[])} 5659 * </p> 5660 * 5661 * <p> 5662 * A {@code null} reference passed to this method is a no-op, or if 5663 * any "search string" or "string to replace" is null, that replace will be 5664 * ignored. 5665 * </p> 5666 * 5667 * <pre> 5668 * StringUtils.replaceEach(null, *, *, *, *) = null 5669 * StringUtils.replaceEach("", *, *, *, *) = "" 5670 * StringUtils.replaceEach("aba", null, null, *, *) = "aba" 5671 * StringUtils.replaceEach("aba", new String[0], null, *, *) = "aba" 5672 * StringUtils.replaceEach("aba", null, new String[0], *, *) = "aba" 5673 * StringUtils.replaceEach("aba", new String[]{"a"}, null, *, *) = "aba" 5674 * StringUtils.replaceEach("aba", new String[]{"a"}, new String[]{""}, *, >=0) = "b" 5675 * StringUtils.replaceEach("aba", new String[]{null}, new String[]{"a"}, *, >=0) = "aba" 5676 * StringUtils.replaceEach("abcde", new String[]{"ab", "d"}, new String[]{"w", "t"}, *, >=0) = "wcte" 5677 * (example of how it repeats) 5678 * StringUtils.replaceEach("abcde", new String[]{"ab", "d"}, new String[]{"d", "t"}, false, >=0) = "dcte" 5679 * StringUtils.replaceEach("abcde", new String[]{"ab", "d"}, new String[]{"d", "t"}, true, >=2) = "tcte" 5680 * StringUtils.replaceEach("abcde", new String[]{"ab", "d"}, new String[]{"d", "ab"}, *, *) = IllegalStateException 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 * @param repeat if true, then replace repeatedly 5690 * until there are no more possible replacements or timeToLive < 0 5691 * @param timeToLive 5692 * if less than 0 then there is a circular reference and endless 5693 * loop 5694 * @return the text with any replacements processed, {@code null} if 5695 * null String input 5696 * @throws IllegalStateException 5697 * if the search is repeating and there is an endless loop due 5698 * to outputs of one being inputs to another 5699 * @throws IllegalArgumentException 5700 * if the lengths of the arrays are not the same (null is ok, 5701 * and/or size 0) 5702 * @since 2.4 5703 */ 5704 private static String replaceEach( 5705 final String text, final String[] searchList, final String[] replacementList, final boolean repeat, final int timeToLive) { 5706 5707 // mchyzer Performance note: This creates very few new objects (one major goal) 5708 // let me know if there are performance requests, we can create a harness to measure 5709 5710 if (text == null || text.isEmpty() || searchList == null || 5711 searchList.length == 0 || replacementList == null || replacementList.length == 0) { 5712 return text; 5713 } 5714 5715 // if recursing, this shouldn't be less than 0 5716 if (timeToLive < 0) { 5717 throw new IllegalStateException("Aborting to protect against StackOverflowError - " + 5718 "output of one loop is the input of another"); 5719 } 5720 5721 final int searchLength = searchList.length; 5722 final int replacementLength = replacementList.length; 5723 5724 // make sure lengths are ok, these need to be equal 5725 if (searchLength != replacementLength) { 5726 throw new IllegalArgumentException("Search and Replace array lengths don't match: " 5727 + searchLength 5728 + " vs " 5729 + replacementLength); 5730 } 5731 5732 // keep track of which still have matches 5733 final boolean[] noMoreMatchesForReplIndex = new boolean[searchLength]; 5734 5735 // index on index that the match was found 5736 int textIndex = -1; 5737 int replaceIndex = -1; 5738 int tempIndex = -1; 5739 5740 // index of replace array that will replace the search string found 5741 // NOTE: logic duplicated below START 5742 for (int i = 0; i < searchLength; i++) { 5743 if (noMoreMatchesForReplIndex[i] || searchList[i] == null || 5744 searchList[i].isEmpty() || replacementList[i] == null) { 5745 continue; 5746 } 5747 tempIndex = text.indexOf(searchList[i]); 5748 5749 // see if we need to keep searching for this 5750 if (tempIndex == -1) { 5751 noMoreMatchesForReplIndex[i] = true; 5752 } else { 5753 if (textIndex == -1 || tempIndex < textIndex) { 5754 textIndex = tempIndex; 5755 replaceIndex = i; 5756 } 5757 } 5758 } 5759 // NOTE: logic mostly below END 5760 5761 // no search strings found, we are done 5762 if (textIndex == -1) { 5763 return text; 5764 } 5765 5766 int start = 0; 5767 5768 // get a good guess on the size of the result buffer so it doesn't have to double if it goes over a bit 5769 int increase = 0; 5770 5771 // count the replacement text elements that are larger than their corresponding text being replaced 5772 for (int i = 0; i < searchList.length; i++) { 5773 if (searchList[i] == null || replacementList[i] == null) { 5774 continue; 5775 } 5776 final int greater = replacementList[i].length() - searchList[i].length(); 5777 if (greater > 0) { 5778 increase += 3 * greater; // assume 3 matches 5779 } 5780 } 5781 // have upper-bound at 20% increase, then let Java take over 5782 increase = Math.min(increase, text.length() / 5); 5783 5784 final StringBuilder buf = new StringBuilder(text.length() + increase); 5785 5786 while (textIndex != -1) { 5787 5788 for (int i = start; i < textIndex; i++) { 5789 buf.append(text.charAt(i)); 5790 } 5791 buf.append(replacementList[replaceIndex]); 5792 5793 start = textIndex + searchList[replaceIndex].length(); 5794 5795 textIndex = -1; 5796 replaceIndex = -1; 5797 tempIndex = -1; 5798 // find the next earliest match 5799 // NOTE: logic mostly duplicated above START 5800 for (int i = 0; i < searchLength; i++) { 5801 if (noMoreMatchesForReplIndex[i] || searchList[i] == null || 5802 searchList[i].isEmpty() || replacementList[i] == null) { 5803 continue; 5804 } 5805 tempIndex = text.indexOf(searchList[i], start); 5806 5807 // see if we need to keep searching for this 5808 if (tempIndex == -1) { 5809 noMoreMatchesForReplIndex[i] = true; 5810 } else { 5811 if (textIndex == -1 || tempIndex < textIndex) { 5812 textIndex = tempIndex; 5813 replaceIndex = i; 5814 } 5815 } 5816 } 5817 // NOTE: logic duplicated above END 5818 5819 } 5820 final int textLength = text.length(); 5821 for (int i = start; i < textLength; i++) { 5822 buf.append(text.charAt(i)); 5823 } 5824 final String result = buf.toString(); 5825 if (!repeat) { 5826 return result; 5827 } 5828 5829 return replaceEach(result, searchList, replacementList, repeat, timeToLive - 1); 5830 } 5831 5832 // Replace, character based 5833 //----------------------------------------------------------------------- 5834 /** 5835 * <p>Replaces all occurrences of a character in a String with another. 5836 * This is a null-safe version of {@link String#replace(char, char)}.</p> 5837 * 5838 * <p>A {@code null} string input returns {@code null}. 5839 * An empty ("") string input returns an empty string.</p> 5840 * 5841 * <pre> 5842 * StringUtils.replaceChars(null, *, *) = null 5843 * StringUtils.replaceChars("", *, *) = "" 5844 * StringUtils.replaceChars("abcba", 'b', 'y') = "aycya" 5845 * StringUtils.replaceChars("abcba", 'z', 'y') = "abcba" 5846 * </pre> 5847 * 5848 * @param str String to replace characters in, may be null 5849 * @param searchChar the character to search for, may be null 5850 * @param replaceChar the character to replace, may be null 5851 * @return modified String, {@code null} if null string input 5852 * @since 2.0 5853 */ 5854 public static String replaceChars(final String str, final char searchChar, final char replaceChar) { 5855 if (str == null) { 5856 return null; 5857 } 5858 return str.replace(searchChar, replaceChar); 5859 } 5860 5861 /** 5862 * <p>Replaces multiple characters in a String in one go. 5863 * This method can also be used to delete characters.</p> 5864 * 5865 * <p>For example:<br> 5866 * <code>replaceChars("hello", "ho", "jy") = jelly</code>.</p> 5867 * 5868 * <p>A {@code null} string input returns {@code null}. 5869 * An empty ("") string input returns an empty string. 5870 * A null or empty set of search characters returns the input string.</p> 5871 * 5872 * <p>The length of the search characters should normally equal the length 5873 * of the replace characters. 5874 * If the search characters is longer, then the extra search characters 5875 * are deleted. 5876 * If the search characters is shorter, then the extra replace characters 5877 * are ignored.</p> 5878 * 5879 * <pre> 5880 * StringUtils.replaceChars(null, *, *) = null 5881 * StringUtils.replaceChars("", *, *) = "" 5882 * StringUtils.replaceChars("abc", null, *) = "abc" 5883 * StringUtils.replaceChars("abc", "", *) = "abc" 5884 * StringUtils.replaceChars("abc", "b", null) = "ac" 5885 * StringUtils.replaceChars("abc", "b", "") = "ac" 5886 * StringUtils.replaceChars("abcba", "bc", "yz") = "ayzya" 5887 * StringUtils.replaceChars("abcba", "bc", "y") = "ayya" 5888 * StringUtils.replaceChars("abcba", "bc", "yzx") = "ayzya" 5889 * </pre> 5890 * 5891 * @param str String to replace characters in, may be null 5892 * @param searchChars a set of characters to search for, may be null 5893 * @param replaceChars a set of characters to replace, may be null 5894 * @return modified String, {@code null} if null string input 5895 * @since 2.0 5896 */ 5897 public static String replaceChars(final String str, final String searchChars, String replaceChars) { 5898 if (isEmpty(str) || isEmpty(searchChars)) { 5899 return str; 5900 } 5901 if (replaceChars == null) { 5902 replaceChars = EMPTY; 5903 } 5904 boolean modified = false; 5905 final int replaceCharsLength = replaceChars.length(); 5906 final int strLength = str.length(); 5907 final StringBuilder buf = new StringBuilder(strLength); 5908 for (int i = 0; i < strLength; i++) { 5909 final char ch = str.charAt(i); 5910 final int index = searchChars.indexOf(ch); 5911 if (index >= 0) { 5912 modified = true; 5913 if (index < replaceCharsLength) { 5914 buf.append(replaceChars.charAt(index)); 5915 } 5916 } else { 5917 buf.append(ch); 5918 } 5919 } 5920 if (modified) { 5921 return buf.toString(); 5922 } 5923 return str; 5924 } 5925 5926 // Overlay 5927 //----------------------------------------------------------------------- 5928 /** 5929 * <p>Overlays part of a String with another String.</p> 5930 * 5931 * <p>A {@code null} string input returns {@code null}. 5932 * A negative index is treated as zero. 5933 * An index greater than the string length is treated as the string length. 5934 * The start index is always the smaller of the two indices.</p> 5935 * 5936 * <pre> 5937 * StringUtils.overlay(null, *, *, *) = null 5938 * StringUtils.overlay("", "abc", 0, 0) = "abc" 5939 * StringUtils.overlay("abcdef", null, 2, 4) = "abef" 5940 * StringUtils.overlay("abcdef", "", 2, 4) = "abef" 5941 * StringUtils.overlay("abcdef", "", 4, 2) = "abef" 5942 * StringUtils.overlay("abcdef", "zzzz", 2, 4) = "abzzzzef" 5943 * StringUtils.overlay("abcdef", "zzzz", 4, 2) = "abzzzzef" 5944 * StringUtils.overlay("abcdef", "zzzz", -1, 4) = "zzzzef" 5945 * StringUtils.overlay("abcdef", "zzzz", 2, 8) = "abzzzz" 5946 * StringUtils.overlay("abcdef", "zzzz", -2, -3) = "zzzzabcdef" 5947 * StringUtils.overlay("abcdef", "zzzz", 8, 10) = "abcdefzzzz" 5948 * </pre> 5949 * 5950 * @param str the String to do overlaying in, may be null 5951 * @param overlay the String to overlay, may be null 5952 * @param start the position to start overlaying at 5953 * @param end the position to stop overlaying before 5954 * @return overlayed String, {@code null} if null String input 5955 * @since 2.0 5956 */ 5957 public static String overlay(final String str, String overlay, int start, int end) { 5958 if (str == null) { 5959 return null; 5960 } 5961 if (overlay == null) { 5962 overlay = EMPTY; 5963 } 5964 final int len = str.length(); 5965 if (start < 0) { 5966 start = 0; 5967 } 5968 if (start > len) { 5969 start = len; 5970 } 5971 if (end < 0) { 5972 end = 0; 5973 } 5974 if (end > len) { 5975 end = len; 5976 } 5977 if (start > end) { 5978 final int temp = start; 5979 start = end; 5980 end = temp; 5981 } 5982 return str.substring(0, start) + 5983 overlay + 5984 str.substring(end); 5985 } 5986 5987 // Chomping 5988 //----------------------------------------------------------------------- 5989 /** 5990 * <p>Removes one newline from end of a String if it's there, 5991 * otherwise leave it alone. A newline is "{@code \n}", 5992 * "{@code \r}", or "{@code \r\n}".</p> 5993 * 5994 * <p>NOTE: This method changed in 2.0. 5995 * It now more closely matches Perl chomp.</p> 5996 * 5997 * <pre> 5998 * StringUtils.chomp(null) = null 5999 * StringUtils.chomp("") = "" 6000 * StringUtils.chomp("abc \r") = "abc " 6001 * StringUtils.chomp("abc\n") = "abc" 6002 * StringUtils.chomp("abc\r\n") = "abc" 6003 * StringUtils.chomp("abc\r\n\r\n") = "abc\r\n" 6004 * StringUtils.chomp("abc\n\r") = "abc\n" 6005 * StringUtils.chomp("abc\n\rabc") = "abc\n\rabc" 6006 * StringUtils.chomp("\r") = "" 6007 * StringUtils.chomp("\n") = "" 6008 * StringUtils.chomp("\r\n") = "" 6009 * </pre> 6010 * 6011 * @param str the String to chomp a newline from, may be null 6012 * @return String without newline, {@code null} if null String input 6013 */ 6014 public static String chomp(final String str) { 6015 if (isEmpty(str)) { 6016 return str; 6017 } 6018 6019 if (str.length() == 1) { 6020 final char ch = str.charAt(0); 6021 if (ch == CharUtils.CR || ch == CharUtils.LF) { 6022 return EMPTY; 6023 } 6024 return str; 6025 } 6026 6027 int lastIdx = str.length() - 1; 6028 final char last = str.charAt(lastIdx); 6029 6030 if (last == CharUtils.LF) { 6031 if (str.charAt(lastIdx - 1) == CharUtils.CR) { 6032 lastIdx--; 6033 } 6034 } else if (last != CharUtils.CR) { 6035 lastIdx++; 6036 } 6037 return str.substring(0, lastIdx); 6038 } 6039 6040 /** 6041 * <p>Removes {@code separator} from the end of 6042 * {@code str} if it's there, otherwise leave it alone.</p> 6043 * 6044 * <p>NOTE: This method changed in version 2.0. 6045 * It now more closely matches Perl chomp. 6046 * For the previous behavior, use {@link #substringBeforeLast(String, String)}. 6047 * This method uses {@link String#endsWith(String)}.</p> 6048 * 6049 * <pre> 6050 * StringUtils.chomp(null, *) = null 6051 * StringUtils.chomp("", *) = "" 6052 * StringUtils.chomp("foobar", "bar") = "foo" 6053 * StringUtils.chomp("foobar", "baz") = "foobar" 6054 * StringUtils.chomp("foo", "foo") = "" 6055 * StringUtils.chomp("foo ", "foo") = "foo " 6056 * StringUtils.chomp(" foo", "foo") = " " 6057 * StringUtils.chomp("foo", "foooo") = "foo" 6058 * StringUtils.chomp("foo", "") = "foo" 6059 * StringUtils.chomp("foo", null) = "foo" 6060 * </pre> 6061 * 6062 * @param str the String to chomp from, may be null 6063 * @param separator separator String, may be null 6064 * @return String without trailing separator, {@code null} if null String input 6065 * @deprecated This feature will be removed in Lang 4.0, use {@link StringUtils#removeEnd(String, String)} instead 6066 */ 6067 @Deprecated 6068 public static String chomp(final String str, final String separator) { 6069 return removeEnd(str,separator); 6070 } 6071 6072 // Chopping 6073 //----------------------------------------------------------------------- 6074 /** 6075 * <p>Remove the last character from a String.</p> 6076 * 6077 * <p>If the String ends in {@code \r\n}, then remove both 6078 * of them.</p> 6079 * 6080 * <pre> 6081 * StringUtils.chop(null) = null 6082 * StringUtils.chop("") = "" 6083 * StringUtils.chop("abc \r") = "abc " 6084 * StringUtils.chop("abc\n") = "abc" 6085 * StringUtils.chop("abc\r\n") = "abc" 6086 * StringUtils.chop("abc") = "ab" 6087 * StringUtils.chop("abc\nabc") = "abc\nab" 6088 * StringUtils.chop("a") = "" 6089 * StringUtils.chop("\r") = "" 6090 * StringUtils.chop("\n") = "" 6091 * StringUtils.chop("\r\n") = "" 6092 * </pre> 6093 * 6094 * @param str the String to chop last character from, may be null 6095 * @return String without last character, {@code null} if null String input 6096 */ 6097 public static String chop(final String str) { 6098 if (str == null) { 6099 return null; 6100 } 6101 final int strLen = str.length(); 6102 if (strLen < 2) { 6103 return EMPTY; 6104 } 6105 final int lastIdx = strLen - 1; 6106 final String ret = str.substring(0, lastIdx); 6107 final char last = str.charAt(lastIdx); 6108 if (last == CharUtils.LF && ret.charAt(lastIdx - 1) == CharUtils.CR) { 6109 return ret.substring(0, lastIdx - 1); 6110 } 6111 return ret; 6112 } 6113 6114 // Conversion 6115 //----------------------------------------------------------------------- 6116 6117 // Padding 6118 //----------------------------------------------------------------------- 6119 /** 6120 * <p>Repeat a String {@code repeat} times to form a 6121 * new String.</p> 6122 * 6123 * <pre> 6124 * StringUtils.repeat(null, 2) = null 6125 * StringUtils.repeat("", 0) = "" 6126 * StringUtils.repeat("", 2) = "" 6127 * StringUtils.repeat("a", 3) = "aaa" 6128 * StringUtils.repeat("ab", 2) = "abab" 6129 * StringUtils.repeat("a", -2) = "" 6130 * </pre> 6131 * 6132 * @param str the String to repeat, may be null 6133 * @param repeat number of times to repeat str, negative treated as zero 6134 * @return a new String consisting of the original String repeated, 6135 * {@code null} if null String input 6136 */ 6137 public static String repeat(final String str, final int repeat) { 6138 // Performance tuned for 2.0 (JDK1.4) 6139 6140 if (str == null) { 6141 return null; 6142 } 6143 if (repeat <= 0) { 6144 return EMPTY; 6145 } 6146 final int inputLength = str.length(); 6147 if (repeat == 1 || inputLength == 0) { 6148 return str; 6149 } 6150 if (inputLength == 1 && repeat <= PAD_LIMIT) { 6151 return repeat(str.charAt(0), repeat); 6152 } 6153 6154 final int outputLength = inputLength * repeat; 6155 switch (inputLength) { 6156 case 1 : 6157 return repeat(str.charAt(0), repeat); 6158 case 2 : 6159 final char ch0 = str.charAt(0); 6160 final char ch1 = str.charAt(1); 6161 final char[] output2 = new char[outputLength]; 6162 for (int i = repeat * 2 - 2; i >= 0; i--, i--) { 6163 output2[i] = ch0; 6164 output2[i + 1] = ch1; 6165 } 6166 return new String(output2); 6167 default : 6168 final StringBuilder buf = new StringBuilder(outputLength); 6169 for (int i = 0; i < repeat; i++) { 6170 buf.append(str); 6171 } 6172 return buf.toString(); 6173 } 6174 } 6175 6176 /** 6177 * <p>Repeat a String {@code repeat} times to form a 6178 * new String, with a String separator injected each time. </p> 6179 * 6180 * <pre> 6181 * StringUtils.repeat(null, null, 2) = null 6182 * StringUtils.repeat(null, "x", 2) = null 6183 * StringUtils.repeat("", null, 0) = "" 6184 * StringUtils.repeat("", "", 2) = "" 6185 * StringUtils.repeat("", "x", 3) = "xxx" 6186 * StringUtils.repeat("?", ", ", 3) = "?, ?, ?" 6187 * </pre> 6188 * 6189 * @param str the String to repeat, may be null 6190 * @param separator the String to inject, may be null 6191 * @param repeat number of times to repeat str, negative treated as zero 6192 * @return a new String consisting of the original String repeated, 6193 * {@code null} if null String input 6194 * @since 2.5 6195 */ 6196 public static String repeat(final String str, final String separator, final int repeat) { 6197 if(str == null || separator == null) { 6198 return repeat(str, repeat); 6199 } 6200 // given that repeat(String, int) is quite optimized, better to rely on it than try and splice this into it 6201 final String result = repeat(str + separator, repeat); 6202 return removeEnd(result, separator); 6203 } 6204 6205 /** 6206 * <p>Returns padding using the specified delimiter repeated 6207 * to a given length.</p> 6208 * 6209 * <pre> 6210 * StringUtils.repeat('e', 0) = "" 6211 * StringUtils.repeat('e', 3) = "eee" 6212 * StringUtils.repeat('e', -2) = "" 6213 * </pre> 6214 * 6215 * <p>Note: this method does not support padding with 6216 * <a href="http://www.unicode.org/glossary/#supplementary_character">Unicode Supplementary Characters</a> 6217 * as they require a pair of {@code char}s to be represented. 6218 * If you are needing to support full I18N of your applications 6219 * consider using {@link #repeat(String, int)} instead. 6220 * </p> 6221 * 6222 * @param ch character to repeat 6223 * @param repeat number of times to repeat char, negative treated as zero 6224 * @return String with repeated character 6225 * @see #repeat(String, int) 6226 */ 6227 public static String repeat(final char ch, final int repeat) { 6228 if (repeat <= 0) { 6229 return EMPTY; 6230 } 6231 final char[] buf = new char[repeat]; 6232 for (int i = repeat - 1; i >= 0; i--) { 6233 buf[i] = ch; 6234 } 6235 return new String(buf); 6236 } 6237 6238 /** 6239 * <p>Right pad a String with spaces (' ').</p> 6240 * 6241 * <p>The String is padded to the size of {@code size}.</p> 6242 * 6243 * <pre> 6244 * StringUtils.rightPad(null, *) = null 6245 * StringUtils.rightPad("", 3) = " " 6246 * StringUtils.rightPad("bat", 3) = "bat" 6247 * StringUtils.rightPad("bat", 5) = "bat " 6248 * StringUtils.rightPad("bat", 1) = "bat" 6249 * StringUtils.rightPad("bat", -1) = "bat" 6250 * </pre> 6251 * 6252 * @param str the String to pad out, may be null 6253 * @param size the size to pad to 6254 * @return right padded String or original String if no padding is necessary, 6255 * {@code null} if null String input 6256 */ 6257 public static String rightPad(final String str, final int size) { 6258 return rightPad(str, size, ' '); 6259 } 6260 6261 /** 6262 * <p>Right pad a String with a specified character.</p> 6263 * 6264 * <p>The String is padded to the size of {@code size}.</p> 6265 * 6266 * <pre> 6267 * StringUtils.rightPad(null, *, *) = null 6268 * StringUtils.rightPad("", 3, 'z') = "zzz" 6269 * StringUtils.rightPad("bat", 3, 'z') = "bat" 6270 * StringUtils.rightPad("bat", 5, 'z') = "batzz" 6271 * StringUtils.rightPad("bat", 1, 'z') = "bat" 6272 * StringUtils.rightPad("bat", -1, 'z') = "bat" 6273 * </pre> 6274 * 6275 * @param str the String to pad out, may be null 6276 * @param size the size to pad to 6277 * @param padChar the character to pad with 6278 * @return right padded String or original String if no padding is necessary, 6279 * {@code null} if null String input 6280 * @since 2.0 6281 */ 6282 public static String rightPad(final String str, final int size, final char padChar) { 6283 if (str == null) { 6284 return null; 6285 } 6286 final int pads = size - str.length(); 6287 if (pads <= 0) { 6288 return str; // returns original String when possible 6289 } 6290 if (pads > PAD_LIMIT) { 6291 return rightPad(str, size, String.valueOf(padChar)); 6292 } 6293 return str.concat(repeat(padChar, pads)); 6294 } 6295 6296 /** 6297 * <p>Right pad a String with a specified String.</p> 6298 * 6299 * <p>The String is padded to the size of {@code size}.</p> 6300 * 6301 * <pre> 6302 * StringUtils.rightPad(null, *, *) = null 6303 * StringUtils.rightPad("", 3, "z") = "zzz" 6304 * StringUtils.rightPad("bat", 3, "yz") = "bat" 6305 * StringUtils.rightPad("bat", 5, "yz") = "batyz" 6306 * StringUtils.rightPad("bat", 8, "yz") = "batyzyzy" 6307 * StringUtils.rightPad("bat", 1, "yz") = "bat" 6308 * StringUtils.rightPad("bat", -1, "yz") = "bat" 6309 * StringUtils.rightPad("bat", 5, null) = "bat " 6310 * StringUtils.rightPad("bat", 5, "") = "bat " 6311 * </pre> 6312 * 6313 * @param str the String to pad out, may be null 6314 * @param size the size to pad to 6315 * @param padStr the String to pad with, null or empty treated as single space 6316 * @return right padded String or original String if no padding is necessary, 6317 * {@code null} if null String input 6318 */ 6319 public static String rightPad(final String str, final int size, String padStr) { 6320 if (str == null) { 6321 return null; 6322 } 6323 if (isEmpty(padStr)) { 6324 padStr = SPACE; 6325 } 6326 final int padLen = padStr.length(); 6327 final int strLen = str.length(); 6328 final int pads = size - strLen; 6329 if (pads <= 0) { 6330 return str; // returns original String when possible 6331 } 6332 if (padLen == 1 && pads <= PAD_LIMIT) { 6333 return rightPad(str, size, padStr.charAt(0)); 6334 } 6335 6336 if (pads == padLen) { 6337 return str.concat(padStr); 6338 } else if (pads < padLen) { 6339 return str.concat(padStr.substring(0, pads)); 6340 } else { 6341 final char[] padding = new char[pads]; 6342 final char[] padChars = padStr.toCharArray(); 6343 for (int i = 0; i < pads; i++) { 6344 padding[i] = padChars[i % padLen]; 6345 } 6346 return str.concat(new String(padding)); 6347 } 6348 } 6349 6350 /** 6351 * <p>Left pad a String with spaces (' ').</p> 6352 * 6353 * <p>The String is padded to the size of {@code size}.</p> 6354 * 6355 * <pre> 6356 * StringUtils.leftPad(null, *) = null 6357 * StringUtils.leftPad("", 3) = " " 6358 * StringUtils.leftPad("bat", 3) = "bat" 6359 * StringUtils.leftPad("bat", 5) = " bat" 6360 * StringUtils.leftPad("bat", 1) = "bat" 6361 * StringUtils.leftPad("bat", -1) = "bat" 6362 * </pre> 6363 * 6364 * @param str the String to pad out, may be null 6365 * @param size the size to pad to 6366 * @return left padded String or original String if no padding is necessary, 6367 * {@code null} if null String input 6368 */ 6369 public static String leftPad(final String str, final int size) { 6370 return leftPad(str, size, ' '); 6371 } 6372 6373 /** 6374 * <p>Left pad a String with a specified character.</p> 6375 * 6376 * <p>Pad to a size of {@code size}.</p> 6377 * 6378 * <pre> 6379 * StringUtils.leftPad(null, *, *) = null 6380 * StringUtils.leftPad("", 3, 'z') = "zzz" 6381 * StringUtils.leftPad("bat", 3, 'z') = "bat" 6382 * StringUtils.leftPad("bat", 5, 'z') = "zzbat" 6383 * StringUtils.leftPad("bat", 1, 'z') = "bat" 6384 * StringUtils.leftPad("bat", -1, 'z') = "bat" 6385 * </pre> 6386 * 6387 * @param str the String to pad out, may be null 6388 * @param size the size to pad to 6389 * @param padChar the character to pad with 6390 * @return left padded String or original String if no padding is necessary, 6391 * {@code null} if null String input 6392 * @since 2.0 6393 */ 6394 public static String leftPad(final String str, final int size, final char padChar) { 6395 if (str == null) { 6396 return null; 6397 } 6398 final int pads = size - str.length(); 6399 if (pads <= 0) { 6400 return str; // returns original String when possible 6401 } 6402 if (pads > PAD_LIMIT) { 6403 return leftPad(str, size, String.valueOf(padChar)); 6404 } 6405 return repeat(padChar, pads).concat(str); 6406 } 6407 6408 /** 6409 * <p>Left pad a String with a specified String.</p> 6410 * 6411 * <p>Pad to a size of {@code size}.</p> 6412 * 6413 * <pre> 6414 * StringUtils.leftPad(null, *, *) = null 6415 * StringUtils.leftPad("", 3, "z") = "zzz" 6416 * StringUtils.leftPad("bat", 3, "yz") = "bat" 6417 * StringUtils.leftPad("bat", 5, "yz") = "yzbat" 6418 * StringUtils.leftPad("bat", 8, "yz") = "yzyzybat" 6419 * StringUtils.leftPad("bat", 1, "yz") = "bat" 6420 * StringUtils.leftPad("bat", -1, "yz") = "bat" 6421 * StringUtils.leftPad("bat", 5, null) = " bat" 6422 * StringUtils.leftPad("bat", 5, "") = " bat" 6423 * </pre> 6424 * 6425 * @param str the String to pad out, may be null 6426 * @param size the size to pad to 6427 * @param padStr the String to pad with, null or empty treated as single space 6428 * @return left padded String or original String if no padding is necessary, 6429 * {@code null} if null String input 6430 */ 6431 public static String leftPad(final String str, final int size, String padStr) { 6432 if (str == null) { 6433 return null; 6434 } 6435 if (isEmpty(padStr)) { 6436 padStr = SPACE; 6437 } 6438 final int padLen = padStr.length(); 6439 final int strLen = str.length(); 6440 final int pads = size - strLen; 6441 if (pads <= 0) { 6442 return str; // returns original String when possible 6443 } 6444 if (padLen == 1 && pads <= PAD_LIMIT) { 6445 return leftPad(str, size, padStr.charAt(0)); 6446 } 6447 6448 if (pads == padLen) { 6449 return padStr.concat(str); 6450 } else if (pads < padLen) { 6451 return padStr.substring(0, pads).concat(str); 6452 } else { 6453 final char[] padding = new char[pads]; 6454 final char[] padChars = padStr.toCharArray(); 6455 for (int i = 0; i < pads; i++) { 6456 padding[i] = padChars[i % padLen]; 6457 } 6458 return new String(padding).concat(str); 6459 } 6460 } 6461 6462 /** 6463 * Gets a CharSequence length or {@code 0} if the CharSequence is 6464 * {@code null}. 6465 * 6466 * @param cs 6467 * a CharSequence or {@code null} 6468 * @return CharSequence length or {@code 0} if the CharSequence is 6469 * {@code null}. 6470 * @since 2.4 6471 * @since 3.0 Changed signature from length(String) to length(CharSequence) 6472 */ 6473 public static int length(final CharSequence cs) { 6474 return cs == null ? 0 : cs.length(); 6475 } 6476 6477 // Centering 6478 //----------------------------------------------------------------------- 6479 /** 6480 * <p>Centers a String in a larger String of size {@code size} 6481 * using the space character (' ').</p> 6482 * 6483 * <p>If the size is less than the String length, the String is returned. 6484 * A {@code null} String returns {@code null}. 6485 * A negative size is treated as zero.</p> 6486 * 6487 * <p>Equivalent to {@code center(str, size, " ")}.</p> 6488 * 6489 * <pre> 6490 * StringUtils.center(null, *) = null 6491 * StringUtils.center("", 4) = " " 6492 * StringUtils.center("ab", -1) = "ab" 6493 * StringUtils.center("ab", 4) = " ab " 6494 * StringUtils.center("abcd", 2) = "abcd" 6495 * StringUtils.center("a", 4) = " a " 6496 * </pre> 6497 * 6498 * @param str the String to center, may be null 6499 * @param size the int size of new String, negative treated as zero 6500 * @return centered String, {@code null} if null String input 6501 */ 6502 public static String center(final String str, final int size) { 6503 return center(str, size, ' '); 6504 } 6505 6506 /** 6507 * <p>Centers a String in a larger String of size {@code size}. 6508 * Uses a supplied character as the value to pad the String with.</p> 6509 * 6510 * <p>If the size is less than the String length, the String is returned. 6511 * A {@code null} String returns {@code null}. 6512 * A negative size is treated as zero.</p> 6513 * 6514 * <pre> 6515 * StringUtils.center(null, *, *) = null 6516 * StringUtils.center("", 4, ' ') = " " 6517 * StringUtils.center("ab", -1, ' ') = "ab" 6518 * StringUtils.center("ab", 4, ' ') = " ab " 6519 * StringUtils.center("abcd", 2, ' ') = "abcd" 6520 * StringUtils.center("a", 4, ' ') = " a " 6521 * StringUtils.center("a", 4, 'y') = "yayy" 6522 * </pre> 6523 * 6524 * @param str the String to center, may be null 6525 * @param size the int size of new String, negative treated as zero 6526 * @param padChar the character to pad the new String with 6527 * @return centered String, {@code null} if null String input 6528 * @since 2.0 6529 */ 6530 public static String center(String str, final int size, final char padChar) { 6531 if (str == null || size <= 0) { 6532 return str; 6533 } 6534 final int strLen = str.length(); 6535 final int pads = size - strLen; 6536 if (pads <= 0) { 6537 return str; 6538 } 6539 str = leftPad(str, strLen + pads / 2, padChar); 6540 str = rightPad(str, size, padChar); 6541 return str; 6542 } 6543 6544 /** 6545 * <p>Centers a String in a larger String of size {@code size}. 6546 * Uses a supplied String as the value to pad the String with.</p> 6547 * 6548 * <p>If the size is less than the String length, the String is returned. 6549 * A {@code null} String returns {@code null}. 6550 * A negative size is treated as zero.</p> 6551 * 6552 * <pre> 6553 * StringUtils.center(null, *, *) = null 6554 * StringUtils.center("", 4, " ") = " " 6555 * StringUtils.center("ab", -1, " ") = "ab" 6556 * StringUtils.center("ab", 4, " ") = " ab " 6557 * StringUtils.center("abcd", 2, " ") = "abcd" 6558 * StringUtils.center("a", 4, " ") = " a " 6559 * StringUtils.center("a", 4, "yz") = "yayz" 6560 * StringUtils.center("abc", 7, null) = " abc " 6561 * StringUtils.center("abc", 7, "") = " abc " 6562 * </pre> 6563 * 6564 * @param str the String to center, may be null 6565 * @param size the int size of new String, negative treated as zero 6566 * @param padStr the String to pad the new String with, must not be null or empty 6567 * @return centered String, {@code null} if null String input 6568 * @throws IllegalArgumentException if padStr is {@code null} or empty 6569 */ 6570 public static String center(String str, final int size, String padStr) { 6571 if (str == null || size <= 0) { 6572 return str; 6573 } 6574 if (isEmpty(padStr)) { 6575 padStr = SPACE; 6576 } 6577 final int strLen = str.length(); 6578 final int pads = size - strLen; 6579 if (pads <= 0) { 6580 return str; 6581 } 6582 str = leftPad(str, strLen + pads / 2, padStr); 6583 str = rightPad(str, size, padStr); 6584 return str; 6585 } 6586 6587 // Case conversion 6588 //----------------------------------------------------------------------- 6589 /** 6590 * <p>Converts a String to upper case as per {@link String#toUpperCase()}.</p> 6591 * 6592 * <p>A {@code null} input String returns {@code null}.</p> 6593 * 6594 * <pre> 6595 * StringUtils.upperCase(null) = null 6596 * StringUtils.upperCase("") = "" 6597 * StringUtils.upperCase("aBc") = "ABC" 6598 * </pre> 6599 * 6600 * <p><strong>Note:</strong> As described in the documentation for {@link String#toUpperCase()}, 6601 * the result of this method is affected by the current locale. 6602 * For platform-independent case transformations, the method {@link #lowerCase(String, Locale)} 6603 * should be used with a specific locale (e.g. {@link Locale#ENGLISH}).</p> 6604 * 6605 * @param str the String to upper case, may be null 6606 * @return the upper cased String, {@code null} if null String input 6607 */ 6608 public static String upperCase(final String str) { 6609 if (str == null) { 6610 return null; 6611 } 6612 return str.toUpperCase(); 6613 } 6614 6615 /** 6616 * <p>Converts a String to upper case as per {@link String#toUpperCase(Locale)}.</p> 6617 * 6618 * <p>A {@code null} input String returns {@code null}.</p> 6619 * 6620 * <pre> 6621 * StringUtils.upperCase(null, Locale.ENGLISH) = null 6622 * StringUtils.upperCase("", Locale.ENGLISH) = "" 6623 * StringUtils.upperCase("aBc", Locale.ENGLISH) = "ABC" 6624 * </pre> 6625 * 6626 * @param str the String to upper case, may be null 6627 * @param locale the locale that defines the case transformation rules, must not be null 6628 * @return the upper cased String, {@code null} if null String input 6629 * @since 2.5 6630 */ 6631 public static String upperCase(final String str, final Locale locale) { 6632 if (str == null) { 6633 return null; 6634 } 6635 return str.toUpperCase(locale); 6636 } 6637 6638 /** 6639 * <p>Converts a String to lower case as per {@link String#toLowerCase()}.</p> 6640 * 6641 * <p>A {@code null} input String returns {@code null}.</p> 6642 * 6643 * <pre> 6644 * StringUtils.lowerCase(null) = null 6645 * StringUtils.lowerCase("") = "" 6646 * StringUtils.lowerCase("aBc") = "abc" 6647 * </pre> 6648 * 6649 * <p><strong>Note:</strong> As described in the documentation for {@link String#toLowerCase()}, 6650 * the result of this method is affected by the current locale. 6651 * For platform-independent case transformations, the method {@link #lowerCase(String, Locale)} 6652 * should be used with a specific locale (e.g. {@link Locale#ENGLISH}).</p> 6653 * 6654 * @param str the String to lower case, may be null 6655 * @return the lower cased String, {@code null} if null String input 6656 */ 6657 public static String lowerCase(final String str) { 6658 if (str == null) { 6659 return null; 6660 } 6661 return str.toLowerCase(); 6662 } 6663 6664 /** 6665 * <p>Converts a String to lower case as per {@link String#toLowerCase(Locale)}.</p> 6666 * 6667 * <p>A {@code null} input String returns {@code null}.</p> 6668 * 6669 * <pre> 6670 * StringUtils.lowerCase(null, Locale.ENGLISH) = null 6671 * StringUtils.lowerCase("", Locale.ENGLISH) = "" 6672 * StringUtils.lowerCase("aBc", Locale.ENGLISH) = "abc" 6673 * </pre> 6674 * 6675 * @param str the String to lower case, may be null 6676 * @param locale the locale that defines the case transformation rules, must not be null 6677 * @return the lower cased String, {@code null} if null String input 6678 * @since 2.5 6679 */ 6680 public static String lowerCase(final String str, final Locale locale) { 6681 if (str == null) { 6682 return null; 6683 } 6684 return str.toLowerCase(locale); 6685 } 6686 6687 /** 6688 * <p>Capitalizes a String changing the first character to title case as 6689 * per {@link Character#toTitleCase(int)}. No other characters are changed.</p> 6690 * 6691 * <p>For a word based algorithm, see {@link org.apache.commons.lang3.text.WordUtils#capitalize(String)}. 6692 * A {@code null} input String returns {@code null}.</p> 6693 * 6694 * <pre> 6695 * StringUtils.capitalize(null) = null 6696 * StringUtils.capitalize("") = "" 6697 * StringUtils.capitalize("cat") = "Cat" 6698 * StringUtils.capitalize("cAt") = "CAt" 6699 * StringUtils.capitalize("'cat'") = "'cat'" 6700 * </pre> 6701 * 6702 * @param str the String to capitalize, may be null 6703 * @return the capitalized String, {@code null} if null String input 6704 * @see org.apache.commons.lang3.text.WordUtils#capitalize(String) 6705 * @see #uncapitalize(String) 6706 * @since 2.0 6707 */ 6708 public static String capitalize(final String str) { 6709 int strLen; 6710 if (str == null || (strLen = str.length()) == 0) { 6711 return str; 6712 } 6713 6714 final int firstCodepoint = str.codePointAt(0); 6715 final int newCodePoint = Character.toTitleCase(firstCodepoint); 6716 if (firstCodepoint == newCodePoint) { 6717 // already capitalized 6718 return str; 6719 } 6720 6721 final int newCodePoints[] = new int[strLen]; // cannot be longer than the char array 6722 int outOffset = 0; 6723 newCodePoints[outOffset++] = newCodePoint; // copy the first codepoint 6724 for (int inOffset = Character.charCount(firstCodepoint); inOffset < strLen; ) { 6725 final int codepoint = str.codePointAt(inOffset); 6726 newCodePoints[outOffset++] = codepoint; // copy the remaining ones 6727 inOffset += Character.charCount(codepoint); 6728 } 6729 return new String(newCodePoints, 0, outOffset); 6730 } 6731 6732 /** 6733 * <p>Uncapitalizes a String, changing the first character to lower case as 6734 * per {@link Character#toLowerCase(int)}. No other characters are changed.</p> 6735 * 6736 * <p>For a word based algorithm, see {@link org.apache.commons.lang3.text.WordUtils#uncapitalize(String)}. 6737 * A {@code null} input String returns {@code null}.</p> 6738 * 6739 * <pre> 6740 * StringUtils.uncapitalize(null) = null 6741 * StringUtils.uncapitalize("") = "" 6742 * StringUtils.uncapitalize("cat") = "cat" 6743 * StringUtils.uncapitalize("Cat") = "cat" 6744 * StringUtils.uncapitalize("CAT") = "cAT" 6745 * </pre> 6746 * 6747 * @param str the String to uncapitalize, may be null 6748 * @return the uncapitalized String, {@code null} if null String input 6749 * @see org.apache.commons.lang3.text.WordUtils#uncapitalize(String) 6750 * @see #capitalize(String) 6751 * @since 2.0 6752 */ 6753 public static String uncapitalize(final String str) { 6754 int strLen; 6755 if (str == null || (strLen = str.length()) == 0) { 6756 return str; 6757 } 6758 6759 final int firstCodepoint = str.codePointAt(0); 6760 final int newCodePoint = Character.toLowerCase(firstCodepoint); 6761 if (firstCodepoint == newCodePoint) { 6762 // already capitalized 6763 return str; 6764 } 6765 6766 final int newCodePoints[] = new int[strLen]; // cannot be longer than the char array 6767 int outOffset = 0; 6768 newCodePoints[outOffset++] = newCodePoint; // copy the first codepoint 6769 for (int inOffset = Character.charCount(firstCodepoint); inOffset < strLen; ) { 6770 final int codepoint = str.codePointAt(inOffset); 6771 newCodePoints[outOffset++] = codepoint; // copy the remaining ones 6772 inOffset += Character.charCount(codepoint); 6773 } 6774 return new String(newCodePoints, 0, outOffset); 6775 } 6776 6777 /** 6778 * <p>Swaps the case of a String changing upper and title case to 6779 * lower case, and lower case to upper case.</p> 6780 * 6781 * <ul> 6782 * <li>Upper case character converts to Lower case</li> 6783 * <li>Title case character converts to Lower case</li> 6784 * <li>Lower case character converts to Upper case</li> 6785 * </ul> 6786 * 6787 * <p>For a word based algorithm, see {@link org.apache.commons.lang3.text.WordUtils#swapCase(String)}. 6788 * A {@code null} input String returns {@code null}.</p> 6789 * 6790 * <pre> 6791 * StringUtils.swapCase(null) = null 6792 * StringUtils.swapCase("") = "" 6793 * StringUtils.swapCase("The dog has a BONE") = "tHE DOG HAS A bone" 6794 * </pre> 6795 * 6796 * <p>NOTE: This method changed in Lang version 2.0. 6797 * It no longer performs a word based algorithm. 6798 * If you only use ASCII, you will notice no change. 6799 * That functionality is available in org.apache.commons.lang3.text.WordUtils.</p> 6800 * 6801 * @param str the String to swap case, may be null 6802 * @return the changed String, {@code null} if null String input 6803 */ 6804 public static String swapCase(final String str) { 6805 if (StringUtils.isEmpty(str)) { 6806 return str; 6807 } 6808 6809 final int strLen = str.length(); 6810 final int newCodePoints[] = new int[strLen]; // cannot be longer than the char array 6811 int outOffset = 0; 6812 for (int i = 0; i < strLen; ) { 6813 final int oldCodepoint = str.codePointAt(i); 6814 final int newCodePoint; 6815 if (Character.isUpperCase(oldCodepoint)) { 6816 newCodePoint = Character.toLowerCase(oldCodepoint); 6817 } else if (Character.isTitleCase(oldCodepoint)) { 6818 newCodePoint = Character.toLowerCase(oldCodepoint); 6819 } else if (Character.isLowerCase(oldCodepoint)) { 6820 newCodePoint = Character.toUpperCase(oldCodepoint); 6821 } else { 6822 newCodePoint = oldCodepoint; 6823 } 6824 newCodePoints[outOffset++] = newCodePoint; 6825 i += Character.charCount(newCodePoint); 6826 } 6827 return new String(newCodePoints, 0, outOffset); 6828 } 6829 6830 // Count matches 6831 //----------------------------------------------------------------------- 6832 /** 6833 * <p>Counts how many times the substring appears in the larger string.</p> 6834 * 6835 * <p>A {@code null} or empty ("") String input returns {@code 0}.</p> 6836 * 6837 * <pre> 6838 * StringUtils.countMatches(null, *) = 0 6839 * StringUtils.countMatches("", *) = 0 6840 * StringUtils.countMatches("abba", null) = 0 6841 * StringUtils.countMatches("abba", "") = 0 6842 * StringUtils.countMatches("abba", "a") = 2 6843 * StringUtils.countMatches("abba", "ab") = 1 6844 * StringUtils.countMatches("abba", "xxx") = 0 6845 * </pre> 6846 * 6847 * @param str the CharSequence to check, may be null 6848 * @param sub the substring to count, may be null 6849 * @return the number of occurrences, 0 if either CharSequence is {@code null} 6850 * @since 3.0 Changed signature from countMatches(String, String) to countMatches(CharSequence, CharSequence) 6851 */ 6852 public static int countMatches(final CharSequence str, final CharSequence sub) { 6853 if (isEmpty(str) || isEmpty(sub)) { 6854 return 0; 6855 } 6856 int count = 0; 6857 int idx = 0; 6858 while ((idx = CharSequenceUtils.indexOf(str, sub, idx)) != INDEX_NOT_FOUND) { 6859 count++; 6860 idx += sub.length(); 6861 } 6862 return count; 6863 } 6864 6865 /** 6866 * <p>Counts how many times the char appears in the given string.</p> 6867 * 6868 * <p>A {@code null} or empty ("") String input returns {@code 0}.</p> 6869 * 6870 * <pre> 6871 * StringUtils.countMatches(null, *) = 0 6872 * StringUtils.countMatches("", *) = 0 6873 * StringUtils.countMatches("abba", 0) = 0 6874 * StringUtils.countMatches("abba", 'a') = 2 6875 * StringUtils.countMatches("abba", 'b') = 2 6876 * StringUtils.countMatches("abba", 'x') = 0 6877 * </pre> 6878 * 6879 * @param str the CharSequence to check, may be null 6880 * @param ch the char to count 6881 * @return the number of occurrences, 0 if the CharSequence is {@code null} 6882 * @since 3.4 6883 */ 6884 public static int countMatches(final CharSequence str, final char ch) { 6885 if (isEmpty(str)) { 6886 return 0; 6887 } 6888 int count = 0; 6889 // We could also call str.toCharArray() for faster look ups but that would generate more garbage. 6890 for (int i = 0; i < str.length(); i++) { 6891 if (ch == str.charAt(i)) { 6892 count++; 6893 } 6894 } 6895 return count; 6896 } 6897 6898 // Character Tests 6899 //----------------------------------------------------------------------- 6900 /** 6901 * <p>Checks if the CharSequence contains only Unicode letters.</p> 6902 * 6903 * <p>{@code null} will return {@code false}. 6904 * An empty CharSequence (length()=0) will return {@code false}.</p> 6905 * 6906 * <pre> 6907 * StringUtils.isAlpha(null) = false 6908 * StringUtils.isAlpha("") = false 6909 * StringUtils.isAlpha(" ") = false 6910 * StringUtils.isAlpha("abc") = true 6911 * StringUtils.isAlpha("ab2c") = false 6912 * StringUtils.isAlpha("ab-c") = false 6913 * </pre> 6914 * 6915 * @param cs the CharSequence to check, may be null 6916 * @return {@code true} if only contains letters, and is non-null 6917 * @since 3.0 Changed signature from isAlpha(String) to isAlpha(CharSequence) 6918 * @since 3.0 Changed "" to return false and not true 6919 */ 6920 public static boolean isAlpha(final CharSequence cs) { 6921 if (isEmpty(cs)) { 6922 return false; 6923 } 6924 final int sz = cs.length(); 6925 for (int i = 0; i < sz; i++) { 6926 if (!Character.isLetter(cs.charAt(i))) { 6927 return false; 6928 } 6929 } 6930 return true; 6931 } 6932 6933 /** 6934 * <p>Checks if the CharSequence contains only Unicode letters and 6935 * space (' ').</p> 6936 * 6937 * <p>{@code null} will return {@code false} 6938 * An empty CharSequence (length()=0) will return {@code true}.</p> 6939 * 6940 * <pre> 6941 * StringUtils.isAlphaSpace(null) = false 6942 * StringUtils.isAlphaSpace("") = true 6943 * StringUtils.isAlphaSpace(" ") = true 6944 * StringUtils.isAlphaSpace("abc") = true 6945 * StringUtils.isAlphaSpace("ab c") = true 6946 * StringUtils.isAlphaSpace("ab2c") = false 6947 * StringUtils.isAlphaSpace("ab-c") = false 6948 * </pre> 6949 * 6950 * @param cs the CharSequence to check, may be null 6951 * @return {@code true} if only contains letters and space, 6952 * and is non-null 6953 * @since 3.0 Changed signature from isAlphaSpace(String) to isAlphaSpace(CharSequence) 6954 */ 6955 public static boolean isAlphaSpace(final CharSequence cs) { 6956 if (cs == null) { 6957 return false; 6958 } 6959 final int sz = cs.length(); 6960 for (int i = 0; i < sz; i++) { 6961 if (!Character.isLetter(cs.charAt(i)) && cs.charAt(i) != ' ') { 6962 return false; 6963 } 6964 } 6965 return true; 6966 } 6967 6968 /** 6969 * <p>Checks if the CharSequence contains only Unicode letters or digits.</p> 6970 * 6971 * <p>{@code null} will return {@code false}. 6972 * An empty CharSequence (length()=0) will return {@code false}.</p> 6973 * 6974 * <pre> 6975 * StringUtils.isAlphanumeric(null) = false 6976 * StringUtils.isAlphanumeric("") = false 6977 * StringUtils.isAlphanumeric(" ") = false 6978 * StringUtils.isAlphanumeric("abc") = true 6979 * StringUtils.isAlphanumeric("ab c") = false 6980 * StringUtils.isAlphanumeric("ab2c") = true 6981 * StringUtils.isAlphanumeric("ab-c") = false 6982 * </pre> 6983 * 6984 * @param cs the CharSequence to check, may be null 6985 * @return {@code true} if only contains letters or digits, 6986 * and is non-null 6987 * @since 3.0 Changed signature from isAlphanumeric(String) to isAlphanumeric(CharSequence) 6988 * @since 3.0 Changed "" to return false and not true 6989 */ 6990 public static boolean isAlphanumeric(final CharSequence cs) { 6991 if (isEmpty(cs)) { 6992 return false; 6993 } 6994 final int sz = cs.length(); 6995 for (int i = 0; i < sz; i++) { 6996 if (!Character.isLetterOrDigit(cs.charAt(i))) { 6997 return false; 6998 } 6999 } 7000 return true; 7001 } 7002 7003 /** 7004 * <p>Checks if the CharSequence contains only Unicode letters, digits 7005 * or space ({@code ' '}).</p> 7006 * 7007 * <p>{@code null} will return {@code false}. 7008 * An empty CharSequence (length()=0) will return {@code true}.</p> 7009 * 7010 * <pre> 7011 * StringUtils.isAlphanumericSpace(null) = false 7012 * StringUtils.isAlphanumericSpace("") = true 7013 * StringUtils.isAlphanumericSpace(" ") = true 7014 * StringUtils.isAlphanumericSpace("abc") = true 7015 * StringUtils.isAlphanumericSpace("ab c") = true 7016 * StringUtils.isAlphanumericSpace("ab2c") = true 7017 * StringUtils.isAlphanumericSpace("ab-c") = false 7018 * </pre> 7019 * 7020 * @param cs the CharSequence to check, may be null 7021 * @return {@code true} if only contains letters, digits or space, 7022 * and is non-null 7023 * @since 3.0 Changed signature from isAlphanumericSpace(String) to isAlphanumericSpace(CharSequence) 7024 */ 7025 public static boolean isAlphanumericSpace(final CharSequence cs) { 7026 if (cs == null) { 7027 return false; 7028 } 7029 final int sz = cs.length(); 7030 for (int i = 0; i < sz; i++) { 7031 if (!Character.isLetterOrDigit(cs.charAt(i)) && cs.charAt(i) != ' ') { 7032 return false; 7033 } 7034 } 7035 return true; 7036 } 7037 7038 /** 7039 * <p>Checks if the CharSequence contains only ASCII printable characters.</p> 7040 * 7041 * <p>{@code null} will return {@code false}. 7042 * An empty CharSequence (length()=0) will return {@code true}.</p> 7043 * 7044 * <pre> 7045 * StringUtils.isAsciiPrintable(null) = false 7046 * StringUtils.isAsciiPrintable("") = true 7047 * StringUtils.isAsciiPrintable(" ") = true 7048 * StringUtils.isAsciiPrintable("Ceki") = true 7049 * StringUtils.isAsciiPrintable("ab2c") = true 7050 * StringUtils.isAsciiPrintable("!ab-c~") = true 7051 * StringUtils.isAsciiPrintable("\u0020") = true 7052 * StringUtils.isAsciiPrintable("\u0021") = true 7053 * StringUtils.isAsciiPrintable("\u007e") = true 7054 * StringUtils.isAsciiPrintable("\u007f") = false 7055 * StringUtils.isAsciiPrintable("Ceki G\u00fclc\u00fc") = false 7056 * </pre> 7057 * 7058 * @param cs the CharSequence to check, may be null 7059 * @return {@code true} if every character is in the range 7060 * 32 thru 126 7061 * @since 2.1 7062 * @since 3.0 Changed signature from isAsciiPrintable(String) to isAsciiPrintable(CharSequence) 7063 */ 7064 public static boolean isAsciiPrintable(final CharSequence cs) { 7065 if (cs == null) { 7066 return false; 7067 } 7068 final int sz = cs.length(); 7069 for (int i = 0; i < sz; i++) { 7070 if (!CharUtils.isAsciiPrintable(cs.charAt(i))) { 7071 return false; 7072 } 7073 } 7074 return true; 7075 } 7076 7077 /** 7078 * <p>Checks if the CharSequence contains only Unicode digits. 7079 * A decimal point is not a Unicode digit and returns false.</p> 7080 * 7081 * <p>{@code null} will return {@code false}. 7082 * An empty CharSequence (length()=0) will return {@code false}.</p> 7083 * 7084 * <p>Note that the method does not allow for a leading sign, either positive or negative. 7085 * Also, if a String passes the numeric test, it may still generate a NumberFormatException 7086 * when parsed by Integer.parseInt or Long.parseLong, e.g. if the value is outside the range 7087 * for int or long respectively.</p> 7088 * 7089 * <pre> 7090 * StringUtils.isNumeric(null) = false 7091 * StringUtils.isNumeric("") = false 7092 * StringUtils.isNumeric(" ") = false 7093 * StringUtils.isNumeric("123") = true 7094 * StringUtils.isNumeric("\u0967\u0968\u0969") = true 7095 * StringUtils.isNumeric("12 3") = false 7096 * StringUtils.isNumeric("ab2c") = false 7097 * StringUtils.isNumeric("12-3") = false 7098 * StringUtils.isNumeric("12.3") = false 7099 * StringUtils.isNumeric("-123") = false 7100 * StringUtils.isNumeric("+123") = false 7101 * </pre> 7102 * 7103 * @param cs the CharSequence to check, may be null 7104 * @return {@code true} if only contains digits, and is non-null 7105 * @since 3.0 Changed signature from isNumeric(String) to isNumeric(CharSequence) 7106 * @since 3.0 Changed "" to return false and not true 7107 */ 7108 public static boolean isNumeric(final CharSequence cs) { 7109 if (isEmpty(cs)) { 7110 return false; 7111 } 7112 final int sz = cs.length(); 7113 for (int i = 0; i < sz; i++) { 7114 if (!Character.isDigit(cs.charAt(i))) { 7115 return false; 7116 } 7117 } 7118 return true; 7119 } 7120 7121 /** 7122 * <p>Checks if the CharSequence contains only Unicode digits or space 7123 * ({@code ' '}). 7124 * A decimal point is not a Unicode digit and returns false.</p> 7125 * 7126 * <p>{@code null} will return {@code false}. 7127 * An empty CharSequence (length()=0) will return {@code true}.</p> 7128 * 7129 * <pre> 7130 * StringUtils.isNumericSpace(null) = false 7131 * StringUtils.isNumericSpace("") = true 7132 * StringUtils.isNumericSpace(" ") = true 7133 * StringUtils.isNumericSpace("123") = true 7134 * StringUtils.isNumericSpace("12 3") = true 7135 * StringUtils.isNumeric("\u0967\u0968\u0969") = true 7136 * StringUtils.isNumeric("\u0967\u0968 \u0969") = true 7137 * StringUtils.isNumericSpace("ab2c") = false 7138 * StringUtils.isNumericSpace("12-3") = false 7139 * StringUtils.isNumericSpace("12.3") = false 7140 * </pre> 7141 * 7142 * @param cs the CharSequence to check, may be null 7143 * @return {@code true} if only contains digits or space, 7144 * and is non-null 7145 * @since 3.0 Changed signature from isNumericSpace(String) to isNumericSpace(CharSequence) 7146 */ 7147 public static boolean isNumericSpace(final CharSequence cs) { 7148 if (cs == null) { 7149 return false; 7150 } 7151 final int sz = cs.length(); 7152 for (int i = 0; i < sz; i++) { 7153 if (!Character.isDigit(cs.charAt(i)) && cs.charAt(i) != ' ') { 7154 return false; 7155 } 7156 } 7157 return true; 7158 } 7159 7160 /** 7161 * <p>Checks if a String {@code str} contains Unicode digits, 7162 * if yes then concatenate all the digits in {@code str} and return it as a String.</p> 7163 * 7164 * <p>An empty ("") String will be returned if no digits found in {@code str}.</p> 7165 * 7166 * <pre> 7167 * StringUtils.getDigits(null) = null 7168 * StringUtils.getDigits("") = "" 7169 * StringUtils.getDigits("abc") = "" 7170 * StringUtils.getDigits("1000$") = "1000" 7171 * StringUtils.getDigits("1123~45") = "12345" 7172 * StringUtils.getDigits("(541) 754-3010") = "5417543010" 7173 * StringUtils.getDigits("\u0967\u0968\u0969") = "\u0967\u0968\u0969" 7174 * </pre> 7175 * 7176 * @param str the String to extract digits from, may be null 7177 * @return String with only digits, 7178 * or an empty ("") String if no digits found, 7179 * or {@code null} String if {@code str} is null 7180 * @since 3.6 7181 */ 7182 public static String getDigits(final String str) { 7183 if (isEmpty(str)) { 7184 return str; 7185 } 7186 final int sz = str.length(); 7187 final StringBuilder strDigits = new StringBuilder(sz); 7188 for (int i = 0; i < sz; i++) { 7189 final char tempChar = str.charAt(i); 7190 if (Character.isDigit(tempChar)) { 7191 strDigits.append(tempChar); 7192 } 7193 } 7194 return strDigits.toString(); 7195 } 7196 7197 /** 7198 * <p>Checks if the CharSequence contains only whitespace.</p> 7199 * 7200 * <p>Whitespace is defined by {@link Character#isWhitespace(char)}.</p> 7201 * 7202 * <p>{@code null} will return {@code false}. 7203 * An empty CharSequence (length()=0) will return {@code true}.</p> 7204 * 7205 * <pre> 7206 * StringUtils.isWhitespace(null) = false 7207 * StringUtils.isWhitespace("") = true 7208 * StringUtils.isWhitespace(" ") = true 7209 * StringUtils.isWhitespace("abc") = false 7210 * StringUtils.isWhitespace("ab2c") = false 7211 * StringUtils.isWhitespace("ab-c") = false 7212 * </pre> 7213 * 7214 * @param cs the CharSequence to check, may be null 7215 * @return {@code true} if only contains whitespace, and is non-null 7216 * @since 2.0 7217 * @since 3.0 Changed signature from isWhitespace(String) to isWhitespace(CharSequence) 7218 */ 7219 public static boolean isWhitespace(final CharSequence cs) { 7220 if (cs == null) { 7221 return false; 7222 } 7223 final int sz = cs.length(); 7224 for (int i = 0; i < sz; i++) { 7225 if (!Character.isWhitespace(cs.charAt(i))) { 7226 return false; 7227 } 7228 } 7229 return true; 7230 } 7231 7232 /** 7233 * <p>Checks if the CharSequence contains only lowercase characters.</p> 7234 * 7235 * <p>{@code null} will return {@code false}. 7236 * An empty CharSequence (length()=0) will return {@code false}.</p> 7237 * 7238 * <pre> 7239 * StringUtils.isAllLowerCase(null) = false 7240 * StringUtils.isAllLowerCase("") = false 7241 * StringUtils.isAllLowerCase(" ") = false 7242 * StringUtils.isAllLowerCase("abc") = true 7243 * StringUtils.isAllLowerCase("abC") = false 7244 * StringUtils.isAllLowerCase("ab c") = false 7245 * StringUtils.isAllLowerCase("ab1c") = false 7246 * StringUtils.isAllLowerCase("ab/c") = false 7247 * </pre> 7248 * 7249 * @param cs the CharSequence to check, may be null 7250 * @return {@code true} if only contains lowercase characters, and is non-null 7251 * @since 2.5 7252 * @since 3.0 Changed signature from isAllLowerCase(String) to isAllLowerCase(CharSequence) 7253 */ 7254 public static boolean isAllLowerCase(final CharSequence cs) { 7255 if (cs == null || isEmpty(cs)) { 7256 return false; 7257 } 7258 final int sz = cs.length(); 7259 for (int i = 0; i < sz; i++) { 7260 if (!Character.isLowerCase(cs.charAt(i))) { 7261 return false; 7262 } 7263 } 7264 return true; 7265 } 7266 7267 /** 7268 * <p>Checks if the CharSequence contains only uppercase characters.</p> 7269 * 7270 * <p>{@code null} will return {@code false}. 7271 * An empty String (length()=0) will return {@code false}.</p> 7272 * 7273 * <pre> 7274 * StringUtils.isAllUpperCase(null) = false 7275 * StringUtils.isAllUpperCase("") = false 7276 * StringUtils.isAllUpperCase(" ") = false 7277 * StringUtils.isAllUpperCase("ABC") = true 7278 * StringUtils.isAllUpperCase("aBC") = false 7279 * StringUtils.isAllUpperCase("A C") = false 7280 * StringUtils.isAllUpperCase("A1C") = false 7281 * StringUtils.isAllUpperCase("A/C") = false 7282 * </pre> 7283 * 7284 * @param cs the CharSequence to check, may be null 7285 * @return {@code true} if only contains uppercase characters, and is non-null 7286 * @since 2.5 7287 * @since 3.0 Changed signature from isAllUpperCase(String) to isAllUpperCase(CharSequence) 7288 */ 7289 public static boolean isAllUpperCase(final CharSequence cs) { 7290 if (cs == null || isEmpty(cs)) { 7291 return false; 7292 } 7293 final int sz = cs.length(); 7294 for (int i = 0; i < sz; i++) { 7295 if (!Character.isUpperCase(cs.charAt(i))) { 7296 return false; 7297 } 7298 } 7299 return true; 7300 } 7301 7302 /** 7303 * <p>Checks if the CharSequence contains mixed casing of both uppercase and lowercase characters.</p> 7304 * 7305 * <p>{@code null} will return {@code false}. An empty CharSequence ({@code length()=0}) will return 7306 * {@code false}.</p> 7307 * 7308 * <pre> 7309 * StringUtils.isMixedCase(null) = false 7310 * StringUtils.isMixedCase("") = false 7311 * StringUtils.isMixedCase("ABC") = false 7312 * StringUtils.isMixedCase("abc") = false 7313 * StringUtils.isMixedCase("aBc") = true 7314 * StringUtils.isMixedCase("A c") = true 7315 * StringUtils.isMixedCase("A1c") = true 7316 * StringUtils.isMixedCase("a/C") = true 7317 * StringUtils.isMixedCase("aC\t") = true 7318 * </pre> 7319 * 7320 * @param cs the CharSequence to check, may be null 7321 * @return {@code true} if the CharSequence contains both uppercase and lowercase characters 7322 * @since 3.5 7323 */ 7324 public static boolean isMixedCase(final CharSequence cs) { 7325 if (isEmpty(cs) || cs.length() == 1) { 7326 return false; 7327 } 7328 boolean containsUppercase = false; 7329 boolean containsLowercase = false; 7330 final int sz = cs.length(); 7331 for (int i = 0; i < sz; i++) { 7332 if (containsUppercase && containsLowercase) { 7333 return true; 7334 } else if (Character.isUpperCase(cs.charAt(i))) { 7335 containsUppercase = true; 7336 } else if (Character.isLowerCase(cs.charAt(i))) { 7337 containsLowercase = true; 7338 } 7339 } 7340 return containsUppercase && containsLowercase; 7341 } 7342 7343 // Defaults 7344 //----------------------------------------------------------------------- 7345 /** 7346 * <p>Returns either the passed in String, 7347 * or if the String is {@code null}, an empty String ("").</p> 7348 * 7349 * <pre> 7350 * StringUtils.defaultString(null) = "" 7351 * StringUtils.defaultString("") = "" 7352 * StringUtils.defaultString("bat") = "bat" 7353 * </pre> 7354 * 7355 * @see ObjectUtils#toString(Object) 7356 * @see String#valueOf(Object) 7357 * @param str the String to check, may be null 7358 * @return the passed in String, or the empty String if it 7359 * was {@code null} 7360 */ 7361 public static String defaultString(final String str) { 7362 return str == null ? EMPTY : str; 7363 } 7364 7365 /** 7366 * <p>Returns either the passed in String, or if the String is 7367 * {@code null}, the value of {@code defaultStr}.</p> 7368 * 7369 * <pre> 7370 * StringUtils.defaultString(null, "NULL") = "NULL" 7371 * StringUtils.defaultString("", "NULL") = "" 7372 * StringUtils.defaultString("bat", "NULL") = "bat" 7373 * </pre> 7374 * 7375 * @see ObjectUtils#toString(Object,String) 7376 * @see String#valueOf(Object) 7377 * @param str the String to check, may be null 7378 * @param defaultStr the default String to return 7379 * if the input is {@code null}, may be null 7380 * @return the passed in String, or the default if it was {@code null} 7381 */ 7382 public static String defaultString(final String str, final String defaultStr) { 7383 return str == null ? defaultStr : str; 7384 } 7385 7386 /** 7387 * <p>Returns either the passed in CharSequence, or if the CharSequence is 7388 * whitespace, empty ("") or {@code null}, the value of {@code defaultStr}.</p> 7389 * 7390 * <p>Whitespace is defined by {@link Character#isWhitespace(char)}.</p> 7391 * 7392 * <pre> 7393 * StringUtils.defaultIfBlank(null, "NULL") = "NULL" 7394 * StringUtils.defaultIfBlank("", "NULL") = "NULL" 7395 * StringUtils.defaultIfBlank(" ", "NULL") = "NULL" 7396 * StringUtils.defaultIfBlank("bat", "NULL") = "bat" 7397 * StringUtils.defaultIfBlank("", null) = null 7398 * </pre> 7399 * @param <T> the specific kind of CharSequence 7400 * @param str the CharSequence to check, may be null 7401 * @param defaultStr the default CharSequence to return 7402 * if the input is whitespace, empty ("") or {@code null}, may be null 7403 * @return the passed in CharSequence, or the default 7404 * @see StringUtils#defaultString(String, String) 7405 */ 7406 public static <T extends CharSequence> T defaultIfBlank(final T str, final T defaultStr) { 7407 return isBlank(str) ? defaultStr : str; 7408 } 7409 7410 /** 7411 * <p>Returns either the passed in CharSequence, or if the CharSequence is 7412 * empty or {@code null}, the value of {@code defaultStr}.</p> 7413 * 7414 * <pre> 7415 * StringUtils.defaultIfEmpty(null, "NULL") = "NULL" 7416 * StringUtils.defaultIfEmpty("", "NULL") = "NULL" 7417 * StringUtils.defaultIfEmpty(" ", "NULL") = " " 7418 * StringUtils.defaultIfEmpty("bat", "NULL") = "bat" 7419 * StringUtils.defaultIfEmpty("", null) = null 7420 * </pre> 7421 * @param <T> the specific kind of CharSequence 7422 * @param str the CharSequence to check, may be null 7423 * @param defaultStr the default CharSequence to return 7424 * if the input is empty ("") or {@code null}, may be null 7425 * @return the passed in CharSequence, or the default 7426 * @see StringUtils#defaultString(String, String) 7427 */ 7428 public static <T extends CharSequence> T defaultIfEmpty(final T str, final T defaultStr) { 7429 return isEmpty(str) ? defaultStr : str; 7430 } 7431 7432 // Rotating (circular shift) 7433 //----------------------------------------------------------------------- 7434 /** 7435 * <p>Rotate (circular shift) a String of {@code shift} characters.</p> 7436 * <ul> 7437 * <li>If {@code shift > 0}, right circular shift (ex : ABCDEF => FABCDE)</li> 7438 * <li>If {@code shift < 0}, left circular shift (ex : ABCDEF => BCDEFA)</li> 7439 * </ul> 7440 * 7441 * <pre> 7442 * StringUtils.rotate(null, *) = null 7443 * StringUtils.rotate("", *) = "" 7444 * StringUtils.rotate("abcdefg", 0) = "abcdefg" 7445 * StringUtils.rotate("abcdefg", 2) = "fgabcde" 7446 * StringUtils.rotate("abcdefg", -2) = "cdefgab" 7447 * StringUtils.rotate("abcdefg", 7) = "abcdefg" 7448 * StringUtils.rotate("abcdefg", -7) = "abcdefg" 7449 * StringUtils.rotate("abcdefg", 9) = "fgabcde" 7450 * StringUtils.rotate("abcdefg", -9) = "cdefgab" 7451 * </pre> 7452 * 7453 * @param str the String to rotate, may be null 7454 * @param shift number of time to shift (positive : right shift, negative : left shift) 7455 * @return the rotated String, 7456 * or the original String if {@code shift == 0}, 7457 * or {@code null} if null String input 7458 * @since 3.5 7459 */ 7460 public static String rotate(final String str, final int shift) { 7461 if (str == null) { 7462 return null; 7463 } 7464 7465 final int strLen = str.length(); 7466 if (shift == 0 || strLen == 0 || shift % strLen == 0) { 7467 return str; 7468 } 7469 7470 final StringBuilder builder = new StringBuilder(strLen); 7471 final int offset = - (shift % strLen); 7472 builder.append(substring(str, offset)); 7473 builder.append(substring(str, 0, offset)); 7474 return builder.toString(); 7475 } 7476 7477 // Reversing 7478 //----------------------------------------------------------------------- 7479 /** 7480 * <p>Reverses a String as per {@link StringBuilder#reverse()}.</p> 7481 * 7482 * <p>A {@code null} String returns {@code null}.</p> 7483 * 7484 * <pre> 7485 * StringUtils.reverse(null) = null 7486 * StringUtils.reverse("") = "" 7487 * StringUtils.reverse("bat") = "tab" 7488 * </pre> 7489 * 7490 * @param str the String to reverse, may be null 7491 * @return the reversed String, {@code null} if null String input 7492 */ 7493 public static String reverse(final String str) { 7494 if (str == null) { 7495 return null; 7496 } 7497 return new StringBuilder(str).reverse().toString(); 7498 } 7499 7500 /** 7501 * <p>Reverses a String that is delimited by a specific character.</p> 7502 * 7503 * <p>The Strings between the delimiters are not reversed. 7504 * Thus java.lang.String becomes String.lang.java (if the delimiter 7505 * is {@code '.'}).</p> 7506 * 7507 * <pre> 7508 * StringUtils.reverseDelimited(null, *) = null 7509 * StringUtils.reverseDelimited("", *) = "" 7510 * StringUtils.reverseDelimited("a.b.c", 'x') = "a.b.c" 7511 * StringUtils.reverseDelimited("a.b.c", ".") = "c.b.a" 7512 * </pre> 7513 * 7514 * @param str the String to reverse, may be null 7515 * @param separatorChar the separator character to use 7516 * @return the reversed String, {@code null} if null String input 7517 * @since 2.0 7518 */ 7519 public static String reverseDelimited(final String str, final char separatorChar) { 7520 if (str == null) { 7521 return null; 7522 } 7523 // could implement manually, but simple way is to reuse other, 7524 // probably slower, methods. 7525 final String[] strs = split(str, separatorChar); 7526 ArrayUtils.reverse(strs); 7527 return join(strs, separatorChar); 7528 } 7529 7530 // Abbreviating 7531 //----------------------------------------------------------------------- 7532 /** 7533 * <p>Abbreviates a String using ellipses. This will turn 7534 * "Now is the time for all good men" into "Now is the time for..."</p> 7535 * 7536 * <p>Specifically:</p> 7537 * <ul> 7538 * <li>If the number of characters in {@code str} is less than or equal to 7539 * {@code maxWidth}, return {@code str}.</li> 7540 * <li>Else abbreviate it to {@code (substring(str, 0, max-3) + "...")}.</li> 7541 * <li>If {@code maxWidth} is less than {@code 4}, throw an 7542 * {@code IllegalArgumentException}.</li> 7543 * <li>In no case will it return a String of length greater than 7544 * {@code maxWidth}.</li> 7545 * </ul> 7546 * 7547 * <pre> 7548 * StringUtils.abbreviate(null, *) = null 7549 * StringUtils.abbreviate("", 4) = "" 7550 * StringUtils.abbreviate("abcdefg", 6) = "abc..." 7551 * StringUtils.abbreviate("abcdefg", 7) = "abcdefg" 7552 * StringUtils.abbreviate("abcdefg", 8) = "abcdefg" 7553 * StringUtils.abbreviate("abcdefg", 4) = "a..." 7554 * StringUtils.abbreviate("abcdefg", 3) = IllegalArgumentException 7555 * </pre> 7556 * 7557 * @param str the String to check, may be null 7558 * @param maxWidth maximum length of result String, must be at least 4 7559 * @return abbreviated String, {@code null} if null String input 7560 * @throws IllegalArgumentException if the width is too small 7561 * @since 2.0 7562 */ 7563 public static String abbreviate(final String str, final int maxWidth) { 7564 final String defaultAbbrevMarker = "..."; 7565 return abbreviate(str, defaultAbbrevMarker, 0, maxWidth); 7566 } 7567 7568 /** 7569 * <p>Abbreviates a String using ellipses. This will turn 7570 * "Now is the time for all good men" into "...is the time for..."</p> 7571 * 7572 * <p>Works like {@code abbreviate(String, int)}, but allows you to specify 7573 * a "left edge" offset. Note that this left edge is not necessarily going to 7574 * be the leftmost character in the result, or the first character following the 7575 * ellipses, but it will appear somewhere in the result. 7576 * 7577 * <p>In no case will it return a String of length greater than 7578 * {@code maxWidth}.</p> 7579 * 7580 * <pre> 7581 * StringUtils.abbreviate(null, *, *) = null 7582 * StringUtils.abbreviate("", 0, 4) = "" 7583 * StringUtils.abbreviate("abcdefghijklmno", -1, 10) = "abcdefg..." 7584 * StringUtils.abbreviate("abcdefghijklmno", 0, 10) = "abcdefg..." 7585 * StringUtils.abbreviate("abcdefghijklmno", 1, 10) = "abcdefg..." 7586 * StringUtils.abbreviate("abcdefghijklmno", 4, 10) = "abcdefg..." 7587 * StringUtils.abbreviate("abcdefghijklmno", 5, 10) = "...fghi..." 7588 * StringUtils.abbreviate("abcdefghijklmno", 6, 10) = "...ghij..." 7589 * StringUtils.abbreviate("abcdefghijklmno", 8, 10) = "...ijklmno" 7590 * StringUtils.abbreviate("abcdefghijklmno", 10, 10) = "...ijklmno" 7591 * StringUtils.abbreviate("abcdefghijklmno", 12, 10) = "...ijklmno" 7592 * StringUtils.abbreviate("abcdefghij", 0, 3) = IllegalArgumentException 7593 * StringUtils.abbreviate("abcdefghij", 5, 6) = IllegalArgumentException 7594 * </pre> 7595 * 7596 * @param str the String to check, may be null 7597 * @param offset left edge of source String 7598 * @param maxWidth maximum length of result String, must be at least 4 7599 * @return abbreviated String, {@code null} if null String input 7600 * @throws IllegalArgumentException if the width is too small 7601 * @since 2.0 7602 */ 7603 public static String abbreviate(final String str, final int offset, final int maxWidth) { 7604 final String defaultAbbrevMarker = "..."; 7605 return abbreviate(str, defaultAbbrevMarker, offset, maxWidth); 7606 } 7607 7608 /** 7609 * <p>Abbreviates a String using another given String as replacement marker. This will turn 7610 * "Now is the time for all good men" into "Now is the time for..." if "..." was defined 7611 * as the replacement marker.</p> 7612 * 7613 * <p>Specifically:</p> 7614 * <ul> 7615 * <li>If the number of characters in {@code str} is less than or equal to 7616 * {@code maxWidth}, return {@code str}.</li> 7617 * <li>Else abbreviate it to {@code (substring(str, 0, max-abbrevMarker.length) + abbrevMarker)}.</li> 7618 * <li>If {@code maxWidth} is less than {@code abbrevMarker.length + 1}, throw an 7619 * {@code IllegalArgumentException}.</li> 7620 * <li>In no case will it return a String of length greater than 7621 * {@code maxWidth}.</li> 7622 * </ul> 7623 * 7624 * <pre> 7625 * StringUtils.abbreviate(null, "...", *) = null 7626 * StringUtils.abbreviate("abcdefg", null, *) = "abcdefg" 7627 * StringUtils.abbreviate("", "...", 4) = "" 7628 * StringUtils.abbreviate("abcdefg", ".", 5) = "abcd." 7629 * StringUtils.abbreviate("abcdefg", ".", 7) = "abcdefg" 7630 * StringUtils.abbreviate("abcdefg", ".", 8) = "abcdefg" 7631 * StringUtils.abbreviate("abcdefg", "..", 4) = "ab.." 7632 * StringUtils.abbreviate("abcdefg", "..", 3) = "a.." 7633 * StringUtils.abbreviate("abcdefg", "..", 2) = IllegalArgumentException 7634 * StringUtils.abbreviate("abcdefg", "...", 3) = IllegalArgumentException 7635 * </pre> 7636 * 7637 * @param str the String to check, may be null 7638 * @param abbrevMarker the String used as replacement marker 7639 * @param maxWidth maximum length of result String, must be at least {@code abbrevMarker.length + 1} 7640 * @return abbreviated String, {@code null} if null String input 7641 * @throws IllegalArgumentException if the width is too small 7642 * @since 3.6 7643 */ 7644 public static String abbreviate(final String str, final String abbrevMarker, final int maxWidth) { 7645 return abbreviate(str, abbrevMarker, 0, maxWidth); 7646 } 7647 7648 /** 7649 * <p>Abbreviates a String using a given replacement marker. This will turn 7650 * "Now is the time for all good men" into "...is the time for..." if "..." was defined 7651 * as the replacement marker.</p> 7652 * 7653 * <p>Works like {@code abbreviate(String, String, int)}, but allows you to specify 7654 * a "left edge" offset. Note that this left edge is not necessarily going to 7655 * be the leftmost character in the result, or the first character following the 7656 * replacement marker, but it will appear somewhere in the result. 7657 * 7658 * <p>In no case will it return a String of length greater than {@code maxWidth}.</p> 7659 * 7660 * <pre> 7661 * StringUtils.abbreviate(null, null, *, *) = null 7662 * StringUtils.abbreviate("abcdefghijklmno", null, *, *) = "abcdefghijklmno" 7663 * StringUtils.abbreviate("", "...", 0, 4) = "" 7664 * StringUtils.abbreviate("abcdefghijklmno", "---", -1, 10) = "abcdefg---" 7665 * StringUtils.abbreviate("abcdefghijklmno", ",", 0, 10) = "abcdefghi," 7666 * StringUtils.abbreviate("abcdefghijklmno", ",", 1, 10) = "abcdefghi," 7667 * StringUtils.abbreviate("abcdefghijklmno", ",", 2, 10) = "abcdefghi," 7668 * StringUtils.abbreviate("abcdefghijklmno", "::", 4, 10) = "::efghij::" 7669 * StringUtils.abbreviate("abcdefghijklmno", "...", 6, 10) = "...ghij..." 7670 * StringUtils.abbreviate("abcdefghijklmno", "*", 9, 10) = "*ghijklmno" 7671 * StringUtils.abbreviate("abcdefghijklmno", "'", 10, 10) = "'ghijklmno" 7672 * StringUtils.abbreviate("abcdefghijklmno", "!", 12, 10) = "!ghijklmno" 7673 * StringUtils.abbreviate("abcdefghij", "abra", 0, 4) = IllegalArgumentException 7674 * StringUtils.abbreviate("abcdefghij", "...", 5, 6) = IllegalArgumentException 7675 * </pre> 7676 * 7677 * @param str the String to check, may be null 7678 * @param abbrevMarker the String used as replacement marker 7679 * @param offset left edge of source String 7680 * @param maxWidth maximum length of result String, must be at least 4 7681 * @return abbreviated String, {@code null} if null String input 7682 * @throws IllegalArgumentException if the width is too small 7683 * @since 3.6 7684 */ 7685 public static String abbreviate(final String str, final String abbrevMarker, int offset, final int maxWidth) { 7686 if (isEmpty(str) || isEmpty(abbrevMarker)) { 7687 return str; 7688 } 7689 7690 final int abbrevMarkerLength = abbrevMarker.length(); 7691 final int minAbbrevWidth = abbrevMarkerLength + 1; 7692 final int minAbbrevWidthOffset = abbrevMarkerLength + abbrevMarkerLength + 1; 7693 7694 if (maxWidth < minAbbrevWidth) { 7695 throw new IllegalArgumentException(String.format("Minimum abbreviation width is %d", minAbbrevWidth)); 7696 } 7697 if (str.length() <= maxWidth) { 7698 return str; 7699 } 7700 if (offset > str.length()) { 7701 offset = str.length(); 7702 } 7703 if (str.length() - offset < maxWidth - abbrevMarkerLength) { 7704 offset = str.length() - (maxWidth - abbrevMarkerLength); 7705 } 7706 if (offset <= abbrevMarkerLength+1) { 7707 return str.substring(0, maxWidth - abbrevMarkerLength) + abbrevMarker; 7708 } 7709 if (maxWidth < minAbbrevWidthOffset) { 7710 throw new IllegalArgumentException(String.format("Minimum abbreviation width with offset is %d", minAbbrevWidthOffset)); 7711 } 7712 if (offset + maxWidth - abbrevMarkerLength < str.length()) { 7713 return abbrevMarker + abbreviate(str.substring(offset), abbrevMarker, maxWidth - abbrevMarkerLength); 7714 } 7715 return abbrevMarker + str.substring(str.length() - (maxWidth - abbrevMarkerLength)); 7716 } 7717 7718 /** 7719 * <p>Abbreviates a String to the length passed, replacing the middle characters with the supplied 7720 * replacement String.</p> 7721 * 7722 * <p>This abbreviation only occurs if the following criteria is met:</p> 7723 * <ul> 7724 * <li>Neither the String for abbreviation nor the replacement String are null or empty </li> 7725 * <li>The length to truncate to is less than the length of the supplied String</li> 7726 * <li>The length to truncate to is greater than 0</li> 7727 * <li>The abbreviated String will have enough room for the length supplied replacement String 7728 * and the first and last characters of the supplied String for abbreviation</li> 7729 * </ul> 7730 * <p>Otherwise, the returned String will be the same as the supplied String for abbreviation. 7731 * </p> 7732 * 7733 * <pre> 7734 * StringUtils.abbreviateMiddle(null, null, 0) = null 7735 * StringUtils.abbreviateMiddle("abc", null, 0) = "abc" 7736 * StringUtils.abbreviateMiddle("abc", ".", 0) = "abc" 7737 * StringUtils.abbreviateMiddle("abc", ".", 3) = "abc" 7738 * StringUtils.abbreviateMiddle("abcdef", ".", 4) = "ab.f" 7739 * </pre> 7740 * 7741 * @param str the String to abbreviate, may be null 7742 * @param middle the String to replace the middle characters with, may be null 7743 * @param length the length to abbreviate {@code str} to. 7744 * @return the abbreviated String if the above criteria is met, or the original String supplied for abbreviation. 7745 * @since 2.5 7746 */ 7747 public static String abbreviateMiddle(final String str, final String middle, final int length) { 7748 if (isEmpty(str) || isEmpty(middle)) { 7749 return str; 7750 } 7751 7752 if (length >= str.length() || length < middle.length()+2) { 7753 return str; 7754 } 7755 7756 final int targetSting = length-middle.length(); 7757 final int startOffset = targetSting/2+targetSting%2; 7758 final int endOffset = str.length()-targetSting/2; 7759 7760 return str.substring(0, startOffset) + 7761 middle + 7762 str.substring(endOffset); 7763 } 7764 7765 // Difference 7766 //----------------------------------------------------------------------- 7767 /** 7768 * <p>Compares two Strings, and returns the portion where they differ. 7769 * More precisely, return the remainder of the second String, 7770 * starting from where it's different from the first. This means that 7771 * the difference between "abc" and "ab" is the empty String and not "c". </p> 7772 * 7773 * <p>For example, 7774 * {@code difference("i am a machine", "i am a robot") -> "robot"}.</p> 7775 * 7776 * <pre> 7777 * StringUtils.difference(null, null) = null 7778 * StringUtils.difference("", "") = "" 7779 * StringUtils.difference("", "abc") = "abc" 7780 * StringUtils.difference("abc", "") = "" 7781 * StringUtils.difference("abc", "abc") = "" 7782 * StringUtils.difference("abc", "ab") = "" 7783 * StringUtils.difference("ab", "abxyz") = "xyz" 7784 * StringUtils.difference("abcde", "abxyz") = "xyz" 7785 * StringUtils.difference("abcde", "xyz") = "xyz" 7786 * </pre> 7787 * 7788 * @param str1 the first String, may be null 7789 * @param str2 the second String, may be null 7790 * @return the portion of str2 where it differs from str1; returns the 7791 * empty String if they are equal 7792 * @see #indexOfDifference(CharSequence,CharSequence) 7793 * @since 2.0 7794 */ 7795 public static String difference(final String str1, final String str2) { 7796 if (str1 == null) { 7797 return str2; 7798 } 7799 if (str2 == null) { 7800 return str1; 7801 } 7802 final int at = indexOfDifference(str1, str2); 7803 if (at == INDEX_NOT_FOUND) { 7804 return EMPTY; 7805 } 7806 return str2.substring(at); 7807 } 7808 7809 /** 7810 * <p>Compares two CharSequences, and returns the index at which the 7811 * CharSequences begin to differ.</p> 7812 * 7813 * <p>For example, 7814 * {@code indexOfDifference("i am a machine", "i am a robot") -> 7}</p> 7815 * 7816 * <pre> 7817 * StringUtils.indexOfDifference(null, null) = -1 7818 * StringUtils.indexOfDifference("", "") = -1 7819 * StringUtils.indexOfDifference("", "abc") = 0 7820 * StringUtils.indexOfDifference("abc", "") = 0 7821 * StringUtils.indexOfDifference("abc", "abc") = -1 7822 * StringUtils.indexOfDifference("ab", "abxyz") = 2 7823 * StringUtils.indexOfDifference("abcde", "abxyz") = 2 7824 * StringUtils.indexOfDifference("abcde", "xyz") = 0 7825 * </pre> 7826 * 7827 * @param cs1 the first CharSequence, may be null 7828 * @param cs2 the second CharSequence, may be null 7829 * @return the index where cs1 and cs2 begin to differ; -1 if they are equal 7830 * @since 2.0 7831 * @since 3.0 Changed signature from indexOfDifference(String, String) to 7832 * indexOfDifference(CharSequence, CharSequence) 7833 */ 7834 public static int indexOfDifference(final CharSequence cs1, final CharSequence cs2) { 7835 if (cs1 == cs2) { 7836 return INDEX_NOT_FOUND; 7837 } 7838 if (cs1 == null || cs2 == null) { 7839 return 0; 7840 } 7841 int i; 7842 for (i = 0; i < cs1.length() && i < cs2.length(); ++i) { 7843 if (cs1.charAt(i) != cs2.charAt(i)) { 7844 break; 7845 } 7846 } 7847 if (i < cs2.length() || i < cs1.length()) { 7848 return i; 7849 } 7850 return INDEX_NOT_FOUND; 7851 } 7852 7853 /** 7854 * <p>Compares all CharSequences in an array and returns the index at which the 7855 * CharSequences begin to differ.</p> 7856 * 7857 * <p>For example, 7858 * <code>indexOfDifference(new String[] {"i am a machine", "i am a robot"}) -> 7</code></p> 7859 * 7860 * <pre> 7861 * StringUtils.indexOfDifference(null) = -1 7862 * StringUtils.indexOfDifference(new String[] {}) = -1 7863 * StringUtils.indexOfDifference(new String[] {"abc"}) = -1 7864 * StringUtils.indexOfDifference(new String[] {null, null}) = -1 7865 * StringUtils.indexOfDifference(new String[] {"", ""}) = -1 7866 * StringUtils.indexOfDifference(new String[] {"", null}) = 0 7867 * StringUtils.indexOfDifference(new String[] {"abc", null, null}) = 0 7868 * StringUtils.indexOfDifference(new String[] {null, null, "abc"}) = 0 7869 * StringUtils.indexOfDifference(new String[] {"", "abc"}) = 0 7870 * StringUtils.indexOfDifference(new String[] {"abc", ""}) = 0 7871 * StringUtils.indexOfDifference(new String[] {"abc", "abc"}) = -1 7872 * StringUtils.indexOfDifference(new String[] {"abc", "a"}) = 1 7873 * StringUtils.indexOfDifference(new String[] {"ab", "abxyz"}) = 2 7874 * StringUtils.indexOfDifference(new String[] {"abcde", "abxyz"}) = 2 7875 * StringUtils.indexOfDifference(new String[] {"abcde", "xyz"}) = 0 7876 * StringUtils.indexOfDifference(new String[] {"xyz", "abcde"}) = 0 7877 * StringUtils.indexOfDifference(new String[] {"i am a machine", "i am a robot"}) = 7 7878 * </pre> 7879 * 7880 * @param css array of CharSequences, entries may be null 7881 * @return the index where the strings begin to differ; -1 if they are all equal 7882 * @since 2.4 7883 * @since 3.0 Changed signature from indexOfDifference(String...) to indexOfDifference(CharSequence...) 7884 */ 7885 public static int indexOfDifference(final CharSequence... css) { 7886 if (css == null || css.length <= 1) { 7887 return INDEX_NOT_FOUND; 7888 } 7889 boolean anyStringNull = false; 7890 boolean allStringsNull = true; 7891 final int arrayLen = css.length; 7892 int shortestStrLen = Integer.MAX_VALUE; 7893 int longestStrLen = 0; 7894 7895 // find the min and max string lengths; this avoids checking to make 7896 // sure we are not exceeding the length of the string each time through 7897 // the bottom loop. 7898 for (final CharSequence cs : css) { 7899 if (cs == null) { 7900 anyStringNull = true; 7901 shortestStrLen = 0; 7902 } else { 7903 allStringsNull = false; 7904 shortestStrLen = Math.min(cs.length(), shortestStrLen); 7905 longestStrLen = Math.max(cs.length(), longestStrLen); 7906 } 7907 } 7908 7909 // handle lists containing all nulls or all empty strings 7910 if (allStringsNull || longestStrLen == 0 && !anyStringNull) { 7911 return INDEX_NOT_FOUND; 7912 } 7913 7914 // handle lists containing some nulls or some empty strings 7915 if (shortestStrLen == 0) { 7916 return 0; 7917 } 7918 7919 // find the position with the first difference across all strings 7920 int firstDiff = -1; 7921 for (int stringPos = 0; stringPos < shortestStrLen; stringPos++) { 7922 final char comparisonChar = css[0].charAt(stringPos); 7923 for (int arrayPos = 1; arrayPos < arrayLen; arrayPos++) { 7924 if (css[arrayPos].charAt(stringPos) != comparisonChar) { 7925 firstDiff = stringPos; 7926 break; 7927 } 7928 } 7929 if (firstDiff != -1) { 7930 break; 7931 } 7932 } 7933 7934 if (firstDiff == -1 && shortestStrLen != longestStrLen) { 7935 // we compared all of the characters up to the length of the 7936 // shortest string and didn't find a match, but the string lengths 7937 // vary, so return the length of the shortest string. 7938 return shortestStrLen; 7939 } 7940 return firstDiff; 7941 } 7942 7943 /** 7944 * <p>Compares all Strings in an array and returns the initial sequence of 7945 * characters that is common to all of them.</p> 7946 * 7947 * <p>For example, 7948 * <code>getCommonPrefix(new String[] {"i am a machine", "i am a robot"}) -> "i am a "</code></p> 7949 * 7950 * <pre> 7951 * StringUtils.getCommonPrefix(null) = "" 7952 * StringUtils.getCommonPrefix(new String[] {}) = "" 7953 * StringUtils.getCommonPrefix(new String[] {"abc"}) = "abc" 7954 * StringUtils.getCommonPrefix(new String[] {null, null}) = "" 7955 * StringUtils.getCommonPrefix(new String[] {"", ""}) = "" 7956 * StringUtils.getCommonPrefix(new String[] {"", null}) = "" 7957 * StringUtils.getCommonPrefix(new String[] {"abc", null, null}) = "" 7958 * StringUtils.getCommonPrefix(new String[] {null, null, "abc"}) = "" 7959 * StringUtils.getCommonPrefix(new String[] {"", "abc"}) = "" 7960 * StringUtils.getCommonPrefix(new String[] {"abc", ""}) = "" 7961 * StringUtils.getCommonPrefix(new String[] {"abc", "abc"}) = "abc" 7962 * StringUtils.getCommonPrefix(new String[] {"abc", "a"}) = "a" 7963 * StringUtils.getCommonPrefix(new String[] {"ab", "abxyz"}) = "ab" 7964 * StringUtils.getCommonPrefix(new String[] {"abcde", "abxyz"}) = "ab" 7965 * StringUtils.getCommonPrefix(new String[] {"abcde", "xyz"}) = "" 7966 * StringUtils.getCommonPrefix(new String[] {"xyz", "abcde"}) = "" 7967 * StringUtils.getCommonPrefix(new String[] {"i am a machine", "i am a robot"}) = "i am a " 7968 * </pre> 7969 * 7970 * @param strs array of String objects, entries may be null 7971 * @return the initial sequence of characters that are common to all Strings 7972 * in the array; empty String if the array is null, the elements are all null 7973 * or if there is no common prefix. 7974 * @since 2.4 7975 */ 7976 public static String getCommonPrefix(final String... strs) { 7977 if (strs == null || strs.length == 0) { 7978 return EMPTY; 7979 } 7980 final int smallestIndexOfDiff = indexOfDifference(strs); 7981 if (smallestIndexOfDiff == INDEX_NOT_FOUND) { 7982 // all strings were identical 7983 if (strs[0] == null) { 7984 return EMPTY; 7985 } 7986 return strs[0]; 7987 } else if (smallestIndexOfDiff == 0) { 7988 // there were no common initial characters 7989 return EMPTY; 7990 } else { 7991 // we found a common initial character sequence 7992 return strs[0].substring(0, smallestIndexOfDiff); 7993 } 7994 } 7995 7996 // Misc 7997 //----------------------------------------------------------------------- 7998 /** 7999 * <p>Find the Levenshtein distance between two Strings.</p> 8000 * 8001 * <p>This is the number of changes needed to change one String into 8002 * another, where each change is a single character modification (deletion, 8003 * insertion or substitution).</p> 8004 * 8005 * <p>The implementation uses a single-dimensional array of length s.length() + 1. See 8006 * <a href="http://blog.softwx.net/2014/12/optimizing-levenshtein-algorithm-in-c.html"> 8007 * http://blog.softwx.net/2014/12/optimizing-levenshtein-algorithm-in-c.html</a> for details.</p> 8008 * 8009 * <pre> 8010 * StringUtils.getLevenshteinDistance(null, *) = IllegalArgumentException 8011 * StringUtils.getLevenshteinDistance(*, null) = IllegalArgumentException 8012 * StringUtils.getLevenshteinDistance("","") = 0 8013 * StringUtils.getLevenshteinDistance("","a") = 1 8014 * StringUtils.getLevenshteinDistance("aaapppp", "") = 7 8015 * StringUtils.getLevenshteinDistance("frog", "fog") = 1 8016 * StringUtils.getLevenshteinDistance("fly", "ant") = 3 8017 * StringUtils.getLevenshteinDistance("elephant", "hippo") = 7 8018 * StringUtils.getLevenshteinDistance("hippo", "elephant") = 7 8019 * StringUtils.getLevenshteinDistance("hippo", "zzzzzzzz") = 8 8020 * StringUtils.getLevenshteinDistance("hello", "hallo") = 1 8021 * </pre> 8022 * 8023 * @param s the first String, must not be null 8024 * @param t the second String, must not be null 8025 * @return result distance 8026 * @throws IllegalArgumentException if either String input {@code null} 8027 * @since 3.0 Changed signature from getLevenshteinDistance(String, String) to 8028 * getLevenshteinDistance(CharSequence, CharSequence) 8029 * @deprecated as of 3.6, use commons-text 8030 * <a href="https://commons.apache.org/proper/commons-text/javadocs/api-release/org/apache/commons/text/similarity/LevenshteinDistance.html"> 8031 * LevenshteinDistance</a> instead 8032 */ 8033 @Deprecated 8034 public static int getLevenshteinDistance(CharSequence s, CharSequence t) { 8035 if (s == null || t == null) { 8036 throw new IllegalArgumentException("Strings must not be null"); 8037 } 8038 8039 int n = s.length(); 8040 int m = t.length(); 8041 8042 if (n == 0) { 8043 return m; 8044 } else if (m == 0) { 8045 return n; 8046 } 8047 8048 if (n > m) { 8049 // swap the input strings to consume less memory 8050 final CharSequence tmp = s; 8051 s = t; 8052 t = tmp; 8053 n = m; 8054 m = t.length(); 8055 } 8056 8057 final int p[] = new int[n + 1]; 8058 // indexes into strings s and t 8059 int i; // iterates through s 8060 int j; // iterates through t 8061 int upper_left; 8062 int upper; 8063 8064 char t_j; // jth character of t 8065 int cost; 8066 8067 for (i = 0; i <= n; i++) { 8068 p[i] = i; 8069 } 8070 8071 for (j = 1; j <= m; j++) { 8072 upper_left = p[0]; 8073 t_j = t.charAt(j - 1); 8074 p[0] = j; 8075 8076 for (i = 1; i <= n; i++) { 8077 upper = p[i]; 8078 cost = s.charAt(i - 1) == t_j ? 0 : 1; 8079 // minimum of cell to the left+1, to the top+1, diagonally left and up +cost 8080 p[i] = Math.min(Math.min(p[i - 1] + 1, p[i] + 1), upper_left + cost); 8081 upper_left = upper; 8082 } 8083 } 8084 8085 return p[n]; 8086 } 8087 8088 /** 8089 * <p>Find the Levenshtein distance between two Strings if it's less than or equal to a given 8090 * threshold.</p> 8091 * 8092 * <p>This is the number of changes needed to change one String into 8093 * another, where each change is a single character modification (deletion, 8094 * insertion or substitution).</p> 8095 * 8096 * <p>This implementation follows from Algorithms on Strings, Trees and Sequences by Dan Gusfield 8097 * and Chas Emerick's implementation of the Levenshtein distance algorithm from 8098 * <a href="http://www.merriampark.com/ld.htm">http://www.merriampark.com/ld.htm</a></p> 8099 * 8100 * <pre> 8101 * StringUtils.getLevenshteinDistance(null, *, *) = IllegalArgumentException 8102 * StringUtils.getLevenshteinDistance(*, null, *) = IllegalArgumentException 8103 * StringUtils.getLevenshteinDistance(*, *, -1) = IllegalArgumentException 8104 * StringUtils.getLevenshteinDistance("","", 0) = 0 8105 * StringUtils.getLevenshteinDistance("aaapppp", "", 8) = 7 8106 * StringUtils.getLevenshteinDistance("aaapppp", "", 7) = 7 8107 * StringUtils.getLevenshteinDistance("aaapppp", "", 6)) = -1 8108 * StringUtils.getLevenshteinDistance("elephant", "hippo", 7) = 7 8109 * StringUtils.getLevenshteinDistance("elephant", "hippo", 6) = -1 8110 * StringUtils.getLevenshteinDistance("hippo", "elephant", 7) = 7 8111 * StringUtils.getLevenshteinDistance("hippo", "elephant", 6) = -1 8112 * </pre> 8113 * 8114 * @param s the first String, must not be null 8115 * @param t the second String, must not be null 8116 * @param threshold the target threshold, must not be negative 8117 * @return result distance, or {@code -1} if the distance would be greater than the threshold 8118 * @throws IllegalArgumentException if either String input {@code null} or negative threshold 8119 * @deprecated as of 3.6, use commons-text 8120 * <a href="https://commons.apache.org/proper/commons-text/javadocs/api-release/org/apache/commons/text/similarity/LevenshteinDistance.html"> 8121 * LevenshteinDistance</a> instead 8122 */ 8123 @Deprecated 8124 public static int getLevenshteinDistance(CharSequence s, CharSequence t, final int threshold) { 8125 if (s == null || t == null) { 8126 throw new IllegalArgumentException("Strings must not be null"); 8127 } 8128 if (threshold < 0) { 8129 throw new IllegalArgumentException("Threshold must not be negative"); 8130 } 8131 8132 /* 8133 This implementation only computes the distance if it's less than or equal to the 8134 threshold value, returning -1 if it's greater. The advantage is performance: unbounded 8135 distance is O(nm), but a bound of k allows us to reduce it to O(km) time by only 8136 computing a diagonal stripe of width 2k + 1 of the cost table. 8137 It is also possible to use this to compute the unbounded Levenshtein distance by starting 8138 the threshold at 1 and doubling each time until the distance is found; this is O(dm), where 8139 d is the distance. 8140 8141 One subtlety comes from needing to ignore entries on the border of our stripe 8142 eg. 8143 p[] = |#|#|#|* 8144 d[] = *|#|#|#| 8145 We must ignore the entry to the left of the leftmost member 8146 We must ignore the entry above the rightmost member 8147 8148 Another subtlety comes from our stripe running off the matrix if the strings aren't 8149 of the same size. Since string s is always swapped to be the shorter of the two, 8150 the stripe will always run off to the upper right instead of the lower left of the matrix. 8151 8152 As a concrete example, suppose s is of length 5, t is of length 7, and our threshold is 1. 8153 In this case we're going to walk a stripe of length 3. The matrix would look like so: 8154 8155 1 2 3 4 5 8156 1 |#|#| | | | 8157 2 |#|#|#| | | 8158 3 | |#|#|#| | 8159 4 | | |#|#|#| 8160 5 | | | |#|#| 8161 6 | | | | |#| 8162 7 | | | | | | 8163 8164 Note how the stripe leads off the table as there is no possible way to turn a string of length 5 8165 into one of length 7 in edit distance of 1. 8166 8167 Additionally, this implementation decreases memory usage by using two 8168 single-dimensional arrays and swapping them back and forth instead of allocating 8169 an entire n by m matrix. This requires a few minor changes, such as immediately returning 8170 when it's detected that the stripe has run off the matrix and initially filling the arrays with 8171 large values so that entries we don't compute are ignored. 8172 8173 See Algorithms on Strings, Trees and Sequences by Dan Gusfield for some discussion. 8174 */ 8175 8176 int n = s.length(); // length of s 8177 int m = t.length(); // length of t 8178 8179 // if one string is empty, the edit distance is necessarily the length of the other 8180 if (n == 0) { 8181 return m <= threshold ? m : -1; 8182 } else if (m == 0) { 8183 return n <= threshold ? n : -1; 8184 } else if (Math.abs(n - m) > threshold) { 8185 // no need to calculate the distance if the length difference is greater than the threshold 8186 return -1; 8187 } 8188 8189 if (n > m) { 8190 // swap the two strings to consume less memory 8191 final CharSequence tmp = s; 8192 s = t; 8193 t = tmp; 8194 n = m; 8195 m = t.length(); 8196 } 8197 8198 int p[] = new int[n + 1]; // 'previous' cost array, horizontally 8199 int d[] = new int[n + 1]; // cost array, horizontally 8200 int _d[]; // placeholder to assist in swapping p and d 8201 8202 // fill in starting table values 8203 final int boundary = Math.min(n, threshold) + 1; 8204 for (int i = 0; i < boundary; i++) { 8205 p[i] = i; 8206 } 8207 // these fills ensure that the value above the rightmost entry of our 8208 // stripe will be ignored in following loop iterations 8209 Arrays.fill(p, boundary, p.length, Integer.MAX_VALUE); 8210 Arrays.fill(d, Integer.MAX_VALUE); 8211 8212 // iterates through t 8213 for (int j = 1; j <= m; j++) { 8214 final char t_j = t.charAt(j - 1); // jth character of t 8215 d[0] = j; 8216 8217 // compute stripe indices, constrain to array size 8218 final int min = Math.max(1, j - threshold); 8219 final int max = j > Integer.MAX_VALUE - threshold ? n : Math.min(n, j + threshold); 8220 8221 // the stripe may lead off of the table if s and t are of different sizes 8222 if (min > max) { 8223 return -1; 8224 } 8225 8226 // ignore entry left of leftmost 8227 if (min > 1) { 8228 d[min - 1] = Integer.MAX_VALUE; 8229 } 8230 8231 // iterates through [min, max] in s 8232 for (int i = min; i <= max; i++) { 8233 if (s.charAt(i - 1) == t_j) { 8234 // diagonally left and up 8235 d[i] = p[i - 1]; 8236 } else { 8237 // 1 + minimum of cell to the left, to the top, diagonally left and up 8238 d[i] = 1 + Math.min(Math.min(d[i - 1], p[i]), p[i - 1]); 8239 } 8240 } 8241 8242 // copy current distance counts to 'previous row' distance counts 8243 _d = p; 8244 p = d; 8245 d = _d; 8246 } 8247 8248 // if p[n] is greater than the threshold, there's no guarantee on it being the correct 8249 // distance 8250 if (p[n] <= threshold) { 8251 return p[n]; 8252 } 8253 return -1; 8254 } 8255 8256 /** 8257 * <p>Find the Jaro Winkler Distance which indicates the similarity score between two Strings.</p> 8258 * 8259 * <p>The Jaro measure is the weighted sum of percentage of matched characters from each file and transposed characters. 8260 * Winkler increased this measure for matching initial characters.</p> 8261 * 8262 * <p>This implementation is based on the Jaro Winkler similarity algorithm 8263 * 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> 8264 * 8265 * <pre> 8266 * StringUtils.getJaroWinklerDistance(null, null) = IllegalArgumentException 8267 * StringUtils.getJaroWinklerDistance("","") = 0.0 8268 * StringUtils.getJaroWinklerDistance("","a") = 0.0 8269 * StringUtils.getJaroWinklerDistance("aaapppp", "") = 0.0 8270 * StringUtils.getJaroWinklerDistance("frog", "fog") = 0.93 8271 * StringUtils.getJaroWinklerDistance("fly", "ant") = 0.0 8272 * StringUtils.getJaroWinklerDistance("elephant", "hippo") = 0.44 8273 * StringUtils.getJaroWinklerDistance("hippo", "elephant") = 0.44 8274 * StringUtils.getJaroWinklerDistance("hippo", "zzzzzzzz") = 0.0 8275 * StringUtils.getJaroWinklerDistance("hello", "hallo") = 0.88 8276 * StringUtils.getJaroWinklerDistance("ABC Corporation", "ABC Corp") = 0.93 8277 * StringUtils.getJaroWinklerDistance("D N H Enterprises Inc", "D & H Enterprises, Inc.") = 0.95 8278 * StringUtils.getJaroWinklerDistance("My Gym Children's Fitness Center", "My Gym. Childrens Fitness") = 0.92 8279 * StringUtils.getJaroWinklerDistance("PENNSYLVANIA", "PENNCISYLVNIA") = 0.88 8280 * </pre> 8281 * 8282 * @param first the first String, must not be null 8283 * @param second the second String, must not be null 8284 * @return result distance 8285 * @throws IllegalArgumentException if either String input {@code null} 8286 * @since 3.3 8287 * @deprecated as of 3.6, use commons-text 8288 * <a href="https://commons.apache.org/proper/commons-text/javadocs/api-release/org/apache/commons/text/similarity/JaroWinklerDistance.html"> 8289 * JaroWinklerDistance</a> instead 8290 */ 8291 @Deprecated 8292 public static double getJaroWinklerDistance(final CharSequence first, final CharSequence second) { 8293 final double DEFAULT_SCALING_FACTOR = 0.1; 8294 8295 if (first == null || second == null) { 8296 throw new IllegalArgumentException("Strings must not be null"); 8297 } 8298 8299 final int[] mtp = matches(first, second); 8300 final double m = mtp[0]; 8301 if (m == 0) { 8302 return 0D; 8303 } 8304 final double j = ((m / first.length() + m / second.length() + (m - mtp[1]) / m)) / 3; 8305 final double jw = j < 0.7D ? j : j + Math.min(DEFAULT_SCALING_FACTOR, 1D / mtp[3]) * mtp[2] * (1D - j); 8306 return Math.round(jw * 100.0D) / 100.0D; 8307 } 8308 8309 private static int[] matches(final CharSequence first, final CharSequence second) { 8310 CharSequence max, min; 8311 if (first.length() > second.length()) { 8312 max = first; 8313 min = second; 8314 } else { 8315 max = second; 8316 min = first; 8317 } 8318 final int range = Math.max(max.length() / 2 - 1, 0); 8319 final int[] matchIndexes = new int[min.length()]; 8320 Arrays.fill(matchIndexes, -1); 8321 final boolean[] matchFlags = new boolean[max.length()]; 8322 int matches = 0; 8323 for (int mi = 0; mi < min.length(); mi++) { 8324 final char c1 = min.charAt(mi); 8325 for (int xi = Math.max(mi - range, 0), xn = Math.min(mi + range + 1, max.length()); xi < xn; xi++) { 8326 if (!matchFlags[xi] && c1 == max.charAt(xi)) { 8327 matchIndexes[mi] = xi; 8328 matchFlags[xi] = true; 8329 matches++; 8330 break; 8331 } 8332 } 8333 } 8334 final char[] ms1 = new char[matches]; 8335 final char[] ms2 = new char[matches]; 8336 for (int i = 0, si = 0; i < min.length(); i++) { 8337 if (matchIndexes[i] != -1) { 8338 ms1[si] = min.charAt(i); 8339 si++; 8340 } 8341 } 8342 for (int i = 0, si = 0; i < max.length(); i++) { 8343 if (matchFlags[i]) { 8344 ms2[si] = max.charAt(i); 8345 si++; 8346 } 8347 } 8348 int transpositions = 0; 8349 for (int mi = 0; mi < ms1.length; mi++) { 8350 if (ms1[mi] != ms2[mi]) { 8351 transpositions++; 8352 } 8353 } 8354 int prefix = 0; 8355 for (int mi = 0; mi < min.length(); mi++) { 8356 if (first.charAt(mi) == second.charAt(mi)) { 8357 prefix++; 8358 } else { 8359 break; 8360 } 8361 } 8362 return new int[] { matches, transpositions / 2, prefix, max.length() }; 8363 } 8364 8365 /** 8366 * <p>Find the Fuzzy Distance which indicates the similarity score between two Strings.</p> 8367 * 8368 * <p>This string matching algorithm is similar to the algorithms of editors such as Sublime Text, 8369 * TextMate, Atom and others. One point is given for every matched character. Subsequent 8370 * matches yield two bonus points. A higher score indicates a higher similarity.</p> 8371 * 8372 * <pre> 8373 * StringUtils.getFuzzyDistance(null, null, null) = IllegalArgumentException 8374 * StringUtils.getFuzzyDistance("", "", Locale.ENGLISH) = 0 8375 * StringUtils.getFuzzyDistance("Workshop", "b", Locale.ENGLISH) = 0 8376 * StringUtils.getFuzzyDistance("Room", "o", Locale.ENGLISH) = 1 8377 * StringUtils.getFuzzyDistance("Workshop", "w", Locale.ENGLISH) = 1 8378 * StringUtils.getFuzzyDistance("Workshop", "ws", Locale.ENGLISH) = 2 8379 * StringUtils.getFuzzyDistance("Workshop", "wo", Locale.ENGLISH) = 4 8380 * StringUtils.getFuzzyDistance("Apache Software Foundation", "asf", Locale.ENGLISH) = 3 8381 * </pre> 8382 * 8383 * @param term a full term that should be matched against, must not be null 8384 * @param query the query that will be matched against a term, must not be null 8385 * @param locale This string matching logic is case insensitive. A locale is necessary to normalize 8386 * both Strings to lower case. 8387 * @return result score 8388 * @throws IllegalArgumentException if either String input {@code null} or Locale input {@code null} 8389 * @since 3.4 8390 * @deprecated as of 3.6, use commons-text 8391 * <a href="https://commons.apache.org/proper/commons-text/javadocs/api-release/org/apache/commons/text/similarity/FuzzyScore.html"> 8392 * FuzzyScore</a> instead 8393 */ 8394 @Deprecated 8395 public static int getFuzzyDistance(final CharSequence term, final CharSequence query, final Locale locale) { 8396 if (term == null || query == null) { 8397 throw new IllegalArgumentException("Strings must not be null"); 8398 } else if (locale == null) { 8399 throw new IllegalArgumentException("Locale must not be null"); 8400 } 8401 8402 // fuzzy logic is case insensitive. We normalize the Strings to lower 8403 // case right from the start. Turning characters to lower case 8404 // via Character.toLowerCase(char) is unfortunately insufficient 8405 // as it does not accept a locale. 8406 final String termLowerCase = term.toString().toLowerCase(locale); 8407 final String queryLowerCase = query.toString().toLowerCase(locale); 8408 8409 // the resulting score 8410 int score = 0; 8411 8412 // the position in the term which will be scanned next for potential 8413 // query character matches 8414 int termIndex = 0; 8415 8416 // index of the previously matched character in the term 8417 int previousMatchingCharacterIndex = Integer.MIN_VALUE; 8418 8419 for (int queryIndex = 0; queryIndex < queryLowerCase.length(); queryIndex++) { 8420 final char queryChar = queryLowerCase.charAt(queryIndex); 8421 8422 boolean termCharacterMatchFound = false; 8423 for (; termIndex < termLowerCase.length() && !termCharacterMatchFound; termIndex++) { 8424 final char termChar = termLowerCase.charAt(termIndex); 8425 8426 if (queryChar == termChar) { 8427 // simple character matches result in one point 8428 score++; 8429 8430 // subsequent character matches further improve 8431 // the score. 8432 if (previousMatchingCharacterIndex + 1 == termIndex) { 8433 score += 2; 8434 } 8435 8436 previousMatchingCharacterIndex = termIndex; 8437 8438 // we can leave the nested loop. Every character in the 8439 // query can match at most one character in the term. 8440 termCharacterMatchFound = true; 8441 } 8442 } 8443 } 8444 8445 return score; 8446 } 8447 8448 // startsWith 8449 //----------------------------------------------------------------------- 8450 8451 /** 8452 * <p>Check if a CharSequence starts with a specified prefix.</p> 8453 * 8454 * <p>{@code null}s are handled without exceptions. Two {@code null} 8455 * references are considered to be equal. The comparison is case sensitive.</p> 8456 * 8457 * <pre> 8458 * StringUtils.startsWith(null, null) = true 8459 * StringUtils.startsWith(null, "abc") = false 8460 * StringUtils.startsWith("abcdef", null) = false 8461 * StringUtils.startsWith("abcdef", "abc") = true 8462 * StringUtils.startsWith("ABCDEF", "abc") = false 8463 * </pre> 8464 * 8465 * @see java.lang.String#startsWith(String) 8466 * @param str the CharSequence to check, may be null 8467 * @param prefix the prefix to find, may be null 8468 * @return {@code true} if the CharSequence starts with the prefix, case sensitive, or 8469 * both {@code null} 8470 * @since 2.4 8471 * @since 3.0 Changed signature from startsWith(String, String) to startsWith(CharSequence, CharSequence) 8472 */ 8473 public static boolean startsWith(final CharSequence str, final CharSequence prefix) { 8474 return startsWith(str, prefix, false); 8475 } 8476 8477 /** 8478 * <p>Case insensitive check if a CharSequence starts with a specified prefix.</p> 8479 * 8480 * <p>{@code null}s are handled without exceptions. Two {@code null} 8481 * references are considered to be equal. The comparison is case insensitive.</p> 8482 * 8483 * <pre> 8484 * StringUtils.startsWithIgnoreCase(null, null) = true 8485 * StringUtils.startsWithIgnoreCase(null, "abc") = false 8486 * StringUtils.startsWithIgnoreCase("abcdef", null) = false 8487 * StringUtils.startsWithIgnoreCase("abcdef", "abc") = true 8488 * StringUtils.startsWithIgnoreCase("ABCDEF", "abc") = true 8489 * </pre> 8490 * 8491 * @see java.lang.String#startsWith(String) 8492 * @param str the CharSequence to check, may be null 8493 * @param prefix the prefix to find, may be null 8494 * @return {@code true} if the CharSequence starts with the prefix, case insensitive, or 8495 * both {@code null} 8496 * @since 2.4 8497 * @since 3.0 Changed signature from startsWithIgnoreCase(String, String) to startsWithIgnoreCase(CharSequence, CharSequence) 8498 */ 8499 public static boolean startsWithIgnoreCase(final CharSequence str, final CharSequence prefix) { 8500 return startsWith(str, prefix, true); 8501 } 8502 8503 /** 8504 * <p>Check if a CharSequence starts with a specified prefix (optionally case insensitive).</p> 8505 * 8506 * @see java.lang.String#startsWith(String) 8507 * @param str the CharSequence to check, may be null 8508 * @param prefix the prefix to find, may be null 8509 * @param ignoreCase indicates whether the compare should ignore case 8510 * (case insensitive) or not. 8511 * @return {@code true} if the CharSequence starts with the prefix or 8512 * both {@code null} 8513 */ 8514 private static boolean startsWith(final CharSequence str, final CharSequence prefix, final boolean ignoreCase) { 8515 if (str == null || prefix == null) { 8516 return str == null && prefix == null; 8517 } 8518 if (prefix.length() > str.length()) { 8519 return false; 8520 } 8521 return CharSequenceUtils.regionMatches(str, ignoreCase, 0, prefix, 0, prefix.length()); 8522 } 8523 8524 /** 8525 * <p>Check if a CharSequence starts with any of the provided case-sensitive prefixes.</p> 8526 * 8527 * <pre> 8528 * StringUtils.startsWithAny(null, null) = false 8529 * StringUtils.startsWithAny(null, new String[] {"abc"}) = false 8530 * StringUtils.startsWithAny("abcxyz", null) = false 8531 * StringUtils.startsWithAny("abcxyz", new String[] {""}) = true 8532 * StringUtils.startsWithAny("abcxyz", new String[] {"abc"}) = true 8533 * StringUtils.startsWithAny("abcxyz", new String[] {null, "xyz", "abc"}) = true 8534 * StringUtils.startsWithAny("abcxyz", null, "xyz", "ABCX") = false 8535 * StringUtils.startsWithAny("ABCXYZ", null, "xyz", "abc") = false 8536 * </pre> 8537 * 8538 * @param sequence the CharSequence to check, may be null 8539 * @param searchStrings the case-sensitive CharSequence prefixes, may be empty or contain {@code null} 8540 * @see StringUtils#startsWith(CharSequence, CharSequence) 8541 * @return {@code true} if the input {@code sequence} is {@code null} AND no {@code searchStrings} are provided, or 8542 * the input {@code sequence} begins with any of the provided case-sensitive {@code searchStrings}. 8543 * @since 2.5 8544 * @since 3.0 Changed signature from startsWithAny(String, String[]) to startsWithAny(CharSequence, CharSequence...) 8545 */ 8546 public static boolean startsWithAny(final CharSequence sequence, final CharSequence... searchStrings) { 8547 if (isEmpty(sequence) || ArrayUtils.isEmpty(searchStrings)) { 8548 return false; 8549 } 8550 for (final CharSequence searchString : searchStrings) { 8551 if (startsWith(sequence, searchString)) { 8552 return true; 8553 } 8554 } 8555 return false; 8556 } 8557 8558 // endsWith 8559 //----------------------------------------------------------------------- 8560 8561 /** 8562 * <p>Check if a CharSequence ends with a specified suffix.</p> 8563 * 8564 * <p>{@code null}s are handled without exceptions. Two {@code null} 8565 * references are considered to be equal. The comparison is case sensitive.</p> 8566 * 8567 * <pre> 8568 * StringUtils.endsWith(null, null) = true 8569 * StringUtils.endsWith(null, "def") = false 8570 * StringUtils.endsWith("abcdef", null) = false 8571 * StringUtils.endsWith("abcdef", "def") = true 8572 * StringUtils.endsWith("ABCDEF", "def") = false 8573 * StringUtils.endsWith("ABCDEF", "cde") = false 8574 * StringUtils.endsWith("ABCDEF", "") = true 8575 * </pre> 8576 * 8577 * @see java.lang.String#endsWith(String) 8578 * @param str the CharSequence to check, may be null 8579 * @param suffix the suffix to find, may be null 8580 * @return {@code true} if the CharSequence ends with the suffix, case sensitive, or 8581 * both {@code null} 8582 * @since 2.4 8583 * @since 3.0 Changed signature from endsWith(String, String) to endsWith(CharSequence, CharSequence) 8584 */ 8585 public static boolean endsWith(final CharSequence str, final CharSequence suffix) { 8586 return endsWith(str, suffix, false); 8587 } 8588 8589 /** 8590 * <p>Case insensitive check if a CharSequence ends with a specified suffix.</p> 8591 * 8592 * <p>{@code null}s are handled without exceptions. Two {@code null} 8593 * references are considered to be equal. The comparison is case insensitive.</p> 8594 * 8595 * <pre> 8596 * StringUtils.endsWithIgnoreCase(null, null) = true 8597 * StringUtils.endsWithIgnoreCase(null, "def") = false 8598 * StringUtils.endsWithIgnoreCase("abcdef", null) = false 8599 * StringUtils.endsWithIgnoreCase("abcdef", "def") = true 8600 * StringUtils.endsWithIgnoreCase("ABCDEF", "def") = true 8601 * StringUtils.endsWithIgnoreCase("ABCDEF", "cde") = false 8602 * </pre> 8603 * 8604 * @see java.lang.String#endsWith(String) 8605 * @param str the CharSequence to check, may be null 8606 * @param suffix the suffix to find, may be null 8607 * @return {@code true} if the CharSequence ends with the suffix, case insensitive, or 8608 * both {@code null} 8609 * @since 2.4 8610 * @since 3.0 Changed signature from endsWithIgnoreCase(String, String) to endsWithIgnoreCase(CharSequence, CharSequence) 8611 */ 8612 public static boolean endsWithIgnoreCase(final CharSequence str, final CharSequence suffix) { 8613 return endsWith(str, suffix, true); 8614 } 8615 8616 /** 8617 * <p>Check if a CharSequence ends with a specified suffix (optionally case insensitive).</p> 8618 * 8619 * @see java.lang.String#endsWith(String) 8620 * @param str the CharSequence to check, may be null 8621 * @param suffix the suffix to find, may be null 8622 * @param ignoreCase indicates whether the compare should ignore case 8623 * (case insensitive) or not. 8624 * @return {@code true} if the CharSequence starts with the prefix or 8625 * both {@code null} 8626 */ 8627 private static boolean endsWith(final CharSequence str, final CharSequence suffix, final boolean ignoreCase) { 8628 if (str == null || suffix == null) { 8629 return str == null && suffix == null; 8630 } 8631 if (suffix.length() > str.length()) { 8632 return false; 8633 } 8634 final int strOffset = str.length() - suffix.length(); 8635 return CharSequenceUtils.regionMatches(str, ignoreCase, strOffset, suffix, 0, suffix.length()); 8636 } 8637 8638 /** 8639 * <p> 8640 * Similar to <a 8641 * href="http://www.w3.org/TR/xpath/#function-normalize-space">http://www.w3.org/TR/xpath/#function-normalize 8642 * -space</a> 8643 * </p> 8644 * <p> 8645 * The function returns the argument string with whitespace normalized by using 8646 * <code>{@link #trim(String)}</code> to remove leading and trailing whitespace 8647 * and then replacing sequences of whitespace characters by a single space. 8648 * </p> 8649 * In XML Whitespace characters are the same as those allowed by the <a 8650 * href="http://www.w3.org/TR/REC-xml/#NT-S">S</a> production, which is S ::= (#x20 | #x9 | #xD | #xA)+ 8651 * <p> 8652 * Java's regexp pattern \s defines whitespace as [ \t\n\x0B\f\r] 8653 * 8654 * <p>For reference:</p> 8655 * <ul> 8656 * <li>\x0B = vertical tab</li> 8657 * <li>\f = #xC = form feed</li> 8658 * <li>#x20 = space</li> 8659 * <li>#x9 = \t</li> 8660 * <li>#xA = \n</li> 8661 * <li>#xD = \r</li> 8662 * </ul> 8663 * 8664 * <p> 8665 * The difference is that Java's whitespace includes vertical tab and form feed, which this functional will also 8666 * normalize. Additionally <code>{@link #trim(String)}</code> removes control characters (char <= 32) from both 8667 * ends of this String. 8668 * </p> 8669 * 8670 * @see Pattern 8671 * @see #trim(String) 8672 * @see <a 8673 * href="http://www.w3.org/TR/xpath/#function-normalize-space">http://www.w3.org/TR/xpath/#function-normalize-space</a> 8674 * @param str the source String to normalize whitespaces from, may be null 8675 * @return the modified string with whitespace normalized, {@code null} if null String input 8676 * 8677 * @since 3.0 8678 */ 8679 public static String normalizeSpace(final String str) { 8680 // LANG-1020: Improved performance significantly by normalizing manually instead of using regex 8681 // See https://github.com/librucha/commons-lang-normalizespaces-benchmark for performance test 8682 if (isEmpty(str)) { 8683 return str; 8684 } 8685 final int size = str.length(); 8686 final char[] newChars = new char[size]; 8687 int count = 0; 8688 int whitespacesCount = 0; 8689 boolean startWhitespaces = true; 8690 for (int i = 0; i < size; i++) { 8691 final char actualChar = str.charAt(i); 8692 final boolean isWhitespace = Character.isWhitespace(actualChar); 8693 if (!isWhitespace) { 8694 startWhitespaces = false; 8695 newChars[count++] = (actualChar == 160 ? 32 : actualChar); 8696 whitespacesCount = 0; 8697 } else { 8698 if (whitespacesCount == 0 && !startWhitespaces) { 8699 newChars[count++] = SPACE.charAt(0); 8700 } 8701 whitespacesCount++; 8702 } 8703 } 8704 if (startWhitespaces) { 8705 return EMPTY; 8706 } 8707 return new String(newChars, 0, count - (whitespacesCount > 0 ? 1 : 0)).trim(); 8708 } 8709 8710 /** 8711 * <p>Check if a CharSequence ends with any of the provided case-sensitive suffixes.</p> 8712 * 8713 * <pre> 8714 * StringUtils.endsWithAny(null, null) = false 8715 * StringUtils.endsWithAny(null, new String[] {"abc"}) = false 8716 * StringUtils.endsWithAny("abcxyz", null) = false 8717 * StringUtils.endsWithAny("abcxyz", new String[] {""}) = true 8718 * StringUtils.endsWithAny("abcxyz", new String[] {"xyz"}) = true 8719 * StringUtils.endsWithAny("abcxyz", new String[] {null, "xyz", "abc"}) = true 8720 * StringUtils.endsWithAny("abcXYZ", "def", "XYZ") = true 8721 * StringUtils.endsWithAny("abcXYZ", "def", "xyz") = false 8722 * </pre> 8723 * 8724 * @param sequence the CharSequence to check, may be null 8725 * @param searchStrings the case-sensitive CharSequences to find, may be empty or contain {@code null} 8726 * @see StringUtils#endsWith(CharSequence, CharSequence) 8727 * @return {@code true} if the input {@code sequence} is {@code null} AND no {@code searchStrings} are provided, or 8728 * the input {@code sequence} ends in any of the provided case-sensitive {@code searchStrings}. 8729 * @since 3.0 8730 */ 8731 public static boolean endsWithAny(final CharSequence sequence, final CharSequence... searchStrings) { 8732 if (isEmpty(sequence) || ArrayUtils.isEmpty(searchStrings)) { 8733 return false; 8734 } 8735 for (final CharSequence searchString : searchStrings) { 8736 if (endsWith(sequence, searchString)) { 8737 return true; 8738 } 8739 } 8740 return false; 8741 } 8742 8743 /** 8744 * Appends the suffix to the end of the string if the string does not 8745 * already end with the suffix. 8746 * 8747 * @param str The string. 8748 * @param suffix The suffix to append to the end of the string. 8749 * @param ignoreCase Indicates whether the compare should ignore case. 8750 * @param suffixes Additional suffixes that are valid terminators (optional). 8751 * 8752 * @return A new String if suffix was appended, the same string otherwise. 8753 */ 8754 private static String appendIfMissing(final String str, final CharSequence suffix, final boolean ignoreCase, final CharSequence... suffixes) { 8755 if (str == null || isEmpty(suffix) || endsWith(str, suffix, ignoreCase)) { 8756 return str; 8757 } 8758 if (suffixes != null && suffixes.length > 0) { 8759 for (final CharSequence s : suffixes) { 8760 if (endsWith(str, s, ignoreCase)) { 8761 return str; 8762 } 8763 } 8764 } 8765 return str + suffix.toString(); 8766 } 8767 8768 /** 8769 * Appends the suffix to the end of the string if the string does not 8770 * already end with any of the suffixes. 8771 * 8772 * <pre> 8773 * StringUtils.appendIfMissing(null, null) = null 8774 * StringUtils.appendIfMissing("abc", null) = "abc" 8775 * StringUtils.appendIfMissing("", "xyz") = "xyz" 8776 * StringUtils.appendIfMissing("abc", "xyz") = "abcxyz" 8777 * StringUtils.appendIfMissing("abcxyz", "xyz") = "abcxyz" 8778 * StringUtils.appendIfMissing("abcXYZ", "xyz") = "abcXYZxyz" 8779 * </pre> 8780 * <p>With additional suffixes,</p> 8781 * <pre> 8782 * StringUtils.appendIfMissing(null, null, null) = null 8783 * StringUtils.appendIfMissing("abc", null, null) = "abc" 8784 * StringUtils.appendIfMissing("", "xyz", null) = "xyz" 8785 * StringUtils.appendIfMissing("abc", "xyz", new CharSequence[]{null}) = "abcxyz" 8786 * StringUtils.appendIfMissing("abc", "xyz", "") = "abc" 8787 * StringUtils.appendIfMissing("abc", "xyz", "mno") = "abcxyz" 8788 * StringUtils.appendIfMissing("abcxyz", "xyz", "mno") = "abcxyz" 8789 * StringUtils.appendIfMissing("abcmno", "xyz", "mno") = "abcmno" 8790 * StringUtils.appendIfMissing("abcXYZ", "xyz", "mno") = "abcXYZxyz" 8791 * StringUtils.appendIfMissing("abcMNO", "xyz", "mno") = "abcMNOxyz" 8792 * </pre> 8793 * 8794 * @param str The string. 8795 * @param suffix The suffix to append to the end of the string. 8796 * @param suffixes Additional suffixes that are valid terminators. 8797 * 8798 * @return A new String if suffix was appended, the same string otherwise. 8799 * 8800 * @since 3.2 8801 */ 8802 public static String appendIfMissing(final String str, final CharSequence suffix, final CharSequence... suffixes) { 8803 return appendIfMissing(str, suffix, false, suffixes); 8804 } 8805 8806 /** 8807 * Appends the suffix to the end of the string if the string does not 8808 * already end, case insensitive, with any of the suffixes. 8809 * 8810 * <pre> 8811 * StringUtils.appendIfMissingIgnoreCase(null, null) = null 8812 * StringUtils.appendIfMissingIgnoreCase("abc", null) = "abc" 8813 * StringUtils.appendIfMissingIgnoreCase("", "xyz") = "xyz" 8814 * StringUtils.appendIfMissingIgnoreCase("abc", "xyz") = "abcxyz" 8815 * StringUtils.appendIfMissingIgnoreCase("abcxyz", "xyz") = "abcxyz" 8816 * StringUtils.appendIfMissingIgnoreCase("abcXYZ", "xyz") = "abcXYZ" 8817 * </pre> 8818 * <p>With additional suffixes,</p> 8819 * <pre> 8820 * StringUtils.appendIfMissingIgnoreCase(null, null, null) = null 8821 * StringUtils.appendIfMissingIgnoreCase("abc", null, null) = "abc" 8822 * StringUtils.appendIfMissingIgnoreCase("", "xyz", null) = "xyz" 8823 * StringUtils.appendIfMissingIgnoreCase("abc", "xyz", new CharSequence[]{null}) = "abcxyz" 8824 * StringUtils.appendIfMissingIgnoreCase("abc", "xyz", "") = "abc" 8825 * StringUtils.appendIfMissingIgnoreCase("abc", "xyz", "mno") = "axyz" 8826 * StringUtils.appendIfMissingIgnoreCase("abcxyz", "xyz", "mno") = "abcxyz" 8827 * StringUtils.appendIfMissingIgnoreCase("abcmno", "xyz", "mno") = "abcmno" 8828 * StringUtils.appendIfMissingIgnoreCase("abcXYZ", "xyz", "mno") = "abcXYZ" 8829 * StringUtils.appendIfMissingIgnoreCase("abcMNO", "xyz", "mno") = "abcMNO" 8830 * </pre> 8831 * 8832 * @param str The string. 8833 * @param suffix The suffix to append to the end of the string. 8834 * @param suffixes Additional suffixes that are valid terminators. 8835 * 8836 * @return A new String if suffix was appended, the same string otherwise. 8837 * 8838 * @since 3.2 8839 */ 8840 public static String appendIfMissingIgnoreCase(final String str, final CharSequence suffix, final CharSequence... suffixes) { 8841 return appendIfMissing(str, suffix, true, suffixes); 8842 } 8843 8844 /** 8845 * Prepends the prefix to the start of the string if the string does not 8846 * already start with any of the prefixes. 8847 * 8848 * @param str The string. 8849 * @param prefix The prefix to prepend to the start of the string. 8850 * @param ignoreCase Indicates whether the compare should ignore case. 8851 * @param prefixes Additional prefixes that are valid (optional). 8852 * 8853 * @return A new String if prefix was prepended, the same string otherwise. 8854 */ 8855 private static String prependIfMissing(final String str, final CharSequence prefix, final boolean ignoreCase, final CharSequence... prefixes) { 8856 if (str == null || isEmpty(prefix) || startsWith(str, prefix, ignoreCase)) { 8857 return str; 8858 } 8859 if (prefixes != null && prefixes.length > 0) { 8860 for (final CharSequence p : prefixes) { 8861 if (startsWith(str, p, ignoreCase)) { 8862 return str; 8863 } 8864 } 8865 } 8866 return prefix.toString() + str; 8867 } 8868 8869 /** 8870 * Prepends the prefix to the start of the string if the string does not 8871 * already start with any of the prefixes. 8872 * 8873 * <pre> 8874 * StringUtils.prependIfMissing(null, null) = null 8875 * StringUtils.prependIfMissing("abc", null) = "abc" 8876 * StringUtils.prependIfMissing("", "xyz") = "xyz" 8877 * StringUtils.prependIfMissing("abc", "xyz") = "xyzabc" 8878 * StringUtils.prependIfMissing("xyzabc", "xyz") = "xyzabc" 8879 * StringUtils.prependIfMissing("XYZabc", "xyz") = "xyzXYZabc" 8880 * </pre> 8881 * <p>With additional prefixes,</p> 8882 * <pre> 8883 * StringUtils.prependIfMissing(null, null, null) = null 8884 * StringUtils.prependIfMissing("abc", null, null) = "abc" 8885 * StringUtils.prependIfMissing("", "xyz", null) = "xyz" 8886 * StringUtils.prependIfMissing("abc", "xyz", new CharSequence[]{null}) = "xyzabc" 8887 * StringUtils.prependIfMissing("abc", "xyz", "") = "abc" 8888 * StringUtils.prependIfMissing("abc", "xyz", "mno") = "xyzabc" 8889 * StringUtils.prependIfMissing("xyzabc", "xyz", "mno") = "xyzabc" 8890 * StringUtils.prependIfMissing("mnoabc", "xyz", "mno") = "mnoabc" 8891 * StringUtils.prependIfMissing("XYZabc", "xyz", "mno") = "xyzXYZabc" 8892 * StringUtils.prependIfMissing("MNOabc", "xyz", "mno") = "xyzMNOabc" 8893 * </pre> 8894 * 8895 * @param str The string. 8896 * @param prefix The prefix to prepend to the start of the string. 8897 * @param prefixes Additional prefixes that are valid. 8898 * 8899 * @return A new String if prefix was prepended, the same string otherwise. 8900 * 8901 * @since 3.2 8902 */ 8903 public static String prependIfMissing(final String str, final CharSequence prefix, final CharSequence... prefixes) { 8904 return prependIfMissing(str, prefix, false, prefixes); 8905 } 8906 8907 /** 8908 * Prepends the prefix to the start of the string if the string does not 8909 * already start, case insensitive, with any of the prefixes. 8910 * 8911 * <pre> 8912 * StringUtils.prependIfMissingIgnoreCase(null, null) = null 8913 * StringUtils.prependIfMissingIgnoreCase("abc", null) = "abc" 8914 * StringUtils.prependIfMissingIgnoreCase("", "xyz") = "xyz" 8915 * StringUtils.prependIfMissingIgnoreCase("abc", "xyz") = "xyzabc" 8916 * StringUtils.prependIfMissingIgnoreCase("xyzabc", "xyz") = "xyzabc" 8917 * StringUtils.prependIfMissingIgnoreCase("XYZabc", "xyz") = "XYZabc" 8918 * </pre> 8919 * <p>With additional prefixes,</p> 8920 * <pre> 8921 * StringUtils.prependIfMissingIgnoreCase(null, null, null) = null 8922 * StringUtils.prependIfMissingIgnoreCase("abc", null, null) = "abc" 8923 * StringUtils.prependIfMissingIgnoreCase("", "xyz", null) = "xyz" 8924 * StringUtils.prependIfMissingIgnoreCase("abc", "xyz", new CharSequence[]{null}) = "xyzabc" 8925 * StringUtils.prependIfMissingIgnoreCase("abc", "xyz", "") = "abc" 8926 * StringUtils.prependIfMissingIgnoreCase("abc", "xyz", "mno") = "xyzabc" 8927 * StringUtils.prependIfMissingIgnoreCase("xyzabc", "xyz", "mno") = "xyzabc" 8928 * StringUtils.prependIfMissingIgnoreCase("mnoabc", "xyz", "mno") = "mnoabc" 8929 * StringUtils.prependIfMissingIgnoreCase("XYZabc", "xyz", "mno") = "XYZabc" 8930 * StringUtils.prependIfMissingIgnoreCase("MNOabc", "xyz", "mno") = "MNOabc" 8931 * </pre> 8932 * 8933 * @param str The string. 8934 * @param prefix The prefix to prepend to the start of the string. 8935 * @param prefixes Additional prefixes that are valid (optional). 8936 * 8937 * @return A new String if prefix was prepended, the same string otherwise. 8938 * 8939 * @since 3.2 8940 */ 8941 public static String prependIfMissingIgnoreCase(final String str, final CharSequence prefix, final CharSequence... prefixes) { 8942 return prependIfMissing(str, prefix, true, prefixes); 8943 } 8944 8945 /** 8946 * Converts a <code>byte[]</code> to a String using the specified character encoding. 8947 * 8948 * @param bytes 8949 * the byte array to read from 8950 * @param charsetName 8951 * the encoding to use, if null then use the platform default 8952 * @return a new String 8953 * @throws UnsupportedEncodingException 8954 * If the named charset is not supported 8955 * @throws NullPointerException 8956 * if the input is null 8957 * @deprecated use {@link StringUtils#toEncodedString(byte[], Charset)} instead of String constants in your code 8958 * @since 3.1 8959 */ 8960 @Deprecated 8961 public static String toString(final byte[] bytes, final String charsetName) throws UnsupportedEncodingException { 8962 return charsetName != null ? new String(bytes, charsetName) : new String(bytes, Charset.defaultCharset()); 8963 } 8964 8965 /** 8966 * Converts a <code>byte[]</code> to a String using the specified character encoding. 8967 * 8968 * @param bytes 8969 * the byte array to read from 8970 * @param charset 8971 * the encoding to use, if null then use the platform default 8972 * @return a new String 8973 * @throws NullPointerException 8974 * if {@code bytes} is null 8975 * @since 3.2 8976 * @since 3.3 No longer throws {@link UnsupportedEncodingException}. 8977 */ 8978 public static String toEncodedString(final byte[] bytes, final Charset charset) { 8979 return new String(bytes, charset != null ? charset : Charset.defaultCharset()); 8980 } 8981 8982 /** 8983 * <p> 8984 * Wraps a string with a char. 8985 * </p> 8986 * 8987 * <pre> 8988 * StringUtils.wrap(null, *) = null 8989 * StringUtils.wrap("", *) = "" 8990 * StringUtils.wrap("ab", '\0') = "ab" 8991 * StringUtils.wrap("ab", 'x') = "xabx" 8992 * StringUtils.wrap("ab", '\'') = "'ab'" 8993 * StringUtils.wrap("\"ab\"", '\"') = "\"\"ab\"\"" 8994 * </pre> 8995 * 8996 * @param str 8997 * the string to be wrapped, may be {@code null} 8998 * @param wrapWith 8999 * the char that will wrap {@code str} 9000 * @return the wrapped string, or {@code null} if {@code str==null} 9001 * @since 3.4 9002 */ 9003 public static String wrap(final String str, final char wrapWith) { 9004 9005 if (isEmpty(str) || wrapWith == CharUtils.NUL) { 9006 return str; 9007 } 9008 9009 return wrapWith + str + wrapWith; 9010 } 9011 9012 /** 9013 * <p> 9014 * Wraps a String with another String. 9015 * </p> 9016 * 9017 * <p> 9018 * A {@code null} input String returns {@code null}. 9019 * </p> 9020 * 9021 * <pre> 9022 * StringUtils.wrap(null, *) = null 9023 * StringUtils.wrap("", *) = "" 9024 * StringUtils.wrap("ab", null) = "ab" 9025 * StringUtils.wrap("ab", "x") = "xabx" 9026 * StringUtils.wrap("ab", "\"") = "\"ab\"" 9027 * StringUtils.wrap("\"ab\"", "\"") = "\"\"ab\"\"" 9028 * StringUtils.wrap("ab", "'") = "'ab'" 9029 * StringUtils.wrap("'abcd'", "'") = "''abcd''" 9030 * StringUtils.wrap("\"abcd\"", "'") = "'\"abcd\"'" 9031 * StringUtils.wrap("'abcd'", "\"") = "\"'abcd'\"" 9032 * </pre> 9033 * 9034 * @param str 9035 * the String to be wrapper, may be null 9036 * @param wrapWith 9037 * the String that will wrap str 9038 * @return wrapped String, {@code null} if null String input 9039 * @since 3.4 9040 */ 9041 public static String wrap(final String str, final String wrapWith) { 9042 9043 if (isEmpty(str) || isEmpty(wrapWith)) { 9044 return str; 9045 } 9046 9047 return wrapWith.concat(str).concat(wrapWith); 9048 } 9049 9050 /** 9051 * <p> 9052 * Wraps a string with a char if that char is missing from the start or end of the given string. 9053 * </p> 9054 * 9055 * <pre> 9056 * StringUtils.wrap(null, *) = null 9057 * StringUtils.wrap("", *) = "" 9058 * StringUtils.wrap("ab", '\0') = "ab" 9059 * StringUtils.wrap("ab", 'x') = "xabx" 9060 * StringUtils.wrap("ab", '\'') = "'ab'" 9061 * StringUtils.wrap("\"ab\"", '\"') = "\"ab\"" 9062 * StringUtils.wrap("/", '/') = "/" 9063 * StringUtils.wrap("a/b/c", '/') = "/a/b/c/" 9064 * StringUtils.wrap("/a/b/c", '/') = "/a/b/c/" 9065 * StringUtils.wrap("a/b/c/", '/') = "/a/b/c/" 9066 * </pre> 9067 * 9068 * @param str 9069 * the string to be wrapped, may be {@code null} 9070 * @param wrapWith 9071 * the char that will wrap {@code str} 9072 * @return the wrapped string, or {@code null} if {@code str==null} 9073 * @since 3.5 9074 */ 9075 public static String wrapIfMissing(final String str, final char wrapWith) { 9076 if (isEmpty(str) || wrapWith == CharUtils.NUL) { 9077 return str; 9078 } 9079 final StringBuilder builder = new StringBuilder(str.length() + 2); 9080 if (str.charAt(0) != wrapWith) { 9081 builder.append(wrapWith); 9082 } 9083 builder.append(str); 9084 if (str.charAt(str.length() - 1) != wrapWith) { 9085 builder.append(wrapWith); 9086 } 9087 return builder.toString(); 9088 } 9089 9090 /** 9091 * <p> 9092 * Wraps a string with a string if that string is missing from the start or end of the given string. 9093 * </p> 9094 * 9095 * <pre> 9096 * StringUtils.wrap(null, *) = null 9097 * StringUtils.wrap("", *) = "" 9098 * StringUtils.wrap("ab", null) = "ab" 9099 * StringUtils.wrap("ab", "x") = "xabx" 9100 * StringUtils.wrap("ab", "\"") = "\"ab\"" 9101 * StringUtils.wrap("\"ab\"", "\"") = "\"ab\"" 9102 * StringUtils.wrap("ab", "'") = "'ab'" 9103 * StringUtils.wrap("'abcd'", "'") = "'abcd'" 9104 * StringUtils.wrap("\"abcd\"", "'") = "'\"abcd\"'" 9105 * StringUtils.wrap("'abcd'", "\"") = "\"'abcd'\"" 9106 * StringUtils.wrap("/", "/") = "/" 9107 * StringUtils.wrap("a/b/c", "/") = "/a/b/c/" 9108 * StringUtils.wrap("/a/b/c", "/") = "/a/b/c/" 9109 * StringUtils.wrap("a/b/c/", "/") = "/a/b/c/" 9110 * </pre> 9111 * 9112 * @param str 9113 * the string to be wrapped, may be {@code null} 9114 * @param wrapWith 9115 * the char that will wrap {@code str} 9116 * @return the wrapped string, or {@code null} if {@code str==null} 9117 * @since 3.5 9118 */ 9119 public static String wrapIfMissing(final String str, final String wrapWith) { 9120 if (isEmpty(str) || isEmpty(wrapWith)) { 9121 return str; 9122 } 9123 final StringBuilder builder = new StringBuilder(str.length() + wrapWith.length() + wrapWith.length()); 9124 if (!str.startsWith(wrapWith)) { 9125 builder.append(wrapWith); 9126 } 9127 builder.append(str); 9128 if (!str.endsWith(wrapWith)) { 9129 builder.append(wrapWith); 9130 } 9131 return builder.toString(); 9132 } 9133 9134 /** 9135 * <p> 9136 * Unwraps a given string from anther string. 9137 * </p> 9138 * 9139 * <pre> 9140 * StringUtils.unwrap(null, null) = null 9141 * StringUtils.unwrap(null, "") = null 9142 * StringUtils.unwrap(null, "1") = null 9143 * StringUtils.unwrap("\'abc\'", "\'") = "abc" 9144 * StringUtils.unwrap("\"abc\"", "\"") = "abc" 9145 * StringUtils.unwrap("AABabcBAA", "AA") = "BabcB" 9146 * StringUtils.unwrap("A", "#") = "A" 9147 * StringUtils.unwrap("#A", "#") = "#A" 9148 * StringUtils.unwrap("A#", "#") = "A#" 9149 * </pre> 9150 * 9151 * @param str 9152 * the String to be unwrapped, can be null 9153 * @param wrapToken 9154 * the String used to unwrap 9155 * @return unwrapped String or the original string 9156 * if it is not quoted properly with the wrapToken 9157 * @since 3.6 9158 */ 9159 public static String unwrap(final String str, final String wrapToken) { 9160 if (isEmpty(str) || isEmpty(wrapToken)) { 9161 return str; 9162 } 9163 9164 if (startsWith(str, wrapToken) && endsWith(str, wrapToken)) { 9165 final int startIndex = str.indexOf(wrapToken); 9166 final int endIndex = str.lastIndexOf(wrapToken); 9167 final int wrapLength = wrapToken.length(); 9168 if (startIndex != -1 && endIndex != -1) { 9169 return str.substring(startIndex + wrapLength, endIndex); 9170 } 9171 } 9172 9173 return str; 9174 } 9175 9176 /** 9177 * <p> 9178 * Unwraps a given string from a character. 9179 * </p> 9180 * 9181 * <pre> 9182 * StringUtils.unwrap(null, null) = null 9183 * StringUtils.unwrap(null, '\0') = null 9184 * StringUtils.unwrap(null, '1') = null 9185 * StringUtils.unwrap("\'abc\'", '\'') = "abc" 9186 * StringUtils.unwrap("AABabcBAA", 'A') = "ABabcBA" 9187 * StringUtils.unwrap("A", '#') = "A" 9188 * StringUtils.unwrap("#A", '#') = "#A" 9189 * StringUtils.unwrap("A#", '#') = "A#" 9190 * </pre> 9191 * 9192 * @param str 9193 * the String to be unwrapped, can be null 9194 * @param wrapChar 9195 * the character used to unwrap 9196 * @return unwrapped String or the original string 9197 * if it is not quoted properly with the wrapChar 9198 * @since 3.6 9199 */ 9200 public static String unwrap(final String str, final char wrapChar) { 9201 if (isEmpty(str) || wrapChar == CharUtils.NUL) { 9202 return str; 9203 } 9204 9205 if (str.charAt(0) == wrapChar && str.charAt(str.length() - 1) == wrapChar) { 9206 final int startIndex = 0; 9207 final int endIndex = str.length() - 1; 9208 if (endIndex != -1) { 9209 return str.substring(startIndex + 1, endIndex); 9210 } 9211 } 9212 9213 return str; 9214 } 9215 9216 /** 9217 * <p>Converts a {@code CharSequence} into an array of code points.</p> 9218 * 9219 * <p>Valid pairs of surrogate code units will be converted into a single supplementary 9220 * code point. Isolated surrogate code units (i.e. a high surrogate not followed by a low surrogate or 9221 * a low surrogate not preceded by a high surrogate) will be returned as-is.</p> 9222 * 9223 * <pre> 9224 * StringUtils.toCodePoints(null) = null 9225 * StringUtils.toCodePoints("") = [] // empty array 9226 * </pre> 9227 * 9228 * @param str the character sequence to convert 9229 * @return an array of code points 9230 * @since 3.6 9231 */ 9232 public static int[] toCodePoints(final CharSequence str) { 9233 if (str == null) { 9234 return null; 9235 } 9236 if (str.length() == 0) { 9237 return ArrayUtils.EMPTY_INT_ARRAY; 9238 } 9239 9240 final String s = str.toString(); 9241 final int[] result = new int[s.codePointCount(0, s.length())]; 9242 int index = 0; 9243 for (int i = 0; i < result.length; i++) { 9244 result[i] = s.codePointAt(index); 9245 index += Character.charCount(result[i]); 9246 } 9247 return result; 9248 } 9249}