001/* 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017package org.apache.commons.lang3; 018 019import java.io.UnsupportedEncodingException; 020import java.nio.charset.Charset; 021import java.text.Normalizer; 022import java.util.ArrayList; 023import java.util.Arrays; 024import java.util.Iterator; 025import java.util.List; 026import java.util.Locale; 027import java.util.Objects; 028import java.util.regex.Pattern; 029 030/** 031 * <p>Operations on {@link java.lang.String} that are 032 * {@code null} safe.</p> 033 * 034 * <ul> 035 * <li><b>IsEmpty/IsBlank</b> 036 * - checks if a String contains text</li> 037 * <li><b>Trim/Strip</b> 038 * - removes leading and trailing whitespace</li> 039 * <li><b>Equals/Compare</b> 040 * - compares two strings null-safe</li> 041 * <li><b>startsWith</b> 042 * - check if a String starts with a prefix null-safe</li> 043 * <li><b>endsWith</b> 044 * - check if a String ends with a suffix null-safe</li> 045 * <li><b>IndexOf/LastIndexOf/Contains</b> 046 * - null-safe index-of checks 047 * <li><b>IndexOfAny/LastIndexOfAny/IndexOfAnyBut/LastIndexOfAnyBut</b> 048 * - index-of any of a set of Strings</li> 049 * <li><b>ContainsOnly/ContainsNone/ContainsAny</b> 050 * - does String contains only/none/any of these characters</li> 051 * <li><b>Substring/Left/Right/Mid</b> 052 * - null-safe substring extractions</li> 053 * <li><b>SubstringBefore/SubstringAfter/SubstringBetween</b> 054 * - substring extraction relative to other strings</li> 055 * <li><b>Split/Join</b> 056 * - splits a String into an array of substrings and vice versa</li> 057 * <li><b>Remove/Delete</b> 058 * - removes part of a String</li> 059 * <li><b>Replace/Overlay</b> 060 * - Searches a String and replaces one String with another</li> 061 * <li><b>Chomp/Chop</b> 062 * - removes the last part of a String</li> 063 * <li><b>AppendIfMissing</b> 064 * - appends a suffix to the end of the String if not present</li> 065 * <li><b>PrependIfMissing</b> 066 * - prepends a prefix to the start of the String if not present</li> 067 * <li><b>LeftPad/RightPad/Center/Repeat</b> 068 * - pads a String</li> 069 * <li><b>UpperCase/LowerCase/SwapCase/Capitalize/Uncapitalize</b> 070 * - changes the case of a String</li> 071 * <li><b>CountMatches</b> 072 * - counts the number of occurrences of one String in another</li> 073 * <li><b>IsAlpha/IsNumeric/IsWhitespace/IsAsciiPrintable</b> 074 * - checks the characters in a String</li> 075 * <li><b>DefaultString</b> 076 * - protects against a null input String</li> 077 * <li><b>Rotate</b> 078 * - rotate (circular shift) a String</li> 079 * <li><b>Reverse/ReverseDelimited</b> 080 * - reverses a String</li> 081 * <li><b>Abbreviate</b> 082 * - abbreviates a string using ellipsis or another given String</li> 083 * <li><b>Difference</b> 084 * - compares Strings and reports on their differences</li> 085 * <li><b>LevenshteinDistance</b> 086 * - the number of changes needed to change one String into another</li> 087 * </ul> 088 * 089 * <p>The {@code StringUtils} class defines certain words related to 090 * String handling.</p> 091 * 092 * <ul> 093 * <li>null - {@code null}</li> 094 * <li>empty - a zero-length string ({@code ""})</li> 095 * <li>space - the space character ({@code ' '}, char 32)</li> 096 * <li>whitespace - the characters defined by {@link Character#isWhitespace(char)}</li> 097 * <li>trim - the characters <= 32 as in {@link String#trim()}</li> 098 * </ul> 099 * 100 * <p>{@code StringUtils} handles {@code null} input Strings quietly. 101 * That is to say that a {@code null} input will return {@code null}. 102 * Where a {@code boolean} or {@code int} is being returned 103 * details vary by method.</p> 104 * 105 * <p>A side effect of the {@code null} handling is that a 106 * {@code NullPointerException} should be considered a bug in 107 * {@code StringUtils}.</p> 108 * 109 * <p>Methods in this class give sample code to explain their operation. 110 * The symbol {@code *} is used to indicate any input including {@code null}.</p> 111 * 112 * <p>#ThreadSafe#</p> 113 * @see java.lang.String 114 * @since 1.0 115 */ 116//@Immutable 117public class StringUtils { 118 119 private static final int STRING_BUILDER_SIZE = 256; 120 121 // Performance testing notes (JDK 1.4, Jul03, scolebourne) 122 // Whitespace: 123 // Character.isWhitespace() is faster than WHITESPACE.indexOf() 124 // where WHITESPACE is a string of all whitespace characters 125 // 126 // Character access: 127 // String.charAt(n) versus toCharArray(), then array[n] 128 // String.charAt(n) is about 15% worse for a 10K string 129 // They are about equal for a length 50 string 130 // String.charAt(n) is about 4 times better for a length 3 string 131 // String.charAt(n) is best bet overall 132 // 133 // Append: 134 // String.concat about twice as fast as StringBuffer.append 135 // (not sure who tested this) 136 137 /** 138 * A String for a space character. 139 * 140 * @since 3.2 141 */ 142 public static final String SPACE = " "; 143 144 /** 145 * The empty String {@code ""}. 146 * @since 2.0 147 */ 148 public static final String EMPTY = ""; 149 150 /** 151 * A String for linefeed LF ("\n"). 152 * 153 * @see <a href="http://docs.oracle.com/javase/specs/jls/se7/html/jls-3.html#jls-3.10.6">JLF: Escape Sequences 154 * for Character and String Literals</a> 155 * @since 3.2 156 */ 157 public static final String LF = "\n"; 158 159 /** 160 * A String for carriage return CR ("\r"). 161 * 162 * @see <a href="http://docs.oracle.com/javase/specs/jls/se7/html/jls-3.html#jls-3.10.6">JLF: Escape Sequences 163 * for Character and String Literals</a> 164 * @since 3.2 165 */ 166 public static final String CR = "\r"; 167 168 /** 169 * Represents a failed index search. 170 * @since 2.1 171 */ 172 public static final int INDEX_NOT_FOUND = -1; 173 174 /** 175 * <p>The maximum size to which the padding constant(s) can expand.</p> 176 */ 177 private static final int PAD_LIMIT = 8192; 178 179 /** 180 * <p>{@code StringUtils} instances should NOT be constructed in 181 * standard programming. Instead, the class should be used as 182 * {@code StringUtils.trim(" foo ");}.</p> 183 * 184 * <p>This constructor is public to permit tools that require a JavaBean 185 * instance to operate.</p> 186 */ 187 public StringUtils() { 188 super(); 189 } 190 191 // Empty checks 192 //----------------------------------------------------------------------- 193 /** 194 * <p>Checks if a CharSequence is empty ("") or null.</p> 195 * 196 * <pre> 197 * StringUtils.isEmpty(null) = true 198 * StringUtils.isEmpty("") = true 199 * StringUtils.isEmpty(" ") = false 200 * StringUtils.isEmpty("bob") = false 201 * StringUtils.isEmpty(" bob ") = false 202 * </pre> 203 * 204 * <p>NOTE: This method changed in Lang version 2.0. 205 * It no longer trims the CharSequence. 206 * That functionality is available in isBlank().</p> 207 * 208 * @param cs the CharSequence to check, may be null 209 * @return {@code true} if the CharSequence is empty or null 210 * @since 3.0 Changed signature from isEmpty(String) to isEmpty(CharSequence) 211 */ 212 public static boolean isEmpty(final CharSequence cs) { 213 return cs == null || cs.length() == 0; 214 } 215 216 /** 217 * <p>Checks if a CharSequence is not empty ("") and not null.</p> 218 * 219 * <pre> 220 * StringUtils.isNotEmpty(null) = false 221 * StringUtils.isNotEmpty("") = false 222 * StringUtils.isNotEmpty(" ") = true 223 * StringUtils.isNotEmpty("bob") = true 224 * StringUtils.isNotEmpty(" bob ") = true 225 * </pre> 226 * 227 * @param cs the CharSequence to check, may be null 228 * @return {@code true} if the CharSequence is not empty and not null 229 * @since 3.0 Changed signature from isNotEmpty(String) to isNotEmpty(CharSequence) 230 */ 231 public static boolean isNotEmpty(final CharSequence cs) { 232 return !isEmpty(cs); 233 } 234 235 /** 236 * <p>Checks if any of the CharSequences are empty ("") or null.</p> 237 * 238 * <pre> 239 * StringUtils.isAnyEmpty((String) null) = true 240 * StringUtils.isAnyEmpty((String[]) null) = false 241 * StringUtils.isAnyEmpty(null, "foo") = true 242 * StringUtils.isAnyEmpty("", "bar") = true 243 * StringUtils.isAnyEmpty("bob", "") = true 244 * StringUtils.isAnyEmpty(" bob ", null) = true 245 * StringUtils.isAnyEmpty(" ", "bar") = false 246 * StringUtils.isAnyEmpty("foo", "bar") = false 247 * StringUtils.isAnyEmpty(new String[]{}) = false 248 * StringUtils.isAnyEmpty(new String[]{""}) = true 249 * </pre> 250 * 251 * @param css the CharSequences to check, may be null or empty 252 * @return {@code true} if any of the CharSequences are empty or null 253 * @since 3.2 254 */ 255 public static boolean isAnyEmpty(final CharSequence... css) { 256 if (ArrayUtils.isEmpty(css)) { 257 return false; 258 } 259 for (final CharSequence cs : css) { 260 if (isEmpty(cs)) { 261 return true; 262 } 263 } 264 return false; 265 } 266 267 /** 268 * <p>Checks if none of the CharSequences are empty ("") or null.</p> 269 * 270 * <pre> 271 * StringUtils.isNoneEmpty((String) null) = false 272 * StringUtils.isNoneEmpty((String[]) null) = true 273 * StringUtils.isNoneEmpty(null, "foo") = false 274 * StringUtils.isNoneEmpty("", "bar") = false 275 * StringUtils.isNoneEmpty("bob", "") = false 276 * StringUtils.isNoneEmpty(" bob ", null) = false 277 * StringUtils.isNoneEmpty(new String[] {}) = true 278 * StringUtils.isNoneEmpty(new String[]{""}) = false 279 * StringUtils.isNoneEmpty(" ", "bar") = true 280 * StringUtils.isNoneEmpty("foo", "bar") = true 281 * </pre> 282 * 283 * @param css the CharSequences to check, may be null or empty 284 * @return {@code true} if none of the CharSequences are empty or null 285 * @since 3.2 286 */ 287 public static boolean isNoneEmpty(final CharSequence... css) { 288 return !isAnyEmpty(css); 289 } 290 291 /** 292 * <p>Checks if all of the CharSequences are empty ("") or null.</p> 293 * 294 * <pre> 295 * StringUtils.isAllEmpty(null) = true 296 * StringUtils.isAllEmpty(null, "") = true 297 * StringUtils.isAllEmpty(new String[] {}) = true 298 * StringUtils.isAllEmpty(null, "foo") = false 299 * StringUtils.isAllEmpty("", "bar") = false 300 * StringUtils.isAllEmpty("bob", "") = false 301 * StringUtils.isAllEmpty(" bob ", null) = false 302 * StringUtils.isAllEmpty(" ", "bar") = false 303 * StringUtils.isAllEmpty("foo", "bar") = false 304 * </pre> 305 * 306 * @param css the CharSequences to check, may be null or empty 307 * @return {@code true} if all of the CharSequences are empty or null 308 * @since 3.6 309 */ 310 public static boolean isAllEmpty(final CharSequence... css) { 311 if (ArrayUtils.isEmpty(css)) { 312 return true; 313 } 314 for (final CharSequence cs : css) { 315 if (isNotEmpty(cs)) { 316 return false; 317 } 318 } 319 return true; 320 } 321 322 /** 323 * <p>Checks if a CharSequence is empty (""), null or whitespace only.</p> 324 * 325 * <p>Whitespace is defined by {@link Character#isWhitespace(char)}.</p> 326 * 327 * <pre> 328 * StringUtils.isBlank(null) = true 329 * StringUtils.isBlank("") = true 330 * StringUtils.isBlank(" ") = true 331 * StringUtils.isBlank("bob") = false 332 * StringUtils.isBlank(" bob ") = false 333 * </pre> 334 * 335 * @param cs the CharSequence to check, may be null 336 * @return {@code true} if the CharSequence is null, empty or whitespace only 337 * @since 2.0 338 * @since 3.0 Changed signature from isBlank(String) to isBlank(CharSequence) 339 */ 340 public static boolean isBlank(final CharSequence cs) { 341 int strLen; 342 if (cs == null || (strLen = cs.length()) == 0) { 343 return true; 344 } 345 for (int i = 0; i < strLen; i++) { 346 if (!Character.isWhitespace(cs.charAt(i))) { 347 return false; 348 } 349 } 350 return true; 351 } 352 353 /** 354 * <p>Checks if a CharSequence is not empty (""), not null and not whitespace only.</p> 355 * 356 * <p>Whitespace is defined by {@link Character#isWhitespace(char)}.</p> 357 * 358 * <pre> 359 * StringUtils.isNotBlank(null) = false 360 * StringUtils.isNotBlank("") = false 361 * StringUtils.isNotBlank(" ") = false 362 * StringUtils.isNotBlank("bob") = true 363 * StringUtils.isNotBlank(" bob ") = true 364 * </pre> 365 * 366 * @param cs the CharSequence to check, may be null 367 * @return {@code true} if the CharSequence is 368 * not empty and not null and not whitespace only 369 * @since 2.0 370 * @since 3.0 Changed signature from isNotBlank(String) to isNotBlank(CharSequence) 371 */ 372 public static boolean isNotBlank(final CharSequence cs) { 373 return !isBlank(cs); 374 } 375 376 /** 377 * <p>Checks if any of the CharSequences are empty ("") or null or whitespace only.</p> 378 * 379 * <p>Whitespace is defined by {@link Character#isWhitespace(char)}.</p> 380 * 381 * <pre> 382 * StringUtils.isAnyBlank((String) null) = true 383 * StringUtils.isAnyBlank((String[]) null) = false 384 * StringUtils.isAnyBlank(null, "foo") = true 385 * StringUtils.isAnyBlank(null, null) = true 386 * StringUtils.isAnyBlank("", "bar") = true 387 * StringUtils.isAnyBlank("bob", "") = true 388 * StringUtils.isAnyBlank(" bob ", null) = true 389 * StringUtils.isAnyBlank(" ", "bar") = true 390 * StringUtils.isAnyBlank(new String[] {}) = false 391 * StringUtils.isAnyBlank(new String[]{""}) = true 392 * StringUtils.isAnyBlank("foo", "bar") = false 393 * </pre> 394 * 395 * @param css the CharSequences to check, may be null or empty 396 * @return {@code true} if any of the CharSequences are empty or null or whitespace only 397 * @since 3.2 398 */ 399 public static boolean isAnyBlank(final CharSequence... css) { 400 if (ArrayUtils.isEmpty(css)) { 401 return false; 402 } 403 for (final CharSequence cs : css) { 404 if (isBlank(cs)) { 405 return true; 406 } 407 } 408 return false; 409 } 410 411 /** 412 * <p>Checks if none of the CharSequences are empty (""), null or whitespace only.</p> 413 * 414 * <p>Whitespace is defined by {@link Character#isWhitespace(char)}.</p> 415 * 416 * <pre> 417 * StringUtils.isNoneBlank((String) null) = false 418 * StringUtils.isNoneBlank((String[]) null) = true 419 * StringUtils.isNoneBlank(null, "foo") = false 420 * StringUtils.isNoneBlank(null, null) = false 421 * StringUtils.isNoneBlank("", "bar") = false 422 * StringUtils.isNoneBlank("bob", "") = false 423 * StringUtils.isNoneBlank(" bob ", null) = false 424 * StringUtils.isNoneBlank(" ", "bar") = false 425 * StringUtils.isNoneBlank(new String[] {}) = true 426 * StringUtils.isNoneBlank(new String[]{""}) = false 427 * StringUtils.isNoneBlank("foo", "bar") = true 428 * </pre> 429 * 430 * @param css the CharSequences to check, may be null or empty 431 * @return {@code true} if none of the CharSequences are empty or null or whitespace only 432 * @since 3.2 433 */ 434 public static boolean isNoneBlank(final CharSequence... css) { 435 return !isAnyBlank(css); 436 } 437 438 /** 439 * <p>Checks if all of the CharSequences are empty (""), null or whitespace only.</p> 440 * 441 * <p>Whitespace is defined by {@link Character#isWhitespace(char)}.</p> 442 * 443 * <pre> 444 * StringUtils.isAllBlank(null) = true 445 * StringUtils.isAllBlank(null, "foo") = false 446 * StringUtils.isAllBlank(null, null) = true 447 * StringUtils.isAllBlank("", "bar") = false 448 * StringUtils.isAllBlank("bob", "") = false 449 * StringUtils.isAllBlank(" bob ", null) = false 450 * StringUtils.isAllBlank(" ", "bar") = false 451 * StringUtils.isAllBlank("foo", "bar") = false 452 * StringUtils.isAllBlank(new String[] {}) = true 453 * </pre> 454 * 455 * @param css the CharSequences to check, may be null or empty 456 * @return {@code true} if all of the CharSequences are empty or null or whitespace only 457 * @since 3.6 458 */ 459 public static boolean isAllBlank(final CharSequence... css) { 460 if (ArrayUtils.isEmpty(css)) { 461 return true; 462 } 463 for (final CharSequence cs : css) { 464 if (isNotBlank(cs)) { 465 return false; 466 } 467 } 468 return true; 469 } 470 471 // Trim 472 //----------------------------------------------------------------------- 473 /** 474 * <p>Removes control characters (char <= 32) from both 475 * ends of this String, handling {@code null} by returning 476 * {@code null}.</p> 477 * 478 * <p>The String is trimmed using {@link String#trim()}. 479 * Trim removes start and end characters <= 32. 480 * To strip whitespace use {@link #strip(String)}.</p> 481 * 482 * <p>To trim your choice of characters, use the 483 * {@link #strip(String, String)} methods.</p> 484 * 485 * <pre> 486 * StringUtils.trim(null) = null 487 * StringUtils.trim("") = "" 488 * StringUtils.trim(" ") = "" 489 * StringUtils.trim("abc") = "abc" 490 * StringUtils.trim(" abc ") = "abc" 491 * </pre> 492 * 493 * @param str the String to be trimmed, may be null 494 * @return the trimmed string, {@code null} if null String input 495 */ 496 public static String trim(final String str) { 497 return str == null ? null : str.trim(); 498 } 499 500 /** 501 * <p>Removes control characters (char <= 32) from both 502 * ends of this String returning {@code null} if the String is 503 * empty ("") after the trim or if it is {@code null}. 504 * 505 * <p>The String is trimmed using {@link String#trim()}. 506 * Trim removes start and end characters <= 32. 507 * To strip whitespace use {@link #stripToNull(String)}.</p> 508 * 509 * <pre> 510 * StringUtils.trimToNull(null) = null 511 * StringUtils.trimToNull("") = null 512 * StringUtils.trimToNull(" ") = null 513 * StringUtils.trimToNull("abc") = "abc" 514 * StringUtils.trimToNull(" abc ") = "abc" 515 * </pre> 516 * 517 * @param str the String to be trimmed, may be null 518 * @return the trimmed String, 519 * {@code null} if only chars <= 32, empty or null String input 520 * @since 2.0 521 */ 522 public static String trimToNull(final String str) { 523 final String ts = trim(str); 524 return isEmpty(ts) ? null : ts; 525 } 526 527 /** 528 * <p>Removes control characters (char <= 32) from both 529 * ends of this String returning an empty String ("") if the String 530 * is empty ("") after the trim or if it is {@code null}. 531 * 532 * <p>The String is trimmed using {@link String#trim()}. 533 * Trim removes start and end characters <= 32. 534 * To strip whitespace use {@link #stripToEmpty(String)}.</p> 535 * 536 * <pre> 537 * StringUtils.trimToEmpty(null) = "" 538 * StringUtils.trimToEmpty("") = "" 539 * StringUtils.trimToEmpty(" ") = "" 540 * StringUtils.trimToEmpty("abc") = "abc" 541 * StringUtils.trimToEmpty(" abc ") = "abc" 542 * </pre> 543 * 544 * @param str the String to be trimmed, may be null 545 * @return the trimmed String, or an empty String if {@code null} input 546 * @since 2.0 547 */ 548 public static String trimToEmpty(final String str) { 549 return str == null ? EMPTY : str.trim(); 550 } 551 552 /** 553 * <p>Truncates a String. This will turn 554 * "Now is the time for all good men" into "Now is the time for".</p> 555 * 556 * <p>Specifically:</p> 557 * <ul> 558 * <li>If {@code str} is less than {@code maxWidth} characters 559 * long, return it.</li> 560 * <li>Else truncate it to {@code substring(str, 0, maxWidth)}.</li> 561 * <li>If {@code maxWidth} is less than {@code 0}, throw an 562 * {@code IllegalArgumentException}.</li> 563 * <li>In no case will it return a String of length greater than 564 * {@code maxWidth}.</li> 565 * </ul> 566 * 567 * <pre> 568 * StringUtils.truncate(null, 0) = null 569 * StringUtils.truncate(null, 2) = null 570 * StringUtils.truncate("", 4) = "" 571 * StringUtils.truncate("abcdefg", 4) = "abcd" 572 * StringUtils.truncate("abcdefg", 6) = "abcdef" 573 * StringUtils.truncate("abcdefg", 7) = "abcdefg" 574 * StringUtils.truncate("abcdefg", 8) = "abcdefg" 575 * StringUtils.truncate("abcdefg", -1) = throws an IllegalArgumentException 576 * </pre> 577 * 578 * @param str the String to truncate, may be null 579 * @param maxWidth maximum length of result String, must be positive 580 * @return truncated String, {@code null} if null String input 581 * @since 3.5 582 */ 583 public static String truncate(final String str, final int maxWidth) { 584 return truncate(str, 0, maxWidth); 585 } 586 587 /** 588 * <p>Truncates a String. This will turn 589 * "Now is the time for all good men" into "is the time for all".</p> 590 * 591 * <p>Works like {@code truncate(String, int)}, but allows you to specify 592 * a "left edge" offset. 593 * 594 * <p>Specifically:</p> 595 * <ul> 596 * <li>If {@code str} is less than {@code maxWidth} characters 597 * long, return it.</li> 598 * <li>Else truncate it to {@code substring(str, offset, maxWidth)}.</li> 599 * <li>If {@code maxWidth} is less than {@code 0}, throw an 600 * {@code IllegalArgumentException}.</li> 601 * <li>If {@code offset} is less than {@code 0}, throw an 602 * {@code IllegalArgumentException}.</li> 603 * <li>In no case will it return a String of length greater than 604 * {@code maxWidth}.</li> 605 * </ul> 606 * 607 * <pre> 608 * StringUtils.truncate(null, 0, 0) = null 609 * StringUtils.truncate(null, 2, 4) = null 610 * StringUtils.truncate("", 0, 10) = "" 611 * StringUtils.truncate("", 2, 10) = "" 612 * StringUtils.truncate("abcdefghij", 0, 3) = "abc" 613 * StringUtils.truncate("abcdefghij", 5, 6) = "fghij" 614 * StringUtils.truncate("raspberry peach", 10, 15) = "peach" 615 * StringUtils.truncate("abcdefghijklmno", 0, 10) = "abcdefghij" 616 * StringUtils.truncate("abcdefghijklmno", -1, 10) = throws an IllegalArgumentException 617 * StringUtils.truncate("abcdefghijklmno", Integer.MIN_VALUE, 10) = "abcdefghij" 618 * StringUtils.truncate("abcdefghijklmno", Integer.MIN_VALUE, Integer.MAX_VALUE) = "abcdefghijklmno" 619 * StringUtils.truncate("abcdefghijklmno", 0, Integer.MAX_VALUE) = "abcdefghijklmno" 620 * StringUtils.truncate("abcdefghijklmno", 1, 10) = "bcdefghijk" 621 * StringUtils.truncate("abcdefghijklmno", 2, 10) = "cdefghijkl" 622 * StringUtils.truncate("abcdefghijklmno", 3, 10) = "defghijklm" 623 * StringUtils.truncate("abcdefghijklmno", 4, 10) = "efghijklmn" 624 * StringUtils.truncate("abcdefghijklmno", 5, 10) = "fghijklmno" 625 * StringUtils.truncate("abcdefghijklmno", 5, 5) = "fghij" 626 * StringUtils.truncate("abcdefghijklmno", 5, 3) = "fgh" 627 * StringUtils.truncate("abcdefghijklmno", 10, 3) = "klm" 628 * StringUtils.truncate("abcdefghijklmno", 10, Integer.MAX_VALUE) = "klmno" 629 * StringUtils.truncate("abcdefghijklmno", 13, 1) = "n" 630 * StringUtils.truncate("abcdefghijklmno", 13, Integer.MAX_VALUE) = "no" 631 * StringUtils.truncate("abcdefghijklmno", 14, 1) = "o" 632 * StringUtils.truncate("abcdefghijklmno", 14, Integer.MAX_VALUE) = "o" 633 * StringUtils.truncate("abcdefghijklmno", 15, 1) = "" 634 * StringUtils.truncate("abcdefghijklmno", 15, Integer.MAX_VALUE) = "" 635 * StringUtils.truncate("abcdefghijklmno", Integer.MAX_VALUE, Integer.MAX_VALUE) = "" 636 * StringUtils.truncate("abcdefghij", 3, -1) = throws an IllegalArgumentException 637 * StringUtils.truncate("abcdefghij", -2, 4) = throws an IllegalArgumentException 638 * </pre> 639 * 640 * @param str the String to check, may be null 641 * @param offset left edge of source String 642 * @param maxWidth maximum length of result String, must be positive 643 * @return truncated String, {@code null} if null String input 644 * @since 3.5 645 */ 646 public static String truncate(final String str, final int offset, final int maxWidth) { 647 if (offset < 0) { 648 throw new IllegalArgumentException("offset cannot be negative"); 649 } 650 if (maxWidth < 0) { 651 throw new IllegalArgumentException("maxWith cannot be negative"); 652 } 653 if (str == null) { 654 return null; 655 } 656 if (offset > str.length()) { 657 return EMPTY; 658 } 659 if (str.length() > maxWidth) { 660 final int ix = offset + maxWidth > str.length() ? str.length() : offset + maxWidth; 661 return str.substring(offset, ix); 662 } 663 return str.substring(offset); 664 } 665 666 // Stripping 667 //----------------------------------------------------------------------- 668 /** 669 * <p>Strips whitespace from the start and end of a String.</p> 670 * 671 * <p>This is similar to {@link #trim(String)} but removes whitespace. 672 * Whitespace is defined by {@link Character#isWhitespace(char)}.</p> 673 * 674 * <p>A {@code null} input String returns {@code null}.</p> 675 * 676 * <pre> 677 * StringUtils.strip(null) = null 678 * StringUtils.strip("") = "" 679 * StringUtils.strip(" ") = "" 680 * StringUtils.strip("abc") = "abc" 681 * StringUtils.strip(" abc") = "abc" 682 * StringUtils.strip("abc ") = "abc" 683 * StringUtils.strip(" abc ") = "abc" 684 * StringUtils.strip(" ab c ") = "ab c" 685 * </pre> 686 * 687 * @param str the String to remove whitespace from, may be null 688 * @return the stripped String, {@code null} if null String input 689 */ 690 public static String strip(final String str) { 691 return strip(str, null); 692 } 693 694 /** 695 * <p>Strips whitespace from the start and end of a String returning 696 * {@code null} if the String is empty ("") after the strip.</p> 697 * 698 * <p>This is similar to {@link #trimToNull(String)} but removes whitespace. 699 * Whitespace is defined by {@link Character#isWhitespace(char)}.</p> 700 * 701 * <pre> 702 * StringUtils.stripToNull(null) = null 703 * StringUtils.stripToNull("") = null 704 * StringUtils.stripToNull(" ") = null 705 * StringUtils.stripToNull("abc") = "abc" 706 * StringUtils.stripToNull(" abc") = "abc" 707 * StringUtils.stripToNull("abc ") = "abc" 708 * StringUtils.stripToNull(" abc ") = "abc" 709 * StringUtils.stripToNull(" ab c ") = "ab c" 710 * </pre> 711 * 712 * @param str the String to be stripped, may be null 713 * @return the stripped String, 714 * {@code null} if whitespace, empty or null String input 715 * @since 2.0 716 */ 717 public static String stripToNull(String str) { 718 if (str == null) { 719 return null; 720 } 721 str = strip(str, null); 722 return str.isEmpty() ? null : str; 723 } 724 725 /** 726 * <p>Strips whitespace from the start and end of a String returning 727 * an empty String if {@code null} input.</p> 728 * 729 * <p>This is similar to {@link #trimToEmpty(String)} but removes whitespace. 730 * Whitespace is defined by {@link Character#isWhitespace(char)}.</p> 731 * 732 * <pre> 733 * StringUtils.stripToEmpty(null) = "" 734 * StringUtils.stripToEmpty("") = "" 735 * StringUtils.stripToEmpty(" ") = "" 736 * StringUtils.stripToEmpty("abc") = "abc" 737 * StringUtils.stripToEmpty(" abc") = "abc" 738 * StringUtils.stripToEmpty("abc ") = "abc" 739 * StringUtils.stripToEmpty(" abc ") = "abc" 740 * StringUtils.stripToEmpty(" ab c ") = "ab c" 741 * </pre> 742 * 743 * @param str the String to be stripped, may be null 744 * @return the trimmed String, or an empty String if {@code null} input 745 * @since 2.0 746 */ 747 public static String stripToEmpty(final String str) { 748 return str == null ? EMPTY : strip(str, null); 749 } 750 751 /** 752 * <p>Strips any of a set of characters from the start and end of a String. 753 * This is similar to {@link String#trim()} but allows the characters 754 * to be stripped to be controlled.</p> 755 * 756 * <p>A {@code null} input String returns {@code null}. 757 * An empty string ("") input returns the empty string.</p> 758 * 759 * <p>If the stripChars String is {@code null}, whitespace is 760 * stripped as defined by {@link Character#isWhitespace(char)}. 761 * Alternatively use {@link #strip(String)}.</p> 762 * 763 * <pre> 764 * StringUtils.strip(null, *) = null 765 * StringUtils.strip("", *) = "" 766 * StringUtils.strip("abc", null) = "abc" 767 * StringUtils.strip(" abc", null) = "abc" 768 * StringUtils.strip("abc ", null) = "abc" 769 * StringUtils.strip(" abc ", null) = "abc" 770 * StringUtils.strip(" abcyx", "xyz") = " abc" 771 * </pre> 772 * 773 * @param str the String to remove characters from, may be null 774 * @param stripChars the characters to remove, null treated as whitespace 775 * @return the stripped String, {@code null} if null String input 776 */ 777 public static String strip(String str, final String stripChars) { 778 if (isEmpty(str)) { 779 return str; 780 } 781 str = stripStart(str, stripChars); 782 return stripEnd(str, stripChars); 783 } 784 785 /** 786 * <p>Strips any of a set of characters from the start of a String.</p> 787 * 788 * <p>A {@code null} input String returns {@code null}. 789 * An empty string ("") input returns the empty string.</p> 790 * 791 * <p>If the stripChars String is {@code null}, whitespace is 792 * stripped as defined by {@link Character#isWhitespace(char)}.</p> 793 * 794 * <pre> 795 * StringUtils.stripStart(null, *) = null 796 * StringUtils.stripStart("", *) = "" 797 * StringUtils.stripStart("abc", "") = "abc" 798 * StringUtils.stripStart("abc", null) = "abc" 799 * StringUtils.stripStart(" abc", null) = "abc" 800 * StringUtils.stripStart("abc ", null) = "abc " 801 * StringUtils.stripStart(" abc ", null) = "abc " 802 * StringUtils.stripStart("yxabc ", "xyz") = "abc " 803 * </pre> 804 * 805 * @param str the String to remove characters from, may be null 806 * @param stripChars the characters to remove, null treated as whitespace 807 * @return the stripped String, {@code null} if null String input 808 */ 809 public static String stripStart(final String str, final String stripChars) { 810 int strLen; 811 if (str == null || (strLen = str.length()) == 0) { 812 return str; 813 } 814 int start = 0; 815 if (stripChars == null) { 816 while (start != strLen && Character.isWhitespace(str.charAt(start))) { 817 start++; 818 } 819 } else if (stripChars.isEmpty()) { 820 return str; 821 } else { 822 while (start != strLen && stripChars.indexOf(str.charAt(start)) != INDEX_NOT_FOUND) { 823 start++; 824 } 825 } 826 return str.substring(start); 827 } 828 829 /** 830 * <p>Strips any of a set of characters from the end of a String.</p> 831 * 832 * <p>A {@code null} input String returns {@code null}. 833 * An empty string ("") input returns the empty string.</p> 834 * 835 * <p>If the stripChars String is {@code null}, whitespace is 836 * stripped as defined by {@link Character#isWhitespace(char)}.</p> 837 * 838 * <pre> 839 * StringUtils.stripEnd(null, *) = null 840 * StringUtils.stripEnd("", *) = "" 841 * StringUtils.stripEnd("abc", "") = "abc" 842 * StringUtils.stripEnd("abc", null) = "abc" 843 * StringUtils.stripEnd(" abc", null) = " abc" 844 * StringUtils.stripEnd("abc ", null) = "abc" 845 * StringUtils.stripEnd(" abc ", null) = " abc" 846 * StringUtils.stripEnd(" abcyx", "xyz") = " abc" 847 * StringUtils.stripEnd("120.00", ".0") = "12" 848 * </pre> 849 * 850 * @param str the String to remove characters from, may be null 851 * @param stripChars the set of characters to remove, null treated as whitespace 852 * @return the stripped String, {@code null} if null String input 853 */ 854 public static String stripEnd(final String str, final String stripChars) { 855 int end; 856 if (str == null || (end = str.length()) == 0) { 857 return str; 858 } 859 860 if (stripChars == null) { 861 while (end != 0 && Character.isWhitespace(str.charAt(end - 1))) { 862 end--; 863 } 864 } else if (stripChars.isEmpty()) { 865 return str; 866 } else { 867 while (end != 0 && stripChars.indexOf(str.charAt(end - 1)) != INDEX_NOT_FOUND) { 868 end--; 869 } 870 } 871 return str.substring(0, end); 872 } 873 874 // StripAll 875 //----------------------------------------------------------------------- 876 /** 877 * <p>Strips whitespace from the start and end of every String in an array. 878 * Whitespace is defined by {@link Character#isWhitespace(char)}.</p> 879 * 880 * <p>A new array is returned each time, except for length zero. 881 * A {@code null} array will return {@code null}. 882 * An empty array will return itself. 883 * A {@code null} array entry will be ignored.</p> 884 * 885 * <pre> 886 * StringUtils.stripAll(null) = null 887 * StringUtils.stripAll([]) = [] 888 * StringUtils.stripAll(["abc", " abc"]) = ["abc", "abc"] 889 * StringUtils.stripAll(["abc ", null]) = ["abc", null] 890 * </pre> 891 * 892 * @param strs the array to remove whitespace from, may be null 893 * @return the stripped Strings, {@code null} if null array input 894 */ 895 public static String[] stripAll(final String... strs) { 896 return stripAll(strs, null); 897 } 898 899 /** 900 * <p>Strips any of a set of characters from the start and end of every 901 * String in an array.</p> 902 * <p>Whitespace is defined by {@link Character#isWhitespace(char)}.</p> 903 * 904 * <p>A new array is returned each time, except for length zero. 905 * A {@code null} array will return {@code null}. 906 * An empty array will return itself. 907 * A {@code null} array entry will be ignored. 908 * A {@code null} stripChars will strip whitespace as defined by 909 * {@link Character#isWhitespace(char)}.</p> 910 * 911 * <pre> 912 * StringUtils.stripAll(null, *) = null 913 * StringUtils.stripAll([], *) = [] 914 * StringUtils.stripAll(["abc", " abc"], null) = ["abc", "abc"] 915 * StringUtils.stripAll(["abc ", null], null) = ["abc", null] 916 * StringUtils.stripAll(["abc ", null], "yz") = ["abc ", null] 917 * StringUtils.stripAll(["yabcz", null], "yz") = ["abc", null] 918 * </pre> 919 * 920 * @param strs the array to remove characters from, may be null 921 * @param stripChars the characters to remove, null treated as whitespace 922 * @return the stripped Strings, {@code null} if null array input 923 */ 924 public static String[] stripAll(final String[] strs, final String stripChars) { 925 int strsLen; 926 if (strs == null || (strsLen = strs.length) == 0) { 927 return strs; 928 } 929 final String[] newArr = new String[strsLen]; 930 for (int i = 0; i < strsLen; i++) { 931 newArr[i] = strip(strs[i], stripChars); 932 } 933 return newArr; 934 } 935 936 /** 937 * <p>Removes diacritics (~= accents) from a string. The case will not be altered.</p> 938 * <p>For instance, 'à' will be replaced by 'a'.</p> 939 * <p>Note that ligatures will be left as is.</p> 940 * 941 * <pre> 942 * StringUtils.stripAccents(null) = null 943 * StringUtils.stripAccents("") = "" 944 * StringUtils.stripAccents("control") = "control" 945 * StringUtils.stripAccents("éclair") = "eclair" 946 * </pre> 947 * 948 * @param input String to be stripped 949 * @return input text with diacritics removed 950 * 951 * @since 3.0 952 */ 953 // See also Lucene's ASCIIFoldingFilter (Lucene 2.9) that replaces accented characters by their unaccented equivalent (and uncommitted bug fix: https://issues.apache.org/jira/browse/LUCENE-1343?focusedCommentId=12858907&page=com.atlassian.jira.plugin.system.issuetabpanels%3Acomment-tabpanel#action_12858907). 954 public static String stripAccents(final String input) { 955 if (input == null) { 956 return null; 957 } 958 final Pattern pattern = Pattern.compile("\\p{InCombiningDiacriticalMarks}+"); //$NON-NLS-1$ 959 final StringBuilder decomposed = new StringBuilder(Normalizer.normalize(input, Normalizer.Form.NFD)); 960 convertRemainingAccentCharacters(decomposed); 961 // Note that this doesn't correctly remove ligatures... 962 return pattern.matcher(decomposed).replaceAll(EMPTY); 963 } 964 965 private static void convertRemainingAccentCharacters(final StringBuilder decomposed) { 966 for (int i = 0; i < decomposed.length(); i++) { 967 if (decomposed.charAt(i) == '\u0141') { 968 decomposed.deleteCharAt(i); 969 decomposed.insert(i, 'L'); 970 } else if (decomposed.charAt(i) == '\u0142') { 971 decomposed.deleteCharAt(i); 972 decomposed.insert(i, 'l'); 973 } 974 } 975 } 976 977 // Equals 978 //----------------------------------------------------------------------- 979 /** 980 * <p>Compares two CharSequences, returning {@code true} if they represent 981 * equal sequences of characters.</p> 982 * 983 * <p>{@code null}s are handled without exceptions. Two {@code null} 984 * references are considered to be equal. The comparison is <strong>case sensitive</strong>.</p> 985 * 986 * <pre> 987 * StringUtils.equals(null, null) = true 988 * StringUtils.equals(null, "abc") = false 989 * StringUtils.equals("abc", null) = false 990 * StringUtils.equals("abc", "abc") = true 991 * StringUtils.equals("abc", "ABC") = false 992 * </pre> 993 * 994 * @param cs1 the first CharSequence, may be {@code null} 995 * @param cs2 the second CharSequence, may be {@code null} 996 * @return {@code true} if the CharSequences are equal (case-sensitive), or both {@code null} 997 * @since 3.0 Changed signature from equals(String, String) to equals(CharSequence, CharSequence) 998 * @see Object#equals(Object) 999 * @see #equalsIgnoreCase(CharSequence, CharSequence) 1000 */ 1001 public static boolean equals(final CharSequence cs1, final CharSequence cs2) { 1002 if (cs1 == cs2) { 1003 return true; 1004 } 1005 if (cs1 == null || cs2 == null) { 1006 return false; 1007 } 1008 if (cs1.length() != cs2.length()) { 1009 return false; 1010 } 1011 if (cs1 instanceof String && cs2 instanceof String) { 1012 return cs1.equals(cs2); 1013 } 1014 // Step-wise comparison 1015 final int length = cs1.length(); 1016 for (int i = 0; i < length; i++) { 1017 if (cs1.charAt(i) != cs2.charAt(i)) { 1018 return false; 1019 } 1020 } 1021 return true; 1022 } 1023 1024 /** 1025 * <p>Compares two CharSequences, returning {@code true} if they represent 1026 * equal sequences of characters, ignoring case.</p> 1027 * 1028 * <p>{@code null}s are handled without exceptions. Two {@code null} 1029 * references are considered equal. The comparison is <strong>case insensitive</strong>.</p> 1030 * 1031 * <pre> 1032 * StringUtils.equalsIgnoreCase(null, null) = true 1033 * StringUtils.equalsIgnoreCase(null, "abc") = false 1034 * StringUtils.equalsIgnoreCase("abc", null) = false 1035 * StringUtils.equalsIgnoreCase("abc", "abc") = true 1036 * StringUtils.equalsIgnoreCase("abc", "ABC") = true 1037 * </pre> 1038 * 1039 * @param cs1 the first CharSequence, may be {@code null} 1040 * @param cs2 the second CharSequence, may be {@code null} 1041 * @return {@code true} if the CharSequences are equal (case-insensitive), or both {@code null} 1042 * @since 3.0 Changed signature from equalsIgnoreCase(String, String) to equalsIgnoreCase(CharSequence, CharSequence) 1043 * @see #equals(CharSequence, CharSequence) 1044 */ 1045 public static boolean equalsIgnoreCase(final CharSequence cs1, final CharSequence cs2) { 1046 if (cs1 == cs2) { 1047 return true; 1048 } 1049 if (cs1 == null || cs2 == null) { 1050 return false; 1051 } 1052 if (cs1.length() != cs2.length()) { 1053 return false; 1054 } 1055 return CharSequenceUtils.regionMatches(cs1, true, 0, cs2, 0, cs1.length()); 1056 } 1057 1058 // Compare 1059 //----------------------------------------------------------------------- 1060 /** 1061 * <p>Compare two Strings lexicographically, as per {@link String#compareTo(String)}, returning :</p> 1062 * <ul> 1063 * <li>{@code int = 0}, if {@code str1} is equal to {@code str2} (or both {@code null})</li> 1064 * <li>{@code int < 0}, if {@code str1} is less than {@code str2}</li> 1065 * <li>{@code int > 0}, if {@code str1} is greater than {@code str2}</li> 1066 * </ul> 1067 * 1068 * <p>This is a {@code null} safe version of :</p> 1069 * <blockquote><pre>str1.compareTo(str2)</pre></blockquote> 1070 * 1071 * <p>{@code null} value is considered less than non-{@code null} value. 1072 * Two {@code null} references are considered equal.</p> 1073 * 1074 * <pre> 1075 * StringUtils.compare(null, null) = 0 1076 * StringUtils.compare(null , "a") < 0 1077 * StringUtils.compare("a", null) > 0 1078 * StringUtils.compare("abc", "abc") = 0 1079 * StringUtils.compare("a", "b") < 0 1080 * StringUtils.compare("b", "a") > 0 1081 * StringUtils.compare("a", "B") > 0 1082 * StringUtils.compare("ab", "abc") < 0 1083 * </pre> 1084 * 1085 * @see #compare(String, String, boolean) 1086 * @see String#compareTo(String) 1087 * @param str1 the String to compare from 1088 * @param str2 the String to compare to 1089 * @return < 0, 0, > 0, if {@code str1} is respectively less, equal or greater than {@code str2} 1090 * @since 3.5 1091 */ 1092 public static int compare(final String str1, final String str2) { 1093 return compare(str1, str2, true); 1094 } 1095 1096 /** 1097 * <p>Compare two Strings lexicographically, as per {@link String#compareTo(String)}, returning :</p> 1098 * <ul> 1099 * <li>{@code int = 0}, if {@code str1} is equal to {@code str2} (or both {@code null})</li> 1100 * <li>{@code int < 0}, if {@code str1} is less than {@code str2}</li> 1101 * <li>{@code int > 0}, if {@code str1} is greater than {@code str2}</li> 1102 * </ul> 1103 * 1104 * <p>This is a {@code null} safe version of :</p> 1105 * <blockquote><pre>str1.compareTo(str2)</pre></blockquote> 1106 * 1107 * <p>{@code null} inputs are handled according to the {@code nullIsLess} parameter. 1108 * Two {@code null} references are considered equal.</p> 1109 * 1110 * <pre> 1111 * StringUtils.compare(null, null, *) = 0 1112 * StringUtils.compare(null , "a", true) < 0 1113 * StringUtils.compare(null , "a", false) > 0 1114 * StringUtils.compare("a", null, true) > 0 1115 * StringUtils.compare("a", null, false) < 0 1116 * StringUtils.compare("abc", "abc", *) = 0 1117 * StringUtils.compare("a", "b", *) < 0 1118 * StringUtils.compare("b", "a", *) > 0 1119 * StringUtils.compare("a", "B", *) > 0 1120 * StringUtils.compare("ab", "abc", *) < 0 1121 * </pre> 1122 * 1123 * @see String#compareTo(String) 1124 * @param str1 the String to compare from 1125 * @param str2 the String to compare to 1126 * @param nullIsLess whether consider {@code null} value less than non-{@code null} value 1127 * @return < 0, 0, > 0, if {@code str1} is respectively less, equal ou greater than {@code str2} 1128 * @since 3.5 1129 */ 1130 public static int compare(final String str1, final String str2, final boolean nullIsLess) { 1131 if (str1 == str2) { 1132 return 0; 1133 } 1134 if (str1 == null) { 1135 return nullIsLess ? -1 : 1; 1136 } 1137 if (str2 == null) { 1138 return nullIsLess ? 1 : - 1; 1139 } 1140 return str1.compareTo(str2); 1141 } 1142 1143 /** 1144 * <p>Compare two Strings lexicographically, ignoring case differences, 1145 * as per {@link String#compareToIgnoreCase(String)}, returning :</p> 1146 * <ul> 1147 * <li>{@code int = 0}, if {@code str1} is equal to {@code str2} (or both {@code null})</li> 1148 * <li>{@code int < 0}, if {@code str1} is less than {@code str2}</li> 1149 * <li>{@code int > 0}, if {@code str1} is greater than {@code str2}</li> 1150 * </ul> 1151 * 1152 * <p>This is a {@code null} safe version of :</p> 1153 * <blockquote><pre>str1.compareToIgnoreCase(str2)</pre></blockquote> 1154 * 1155 * <p>{@code null} value is considered less than non-{@code null} value. 1156 * Two {@code null} references are considered equal. 1157 * Comparison is case insensitive.</p> 1158 * 1159 * <pre> 1160 * StringUtils.compareIgnoreCase(null, null) = 0 1161 * StringUtils.compareIgnoreCase(null , "a") < 0 1162 * StringUtils.compareIgnoreCase("a", null) > 0 1163 * StringUtils.compareIgnoreCase("abc", "abc") = 0 1164 * StringUtils.compareIgnoreCase("abc", "ABC") = 0 1165 * StringUtils.compareIgnoreCase("a", "b") < 0 1166 * StringUtils.compareIgnoreCase("b", "a") > 0 1167 * StringUtils.compareIgnoreCase("a", "B") < 0 1168 * StringUtils.compareIgnoreCase("A", "b") < 0 1169 * StringUtils.compareIgnoreCase("ab", "ABC") < 0 1170 * </pre> 1171 * 1172 * @see #compareIgnoreCase(String, String, boolean) 1173 * @see String#compareToIgnoreCase(String) 1174 * @param str1 the String to compare from 1175 * @param str2 the String to compare to 1176 * @return < 0, 0, > 0, if {@code str1} is respectively less, equal ou greater than {@code str2}, 1177 * ignoring case differences. 1178 * @since 3.5 1179 */ 1180 public static int compareIgnoreCase(final String str1, final String str2) { 1181 return compareIgnoreCase(str1, str2, true); 1182 } 1183 1184 /** 1185 * <p>Compare two Strings lexicographically, ignoring case differences, 1186 * as per {@link String#compareToIgnoreCase(String)}, returning :</p> 1187 * <ul> 1188 * <li>{@code int = 0}, if {@code str1} is equal to {@code str2} (or both {@code null})</li> 1189 * <li>{@code int < 0}, if {@code str1} is less than {@code str2}</li> 1190 * <li>{@code int > 0}, if {@code str1} is greater than {@code str2}</li> 1191 * </ul> 1192 * 1193 * <p>This is a {@code null} safe version of :</p> 1194 * <blockquote><pre>str1.compareToIgnoreCase(str2)</pre></blockquote> 1195 * 1196 * <p>{@code null} inputs are handled according to the {@code nullIsLess} parameter. 1197 * Two {@code null} references are considered equal. 1198 * Comparison is case insensitive.</p> 1199 * 1200 * <pre> 1201 * StringUtils.compareIgnoreCase(null, null, *) = 0 1202 * StringUtils.compareIgnoreCase(null , "a", true) < 0 1203 * StringUtils.compareIgnoreCase(null , "a", false) > 0 1204 * StringUtils.compareIgnoreCase("a", null, true) > 0 1205 * StringUtils.compareIgnoreCase("a", null, false) < 0 1206 * StringUtils.compareIgnoreCase("abc", "abc", *) = 0 1207 * StringUtils.compareIgnoreCase("abc", "ABC", *) = 0 1208 * StringUtils.compareIgnoreCase("a", "b", *) < 0 1209 * StringUtils.compareIgnoreCase("b", "a", *) > 0 1210 * StringUtils.compareIgnoreCase("a", "B", *) < 0 1211 * StringUtils.compareIgnoreCase("A", "b", *) < 0 1212 * StringUtils.compareIgnoreCase("ab", "abc", *) < 0 1213 * </pre> 1214 * 1215 * @see String#compareToIgnoreCase(String) 1216 * @param str1 the String to compare from 1217 * @param str2 the String to compare to 1218 * @param nullIsLess whether consider {@code null} value less than non-{@code null} value 1219 * @return < 0, 0, > 0, if {@code str1} is respectively less, equal ou greater than {@code str2}, 1220 * ignoring case differences. 1221 * @since 3.5 1222 */ 1223 public static int compareIgnoreCase(final String str1, final String str2, final boolean nullIsLess) { 1224 if (str1 == str2) { 1225 return 0; 1226 } 1227 if (str1 == null) { 1228 return nullIsLess ? -1 : 1; 1229 } 1230 if (str2 == null) { 1231 return nullIsLess ? 1 : - 1; 1232 } 1233 return str1.compareToIgnoreCase(str2); 1234 } 1235 1236 /** 1237 * <p>Compares given <code>string</code> to a CharSequences vararg of <code>searchStrings</code>, 1238 * returning {@code true} if the <code>string</code> is equal to any of the <code>searchStrings</code>.</p> 1239 * 1240 * <pre> 1241 * StringUtils.equalsAny(null, (CharSequence[]) null) = false 1242 * StringUtils.equalsAny(null, null, null) = true 1243 * StringUtils.equalsAny(null, "abc", "def") = false 1244 * StringUtils.equalsAny("abc", null, "def") = false 1245 * StringUtils.equalsAny("abc", "abc", "def") = true 1246 * StringUtils.equalsAny("abc", "ABC", "DEF") = false 1247 * </pre> 1248 * 1249 * @param string to compare, may be {@code null}. 1250 * @param searchStrings a vararg of strings, may be {@code null}. 1251 * @return {@code true} if the string is equal (case-sensitive) to any other element of <code>searchStrings</code>; 1252 * {@code false} if <code>searchStrings</code> is null or contains no matches. 1253 * @since 3.5 1254 */ 1255 public static boolean equalsAny(final CharSequence string, final CharSequence... searchStrings) { 1256 if (ArrayUtils.isNotEmpty(searchStrings)) { 1257 for (final CharSequence next : searchStrings) { 1258 if (equals(string, next)) { 1259 return true; 1260 } 1261 } 1262 } 1263 return false; 1264 } 1265 1266 1267 /** 1268 * <p>Compares given <code>string</code> to a CharSequences vararg of <code>searchStrings</code>, 1269 * returning {@code true} if the <code>string</code> is equal to any of the <code>searchStrings</code>, ignoring case.</p> 1270 * 1271 * <pre> 1272 * StringUtils.equalsAnyIgnoreCase(null, (CharSequence[]) null) = false 1273 * StringUtils.equalsAnyIgnoreCase(null, null, null) = true 1274 * StringUtils.equalsAnyIgnoreCase(null, "abc", "def") = false 1275 * StringUtils.equalsAnyIgnoreCase("abc", null, "def") = false 1276 * StringUtils.equalsAnyIgnoreCase("abc", "abc", "def") = true 1277 * StringUtils.equalsAnyIgnoreCase("abc", "ABC", "DEF") = true 1278 * </pre> 1279 * 1280 * @param string to compare, may be {@code null}. 1281 * @param searchStrings a vararg of strings, may be {@code null}. 1282 * @return {@code true} if the string is equal (case-insensitive) to any other element of <code>searchStrings</code>; 1283 * {@code false} if <code>searchStrings</code> is null or contains no matches. 1284 * @since 3.5 1285 */ 1286 public static boolean equalsAnyIgnoreCase(final CharSequence string, final CharSequence...searchStrings) { 1287 if (ArrayUtils.isNotEmpty(searchStrings)) { 1288 for (final CharSequence next : searchStrings) { 1289 if (equalsIgnoreCase(string, next)) { 1290 return true; 1291 } 1292 } 1293 } 1294 return false; 1295 } 1296 1297 // IndexOf 1298 //----------------------------------------------------------------------- 1299 /** 1300 * Returns the index within <code>seq</code> of the first occurrence of 1301 * the specified character. If a character with value 1302 * <code>searchChar</code> occurs in the character sequence represented by 1303 * <code>seq</code> <code>CharSequence</code> object, then the index (in Unicode 1304 * code units) of the first such occurrence is returned. For 1305 * values of <code>searchChar</code> in the range from 0 to 0xFFFF 1306 * (inclusive), this is the smallest value <i>k</i> such that: 1307 * <blockquote><pre> 1308 * this.charAt(<i>k</i>) == searchChar 1309 * </pre></blockquote> 1310 * is true. For other values of <code>searchChar</code>, it is the 1311 * smallest value <i>k</i> such that: 1312 * <blockquote><pre> 1313 * this.codePointAt(<i>k</i>) == searchChar 1314 * </pre></blockquote> 1315 * is true. In either case, if no such character occurs in <code>seq</code>, 1316 * then {@code INDEX_NOT_FOUND (-1)} is returned. 1317 * 1318 * <p>Furthermore, a {@code null} or empty ("") CharSequence will 1319 * return {@code INDEX_NOT_FOUND (-1)}.</p> 1320 * 1321 * <pre> 1322 * StringUtils.indexOf(null, *) = -1 1323 * StringUtils.indexOf("", *) = -1 1324 * StringUtils.indexOf("aabaabaa", 'a') = 0 1325 * StringUtils.indexOf("aabaabaa", 'b') = 2 1326 * </pre> 1327 * 1328 * @param seq the CharSequence to check, may be null 1329 * @param searchChar the character to find 1330 * @return the first index of the search character, 1331 * -1 if no match or {@code null} string input 1332 * @since 2.0 1333 * @since 3.0 Changed signature from indexOf(String, int) to indexOf(CharSequence, int) 1334 * @since 3.6 Updated {@link CharSequenceUtils} call to behave more like <code>String</code> 1335 */ 1336 public static int indexOf(final CharSequence seq, final int searchChar) { 1337 if (isEmpty(seq)) { 1338 return INDEX_NOT_FOUND; 1339 } 1340 return CharSequenceUtils.indexOf(seq, searchChar, 0); 1341 } 1342 1343 /** 1344 * 1345 * Returns the index within <code>seq</code> of the first occurrence of the 1346 * specified character, starting the search at the specified index. 1347 * <p> 1348 * If a character with value <code>searchChar</code> occurs in the 1349 * character sequence represented by the <code>seq</code> <code>CharSequence</code> 1350 * object at an index no smaller than <code>startPos</code>, then 1351 * the index of the first such occurrence is returned. For values 1352 * of <code>searchChar</code> in the range from 0 to 0xFFFF (inclusive), 1353 * this is the smallest value <i>k</i> such that: 1354 * <blockquote><pre> 1355 * (this.charAt(<i>k</i>) == searchChar) && (<i>k</i> >= startPos) 1356 * </pre></blockquote> 1357 * is true. For other values of <code>searchChar</code>, it is the 1358 * smallest value <i>k</i> such that: 1359 * <blockquote><pre> 1360 * (this.codePointAt(<i>k</i>) == searchChar) && (<i>k</i> >= startPos) 1361 * </pre></blockquote> 1362 * is true. In either case, if no such character occurs in <code>seq</code> 1363 * at or after position <code>startPos</code>, then 1364 * <code>-1</code> is returned. 1365 * 1366 * <p> 1367 * There is no restriction on the value of <code>startPos</code>. If it 1368 * is negative, it has the same effect as if it were zero: this entire 1369 * string may be searched. If it is greater than the length of this 1370 * string, it has the same effect as if it were equal to the length of 1371 * this string: {@code (INDEX_NOT_FOUND) -1} is returned. Furthermore, a 1372 * {@code null} or empty ("") CharSequence will 1373 * return {@code (INDEX_NOT_FOUND) -1}. 1374 * 1375 * <p>All indices are specified in <code>char</code> values 1376 * (Unicode code units). 1377 * 1378 * <pre> 1379 * StringUtils.indexOf(null, *, *) = -1 1380 * StringUtils.indexOf("", *, *) = -1 1381 * StringUtils.indexOf("aabaabaa", 'b', 0) = 2 1382 * StringUtils.indexOf("aabaabaa", 'b', 3) = 5 1383 * StringUtils.indexOf("aabaabaa", 'b', 9) = -1 1384 * StringUtils.indexOf("aabaabaa", 'b', -1) = 2 1385 * </pre> 1386 * 1387 * @param seq the CharSequence to check, may be null 1388 * @param searchChar the character to find 1389 * @param startPos the start position, negative treated as zero 1390 * @return the first index of the search character (always ≥ startPos), 1391 * -1 if no match or {@code null} string input 1392 * @since 2.0 1393 * @since 3.0 Changed signature from indexOf(String, int, int) to indexOf(CharSequence, int, int) 1394 * @since 3.6 Updated {@link CharSequenceUtils} call to behave more like <code>String</code> 1395 */ 1396 public static int indexOf(final CharSequence seq, final int searchChar, final int startPos) { 1397 if (isEmpty(seq)) { 1398 return INDEX_NOT_FOUND; 1399 } 1400 return CharSequenceUtils.indexOf(seq, searchChar, startPos); 1401 } 1402 1403 /** 1404 * <p>Finds the first index within a CharSequence, handling {@code null}. 1405 * This method uses {@link String#indexOf(String, int)} if possible.</p> 1406 * 1407 * <p>A {@code null} CharSequence will return {@code -1}.</p> 1408 * 1409 * <pre> 1410 * StringUtils.indexOf(null, *) = -1 1411 * StringUtils.indexOf(*, null) = -1 1412 * StringUtils.indexOf("", "") = 0 1413 * StringUtils.indexOf("", *) = -1 (except when * = "") 1414 * StringUtils.indexOf("aabaabaa", "a") = 0 1415 * StringUtils.indexOf("aabaabaa", "b") = 2 1416 * StringUtils.indexOf("aabaabaa", "ab") = 1 1417 * StringUtils.indexOf("aabaabaa", "") = 0 1418 * </pre> 1419 * 1420 * @param seq the CharSequence to check, may be null 1421 * @param searchSeq the CharSequence to find, may be null 1422 * @return the first index of the search CharSequence, 1423 * -1 if no match or {@code null} string input 1424 * @since 2.0 1425 * @since 3.0 Changed signature from indexOf(String, String) to indexOf(CharSequence, CharSequence) 1426 */ 1427 public static int indexOf(final CharSequence seq, final CharSequence searchSeq) { 1428 if (seq == null || searchSeq == null) { 1429 return INDEX_NOT_FOUND; 1430 } 1431 return CharSequenceUtils.indexOf(seq, searchSeq, 0); 1432 } 1433 1434 /** 1435 * <p>Finds the first index within a CharSequence, handling {@code null}. 1436 * This method uses {@link String#indexOf(String, int)} if possible.</p> 1437 * 1438 * <p>A {@code null} CharSequence will return {@code -1}. 1439 * A negative start position is treated as zero. 1440 * An empty ("") search CharSequence always matches. 1441 * A start position greater than the string length only matches 1442 * an empty search CharSequence.</p> 1443 * 1444 * <pre> 1445 * StringUtils.indexOf(null, *, *) = -1 1446 * StringUtils.indexOf(*, null, *) = -1 1447 * StringUtils.indexOf("", "", 0) = 0 1448 * StringUtils.indexOf("", *, 0) = -1 (except when * = "") 1449 * StringUtils.indexOf("aabaabaa", "a", 0) = 0 1450 * StringUtils.indexOf("aabaabaa", "b", 0) = 2 1451 * StringUtils.indexOf("aabaabaa", "ab", 0) = 1 1452 * StringUtils.indexOf("aabaabaa", "b", 3) = 5 1453 * StringUtils.indexOf("aabaabaa", "b", 9) = -1 1454 * StringUtils.indexOf("aabaabaa", "b", -1) = 2 1455 * StringUtils.indexOf("aabaabaa", "", 2) = 2 1456 * StringUtils.indexOf("abc", "", 9) = 3 1457 * </pre> 1458 * 1459 * @param seq the CharSequence to check, may be null 1460 * @param searchSeq the CharSequence to find, may be null 1461 * @param startPos the start position, negative treated as zero 1462 * @return the first index of the search CharSequence (always ≥ startPos), 1463 * -1 if no match or {@code null} string input 1464 * @since 2.0 1465 * @since 3.0 Changed signature from indexOf(String, String, int) to indexOf(CharSequence, CharSequence, int) 1466 */ 1467 public static int indexOf(final CharSequence seq, final CharSequence searchSeq, final int startPos) { 1468 if (seq == null || searchSeq == null) { 1469 return INDEX_NOT_FOUND; 1470 } 1471 return CharSequenceUtils.indexOf(seq, searchSeq, startPos); 1472 } 1473 1474 /** 1475 * <p>Finds the n-th index within a CharSequence, handling {@code null}. 1476 * This method uses {@link String#indexOf(String)} if possible.</p> 1477 * <p><b>Note:</b> The code starts looking for a match at the start of the target, 1478 * incrementing the starting index by one after each successful match 1479 * (unless {@code searchStr} is an empty string in which case the position 1480 * is never incremented and {@code 0} is returned immediately). 1481 * This means that matches may overlap.</p> 1482 * <p>A {@code null} CharSequence will return {@code -1}.</p> 1483 * 1484 * <pre> 1485 * StringUtils.ordinalIndexOf(null, *, *) = -1 1486 * StringUtils.ordinalIndexOf(*, null, *) = -1 1487 * StringUtils.ordinalIndexOf("", "", *) = 0 1488 * StringUtils.ordinalIndexOf("aabaabaa", "a", 1) = 0 1489 * StringUtils.ordinalIndexOf("aabaabaa", "a", 2) = 1 1490 * StringUtils.ordinalIndexOf("aabaabaa", "b", 1) = 2 1491 * StringUtils.ordinalIndexOf("aabaabaa", "b", 2) = 5 1492 * StringUtils.ordinalIndexOf("aabaabaa", "ab", 1) = 1 1493 * StringUtils.ordinalIndexOf("aabaabaa", "ab", 2) = 4 1494 * StringUtils.ordinalIndexOf("aabaabaa", "", 1) = 0 1495 * StringUtils.ordinalIndexOf("aabaabaa", "", 2) = 0 1496 * </pre> 1497 * 1498 * <p>Matches may overlap:</p> 1499 * <pre> 1500 * StringUtils.ordinalIndexOf("ababab", "aba", 1) = 0 1501 * StringUtils.ordinalIndexOf("ababab", "aba", 2) = 2 1502 * StringUtils.ordinalIndexOf("ababab", "aba", 3) = -1 1503 * 1504 * StringUtils.ordinalIndexOf("abababab", "abab", 1) = 0 1505 * StringUtils.ordinalIndexOf("abababab", "abab", 2) = 2 1506 * StringUtils.ordinalIndexOf("abababab", "abab", 3) = 4 1507 * StringUtils.ordinalIndexOf("abababab", "abab", 4) = -1 1508 * </pre> 1509 * 1510 * <p>Note that 'head(CharSequence str, int n)' may be implemented as: </p> 1511 * 1512 * <pre> 1513 * str.substring(0, lastOrdinalIndexOf(str, "\n", n)) 1514 * </pre> 1515 * 1516 * @param str the CharSequence to check, may be null 1517 * @param searchStr the CharSequence to find, may be null 1518 * @param ordinal the n-th {@code searchStr} to find 1519 * @return the n-th index of the search CharSequence, 1520 * {@code -1} ({@code INDEX_NOT_FOUND}) if no match or {@code null} string input 1521 * @since 2.1 1522 * @since 3.0 Changed signature from ordinalIndexOf(String, String, int) to ordinalIndexOf(CharSequence, CharSequence, int) 1523 */ 1524 public static int ordinalIndexOf(final CharSequence str, final CharSequence searchStr, final int ordinal) { 1525 return ordinalIndexOf(str, searchStr, ordinal, false); 1526 } 1527 1528 /** 1529 * <p>Finds the n-th index within a String, handling {@code null}. 1530 * This method uses {@link String#indexOf(String)} if possible.</p> 1531 * <p>Note that matches may overlap<p> 1532 * 1533 * <p>A {@code null} CharSequence will return {@code -1}.</p> 1534 * 1535 * @param str the CharSequence to check, may be null 1536 * @param searchStr the CharSequence to find, may be null 1537 * @param ordinal the n-th {@code searchStr} to find, overlapping matches are allowed. 1538 * @param lastIndex true if lastOrdinalIndexOf() otherwise false if ordinalIndexOf() 1539 * @return the n-th index of the search CharSequence, 1540 * {@code -1} ({@code INDEX_NOT_FOUND}) if no match or {@code null} string input 1541 */ 1542 // Shared code between ordinalIndexOf(String, String, int) and lastOrdinalIndexOf(String, String, int) 1543 private static int ordinalIndexOf(final CharSequence str, final CharSequence searchStr, final int ordinal, final boolean lastIndex) { 1544 if (str == null || searchStr == null || ordinal <= 0) { 1545 return INDEX_NOT_FOUND; 1546 } 1547 if (searchStr.length() == 0) { 1548 return lastIndex ? str.length() : 0; 1549 } 1550 int found = 0; 1551 // set the initial index beyond the end of the string 1552 // this is to allow for the initial index decrement/increment 1553 int index = lastIndex ? str.length() : INDEX_NOT_FOUND; 1554 do { 1555 if (lastIndex) { 1556 index = CharSequenceUtils.lastIndexOf(str, searchStr, index - 1); // step backwards thru string 1557 } else { 1558 index = CharSequenceUtils.indexOf(str, searchStr, index + 1); // step forwards through string 1559 } 1560 if (index < 0) { 1561 return index; 1562 } 1563 found++; 1564 } while (found < ordinal); 1565 return index; 1566 } 1567 1568 /** 1569 * <p>Case in-sensitive find of the first index within a CharSequence.</p> 1570 * 1571 * <p>A {@code null} CharSequence will return {@code -1}. 1572 * A negative start position is treated as zero. 1573 * An empty ("") search CharSequence always matches. 1574 * A start position greater than the string length only matches 1575 * an empty search CharSequence.</p> 1576 * 1577 * <pre> 1578 * StringUtils.indexOfIgnoreCase(null, *) = -1 1579 * StringUtils.indexOfIgnoreCase(*, null) = -1 1580 * StringUtils.indexOfIgnoreCase("", "") = 0 1581 * StringUtils.indexOfIgnoreCase("aabaabaa", "a") = 0 1582 * StringUtils.indexOfIgnoreCase("aabaabaa", "b") = 2 1583 * StringUtils.indexOfIgnoreCase("aabaabaa", "ab") = 1 1584 * </pre> 1585 * 1586 * @param str the CharSequence to check, may be null 1587 * @param searchStr the CharSequence to find, may be null 1588 * @return the first index of the search CharSequence, 1589 * -1 if no match or {@code null} string input 1590 * @since 2.5 1591 * @since 3.0 Changed signature from indexOfIgnoreCase(String, String) to indexOfIgnoreCase(CharSequence, CharSequence) 1592 */ 1593 public static int indexOfIgnoreCase(final CharSequence str, final CharSequence searchStr) { 1594 return indexOfIgnoreCase(str, searchStr, 0); 1595 } 1596 1597 /** 1598 * <p>Case in-sensitive find of the first index within a CharSequence 1599 * from the specified position.</p> 1600 * 1601 * <p>A {@code null} CharSequence will return {@code -1}. 1602 * A negative start position is treated as zero. 1603 * An empty ("") search CharSequence always matches. 1604 * A start position greater than the string length only matches 1605 * an empty search CharSequence.</p> 1606 * 1607 * <pre> 1608 * StringUtils.indexOfIgnoreCase(null, *, *) = -1 1609 * StringUtils.indexOfIgnoreCase(*, null, *) = -1 1610 * StringUtils.indexOfIgnoreCase("", "", 0) = 0 1611 * StringUtils.indexOfIgnoreCase("aabaabaa", "A", 0) = 0 1612 * StringUtils.indexOfIgnoreCase("aabaabaa", "B", 0) = 2 1613 * StringUtils.indexOfIgnoreCase("aabaabaa", "AB", 0) = 1 1614 * StringUtils.indexOfIgnoreCase("aabaabaa", "B", 3) = 5 1615 * StringUtils.indexOfIgnoreCase("aabaabaa", "B", 9) = -1 1616 * StringUtils.indexOfIgnoreCase("aabaabaa", "B", -1) = 2 1617 * StringUtils.indexOfIgnoreCase("aabaabaa", "", 2) = 2 1618 * StringUtils.indexOfIgnoreCase("abc", "", 9) = -1 1619 * </pre> 1620 * 1621 * @param str the CharSequence to check, may be null 1622 * @param searchStr the CharSequence to find, may be null 1623 * @param startPos the start position, negative treated as zero 1624 * @return the first index of the search CharSequence (always ≥ startPos), 1625 * -1 if no match or {@code null} string input 1626 * @since 2.5 1627 * @since 3.0 Changed signature from indexOfIgnoreCase(String, String, int) to indexOfIgnoreCase(CharSequence, CharSequence, int) 1628 */ 1629 public static int indexOfIgnoreCase(final CharSequence str, final CharSequence searchStr, int startPos) { 1630 if (str == null || searchStr == null) { 1631 return INDEX_NOT_FOUND; 1632 } 1633 if (startPos < 0) { 1634 startPos = 0; 1635 } 1636 final int endLimit = str.length() - searchStr.length() + 1; 1637 if (startPos > endLimit) { 1638 return INDEX_NOT_FOUND; 1639 } 1640 if (searchStr.length() == 0) { 1641 return startPos; 1642 } 1643 for (int i = startPos; i < endLimit; i++) { 1644 if (CharSequenceUtils.regionMatches(str, true, i, searchStr, 0, searchStr.length())) { 1645 return i; 1646 } 1647 } 1648 return INDEX_NOT_FOUND; 1649 } 1650 1651 // LastIndexOf 1652 //----------------------------------------------------------------------- 1653 /** 1654 * Returns the index within <code>seq</code> of the last occurrence of 1655 * the specified character. For values of <code>searchChar</code> in the 1656 * range from 0 to 0xFFFF (inclusive), the index (in Unicode code 1657 * units) returned is the largest value <i>k</i> such that: 1658 * <blockquote><pre> 1659 * this.charAt(<i>k</i>) == searchChar 1660 * </pre></blockquote> 1661 * is true. For other values of <code>searchChar</code>, it is the 1662 * largest value <i>k</i> such that: 1663 * <blockquote><pre> 1664 * this.codePointAt(<i>k</i>) == searchChar 1665 * </pre></blockquote> 1666 * is true. In either case, if no such character occurs in this 1667 * string, then <code>-1</code> is returned. Furthermore, a {@code null} or empty ("") 1668 * <code>CharSequence</code> will return {@code -1}. The 1669 * <code>seq</code> <code>CharSequence</code> object is searched backwards 1670 * starting at the last character. 1671 * 1672 * <pre> 1673 * StringUtils.lastIndexOf(null, *) = -1 1674 * StringUtils.lastIndexOf("", *) = -1 1675 * StringUtils.lastIndexOf("aabaabaa", 'a') = 7 1676 * StringUtils.lastIndexOf("aabaabaa", 'b') = 5 1677 * </pre> 1678 * 1679 * @param seq the <code>CharSequence</code> to check, may be null 1680 * @param searchChar the character to find 1681 * @return the last index of the search character, 1682 * -1 if no match or {@code null} string input 1683 * @since 2.0 1684 * @since 3.0 Changed signature from lastIndexOf(String, int) to lastIndexOf(CharSequence, int) 1685 * @since 3.6 Updated {@link CharSequenceUtils} call to behave more like <code>String</code> 1686 */ 1687 public static int lastIndexOf(final CharSequence seq, final int searchChar) { 1688 if (isEmpty(seq)) { 1689 return INDEX_NOT_FOUND; 1690 } 1691 return CharSequenceUtils.lastIndexOf(seq, searchChar, seq.length()); 1692 } 1693 1694 /** 1695 * Returns the index within <code>seq</code> of the last occurrence of 1696 * the specified character, searching backward starting at the 1697 * specified index. For values of <code>searchChar</code> in the range 1698 * from 0 to 0xFFFF (inclusive), the index returned is the largest 1699 * value <i>k</i> such that: 1700 * <blockquote><pre> 1701 * (this.charAt(<i>k</i>) == searchChar) && (<i>k</i> <= startPos) 1702 * </pre></blockquote> 1703 * is true. For other values of <code>searchChar</code>, it is the 1704 * largest value <i>k</i> such that: 1705 * <blockquote><pre> 1706 * (this.codePointAt(<i>k</i>) == searchChar) && (<i>k</i> <= startPos) 1707 * </pre></blockquote> 1708 * is true. In either case, if no such character occurs in <code>seq</code> 1709 * at or before position <code>startPos</code>, then 1710 * <code>-1</code> is returned. Furthermore, a {@code null} or empty ("") 1711 * <code>CharSequence</code> will return {@code -1}. A start position greater 1712 * than the string length searches the whole string. 1713 * The search starts at the <code>startPos</code> and works backwards; 1714 * matches starting after the start position are ignored. 1715 * 1716 * <p>All indices are specified in <code>char</code> values 1717 * (Unicode code units). 1718 * 1719 * <pre> 1720 * StringUtils.lastIndexOf(null, *, *) = -1 1721 * StringUtils.lastIndexOf("", *, *) = -1 1722 * StringUtils.lastIndexOf("aabaabaa", 'b', 8) = 5 1723 * StringUtils.lastIndexOf("aabaabaa", 'b', 4) = 2 1724 * StringUtils.lastIndexOf("aabaabaa", 'b', 0) = -1 1725 * StringUtils.lastIndexOf("aabaabaa", 'b', 9) = 5 1726 * StringUtils.lastIndexOf("aabaabaa", 'b', -1) = -1 1727 * StringUtils.lastIndexOf("aabaabaa", 'a', 0) = 0 1728 * </pre> 1729 * 1730 * @param seq the CharSequence to check, may be null 1731 * @param searchChar the character to find 1732 * @param startPos the start position 1733 * @return the last index of the search character (always ≤ startPos), 1734 * -1 if no match or {@code null} string input 1735 * @since 2.0 1736 * @since 3.0 Changed signature from lastIndexOf(String, int, int) to lastIndexOf(CharSequence, int, int) 1737 */ 1738 public static int lastIndexOf(final CharSequence seq, final int searchChar, final int startPos) { 1739 if (isEmpty(seq)) { 1740 return INDEX_NOT_FOUND; 1741 } 1742 return CharSequenceUtils.lastIndexOf(seq, searchChar, startPos); 1743 } 1744 1745 /** 1746 * <p>Finds the last index within a CharSequence, handling {@code null}. 1747 * This method uses {@link String#lastIndexOf(String)} if possible.</p> 1748 * 1749 * <p>A {@code null} CharSequence will return {@code -1}.</p> 1750 * 1751 * <pre> 1752 * StringUtils.lastIndexOf(null, *) = -1 1753 * StringUtils.lastIndexOf(*, null) = -1 1754 * StringUtils.lastIndexOf("", "") = 0 1755 * StringUtils.lastIndexOf("aabaabaa", "a") = 7 1756 * StringUtils.lastIndexOf("aabaabaa", "b") = 5 1757 * StringUtils.lastIndexOf("aabaabaa", "ab") = 4 1758 * StringUtils.lastIndexOf("aabaabaa", "") = 8 1759 * </pre> 1760 * 1761 * @param seq the CharSequence to check, may be null 1762 * @param searchSeq the CharSequence to find, may be null 1763 * @return the last index of the search String, 1764 * -1 if no match or {@code null} string input 1765 * @since 2.0 1766 * @since 3.0 Changed signature from lastIndexOf(String, String) to lastIndexOf(CharSequence, CharSequence) 1767 */ 1768 public static int lastIndexOf(final CharSequence seq, final CharSequence searchSeq) { 1769 if (seq == null || searchSeq == null) { 1770 return INDEX_NOT_FOUND; 1771 } 1772 return CharSequenceUtils.lastIndexOf(seq, searchSeq, seq.length()); 1773 } 1774 1775 /** 1776 * <p>Finds the n-th last index within a String, handling {@code null}. 1777 * This method uses {@link String#lastIndexOf(String)}.</p> 1778 * 1779 * <p>A {@code null} String will return {@code -1}.</p> 1780 * 1781 * <pre> 1782 * StringUtils.lastOrdinalIndexOf(null, *, *) = -1 1783 * StringUtils.lastOrdinalIndexOf(*, null, *) = -1 1784 * StringUtils.lastOrdinalIndexOf("", "", *) = 0 1785 * StringUtils.lastOrdinalIndexOf("aabaabaa", "a", 1) = 7 1786 * StringUtils.lastOrdinalIndexOf("aabaabaa", "a", 2) = 6 1787 * StringUtils.lastOrdinalIndexOf("aabaabaa", "b", 1) = 5 1788 * StringUtils.lastOrdinalIndexOf("aabaabaa", "b", 2) = 2 1789 * StringUtils.lastOrdinalIndexOf("aabaabaa", "ab", 1) = 4 1790 * StringUtils.lastOrdinalIndexOf("aabaabaa", "ab", 2) = 1 1791 * StringUtils.lastOrdinalIndexOf("aabaabaa", "", 1) = 8 1792 * StringUtils.lastOrdinalIndexOf("aabaabaa", "", 2) = 8 1793 * </pre> 1794 * 1795 * <p>Note that 'tail(CharSequence str, int n)' may be implemented as: </p> 1796 * 1797 * <pre> 1798 * str.substring(lastOrdinalIndexOf(str, "\n", n) + 1) 1799 * </pre> 1800 * 1801 * @param str the CharSequence to check, may be null 1802 * @param searchStr the CharSequence to find, may be null 1803 * @param ordinal the n-th last {@code searchStr} to find 1804 * @return the n-th last index of the search CharSequence, 1805 * {@code -1} ({@code INDEX_NOT_FOUND}) if no match or {@code null} string input 1806 * @since 2.5 1807 * @since 3.0 Changed signature from lastOrdinalIndexOf(String, String, int) to lastOrdinalIndexOf(CharSequence, CharSequence, int) 1808 */ 1809 public static int lastOrdinalIndexOf(final CharSequence str, final CharSequence searchStr, final int ordinal) { 1810 return ordinalIndexOf(str, searchStr, ordinal, true); 1811 } 1812 1813 /** 1814 * <p>Finds the last index within a CharSequence, handling {@code null}. 1815 * This method uses {@link String#lastIndexOf(String, int)} if possible.</p> 1816 * 1817 * <p>A {@code null} CharSequence will return {@code -1}. 1818 * A negative start position returns {@code -1}. 1819 * An empty ("") search CharSequence always matches unless the start position is negative. 1820 * A start position greater than the string length searches the whole string. 1821 * The search starts at the startPos and works backwards; matches starting after the start 1822 * position are ignored. 1823 * </p> 1824 * 1825 * <pre> 1826 * StringUtils.lastIndexOf(null, *, *) = -1 1827 * StringUtils.lastIndexOf(*, null, *) = -1 1828 * StringUtils.lastIndexOf("aabaabaa", "a", 8) = 7 1829 * StringUtils.lastIndexOf("aabaabaa", "b", 8) = 5 1830 * StringUtils.lastIndexOf("aabaabaa", "ab", 8) = 4 1831 * StringUtils.lastIndexOf("aabaabaa", "b", 9) = 5 1832 * StringUtils.lastIndexOf("aabaabaa", "b", -1) = -1 1833 * StringUtils.lastIndexOf("aabaabaa", "a", 0) = 0 1834 * StringUtils.lastIndexOf("aabaabaa", "b", 0) = -1 1835 * StringUtils.lastIndexOf("aabaabaa", "b", 1) = -1 1836 * StringUtils.lastIndexOf("aabaabaa", "b", 2) = 2 1837 * StringUtils.lastIndexOf("aabaabaa", "ba", 2) = 2 1838 * </pre> 1839 * 1840 * @param seq the CharSequence to check, may be null 1841 * @param searchSeq the CharSequence to find, may be null 1842 * @param startPos the start position, negative treated as zero 1843 * @return the last index of the search CharSequence (always ≤ startPos), 1844 * -1 if no match or {@code null} string input 1845 * @since 2.0 1846 * @since 3.0 Changed signature from lastIndexOf(String, String, int) to lastIndexOf(CharSequence, CharSequence, int) 1847 */ 1848 public static int lastIndexOf(final CharSequence seq, final CharSequence searchSeq, final int startPos) { 1849 if (seq == null || searchSeq == null) { 1850 return INDEX_NOT_FOUND; 1851 } 1852 return CharSequenceUtils.lastIndexOf(seq, searchSeq, startPos); 1853 } 1854 1855 /** 1856 * <p>Case in-sensitive find of the last index within a CharSequence.</p> 1857 * 1858 * <p>A {@code null} CharSequence will return {@code -1}. 1859 * A negative start position returns {@code -1}. 1860 * An empty ("") search CharSequence always matches unless the start position is negative. 1861 * A start position greater than the string length searches the whole string.</p> 1862 * 1863 * <pre> 1864 * StringUtils.lastIndexOfIgnoreCase(null, *) = -1 1865 * StringUtils.lastIndexOfIgnoreCase(*, null) = -1 1866 * StringUtils.lastIndexOfIgnoreCase("aabaabaa", "A") = 7 1867 * StringUtils.lastIndexOfIgnoreCase("aabaabaa", "B") = 5 1868 * StringUtils.lastIndexOfIgnoreCase("aabaabaa", "AB") = 4 1869 * </pre> 1870 * 1871 * @param str the CharSequence to check, may be null 1872 * @param searchStr the CharSequence to find, may be null 1873 * @return the first index of the search CharSequence, 1874 * -1 if no match or {@code null} string input 1875 * @since 2.5 1876 * @since 3.0 Changed signature from lastIndexOfIgnoreCase(String, String) to lastIndexOfIgnoreCase(CharSequence, CharSequence) 1877 */ 1878 public static int lastIndexOfIgnoreCase(final CharSequence str, final CharSequence searchStr) { 1879 if (str == null || searchStr == null) { 1880 return INDEX_NOT_FOUND; 1881 } 1882 return lastIndexOfIgnoreCase(str, searchStr, str.length()); 1883 } 1884 1885 /** 1886 * <p>Case in-sensitive find of the last index within a CharSequence 1887 * from the specified position.</p> 1888 * 1889 * <p>A {@code null} CharSequence will return {@code -1}. 1890 * A negative start position returns {@code -1}. 1891 * An empty ("") search CharSequence always matches unless the start position is negative. 1892 * A start position greater than the string length searches the whole string. 1893 * The search starts at the startPos and works backwards; matches starting after the start 1894 * position are ignored. 1895 * </p> 1896 * 1897 * <pre> 1898 * StringUtils.lastIndexOfIgnoreCase(null, *, *) = -1 1899 * StringUtils.lastIndexOfIgnoreCase(*, null, *) = -1 1900 * StringUtils.lastIndexOfIgnoreCase("aabaabaa", "A", 8) = 7 1901 * StringUtils.lastIndexOfIgnoreCase("aabaabaa", "B", 8) = 5 1902 * StringUtils.lastIndexOfIgnoreCase("aabaabaa", "AB", 8) = 4 1903 * StringUtils.lastIndexOfIgnoreCase("aabaabaa", "B", 9) = 5 1904 * StringUtils.lastIndexOfIgnoreCase("aabaabaa", "B", -1) = -1 1905 * StringUtils.lastIndexOfIgnoreCase("aabaabaa", "A", 0) = 0 1906 * StringUtils.lastIndexOfIgnoreCase("aabaabaa", "B", 0) = -1 1907 * </pre> 1908 * 1909 * @param str the CharSequence to check, may be null 1910 * @param searchStr the CharSequence to find, may be null 1911 * @param startPos the start position 1912 * @return the last index of the search CharSequence (always ≤ startPos), 1913 * -1 if no match or {@code null} input 1914 * @since 2.5 1915 * @since 3.0 Changed signature from lastIndexOfIgnoreCase(String, String, int) to lastIndexOfIgnoreCase(CharSequence, CharSequence, int) 1916 */ 1917 public static int lastIndexOfIgnoreCase(final CharSequence str, final CharSequence searchStr, int startPos) { 1918 if (str == null || searchStr == null) { 1919 return INDEX_NOT_FOUND; 1920 } 1921 if (startPos > str.length() - searchStr.length()) { 1922 startPos = str.length() - searchStr.length(); 1923 } 1924 if (startPos < 0) { 1925 return INDEX_NOT_FOUND; 1926 } 1927 if (searchStr.length() == 0) { 1928 return startPos; 1929 } 1930 1931 for (int i = startPos; i >= 0; i--) { 1932 if (CharSequenceUtils.regionMatches(str, true, i, searchStr, 0, searchStr.length())) { 1933 return i; 1934 } 1935 } 1936 return INDEX_NOT_FOUND; 1937 } 1938 1939 // Contains 1940 //----------------------------------------------------------------------- 1941 /** 1942 * <p>Checks if CharSequence contains a search character, handling {@code null}. 1943 * This method uses {@link String#indexOf(int)} if possible.</p> 1944 * 1945 * <p>A {@code null} or empty ("") CharSequence will return {@code false}.</p> 1946 * 1947 * <pre> 1948 * StringUtils.contains(null, *) = false 1949 * StringUtils.contains("", *) = false 1950 * StringUtils.contains("abc", 'a') = true 1951 * StringUtils.contains("abc", 'z') = false 1952 * </pre> 1953 * 1954 * @param seq the CharSequence to check, may be null 1955 * @param searchChar the character to find 1956 * @return true if the CharSequence contains the search character, 1957 * false if not or {@code null} string input 1958 * @since 2.0 1959 * @since 3.0 Changed signature from contains(String, int) to contains(CharSequence, int) 1960 */ 1961 public static boolean contains(final CharSequence seq, final int searchChar) { 1962 if (isEmpty(seq)) { 1963 return false; 1964 } 1965 return CharSequenceUtils.indexOf(seq, searchChar, 0) >= 0; 1966 } 1967 1968 /** 1969 * <p>Checks if CharSequence contains a search CharSequence, handling {@code null}. 1970 * This method uses {@link String#indexOf(String)} if possible.</p> 1971 * 1972 * <p>A {@code null} CharSequence will return {@code false}.</p> 1973 * 1974 * <pre> 1975 * StringUtils.contains(null, *) = false 1976 * StringUtils.contains(*, null) = false 1977 * StringUtils.contains("", "") = true 1978 * StringUtils.contains("abc", "") = true 1979 * StringUtils.contains("abc", "a") = true 1980 * StringUtils.contains("abc", "z") = false 1981 * </pre> 1982 * 1983 * @param seq the CharSequence to check, may be null 1984 * @param searchSeq the CharSequence to find, may be null 1985 * @return true if the CharSequence contains the search CharSequence, 1986 * false if not or {@code null} string input 1987 * @since 2.0 1988 * @since 3.0 Changed signature from contains(String, String) to contains(CharSequence, CharSequence) 1989 */ 1990 public static boolean contains(final CharSequence seq, final CharSequence searchSeq) { 1991 if (seq == null || searchSeq == null) { 1992 return false; 1993 } 1994 return CharSequenceUtils.indexOf(seq, searchSeq, 0) >= 0; 1995 } 1996 1997 /** 1998 * <p>Checks if CharSequence contains a search CharSequence irrespective of case, 1999 * handling {@code null}. Case-insensitivity is defined as by 2000 * {@link String#equalsIgnoreCase(String)}. 2001 * 2002 * <p>A {@code null} CharSequence will return {@code false}.</p> 2003 * 2004 * <pre> 2005 * StringUtils.containsIgnoreCase(null, *) = false 2006 * StringUtils.containsIgnoreCase(*, null) = false 2007 * StringUtils.containsIgnoreCase("", "") = true 2008 * StringUtils.containsIgnoreCase("abc", "") = true 2009 * StringUtils.containsIgnoreCase("abc", "a") = true 2010 * StringUtils.containsIgnoreCase("abc", "z") = false 2011 * StringUtils.containsIgnoreCase("abc", "A") = true 2012 * StringUtils.containsIgnoreCase("abc", "Z") = false 2013 * </pre> 2014 * 2015 * @param str the CharSequence to check, may be null 2016 * @param searchStr the CharSequence to find, may be null 2017 * @return true if the CharSequence contains the search CharSequence irrespective of 2018 * case or false if not or {@code null} string input 2019 * @since 3.0 Changed signature from containsIgnoreCase(String, String) to containsIgnoreCase(CharSequence, CharSequence) 2020 */ 2021 public static boolean containsIgnoreCase(final CharSequence str, final CharSequence searchStr) { 2022 if (str == null || searchStr == null) { 2023 return false; 2024 } 2025 final int len = searchStr.length(); 2026 final int max = str.length() - len; 2027 for (int i = 0; i <= max; i++) { 2028 if (CharSequenceUtils.regionMatches(str, true, i, searchStr, 0, len)) { 2029 return true; 2030 } 2031 } 2032 return false; 2033 } 2034 2035 /** 2036 * <p>Check whether the given CharSequence contains any whitespace characters.</p> 2037 * 2038 * <p>Whitespace is defined by {@link Character#isWhitespace(char)}.</p> 2039 * 2040 * @param seq the CharSequence to check (may be {@code null}) 2041 * @return {@code true} if the CharSequence is not empty and 2042 * contains at least 1 (breaking) whitespace character 2043 * @since 3.0 2044 */ 2045 // From org.springframework.util.StringUtils, under Apache License 2.0 2046 public static boolean containsWhitespace(final CharSequence seq) { 2047 if (isEmpty(seq)) { 2048 return false; 2049 } 2050 final int strLen = seq.length(); 2051 for (int i = 0; i < strLen; i++) { 2052 if (Character.isWhitespace(seq.charAt(i))) { 2053 return true; 2054 } 2055 } 2056 return false; 2057 } 2058 2059 // IndexOfAny chars 2060 //----------------------------------------------------------------------- 2061 /** 2062 * <p>Search a CharSequence to find the first index of any 2063 * character in the given set of characters.</p> 2064 * 2065 * <p>A {@code null} String will return {@code -1}. 2066 * A {@code null} or zero length search array will return {@code -1}.</p> 2067 * 2068 * <pre> 2069 * StringUtils.indexOfAny(null, *) = -1 2070 * StringUtils.indexOfAny("", *) = -1 2071 * StringUtils.indexOfAny(*, null) = -1 2072 * StringUtils.indexOfAny(*, []) = -1 2073 * StringUtils.indexOfAny("zzabyycdxx", ['z', 'a']) = 0 2074 * StringUtils.indexOfAny("zzabyycdxx", ['b', 'y']) = 3 2075 * StringUtils.indexOfAny("aba", ['z']) = -1 2076 * </pre> 2077 * 2078 * @param cs the CharSequence to check, may be null 2079 * @param searchChars the chars to search for, may be null 2080 * @return the index of any of the chars, -1 if no match or null input 2081 * @since 2.0 2082 * @since 3.0 Changed signature from indexOfAny(String, char[]) to indexOfAny(CharSequence, char...) 2083 */ 2084 public static int indexOfAny(final CharSequence cs, final char... searchChars) { 2085 if (isEmpty(cs) || ArrayUtils.isEmpty(searchChars)) { 2086 return INDEX_NOT_FOUND; 2087 } 2088 final int csLen = cs.length(); 2089 final int csLast = csLen - 1; 2090 final int searchLen = searchChars.length; 2091 final int searchLast = searchLen - 1; 2092 for (int i = 0; i < csLen; i++) { 2093 final char ch = cs.charAt(i); 2094 for (int j = 0; j < searchLen; j++) { 2095 if (searchChars[j] == ch) { 2096 if (i < csLast && j < searchLast && Character.isHighSurrogate(ch)) { 2097 // ch is a supplementary character 2098 if (searchChars[j + 1] == cs.charAt(i + 1)) { 2099 return i; 2100 } 2101 } else { 2102 return i; 2103 } 2104 } 2105 } 2106 } 2107 return INDEX_NOT_FOUND; 2108 } 2109 2110 /** 2111 * <p>Search a CharSequence to find the first index of any 2112 * character in the given set of characters.</p> 2113 * 2114 * <p>A {@code null} String will return {@code -1}. 2115 * A {@code null} search string will return {@code -1}.</p> 2116 * 2117 * <pre> 2118 * StringUtils.indexOfAny(null, *) = -1 2119 * StringUtils.indexOfAny("", *) = -1 2120 * StringUtils.indexOfAny(*, null) = -1 2121 * StringUtils.indexOfAny(*, "") = -1 2122 * StringUtils.indexOfAny("zzabyycdxx", "za") = 0 2123 * StringUtils.indexOfAny("zzabyycdxx", "by") = 3 2124 * StringUtils.indexOfAny("aba", "z") = -1 2125 * </pre> 2126 * 2127 * @param cs the CharSequence to check, may be null 2128 * @param searchChars the chars to search for, may be null 2129 * @return the index of any of the chars, -1 if no match or null input 2130 * @since 2.0 2131 * @since 3.0 Changed signature from indexOfAny(String, String) to indexOfAny(CharSequence, String) 2132 */ 2133 public static int indexOfAny(final CharSequence cs, final String searchChars) { 2134 if (isEmpty(cs) || isEmpty(searchChars)) { 2135 return INDEX_NOT_FOUND; 2136 } 2137 return indexOfAny(cs, searchChars.toCharArray()); 2138 } 2139 2140 // ContainsAny 2141 //----------------------------------------------------------------------- 2142 /** 2143 * <p>Checks if the CharSequence contains any character in the given 2144 * set of characters.</p> 2145 * 2146 * <p>A {@code null} CharSequence will return {@code false}. 2147 * A {@code null} or zero length search array will return {@code false}.</p> 2148 * 2149 * <pre> 2150 * StringUtils.containsAny(null, *) = false 2151 * StringUtils.containsAny("", *) = false 2152 * StringUtils.containsAny(*, null) = false 2153 * StringUtils.containsAny(*, []) = false 2154 * StringUtils.containsAny("zzabyycdxx", ['z', 'a']) = true 2155 * StringUtils.containsAny("zzabyycdxx", ['b', 'y']) = true 2156 * StringUtils.containsAny("zzabyycdxx", ['z', 'y']) = true 2157 * StringUtils.containsAny("aba", ['z']) = false 2158 * </pre> 2159 * 2160 * @param cs the CharSequence to check, may be null 2161 * @param searchChars the chars to search for, may be null 2162 * @return the {@code true} if any of the chars are found, 2163 * {@code false} if no match or null input 2164 * @since 2.4 2165 * @since 3.0 Changed signature from containsAny(String, char[]) to containsAny(CharSequence, char...) 2166 */ 2167 public static boolean containsAny(final CharSequence cs, final char... searchChars) { 2168 if (isEmpty(cs) || ArrayUtils.isEmpty(searchChars)) { 2169 return false; 2170 } 2171 final int csLength = cs.length(); 2172 final int searchLength = searchChars.length; 2173 final int csLast = csLength - 1; 2174 final int searchLast = searchLength - 1; 2175 for (int i = 0; i < csLength; i++) { 2176 final char ch = cs.charAt(i); 2177 for (int j = 0; j < searchLength; j++) { 2178 if (searchChars[j] == ch) { 2179 if (Character.isHighSurrogate(ch)) { 2180 if (j == searchLast) { 2181 // missing low surrogate, fine, like String.indexOf(String) 2182 return true; 2183 } 2184 if (i < csLast && searchChars[j + 1] == cs.charAt(i + 1)) { 2185 return true; 2186 } 2187 } else { 2188 // ch is in the Basic Multilingual Plane 2189 return true; 2190 } 2191 } 2192 } 2193 } 2194 return false; 2195 } 2196 2197 /** 2198 * <p> 2199 * Checks if the CharSequence contains any character in the given set of characters. 2200 * </p> 2201 * 2202 * <p> 2203 * A {@code null} CharSequence will return {@code false}. A {@code null} search CharSequence will return 2204 * {@code false}. 2205 * </p> 2206 * 2207 * <pre> 2208 * StringUtils.containsAny(null, *) = false 2209 * StringUtils.containsAny("", *) = false 2210 * StringUtils.containsAny(*, null) = false 2211 * StringUtils.containsAny(*, "") = false 2212 * StringUtils.containsAny("zzabyycdxx", "za") = true 2213 * StringUtils.containsAny("zzabyycdxx", "by") = true 2214 * StringUtils.containsAny("zzabyycdxx", "zy") = true 2215 * StringUtils.containsAny("zzabyycdxx", "\tx") = true 2216 * StringUtils.containsAny("zzabyycdxx", "$.#yF") = true 2217 * StringUtils.containsAny("aba", "z") = false 2218 * </pre> 2219 * 2220 * @param cs 2221 * the CharSequence to check, may be null 2222 * @param searchChars 2223 * the chars to search for, may be null 2224 * @return the {@code true} if any of the chars are found, {@code false} if no match or null input 2225 * @since 2.4 2226 * @since 3.0 Changed signature from containsAny(String, String) to containsAny(CharSequence, CharSequence) 2227 */ 2228 public static boolean containsAny(final CharSequence cs, final CharSequence searchChars) { 2229 if (searchChars == null) { 2230 return false; 2231 } 2232 return containsAny(cs, CharSequenceUtils.toCharArray(searchChars)); 2233 } 2234 2235 /** 2236 * <p>Checks if the CharSequence contains any of the CharSequences in the given array.</p> 2237 * 2238 * <p> 2239 * A {@code null} {@code cs} CharSequence will return {@code false}. A {@code null} or zero 2240 * length search array will return {@code false}. 2241 * </p> 2242 * 2243 * <pre> 2244 * StringUtils.containsAny(null, *) = false 2245 * StringUtils.containsAny("", *) = false 2246 * StringUtils.containsAny(*, null) = false 2247 * StringUtils.containsAny(*, []) = false 2248 * StringUtils.containsAny("abcd", "ab", null) = true 2249 * StringUtils.containsAny("abcd", "ab", "cd") = true 2250 * StringUtils.containsAny("abc", "d", "abc") = true 2251 * </pre> 2252 * 2253 * 2254 * @param cs The CharSequence to check, may be null 2255 * @param searchCharSequences The array of CharSequences to search for, may be null. 2256 * Individual CharSequences may be null as well. 2257 * @return {@code true} if any of the search CharSequences are found, {@code false} otherwise 2258 * @since 3.4 2259 */ 2260 public static boolean containsAny(final CharSequence cs, final CharSequence... searchCharSequences) { 2261 if (isEmpty(cs) || ArrayUtils.isEmpty(searchCharSequences)) { 2262 return false; 2263 } 2264 for (final CharSequence searchCharSequence : searchCharSequences) { 2265 if (contains(cs, searchCharSequence)) { 2266 return true; 2267 } 2268 } 2269 return false; 2270 } 2271 2272 // IndexOfAnyBut chars 2273 //----------------------------------------------------------------------- 2274 /** 2275 * <p>Searches a CharSequence to find the first index of any 2276 * character not in the given set of characters.</p> 2277 * 2278 * <p>A {@code null} CharSequence will return {@code -1}. 2279 * A {@code null} or zero length search array will return {@code -1}.</p> 2280 * 2281 * <pre> 2282 * StringUtils.indexOfAnyBut(null, *) = -1 2283 * StringUtils.indexOfAnyBut("", *) = -1 2284 * StringUtils.indexOfAnyBut(*, null) = -1 2285 * StringUtils.indexOfAnyBut(*, []) = -1 2286 * StringUtils.indexOfAnyBut("zzabyycdxx", new char[] {'z', 'a'} ) = 3 2287 * StringUtils.indexOfAnyBut("aba", new char[] {'z'} ) = 0 2288 * StringUtils.indexOfAnyBut("aba", new char[] {'a', 'b'} ) = -1 2289 2290 * </pre> 2291 * 2292 * @param cs the CharSequence to check, may be null 2293 * @param searchChars the chars to search for, may be null 2294 * @return the index of any of the chars, -1 if no match or null input 2295 * @since 2.0 2296 * @since 3.0 Changed signature from indexOfAnyBut(String, char[]) to indexOfAnyBut(CharSequence, char...) 2297 */ 2298 public static int indexOfAnyBut(final CharSequence cs, final char... searchChars) { 2299 if (isEmpty(cs) || ArrayUtils.isEmpty(searchChars)) { 2300 return INDEX_NOT_FOUND; 2301 } 2302 final int csLen = cs.length(); 2303 final int csLast = csLen - 1; 2304 final int searchLen = searchChars.length; 2305 final int searchLast = searchLen - 1; 2306 outer: 2307 for (int i = 0; i < csLen; i++) { 2308 final char ch = cs.charAt(i); 2309 for (int j = 0; j < searchLen; j++) { 2310 if (searchChars[j] == ch) { 2311 if (i < csLast && j < searchLast && Character.isHighSurrogate(ch)) { 2312 if (searchChars[j + 1] == cs.charAt(i + 1)) { 2313 continue outer; 2314 } 2315 } else { 2316 continue outer; 2317 } 2318 } 2319 } 2320 return i; 2321 } 2322 return INDEX_NOT_FOUND; 2323 } 2324 2325 /** 2326 * <p>Search a CharSequence to find the first index of any 2327 * character not in the given set of characters.</p> 2328 * 2329 * <p>A {@code null} CharSequence will return {@code -1}. 2330 * A {@code null} or empty search string will return {@code -1}.</p> 2331 * 2332 * <pre> 2333 * StringUtils.indexOfAnyBut(null, *) = -1 2334 * StringUtils.indexOfAnyBut("", *) = -1 2335 * StringUtils.indexOfAnyBut(*, null) = -1 2336 * StringUtils.indexOfAnyBut(*, "") = -1 2337 * StringUtils.indexOfAnyBut("zzabyycdxx", "za") = 3 2338 * StringUtils.indexOfAnyBut("zzabyycdxx", "") = -1 2339 * StringUtils.indexOfAnyBut("aba", "ab") = -1 2340 * </pre> 2341 * 2342 * @param seq the CharSequence to check, may be null 2343 * @param searchChars the chars to search for, may be null 2344 * @return the index of any of the chars, -1 if no match or null input 2345 * @since 2.0 2346 * @since 3.0 Changed signature from indexOfAnyBut(String, String) to indexOfAnyBut(CharSequence, CharSequence) 2347 */ 2348 public static int indexOfAnyBut(final CharSequence seq, final CharSequence searchChars) { 2349 if (isEmpty(seq) || isEmpty(searchChars)) { 2350 return INDEX_NOT_FOUND; 2351 } 2352 final int strLen = seq.length(); 2353 for (int i = 0; i < strLen; i++) { 2354 final char ch = seq.charAt(i); 2355 final boolean chFound = CharSequenceUtils.indexOf(searchChars, ch, 0) >= 0; 2356 if (i + 1 < strLen && Character.isHighSurrogate(ch)) { 2357 final char ch2 = seq.charAt(i + 1); 2358 if (chFound && CharSequenceUtils.indexOf(searchChars, ch2, 0) < 0) { 2359 return i; 2360 } 2361 } else { 2362 if (!chFound) { 2363 return i; 2364 } 2365 } 2366 } 2367 return INDEX_NOT_FOUND; 2368 } 2369 2370 // ContainsOnly 2371 //----------------------------------------------------------------------- 2372 /** 2373 * <p>Checks if the CharSequence contains only certain characters.</p> 2374 * 2375 * <p>A {@code null} CharSequence will return {@code false}. 2376 * A {@code null} valid character array will return {@code false}. 2377 * An empty CharSequence (length()=0) always returns {@code true}.</p> 2378 * 2379 * <pre> 2380 * StringUtils.containsOnly(null, *) = false 2381 * StringUtils.containsOnly(*, null) = false 2382 * StringUtils.containsOnly("", *) = true 2383 * StringUtils.containsOnly("ab", '') = false 2384 * StringUtils.containsOnly("abab", 'abc') = true 2385 * StringUtils.containsOnly("ab1", 'abc') = false 2386 * StringUtils.containsOnly("abz", 'abc') = false 2387 * </pre> 2388 * 2389 * @param cs the String to check, may be null 2390 * @param valid an array of valid chars, may be null 2391 * @return true if it only contains valid chars and is non-null 2392 * @since 3.0 Changed signature from containsOnly(String, char[]) to containsOnly(CharSequence, char...) 2393 */ 2394 public static boolean containsOnly(final CharSequence cs, final char... valid) { 2395 // All these pre-checks are to maintain API with an older version 2396 if (valid == null || cs == null) { 2397 return false; 2398 } 2399 if (cs.length() == 0) { 2400 return true; 2401 } 2402 if (valid.length == 0) { 2403 return false; 2404 } 2405 return indexOfAnyBut(cs, valid) == INDEX_NOT_FOUND; 2406 } 2407 2408 /** 2409 * <p>Checks if the CharSequence contains only certain characters.</p> 2410 * 2411 * <p>A {@code null} CharSequence will return {@code false}. 2412 * A {@code null} valid character String will return {@code false}. 2413 * An empty String (length()=0) always returns {@code true}.</p> 2414 * 2415 * <pre> 2416 * StringUtils.containsOnly(null, *) = false 2417 * StringUtils.containsOnly(*, null) = false 2418 * StringUtils.containsOnly("", *) = true 2419 * StringUtils.containsOnly("ab", "") = false 2420 * StringUtils.containsOnly("abab", "abc") = true 2421 * StringUtils.containsOnly("ab1", "abc") = false 2422 * StringUtils.containsOnly("abz", "abc") = false 2423 * </pre> 2424 * 2425 * @param cs the CharSequence to check, may be null 2426 * @param validChars a String of valid chars, may be null 2427 * @return true if it only contains valid chars and is non-null 2428 * @since 2.0 2429 * @since 3.0 Changed signature from containsOnly(String, String) to containsOnly(CharSequence, String) 2430 */ 2431 public static boolean containsOnly(final CharSequence cs, final String validChars) { 2432 if (cs == null || validChars == null) { 2433 return false; 2434 } 2435 return containsOnly(cs, validChars.toCharArray()); 2436 } 2437 2438 // ContainsNone 2439 //----------------------------------------------------------------------- 2440 /** 2441 * <p>Checks that the CharSequence does not contain certain characters.</p> 2442 * 2443 * <p>A {@code null} CharSequence will return {@code true}. 2444 * A {@code null} invalid character array will return {@code true}. 2445 * An empty CharSequence (length()=0) always returns true.</p> 2446 * 2447 * <pre> 2448 * StringUtils.containsNone(null, *) = true 2449 * StringUtils.containsNone(*, null) = true 2450 * StringUtils.containsNone("", *) = true 2451 * StringUtils.containsNone("ab", '') = true 2452 * StringUtils.containsNone("abab", 'xyz') = true 2453 * StringUtils.containsNone("ab1", 'xyz') = true 2454 * StringUtils.containsNone("abz", 'xyz') = false 2455 * </pre> 2456 * 2457 * @param cs the CharSequence to check, may be null 2458 * @param searchChars an array of invalid chars, may be null 2459 * @return true if it contains none of the invalid chars, or is null 2460 * @since 2.0 2461 * @since 3.0 Changed signature from containsNone(String, char[]) to containsNone(CharSequence, char...) 2462 */ 2463 public static boolean containsNone(final CharSequence cs, final char... searchChars) { 2464 if (cs == null || searchChars == null) { 2465 return true; 2466 } 2467 final int csLen = cs.length(); 2468 final int csLast = csLen - 1; 2469 final int searchLen = searchChars.length; 2470 final int searchLast = searchLen - 1; 2471 for (int i = 0; i < csLen; i++) { 2472 final char ch = cs.charAt(i); 2473 for (int j = 0; j < searchLen; j++) { 2474 if (searchChars[j] == ch) { 2475 if (Character.isHighSurrogate(ch)) { 2476 if (j == searchLast) { 2477 // missing low surrogate, fine, like String.indexOf(String) 2478 return false; 2479 } 2480 if (i < csLast && searchChars[j + 1] == cs.charAt(i + 1)) { 2481 return false; 2482 } 2483 } else { 2484 // ch is in the Basic Multilingual Plane 2485 return false; 2486 } 2487 } 2488 } 2489 } 2490 return true; 2491 } 2492 2493 /** 2494 * <p>Checks that the CharSequence does not contain certain characters.</p> 2495 * 2496 * <p>A {@code null} CharSequence will return {@code true}. 2497 * A {@code null} invalid character array will return {@code true}. 2498 * An empty String ("") always returns true.</p> 2499 * 2500 * <pre> 2501 * StringUtils.containsNone(null, *) = true 2502 * StringUtils.containsNone(*, null) = true 2503 * StringUtils.containsNone("", *) = true 2504 * StringUtils.containsNone("ab", "") = true 2505 * StringUtils.containsNone("abab", "xyz") = true 2506 * StringUtils.containsNone("ab1", "xyz") = true 2507 * StringUtils.containsNone("abz", "xyz") = false 2508 * </pre> 2509 * 2510 * @param cs the CharSequence to check, may be null 2511 * @param invalidChars a String of invalid chars, may be null 2512 * @return true if it contains none of the invalid chars, or is null 2513 * @since 2.0 2514 * @since 3.0 Changed signature from containsNone(String, String) to containsNone(CharSequence, String) 2515 */ 2516 public static boolean containsNone(final CharSequence cs, final String invalidChars) { 2517 if (cs == null || invalidChars == null) { 2518 return true; 2519 } 2520 return containsNone(cs, invalidChars.toCharArray()); 2521 } 2522 2523 // IndexOfAny strings 2524 //----------------------------------------------------------------------- 2525 /** 2526 * <p>Find the first index of any of a set of potential substrings.</p> 2527 * 2528 * <p>A {@code null} CharSequence will return {@code -1}. 2529 * A {@code null} or zero length search array will return {@code -1}. 2530 * A {@code null} search array entry will be ignored, but a search 2531 * array containing "" will return {@code 0} if {@code str} is not 2532 * null. This method uses {@link String#indexOf(String)} if possible.</p> 2533 * 2534 * <pre> 2535 * StringUtils.indexOfAny(null, *) = -1 2536 * StringUtils.indexOfAny(*, null) = -1 2537 * StringUtils.indexOfAny(*, []) = -1 2538 * StringUtils.indexOfAny("zzabyycdxx", ["ab", "cd"]) = 2 2539 * StringUtils.indexOfAny("zzabyycdxx", ["cd", "ab"]) = 2 2540 * StringUtils.indexOfAny("zzabyycdxx", ["mn", "op"]) = -1 2541 * StringUtils.indexOfAny("zzabyycdxx", ["zab", "aby"]) = 1 2542 * StringUtils.indexOfAny("zzabyycdxx", [""]) = 0 2543 * StringUtils.indexOfAny("", [""]) = 0 2544 * StringUtils.indexOfAny("", ["a"]) = -1 2545 * </pre> 2546 * 2547 * @param str the CharSequence to check, may be null 2548 * @param searchStrs the CharSequences to search for, may be null 2549 * @return the first index of any of the searchStrs in str, -1 if no match 2550 * @since 3.0 Changed signature from indexOfAny(String, String[]) to indexOfAny(CharSequence, CharSequence...) 2551 */ 2552 public static int indexOfAny(final CharSequence str, final CharSequence... searchStrs) { 2553 if (str == null || searchStrs == null) { 2554 return INDEX_NOT_FOUND; 2555 } 2556 2557 // String's can't have a MAX_VALUEth index. 2558 int ret = Integer.MAX_VALUE; 2559 2560 int tmp = 0; 2561 for (final CharSequence search : searchStrs) { 2562 if (search == null) { 2563 continue; 2564 } 2565 tmp = CharSequenceUtils.indexOf(str, search, 0); 2566 if (tmp == INDEX_NOT_FOUND) { 2567 continue; 2568 } 2569 2570 if (tmp < ret) { 2571 ret = tmp; 2572 } 2573 } 2574 2575 return ret == Integer.MAX_VALUE ? INDEX_NOT_FOUND : ret; 2576 } 2577 2578 /** 2579 * <p>Find the latest index of any of a set of potential substrings.</p> 2580 * 2581 * <p>A {@code null} CharSequence will return {@code -1}. 2582 * A {@code null} search array will return {@code -1}. 2583 * A {@code null} or zero length search array entry will be ignored, 2584 * but a search array containing "" will return the length of {@code str} 2585 * if {@code str} is not null. This method uses {@link String#indexOf(String)} if possible</p> 2586 * 2587 * <pre> 2588 * StringUtils.lastIndexOfAny(null, *) = -1 2589 * StringUtils.lastIndexOfAny(*, null) = -1 2590 * StringUtils.lastIndexOfAny(*, []) = -1 2591 * StringUtils.lastIndexOfAny(*, [null]) = -1 2592 * StringUtils.lastIndexOfAny("zzabyycdxx", ["ab", "cd"]) = 6 2593 * StringUtils.lastIndexOfAny("zzabyycdxx", ["cd", "ab"]) = 6 2594 * StringUtils.lastIndexOfAny("zzabyycdxx", ["mn", "op"]) = -1 2595 * StringUtils.lastIndexOfAny("zzabyycdxx", ["mn", "op"]) = -1 2596 * StringUtils.lastIndexOfAny("zzabyycdxx", ["mn", ""]) = 10 2597 * </pre> 2598 * 2599 * @param str the CharSequence to check, may be null 2600 * @param searchStrs the CharSequences to search for, may be null 2601 * @return the last index of any of the CharSequences, -1 if no match 2602 * @since 3.0 Changed signature from lastIndexOfAny(String, String[]) to lastIndexOfAny(CharSequence, CharSequence) 2603 */ 2604 public static int lastIndexOfAny(final CharSequence str, final CharSequence... searchStrs) { 2605 if (str == null || searchStrs == null) { 2606 return INDEX_NOT_FOUND; 2607 } 2608 int ret = INDEX_NOT_FOUND; 2609 int tmp = 0; 2610 for (final CharSequence search : searchStrs) { 2611 if (search == null) { 2612 continue; 2613 } 2614 tmp = CharSequenceUtils.lastIndexOf(str, search, str.length()); 2615 if (tmp > ret) { 2616 ret = tmp; 2617 } 2618 } 2619 return ret; 2620 } 2621 2622 // Substring 2623 //----------------------------------------------------------------------- 2624 /** 2625 * <p>Gets a substring from the specified String avoiding exceptions.</p> 2626 * 2627 * <p>A negative start position can be used to start {@code n} 2628 * characters from the end of the String.</p> 2629 * 2630 * <p>A {@code null} String will return {@code null}. 2631 * An empty ("") String will return "".</p> 2632 * 2633 * <pre> 2634 * StringUtils.substring(null, *) = null 2635 * StringUtils.substring("", *) = "" 2636 * StringUtils.substring("abc", 0) = "abc" 2637 * StringUtils.substring("abc", 2) = "c" 2638 * StringUtils.substring("abc", 4) = "" 2639 * StringUtils.substring("abc", -2) = "bc" 2640 * StringUtils.substring("abc", -4) = "abc" 2641 * </pre> 2642 * 2643 * @param str the String to get the substring from, may be null 2644 * @param start the position to start from, negative means 2645 * count back from the end of the String by this many characters 2646 * @return substring from start position, {@code null} if null String input 2647 */ 2648 public static String substring(final String str, int start) { 2649 if (str == null) { 2650 return null; 2651 } 2652 2653 // handle negatives, which means last n characters 2654 if (start < 0) { 2655 start = str.length() + start; // remember start is negative 2656 } 2657 2658 if (start < 0) { 2659 start = 0; 2660 } 2661 if (start > str.length()) { 2662 return EMPTY; 2663 } 2664 2665 return str.substring(start); 2666 } 2667 2668 /** 2669 * <p>Gets a substring from the specified String avoiding exceptions.</p> 2670 * 2671 * <p>A negative start position can be used to start/end {@code n} 2672 * characters from the end of the String.</p> 2673 * 2674 * <p>The returned substring starts with the character in the {@code start} 2675 * position and ends before the {@code end} position. All position counting is 2676 * zero-based -- i.e., to start at the beginning of the string use 2677 * {@code start = 0}. Negative start and end positions can be used to 2678 * specify offsets relative to the end of the String.</p> 2679 * 2680 * <p>If {@code start} is not strictly to the left of {@code end}, "" 2681 * is returned.</p> 2682 * 2683 * <pre> 2684 * StringUtils.substring(null, *, *) = null 2685 * StringUtils.substring("", * , *) = ""; 2686 * StringUtils.substring("abc", 0, 2) = "ab" 2687 * StringUtils.substring("abc", 2, 0) = "" 2688 * StringUtils.substring("abc", 2, 4) = "c" 2689 * StringUtils.substring("abc", 4, 6) = "" 2690 * StringUtils.substring("abc", 2, 2) = "" 2691 * StringUtils.substring("abc", -2, -1) = "b" 2692 * StringUtils.substring("abc", -4, 2) = "ab" 2693 * </pre> 2694 * 2695 * @param str the String to get the substring from, may be null 2696 * @param start the position to start from, negative means 2697 * count back from the end of the String by this many characters 2698 * @param end the position to end at (exclusive), negative means 2699 * count back from the end of the String by this many characters 2700 * @return substring from start position to end position, 2701 * {@code null} if null String input 2702 */ 2703 public static String substring(final String str, int start, int end) { 2704 if (str == null) { 2705 return null; 2706 } 2707 2708 // handle negatives 2709 if (end < 0) { 2710 end = str.length() + end; // remember end is negative 2711 } 2712 if (start < 0) { 2713 start = str.length() + start; // remember start is negative 2714 } 2715 2716 // check length next 2717 if (end > str.length()) { 2718 end = str.length(); 2719 } 2720 2721 // if start is greater than end, return "" 2722 if (start > end) { 2723 return EMPTY; 2724 } 2725 2726 if (start < 0) { 2727 start = 0; 2728 } 2729 if (end < 0) { 2730 end = 0; 2731 } 2732 2733 return str.substring(start, end); 2734 } 2735 2736 // Left/Right/Mid 2737 //----------------------------------------------------------------------- 2738 /** 2739 * <p>Gets the leftmost {@code len} characters of a String.</p> 2740 * 2741 * <p>If {@code len} characters are not available, or the 2742 * String is {@code null}, the String will be returned without 2743 * an exception. An empty String is returned if len is negative.</p> 2744 * 2745 * <pre> 2746 * StringUtils.left(null, *) = null 2747 * StringUtils.left(*, -ve) = "" 2748 * StringUtils.left("", *) = "" 2749 * StringUtils.left("abc", 0) = "" 2750 * StringUtils.left("abc", 2) = "ab" 2751 * StringUtils.left("abc", 4) = "abc" 2752 * </pre> 2753 * 2754 * @param str the String to get the leftmost characters from, may be null 2755 * @param len the length of the required String 2756 * @return the leftmost characters, {@code null} if null String input 2757 */ 2758 public static String left(final String str, final int len) { 2759 if (str == null) { 2760 return null; 2761 } 2762 if (len < 0) { 2763 return EMPTY; 2764 } 2765 if (str.length() <= len) { 2766 return str; 2767 } 2768 return str.substring(0, len); 2769 } 2770 2771 /** 2772 * <p>Gets the rightmost {@code len} characters of a String.</p> 2773 * 2774 * <p>If {@code len} characters are not available, or the String 2775 * is {@code null}, the String will be returned without an 2776 * an exception. An empty String is returned if len is negative.</p> 2777 * 2778 * <pre> 2779 * StringUtils.right(null, *) = null 2780 * StringUtils.right(*, -ve) = "" 2781 * StringUtils.right("", *) = "" 2782 * StringUtils.right("abc", 0) = "" 2783 * StringUtils.right("abc", 2) = "bc" 2784 * StringUtils.right("abc", 4) = "abc" 2785 * </pre> 2786 * 2787 * @param str the String to get the rightmost characters from, may be null 2788 * @param len the length of the required String 2789 * @return the rightmost characters, {@code null} if null String input 2790 */ 2791 public static String right(final String str, final int len) { 2792 if (str == null) { 2793 return null; 2794 } 2795 if (len < 0) { 2796 return EMPTY; 2797 } 2798 if (str.length() <= len) { 2799 return str; 2800 } 2801 return str.substring(str.length() - len); 2802 } 2803 2804 /** 2805 * <p>Gets {@code len} characters from the middle of a String.</p> 2806 * 2807 * <p>If {@code len} characters are not available, the remainder 2808 * of the String will be returned without an exception. If the 2809 * String is {@code null}, {@code null} will be returned. 2810 * An empty String is returned if len is negative or exceeds the 2811 * length of {@code str}.</p> 2812 * 2813 * <pre> 2814 * StringUtils.mid(null, *, *) = null 2815 * StringUtils.mid(*, *, -ve) = "" 2816 * StringUtils.mid("", 0, *) = "" 2817 * StringUtils.mid("abc", 0, 2) = "ab" 2818 * StringUtils.mid("abc", 0, 4) = "abc" 2819 * StringUtils.mid("abc", 2, 4) = "c" 2820 * StringUtils.mid("abc", 4, 2) = "" 2821 * StringUtils.mid("abc", -2, 2) = "ab" 2822 * </pre> 2823 * 2824 * @param str the String to get the characters from, may be null 2825 * @param pos the position to start from, negative treated as zero 2826 * @param len the length of the required String 2827 * @return the middle characters, {@code null} if null String input 2828 */ 2829 public static String mid(final String str, int pos, final int len) { 2830 if (str == null) { 2831 return null; 2832 } 2833 if (len < 0 || pos > str.length()) { 2834 return EMPTY; 2835 } 2836 if (pos < 0) { 2837 pos = 0; 2838 } 2839 if (str.length() <= pos + len) { 2840 return str.substring(pos); 2841 } 2842 return str.substring(pos, pos + len); 2843 } 2844 2845 private static StringBuilder newStringBuilder(final int noOfItems) { 2846 return new StringBuilder(noOfItems * 16); 2847 } 2848 2849 // SubStringAfter/SubStringBefore 2850 //----------------------------------------------------------------------- 2851 /** 2852 * <p>Gets the substring before the first occurrence of a separator. 2853 * The separator is not returned.</p> 2854 * 2855 * <p>A {@code null} string input will return {@code null}. 2856 * An empty ("") string input will return the empty string. 2857 * A {@code null} separator will return the input string.</p> 2858 * 2859 * <p>If nothing is found, the string input is returned.</p> 2860 * 2861 * <pre> 2862 * StringUtils.substringBefore(null, *) = null 2863 * StringUtils.substringBefore("", *) = "" 2864 * StringUtils.substringBefore("abc", "a") = "" 2865 * StringUtils.substringBefore("abcba", "b") = "a" 2866 * StringUtils.substringBefore("abc", "c") = "ab" 2867 * StringUtils.substringBefore("abc", "d") = "abc" 2868 * StringUtils.substringBefore("abc", "") = "" 2869 * StringUtils.substringBefore("abc", null) = "abc" 2870 * </pre> 2871 * 2872 * @param str the String to get a substring from, may be null 2873 * @param separator the String to search for, may be null 2874 * @return the substring before the first occurrence of the separator, 2875 * {@code null} if null String input 2876 * @since 2.0 2877 */ 2878 public static String substringBefore(final String str, final String separator) { 2879 if (isEmpty(str) || separator == null) { 2880 return str; 2881 } 2882 if (separator.isEmpty()) { 2883 return EMPTY; 2884 } 2885 final int pos = str.indexOf(separator); 2886 if (pos == INDEX_NOT_FOUND) { 2887 return str; 2888 } 2889 return str.substring(0, pos); 2890 } 2891 2892 /** 2893 * <p>Gets the substring after the first occurrence of a separator. 2894 * The separator is not returned.</p> 2895 * 2896 * <p>A {@code null} string input will return {@code null}. 2897 * An empty ("") string input will return the empty string. 2898 * A {@code null} separator will return the empty string if the 2899 * input string is not {@code null}.</p> 2900 * 2901 * <p>If nothing is found, the empty string is returned.</p> 2902 * 2903 * <pre> 2904 * StringUtils.substringAfter(null, *) = null 2905 * StringUtils.substringAfter("", *) = "" 2906 * StringUtils.substringAfter(*, null) = "" 2907 * StringUtils.substringAfter("abc", "a") = "bc" 2908 * StringUtils.substringAfter("abcba", "b") = "cba" 2909 * StringUtils.substringAfter("abc", "c") = "" 2910 * StringUtils.substringAfter("abc", "d") = "" 2911 * StringUtils.substringAfter("abc", "") = "abc" 2912 * </pre> 2913 * 2914 * @param str the String to get a substring from, may be null 2915 * @param separator the String to search for, may be null 2916 * @return the substring after the first occurrence of the separator, 2917 * {@code null} if null String input 2918 * @since 2.0 2919 */ 2920 public static String substringAfter(final String str, final String separator) { 2921 if (isEmpty(str)) { 2922 return str; 2923 } 2924 if (separator == null) { 2925 return EMPTY; 2926 } 2927 final int pos = str.indexOf(separator); 2928 if (pos == INDEX_NOT_FOUND) { 2929 return EMPTY; 2930 } 2931 return str.substring(pos + separator.length()); 2932 } 2933 2934 /** 2935 * <p>Gets the substring before the last occurrence of a separator. 2936 * The separator is not returned.</p> 2937 * 2938 * <p>A {@code null} string input will return {@code null}. 2939 * An empty ("") string input will return the empty string. 2940 * An empty or {@code null} separator will return the input string.</p> 2941 * 2942 * <p>If nothing is found, the string input is returned.</p> 2943 * 2944 * <pre> 2945 * StringUtils.substringBeforeLast(null, *) = null 2946 * StringUtils.substringBeforeLast("", *) = "" 2947 * StringUtils.substringBeforeLast("abcba", "b") = "abc" 2948 * StringUtils.substringBeforeLast("abc", "c") = "ab" 2949 * StringUtils.substringBeforeLast("a", "a") = "" 2950 * StringUtils.substringBeforeLast("a", "z") = "a" 2951 * StringUtils.substringBeforeLast("a", null) = "a" 2952 * StringUtils.substringBeforeLast("a", "") = "a" 2953 * </pre> 2954 * 2955 * @param str the String to get a substring from, may be null 2956 * @param separator the String to search for, may be null 2957 * @return the substring before the last occurrence of the separator, 2958 * {@code null} if null String input 2959 * @since 2.0 2960 */ 2961 public static String substringBeforeLast(final String str, final String separator) { 2962 if (isEmpty(str) || isEmpty(separator)) { 2963 return str; 2964 } 2965 final int pos = str.lastIndexOf(separator); 2966 if (pos == INDEX_NOT_FOUND) { 2967 return str; 2968 } 2969 return str.substring(0, pos); 2970 } 2971 2972 /** 2973 * <p>Gets the substring after the last occurrence of a separator. 2974 * The separator is not returned.</p> 2975 * 2976 * <p>A {@code null} string input will return {@code null}. 2977 * An empty ("") string input will return the empty string. 2978 * An empty or {@code null} separator will return the empty string if 2979 * the input string is not {@code null}.</p> 2980 * 2981 * <p>If nothing is found, the empty string is returned.</p> 2982 * 2983 * <pre> 2984 * StringUtils.substringAfterLast(null, *) = null 2985 * StringUtils.substringAfterLast("", *) = "" 2986 * StringUtils.substringAfterLast(*, "") = "" 2987 * StringUtils.substringAfterLast(*, null) = "" 2988 * StringUtils.substringAfterLast("abc", "a") = "bc" 2989 * StringUtils.substringAfterLast("abcba", "b") = "a" 2990 * StringUtils.substringAfterLast("abc", "c") = "" 2991 * StringUtils.substringAfterLast("a", "a") = "" 2992 * StringUtils.substringAfterLast("a", "z") = "" 2993 * </pre> 2994 * 2995 * @param str the String to get a substring from, may be null 2996 * @param separator the String to search for, may be null 2997 * @return the substring after the last occurrence of the separator, 2998 * {@code null} if null String input 2999 * @since 2.0 3000 */ 3001 public static String substringAfterLast(final String str, final String separator) { 3002 if (isEmpty(str)) { 3003 return str; 3004 } 3005 if (isEmpty(separator)) { 3006 return EMPTY; 3007 } 3008 final int pos = str.lastIndexOf(separator); 3009 if (pos == INDEX_NOT_FOUND || pos == str.length() - separator.length()) { 3010 return EMPTY; 3011 } 3012 return str.substring(pos + separator.length()); 3013 } 3014 3015 // Substring between 3016 //----------------------------------------------------------------------- 3017 /** 3018 * <p>Gets the String that is nested in between two instances of the 3019 * same String.</p> 3020 * 3021 * <p>A {@code null} input String returns {@code null}. 3022 * A {@code null} tag returns {@code null}.</p> 3023 * 3024 * <pre> 3025 * StringUtils.substringBetween(null, *) = null 3026 * StringUtils.substringBetween("", "") = "" 3027 * StringUtils.substringBetween("", "tag") = null 3028 * StringUtils.substringBetween("tagabctag", null) = null 3029 * StringUtils.substringBetween("tagabctag", "") = "" 3030 * StringUtils.substringBetween("tagabctag", "tag") = "abc" 3031 * </pre> 3032 * 3033 * @param str the String containing the substring, may be null 3034 * @param tag the String before and after the substring, may be null 3035 * @return the substring, {@code null} if no match 3036 * @since 2.0 3037 */ 3038 public static String substringBetween(final String str, final String tag) { 3039 return substringBetween(str, tag, tag); 3040 } 3041 3042 /** 3043 * <p>Gets the String that is nested in between two Strings. 3044 * Only the first match is returned.</p> 3045 * 3046 * <p>A {@code null} input String returns {@code null}. 3047 * A {@code null} open/close returns {@code null} (no match). 3048 * An empty ("") open and close returns an empty string.</p> 3049 * 3050 * <pre> 3051 * StringUtils.substringBetween("wx[b]yz", "[", "]") = "b" 3052 * StringUtils.substringBetween(null, *, *) = null 3053 * StringUtils.substringBetween(*, null, *) = null 3054 * StringUtils.substringBetween(*, *, null) = null 3055 * StringUtils.substringBetween("", "", "") = "" 3056 * StringUtils.substringBetween("", "", "]") = null 3057 * StringUtils.substringBetween("", "[", "]") = null 3058 * StringUtils.substringBetween("yabcz", "", "") = "" 3059 * StringUtils.substringBetween("yabcz", "y", "z") = "abc" 3060 * StringUtils.substringBetween("yabczyabcz", "y", "z") = "abc" 3061 * </pre> 3062 * 3063 * @param str the String containing the substring, may be null 3064 * @param open the String before the substring, may be null 3065 * @param close the String after the substring, may be null 3066 * @return the substring, {@code null} if no match 3067 * @since 2.0 3068 */ 3069 public static String substringBetween(final String str, final String open, final String close) { 3070 if (str == null || open == null || close == null) { 3071 return null; 3072 } 3073 final int start = str.indexOf(open); 3074 if (start != INDEX_NOT_FOUND) { 3075 final int end = str.indexOf(close, start + open.length()); 3076 if (end != INDEX_NOT_FOUND) { 3077 return str.substring(start + open.length(), end); 3078 } 3079 } 3080 return null; 3081 } 3082 3083 /** 3084 * <p>Searches a String for substrings delimited by a start and end tag, 3085 * returning all matching substrings in an array.</p> 3086 * 3087 * <p>A {@code null} input String returns {@code null}. 3088 * A {@code null} open/close returns {@code null} (no match). 3089 * An empty ("") open/close returns {@code null} (no match).</p> 3090 * 3091 * <pre> 3092 * StringUtils.substringsBetween("[a][b][c]", "[", "]") = ["a","b","c"] 3093 * StringUtils.substringsBetween(null, *, *) = null 3094 * StringUtils.substringsBetween(*, null, *) = null 3095 * StringUtils.substringsBetween(*, *, null) = null 3096 * StringUtils.substringsBetween("", "[", "]") = [] 3097 * </pre> 3098 * 3099 * @param str the String containing the substrings, null returns null, empty returns empty 3100 * @param open the String identifying the start of the substring, empty returns null 3101 * @param close the String identifying the end of the substring, empty returns null 3102 * @return a String Array of substrings, or {@code null} if no match 3103 * @since 2.3 3104 */ 3105 public static String[] substringsBetween(final String str, final String open, final String close) { 3106 if (str == null || isEmpty(open) || isEmpty(close)) { 3107 return null; 3108 } 3109 final int strLen = str.length(); 3110 if (strLen == 0) { 3111 return ArrayUtils.EMPTY_STRING_ARRAY; 3112 } 3113 final int closeLen = close.length(); 3114 final int openLen = open.length(); 3115 final List<String> list = new ArrayList<>(); 3116 int pos = 0; 3117 while (pos < strLen - closeLen) { 3118 int start = str.indexOf(open, pos); 3119 if (start < 0) { 3120 break; 3121 } 3122 start += openLen; 3123 final int end = str.indexOf(close, start); 3124 if (end < 0) { 3125 break; 3126 } 3127 list.add(str.substring(start, end)); 3128 pos = end + closeLen; 3129 } 3130 if (list.isEmpty()) { 3131 return null; 3132 } 3133 return list.toArray(new String [list.size()]); 3134 } 3135 3136 // Nested extraction 3137 //----------------------------------------------------------------------- 3138 3139 // Splitting 3140 //----------------------------------------------------------------------- 3141 /** 3142 * <p>Splits the provided text into an array, using whitespace as the 3143 * separator. 3144 * Whitespace is defined by {@link Character#isWhitespace(char)}.</p> 3145 * 3146 * <p>The separator is not included in the returned String array. 3147 * Adjacent separators are treated as one separator. 3148 * For more control over the split use the StrTokenizer class.</p> 3149 * 3150 * <p>A {@code null} input String returns {@code null}.</p> 3151 * 3152 * <pre> 3153 * StringUtils.split(null) = null 3154 * StringUtils.split("") = [] 3155 * StringUtils.split("abc def") = ["abc", "def"] 3156 * StringUtils.split("abc def") = ["abc", "def"] 3157 * StringUtils.split(" abc ") = ["abc"] 3158 * </pre> 3159 * 3160 * @param str the String to parse, may be null 3161 * @return an array of parsed Strings, {@code null} if null String input 3162 */ 3163 public static String[] split(final String str) { 3164 return split(str, null, -1); 3165 } 3166 3167 /** 3168 * <p>Splits the provided text into an array, separator specified. 3169 * This is an alternative to using StringTokenizer.</p> 3170 * 3171 * <p>The separator is not included in the returned String array. 3172 * Adjacent separators are treated as one separator. 3173 * For more control over the split use the StrTokenizer class.</p> 3174 * 3175 * <p>A {@code null} input String returns {@code null}.</p> 3176 * 3177 * <pre> 3178 * StringUtils.split(null, *) = null 3179 * StringUtils.split("", *) = [] 3180 * StringUtils.split("a.b.c", '.') = ["a", "b", "c"] 3181 * StringUtils.split("a..b.c", '.') = ["a", "b", "c"] 3182 * StringUtils.split("a:b:c", '.') = ["a:b:c"] 3183 * StringUtils.split("a b c", ' ') = ["a", "b", "c"] 3184 * </pre> 3185 * 3186 * @param str the String to parse, may be null 3187 * @param separatorChar the character used as the delimiter 3188 * @return an array of parsed Strings, {@code null} if null String input 3189 * @since 2.0 3190 */ 3191 public static String[] split(final String str, final char separatorChar) { 3192 return splitWorker(str, separatorChar, false); 3193 } 3194 3195 /** 3196 * <p>Splits the provided text into an array, separators specified. 3197 * This is an alternative to using StringTokenizer.</p> 3198 * 3199 * <p>The separator is not included in the returned String array. 3200 * Adjacent separators are treated as one separator. 3201 * For more control over the split use the StrTokenizer class.</p> 3202 * 3203 * <p>A {@code null} input String returns {@code null}. 3204 * A {@code null} separatorChars splits on whitespace.</p> 3205 * 3206 * <pre> 3207 * StringUtils.split(null, *) = null 3208 * StringUtils.split("", *) = [] 3209 * StringUtils.split("abc def", null) = ["abc", "def"] 3210 * StringUtils.split("abc def", " ") = ["abc", "def"] 3211 * StringUtils.split("abc def", " ") = ["abc", "def"] 3212 * StringUtils.split("ab:cd:ef", ":") = ["ab", "cd", "ef"] 3213 * </pre> 3214 * 3215 * @param str the String to parse, may be null 3216 * @param separatorChars the characters used as the delimiters, 3217 * {@code null} splits on whitespace 3218 * @return an array of parsed Strings, {@code null} if null String input 3219 */ 3220 public static String[] split(final String str, final String separatorChars) { 3221 return splitWorker(str, separatorChars, -1, false); 3222 } 3223 3224 /** 3225 * <p>Splits the provided text into an array with a maximum length, 3226 * separators specified.</p> 3227 * 3228 * <p>The separator is not included in the returned String array. 3229 * Adjacent separators are treated as one separator.</p> 3230 * 3231 * <p>A {@code null} input String returns {@code null}. 3232 * A {@code null} separatorChars splits on whitespace.</p> 3233 * 3234 * <p>If more than {@code max} delimited substrings are found, the last 3235 * returned string includes all characters after the first {@code max - 1} 3236 * returned strings (including separator characters).</p> 3237 * 3238 * <pre> 3239 * StringUtils.split(null, *, *) = null 3240 * StringUtils.split("", *, *) = [] 3241 * StringUtils.split("ab cd ef", null, 0) = ["ab", "cd", "ef"] 3242 * StringUtils.split("ab cd ef", null, 0) = ["ab", "cd", "ef"] 3243 * StringUtils.split("ab:cd:ef", ":", 0) = ["ab", "cd", "ef"] 3244 * StringUtils.split("ab:cd:ef", ":", 2) = ["ab", "cd:ef"] 3245 * </pre> 3246 * 3247 * @param str the String to parse, may be null 3248 * @param separatorChars the characters used as the delimiters, 3249 * {@code null} splits on whitespace 3250 * @param max the maximum number of elements to include in the 3251 * array. A zero or negative value implies no limit 3252 * @return an array of parsed Strings, {@code null} if null String input 3253 */ 3254 public static String[] split(final String str, final String separatorChars, final int max) { 3255 return splitWorker(str, separatorChars, max, false); 3256 } 3257 3258 /** 3259 * <p>Splits the provided text into an array, separator string specified.</p> 3260 * 3261 * <p>The separator(s) will not be included in the returned String array. 3262 * Adjacent separators are treated as one separator.</p> 3263 * 3264 * <p>A {@code null} input String returns {@code null}. 3265 * A {@code null} separator splits on whitespace.</p> 3266 * 3267 * <pre> 3268 * StringUtils.splitByWholeSeparator(null, *) = null 3269 * StringUtils.splitByWholeSeparator("", *) = [] 3270 * StringUtils.splitByWholeSeparator("ab de fg", null) = ["ab", "de", "fg"] 3271 * StringUtils.splitByWholeSeparator("ab de fg", null) = ["ab", "de", "fg"] 3272 * StringUtils.splitByWholeSeparator("ab:cd:ef", ":") = ["ab", "cd", "ef"] 3273 * StringUtils.splitByWholeSeparator("ab-!-cd-!-ef", "-!-") = ["ab", "cd", "ef"] 3274 * </pre> 3275 * 3276 * @param str the String to parse, may be null 3277 * @param separator String containing the String to be used as a delimiter, 3278 * {@code null} splits on whitespace 3279 * @return an array of parsed Strings, {@code null} if null String was input 3280 */ 3281 public static String[] splitByWholeSeparator(final String str, final String separator) { 3282 return splitByWholeSeparatorWorker(str, separator, -1, false); 3283 } 3284 3285 /** 3286 * <p>Splits the provided text into an array, separator string specified. 3287 * Returns a maximum of {@code max} substrings.</p> 3288 * 3289 * <p>The separator(s) will not be included in the returned String array. 3290 * Adjacent separators are treated as one separator.</p> 3291 * 3292 * <p>A {@code null} input String returns {@code null}. 3293 * A {@code null} separator splits on whitespace.</p> 3294 * 3295 * <pre> 3296 * StringUtils.splitByWholeSeparator(null, *, *) = null 3297 * StringUtils.splitByWholeSeparator("", *, *) = [] 3298 * StringUtils.splitByWholeSeparator("ab de fg", null, 0) = ["ab", "de", "fg"] 3299 * StringUtils.splitByWholeSeparator("ab de fg", null, 0) = ["ab", "de", "fg"] 3300 * StringUtils.splitByWholeSeparator("ab:cd:ef", ":", 2) = ["ab", "cd:ef"] 3301 * StringUtils.splitByWholeSeparator("ab-!-cd-!-ef", "-!-", 5) = ["ab", "cd", "ef"] 3302 * StringUtils.splitByWholeSeparator("ab-!-cd-!-ef", "-!-", 2) = ["ab", "cd-!-ef"] 3303 * </pre> 3304 * 3305 * @param str the String to parse, may be null 3306 * @param separator String containing the String to be used as a delimiter, 3307 * {@code null} splits on whitespace 3308 * @param max the maximum number of elements to include in the returned 3309 * array. A zero or negative value implies no limit. 3310 * @return an array of parsed Strings, {@code null} if null String was input 3311 */ 3312 public static String[] splitByWholeSeparator( final String str, final String separator, final int max) { 3313 return splitByWholeSeparatorWorker(str, separator, max, false); 3314 } 3315 3316 /** 3317 * <p>Splits the provided text into an array, separator string specified. </p> 3318 * 3319 * <p>The separator is not included in the returned String array. 3320 * Adjacent separators are treated as separators for empty tokens. 3321 * For more control over the split use the StrTokenizer class.</p> 3322 * 3323 * <p>A {@code null} input String returns {@code null}. 3324 * A {@code null} separator splits on whitespace.</p> 3325 * 3326 * <pre> 3327 * StringUtils.splitByWholeSeparatorPreserveAllTokens(null, *) = null 3328 * StringUtils.splitByWholeSeparatorPreserveAllTokens("", *) = [] 3329 * StringUtils.splitByWholeSeparatorPreserveAllTokens("ab de fg", null) = ["ab", "de", "fg"] 3330 * StringUtils.splitByWholeSeparatorPreserveAllTokens("ab de fg", null) = ["ab", "", "", "de", "fg"] 3331 * StringUtils.splitByWholeSeparatorPreserveAllTokens("ab:cd:ef", ":") = ["ab", "cd", "ef"] 3332 * StringUtils.splitByWholeSeparatorPreserveAllTokens("ab-!-cd-!-ef", "-!-") = ["ab", "cd", "ef"] 3333 * </pre> 3334 * 3335 * @param str the String to parse, may be null 3336 * @param separator String containing the String to be used as a delimiter, 3337 * {@code null} splits on whitespace 3338 * @return an array of parsed Strings, {@code null} if null String was input 3339 * @since 2.4 3340 */ 3341 public static String[] splitByWholeSeparatorPreserveAllTokens(final String str, final String separator) { 3342 return splitByWholeSeparatorWorker(str, separator, -1, true); 3343 } 3344 3345 /** 3346 * <p>Splits the provided text into an array, separator string specified. 3347 * Returns a maximum of {@code max} substrings.</p> 3348 * 3349 * <p>The separator is not included in the returned String array. 3350 * Adjacent separators are treated as separators for empty tokens. 3351 * For more control over the split use the StrTokenizer class.</p> 3352 * 3353 * <p>A {@code null} input String returns {@code null}. 3354 * A {@code null} separator splits on whitespace.</p> 3355 * 3356 * <pre> 3357 * StringUtils.splitByWholeSeparatorPreserveAllTokens(null, *, *) = null 3358 * StringUtils.splitByWholeSeparatorPreserveAllTokens("", *, *) = [] 3359 * StringUtils.splitByWholeSeparatorPreserveAllTokens("ab de fg", null, 0) = ["ab", "de", "fg"] 3360 * StringUtils.splitByWholeSeparatorPreserveAllTokens("ab de fg", null, 0) = ["ab", "", "", "de", "fg"] 3361 * StringUtils.splitByWholeSeparatorPreserveAllTokens("ab:cd:ef", ":", 2) = ["ab", "cd:ef"] 3362 * StringUtils.splitByWholeSeparatorPreserveAllTokens("ab-!-cd-!-ef", "-!-", 5) = ["ab", "cd", "ef"] 3363 * StringUtils.splitByWholeSeparatorPreserveAllTokens("ab-!-cd-!-ef", "-!-", 2) = ["ab", "cd-!-ef"] 3364 * </pre> 3365 * 3366 * @param str the String to parse, may be null 3367 * @param separator String containing the String to be used as a delimiter, 3368 * {@code null} splits on whitespace 3369 * @param max the maximum number of elements to include in the returned 3370 * array. A zero or negative value implies no limit. 3371 * @return an array of parsed Strings, {@code null} if null String was input 3372 * @since 2.4 3373 */ 3374 public static String[] splitByWholeSeparatorPreserveAllTokens(final String str, final String separator, final int max) { 3375 return splitByWholeSeparatorWorker(str, separator, max, true); 3376 } 3377 3378 /** 3379 * Performs the logic for the {@code splitByWholeSeparatorPreserveAllTokens} methods. 3380 * 3381 * @param str the String to parse, may be {@code null} 3382 * @param separator String containing the String to be used as a delimiter, 3383 * {@code null} splits on whitespace 3384 * @param max the maximum number of elements to include in the returned 3385 * array. A zero or negative value implies no limit. 3386 * @param preserveAllTokens if {@code true}, adjacent separators are 3387 * treated as empty token separators; if {@code false}, adjacent 3388 * separators are treated as one separator. 3389 * @return an array of parsed Strings, {@code null} if null String input 3390 * @since 2.4 3391 */ 3392 private static String[] splitByWholeSeparatorWorker( 3393 final String str, final String separator, final int max, final boolean preserveAllTokens) { 3394 if (str == null) { 3395 return null; 3396 } 3397 3398 final int len = str.length(); 3399 3400 if (len == 0) { 3401 return ArrayUtils.EMPTY_STRING_ARRAY; 3402 } 3403 3404 if (separator == null || EMPTY.equals(separator)) { 3405 // Split on whitespace. 3406 return splitWorker(str, null, max, preserveAllTokens); 3407 } 3408 3409 final int separatorLength = separator.length(); 3410 3411 final ArrayList<String> substrings = new ArrayList<>(); 3412 int numberOfSubstrings = 0; 3413 int beg = 0; 3414 int end = 0; 3415 while (end < len) { 3416 end = str.indexOf(separator, beg); 3417 3418 if (end > -1) { 3419 if (end > beg) { 3420 numberOfSubstrings += 1; 3421 3422 if (numberOfSubstrings == max) { 3423 end = len; 3424 substrings.add(str.substring(beg)); 3425 } else { 3426 // The following is OK, because String.substring( beg, end ) excludes 3427 // the character at the position 'end'. 3428 substrings.add(str.substring(beg, end)); 3429 3430 // Set the starting point for the next search. 3431 // The following is equivalent to beg = end + (separatorLength - 1) + 1, 3432 // which is the right calculation: 3433 beg = end + separatorLength; 3434 } 3435 } else { 3436 // We found a consecutive occurrence of the separator, so skip it. 3437 if (preserveAllTokens) { 3438 numberOfSubstrings += 1; 3439 if (numberOfSubstrings == max) { 3440 end = len; 3441 substrings.add(str.substring(beg)); 3442 } else { 3443 substrings.add(EMPTY); 3444 } 3445 } 3446 beg = end + separatorLength; 3447 } 3448 } else { 3449 // String.substring( beg ) goes from 'beg' to the end of the String. 3450 substrings.add(str.substring(beg)); 3451 end = len; 3452 } 3453 } 3454 3455 return substrings.toArray(new String[substrings.size()]); 3456 } 3457 3458 // ----------------------------------------------------------------------- 3459 /** 3460 * <p>Splits the provided text into an array, using whitespace as the 3461 * separator, preserving all tokens, including empty tokens created by 3462 * adjacent separators. This is an alternative to using StringTokenizer. 3463 * Whitespace is defined by {@link Character#isWhitespace(char)}.</p> 3464 * 3465 * <p>The separator is not included in the returned String array. 3466 * Adjacent separators are treated as separators for empty tokens. 3467 * For more control over the split use the StrTokenizer class.</p> 3468 * 3469 * <p>A {@code null} input String returns {@code null}.</p> 3470 * 3471 * <pre> 3472 * StringUtils.splitPreserveAllTokens(null) = null 3473 * StringUtils.splitPreserveAllTokens("") = [] 3474 * StringUtils.splitPreserveAllTokens("abc def") = ["abc", "def"] 3475 * StringUtils.splitPreserveAllTokens("abc def") = ["abc", "", "def"] 3476 * StringUtils.splitPreserveAllTokens(" abc ") = ["", "abc", ""] 3477 * </pre> 3478 * 3479 * @param str the String to parse, may be {@code null} 3480 * @return an array of parsed Strings, {@code null} if null String input 3481 * @since 2.1 3482 */ 3483 public static String[] splitPreserveAllTokens(final String str) { 3484 return splitWorker(str, null, -1, true); 3485 } 3486 3487 /** 3488 * <p>Splits the provided text into an array, separator specified, 3489 * preserving all tokens, including empty tokens created by adjacent 3490 * separators. This is an alternative to using StringTokenizer.</p> 3491 * 3492 * <p>The separator is not included in the returned String array. 3493 * Adjacent separators are treated as separators for empty tokens. 3494 * For more control over the split use the StrTokenizer class.</p> 3495 * 3496 * <p>A {@code null} input String returns {@code null}.</p> 3497 * 3498 * <pre> 3499 * StringUtils.splitPreserveAllTokens(null, *) = null 3500 * StringUtils.splitPreserveAllTokens("", *) = [] 3501 * StringUtils.splitPreserveAllTokens("a.b.c", '.') = ["a", "b", "c"] 3502 * StringUtils.splitPreserveAllTokens("a..b.c", '.') = ["a", "", "b", "c"] 3503 * StringUtils.splitPreserveAllTokens("a:b:c", '.') = ["a:b:c"] 3504 * StringUtils.splitPreserveAllTokens("a\tb\nc", null) = ["a", "b", "c"] 3505 * StringUtils.splitPreserveAllTokens("a b c", ' ') = ["a", "b", "c"] 3506 * StringUtils.splitPreserveAllTokens("a b c ", ' ') = ["a", "b", "c", ""] 3507 * StringUtils.splitPreserveAllTokens("a b c ", ' ') = ["a", "b", "c", "", ""] 3508 * StringUtils.splitPreserveAllTokens(" a b c", ' ') = ["", a", "b", "c"] 3509 * StringUtils.splitPreserveAllTokens(" a b c", ' ') = ["", "", a", "b", "c"] 3510 * StringUtils.splitPreserveAllTokens(" a b c ", ' ') = ["", a", "b", "c", ""] 3511 * </pre> 3512 * 3513 * @param str the String to parse, may be {@code null} 3514 * @param separatorChar the character used as the delimiter, 3515 * {@code null} splits on whitespace 3516 * @return an array of parsed Strings, {@code null} if null String input 3517 * @since 2.1 3518 */ 3519 public static String[] splitPreserveAllTokens(final String str, final char separatorChar) { 3520 return splitWorker(str, separatorChar, true); 3521 } 3522 3523 /** 3524 * Performs the logic for the {@code split} and 3525 * {@code splitPreserveAllTokens} methods that do not return a 3526 * maximum array length. 3527 * 3528 * @param str the String to parse, may be {@code null} 3529 * @param separatorChar the separate character 3530 * @param preserveAllTokens if {@code true}, adjacent separators are 3531 * treated as empty token separators; if {@code false}, adjacent 3532 * separators are treated as one separator. 3533 * @return an array of parsed Strings, {@code null} if null String input 3534 */ 3535 private static String[] splitWorker(final String str, final char separatorChar, final boolean preserveAllTokens) { 3536 // Performance tuned for 2.0 (JDK1.4) 3537 3538 if (str == null) { 3539 return null; 3540 } 3541 final int len = str.length(); 3542 if (len == 0) { 3543 return ArrayUtils.EMPTY_STRING_ARRAY; 3544 } 3545 final List<String> list = new ArrayList<>(); 3546 int i = 0, start = 0; 3547 boolean match = false; 3548 boolean lastMatch = false; 3549 while (i < len) { 3550 if (str.charAt(i) == separatorChar) { 3551 if (match || preserveAllTokens) { 3552 list.add(str.substring(start, i)); 3553 match = false; 3554 lastMatch = true; 3555 } 3556 start = ++i; 3557 continue; 3558 } 3559 lastMatch = false; 3560 match = true; 3561 i++; 3562 } 3563 if (match || preserveAllTokens && lastMatch) { 3564 list.add(str.substring(start, i)); 3565 } 3566 return list.toArray(new String[list.size()]); 3567 } 3568 3569 /** 3570 * <p>Splits the provided text into an array, separators specified, 3571 * preserving all tokens, including empty tokens created by adjacent 3572 * separators. This is an alternative to using StringTokenizer.</p> 3573 * 3574 * <p>The separator is not included in the returned String array. 3575 * Adjacent separators are treated as separators for empty tokens. 3576 * For more control over the split use the StrTokenizer class.</p> 3577 * 3578 * <p>A {@code null} input String returns {@code null}. 3579 * A {@code null} separatorChars splits on whitespace.</p> 3580 * 3581 * <pre> 3582 * StringUtils.splitPreserveAllTokens(null, *) = null 3583 * StringUtils.splitPreserveAllTokens("", *) = [] 3584 * StringUtils.splitPreserveAllTokens("abc def", null) = ["abc", "def"] 3585 * StringUtils.splitPreserveAllTokens("abc def", " ") = ["abc", "def"] 3586 * StringUtils.splitPreserveAllTokens("abc def", " ") = ["abc", "", def"] 3587 * StringUtils.splitPreserveAllTokens("ab:cd:ef", ":") = ["ab", "cd", "ef"] 3588 * StringUtils.splitPreserveAllTokens("ab:cd:ef:", ":") = ["ab", "cd", "ef", ""] 3589 * StringUtils.splitPreserveAllTokens("ab:cd:ef::", ":") = ["ab", "cd", "ef", "", ""] 3590 * StringUtils.splitPreserveAllTokens("ab::cd:ef", ":") = ["ab", "", cd", "ef"] 3591 * StringUtils.splitPreserveAllTokens(":cd:ef", ":") = ["", cd", "ef"] 3592 * StringUtils.splitPreserveAllTokens("::cd:ef", ":") = ["", "", cd", "ef"] 3593 * StringUtils.splitPreserveAllTokens(":cd:ef:", ":") = ["", cd", "ef", ""] 3594 * </pre> 3595 * 3596 * @param str the String to parse, may be {@code null} 3597 * @param separatorChars the characters used as the delimiters, 3598 * {@code null} splits on whitespace 3599 * @return an array of parsed Strings, {@code null} if null String input 3600 * @since 2.1 3601 */ 3602 public static String[] splitPreserveAllTokens(final String str, final String separatorChars) { 3603 return splitWorker(str, separatorChars, -1, true); 3604 } 3605 3606 /** 3607 * <p>Splits the provided text into an array with a maximum length, 3608 * separators specified, preserving all tokens, including empty tokens 3609 * created by adjacent separators.</p> 3610 * 3611 * <p>The separator is not included in the returned String array. 3612 * Adjacent separators are treated as separators for empty tokens. 3613 * Adjacent separators are treated as one separator.</p> 3614 * 3615 * <p>A {@code null} input String returns {@code null}. 3616 * A {@code null} separatorChars splits on whitespace.</p> 3617 * 3618 * <p>If more than {@code max} delimited substrings are found, the last 3619 * returned string includes all characters after the first {@code max - 1} 3620 * returned strings (including separator characters).</p> 3621 * 3622 * <pre> 3623 * StringUtils.splitPreserveAllTokens(null, *, *) = null 3624 * StringUtils.splitPreserveAllTokens("", *, *) = [] 3625 * StringUtils.splitPreserveAllTokens("ab de fg", null, 0) = ["ab", "cd", "ef"] 3626 * StringUtils.splitPreserveAllTokens("ab de fg", null, 0) = ["ab", "cd", "ef"] 3627 * StringUtils.splitPreserveAllTokens("ab:cd:ef", ":", 0) = ["ab", "cd", "ef"] 3628 * StringUtils.splitPreserveAllTokens("ab:cd:ef", ":", 2) = ["ab", "cd:ef"] 3629 * StringUtils.splitPreserveAllTokens("ab de fg", null, 2) = ["ab", " de fg"] 3630 * StringUtils.splitPreserveAllTokens("ab de fg", null, 3) = ["ab", "", " de fg"] 3631 * StringUtils.splitPreserveAllTokens("ab de fg", null, 4) = ["ab", "", "", "de fg"] 3632 * </pre> 3633 * 3634 * @param str the String to parse, may be {@code null} 3635 * @param separatorChars the characters used as the delimiters, 3636 * {@code null} splits on whitespace 3637 * @param max the maximum number of elements to include in the 3638 * array. A zero or negative value implies no limit 3639 * @return an array of parsed Strings, {@code null} if null String input 3640 * @since 2.1 3641 */ 3642 public static String[] splitPreserveAllTokens(final String str, final String separatorChars, final int max) { 3643 return splitWorker(str, separatorChars, max, true); 3644 } 3645 3646 /** 3647 * Performs the logic for the {@code split} and 3648 * {@code splitPreserveAllTokens} methods that return a maximum array 3649 * length. 3650 * 3651 * @param str the String to parse, may be {@code null} 3652 * @param separatorChars the separate character 3653 * @param max the maximum number of elements to include in the 3654 * array. A zero or negative value implies no limit. 3655 * @param preserveAllTokens if {@code true}, adjacent separators are 3656 * treated as empty token separators; if {@code false}, adjacent 3657 * separators are treated as one separator. 3658 * @return an array of parsed Strings, {@code null} if null String input 3659 */ 3660 private static String[] splitWorker(final String str, final String separatorChars, final int max, final boolean preserveAllTokens) { 3661 // Performance tuned for 2.0 (JDK1.4) 3662 // Direct code is quicker than StringTokenizer. 3663 // Also, StringTokenizer uses isSpace() not isWhitespace() 3664 3665 if (str == null) { 3666 return null; 3667 } 3668 final int len = str.length(); 3669 if (len == 0) { 3670 return ArrayUtils.EMPTY_STRING_ARRAY; 3671 } 3672 final List<String> list = new ArrayList<>(); 3673 int sizePlus1 = 1; 3674 int i = 0, start = 0; 3675 boolean match = false; 3676 boolean lastMatch = false; 3677 if (separatorChars == null) { 3678 // Null separator means use whitespace 3679 while (i < len) { 3680 if (Character.isWhitespace(str.charAt(i))) { 3681 if (match || preserveAllTokens) { 3682 lastMatch = true; 3683 if (sizePlus1++ == max) { 3684 i = len; 3685 lastMatch = false; 3686 } 3687 list.add(str.substring(start, i)); 3688 match = false; 3689 } 3690 start = ++i; 3691 continue; 3692 } 3693 lastMatch = false; 3694 match = true; 3695 i++; 3696 } 3697 } else if (separatorChars.length() == 1) { 3698 // Optimise 1 character case 3699 final char sep = separatorChars.charAt(0); 3700 while (i < len) { 3701 if (str.charAt(i) == sep) { 3702 if (match || preserveAllTokens) { 3703 lastMatch = true; 3704 if (sizePlus1++ == max) { 3705 i = len; 3706 lastMatch = false; 3707 } 3708 list.add(str.substring(start, i)); 3709 match = false; 3710 } 3711 start = ++i; 3712 continue; 3713 } 3714 lastMatch = false; 3715 match = true; 3716 i++; 3717 } 3718 } else { 3719 // standard case 3720 while (i < len) { 3721 if (separatorChars.indexOf(str.charAt(i)) >= 0) { 3722 if (match || preserveAllTokens) { 3723 lastMatch = true; 3724 if (sizePlus1++ == max) { 3725 i = len; 3726 lastMatch = false; 3727 } 3728 list.add(str.substring(start, i)); 3729 match = false; 3730 } 3731 start = ++i; 3732 continue; 3733 } 3734 lastMatch = false; 3735 match = true; 3736 i++; 3737 } 3738 } 3739 if (match || preserveAllTokens && lastMatch) { 3740 list.add(str.substring(start, i)); 3741 } 3742 return list.toArray(new String[list.size()]); 3743 } 3744 3745 /** 3746 * <p>Splits a String by Character type as returned by 3747 * {@code java.lang.Character.getType(char)}. Groups of contiguous 3748 * characters of the same type are returned as complete tokens. 3749 * <pre> 3750 * StringUtils.splitByCharacterType(null) = null 3751 * StringUtils.splitByCharacterType("") = [] 3752 * StringUtils.splitByCharacterType("ab de fg") = ["ab", " ", "de", " ", "fg"] 3753 * StringUtils.splitByCharacterType("ab de fg") = ["ab", " ", "de", " ", "fg"] 3754 * StringUtils.splitByCharacterType("ab:cd:ef") = ["ab", ":", "cd", ":", "ef"] 3755 * StringUtils.splitByCharacterType("number5") = ["number", "5"] 3756 * StringUtils.splitByCharacterType("fooBar") = ["foo", "B", "ar"] 3757 * StringUtils.splitByCharacterType("foo200Bar") = ["foo", "200", "B", "ar"] 3758 * StringUtils.splitByCharacterType("ASFRules") = ["ASFR", "ules"] 3759 * </pre> 3760 * @param str the String to split, may be {@code null} 3761 * @return an array of parsed Strings, {@code null} if null String input 3762 * @since 2.4 3763 */ 3764 public static String[] splitByCharacterType(final String str) { 3765 return splitByCharacterType(str, false); 3766 } 3767 3768 /** 3769 * <p>Splits a String by Character type as returned by 3770 * {@code java.lang.Character.getType(char)}. Groups of contiguous 3771 * characters of the same type are returned as complete tokens, with the 3772 * following exception: the character of type 3773 * {@code Character.UPPERCASE_LETTER}, if any, immediately 3774 * preceding a token of type {@code Character.LOWERCASE_LETTER} 3775 * will belong to the following token rather than to the preceding, if any, 3776 * {@code Character.UPPERCASE_LETTER} token. 3777 * <pre> 3778 * StringUtils.splitByCharacterTypeCamelCase(null) = null 3779 * StringUtils.splitByCharacterTypeCamelCase("") = [] 3780 * StringUtils.splitByCharacterTypeCamelCase("ab de fg") = ["ab", " ", "de", " ", "fg"] 3781 * StringUtils.splitByCharacterTypeCamelCase("ab de fg") = ["ab", " ", "de", " ", "fg"] 3782 * StringUtils.splitByCharacterTypeCamelCase("ab:cd:ef") = ["ab", ":", "cd", ":", "ef"] 3783 * StringUtils.splitByCharacterTypeCamelCase("number5") = ["number", "5"] 3784 * StringUtils.splitByCharacterTypeCamelCase("fooBar") = ["foo", "Bar"] 3785 * StringUtils.splitByCharacterTypeCamelCase("foo200Bar") = ["foo", "200", "Bar"] 3786 * StringUtils.splitByCharacterTypeCamelCase("ASFRules") = ["ASF", "Rules"] 3787 * </pre> 3788 * @param str the String to split, may be {@code null} 3789 * @return an array of parsed Strings, {@code null} if null String input 3790 * @since 2.4 3791 */ 3792 public static String[] splitByCharacterTypeCamelCase(final String str) { 3793 return splitByCharacterType(str, true); 3794 } 3795 3796 /** 3797 * <p>Splits a String by Character type as returned by 3798 * {@code java.lang.Character.getType(char)}. Groups of contiguous 3799 * characters of the same type are returned as complete tokens, with the 3800 * following exception: if {@code camelCase} is {@code true}, 3801 * the character of type {@code Character.UPPERCASE_LETTER}, if any, 3802 * immediately preceding a token of type {@code Character.LOWERCASE_LETTER} 3803 * will belong to the following token rather than to the preceding, if any, 3804 * {@code Character.UPPERCASE_LETTER} token. 3805 * @param str the String to split, may be {@code null} 3806 * @param camelCase whether to use so-called "camel-case" for letter types 3807 * @return an array of parsed Strings, {@code null} if null String input 3808 * @since 2.4 3809 */ 3810 private static String[] splitByCharacterType(final String str, final boolean camelCase) { 3811 if (str == null) { 3812 return null; 3813 } 3814 if (str.isEmpty()) { 3815 return ArrayUtils.EMPTY_STRING_ARRAY; 3816 } 3817 final char[] c = str.toCharArray(); 3818 final List<String> list = new ArrayList<>(); 3819 int tokenStart = 0; 3820 int currentType = Character.getType(c[tokenStart]); 3821 for (int pos = tokenStart + 1; pos < c.length; pos++) { 3822 final int type = Character.getType(c[pos]); 3823 if (type == currentType) { 3824 continue; 3825 } 3826 if (camelCase && type == Character.LOWERCASE_LETTER && currentType == Character.UPPERCASE_LETTER) { 3827 final int newTokenStart = pos - 1; 3828 if (newTokenStart != tokenStart) { 3829 list.add(new String(c, tokenStart, newTokenStart - tokenStart)); 3830 tokenStart = newTokenStart; 3831 } 3832 } else { 3833 list.add(new String(c, tokenStart, pos - tokenStart)); 3834 tokenStart = pos; 3835 } 3836 currentType = type; 3837 } 3838 list.add(new String(c, tokenStart, c.length - tokenStart)); 3839 return list.toArray(new String[list.size()]); 3840 } 3841 3842 // Joining 3843 //----------------------------------------------------------------------- 3844 /** 3845 * <p>Joins the elements of the provided array into a single String 3846 * containing the provided list of elements.</p> 3847 * 3848 * <p>No separator is added to the joined String. 3849 * Null objects or empty strings within the array are represented by 3850 * empty strings.</p> 3851 * 3852 * <pre> 3853 * StringUtils.join(null) = null 3854 * StringUtils.join([]) = "" 3855 * StringUtils.join([null]) = "" 3856 * StringUtils.join(["a", "b", "c"]) = "abc" 3857 * StringUtils.join([null, "", "a"]) = "a" 3858 * </pre> 3859 * 3860 * @param <T> the specific type of values to join together 3861 * @param elements the values to join together, may be null 3862 * @return the joined String, {@code null} if null array input 3863 * @since 2.0 3864 * @since 3.0 Changed signature to use varargs 3865 */ 3866 @SafeVarargs 3867 public static <T> String join(final T... elements) { 3868 return join(elements, null); 3869 } 3870 3871 /** 3872 * <p>Joins the elements of the provided array into a single String 3873 * containing the provided list of elements.</p> 3874 * 3875 * <p>No delimiter is added before or after the list. 3876 * Null objects or empty strings within the array are represented by 3877 * empty strings.</p> 3878 * 3879 * <pre> 3880 * StringUtils.join(null, *) = null 3881 * StringUtils.join([], *) = "" 3882 * StringUtils.join([null], *) = "" 3883 * StringUtils.join(["a", "b", "c"], ';') = "a;b;c" 3884 * StringUtils.join(["a", "b", "c"], null) = "abc" 3885 * StringUtils.join([null, "", "a"], ';') = ";;a" 3886 * </pre> 3887 * 3888 * @param array the array of values to join together, may be null 3889 * @param separator the separator character to use 3890 * @return the joined String, {@code null} if null array input 3891 * @since 2.0 3892 */ 3893 public static String join(final Object[] array, final char separator) { 3894 if (array == null) { 3895 return null; 3896 } 3897 return join(array, separator, 0, array.length); 3898 } 3899 3900 /** 3901 * <p> 3902 * Joins the elements of the provided array into a single String containing the provided list of elements. 3903 * </p> 3904 * 3905 * <p> 3906 * No delimiter is added before or after the list. Null objects or empty strings within the array are represented 3907 * by empty strings. 3908 * </p> 3909 * 3910 * <pre> 3911 * StringUtils.join(null, *) = null 3912 * StringUtils.join([], *) = "" 3913 * StringUtils.join([null], *) = "" 3914 * StringUtils.join([1, 2, 3], ';') = "1;2;3" 3915 * StringUtils.join([1, 2, 3], null) = "123" 3916 * </pre> 3917 * 3918 * @param array 3919 * the array of values to join together, may be null 3920 * @param separator 3921 * the separator character to use 3922 * @return the joined String, {@code null} if null array input 3923 * @since 3.2 3924 */ 3925 public static String join(final long[] array, final char separator) { 3926 if (array == null) { 3927 return null; 3928 } 3929 return join(array, separator, 0, array.length); 3930 } 3931 3932 /** 3933 * <p> 3934 * Joins the elements of the provided array into a single String containing the provided list of elements. 3935 * </p> 3936 * 3937 * <p> 3938 * No delimiter is added before or after the list. Null objects or empty strings within the array are represented 3939 * by empty strings. 3940 * </p> 3941 * 3942 * <pre> 3943 * StringUtils.join(null, *) = null 3944 * StringUtils.join([], *) = "" 3945 * StringUtils.join([null], *) = "" 3946 * StringUtils.join([1, 2, 3], ';') = "1;2;3" 3947 * StringUtils.join([1, 2, 3], null) = "123" 3948 * </pre> 3949 * 3950 * @param array 3951 * the array of values to join together, may be null 3952 * @param separator 3953 * the separator character to use 3954 * @return the joined String, {@code null} if null array input 3955 * @since 3.2 3956 */ 3957 public static String join(final int[] array, final char separator) { 3958 if (array == null) { 3959 return null; 3960 } 3961 return join(array, separator, 0, array.length); 3962 } 3963 3964 /** 3965 * <p> 3966 * Joins the elements of the provided array into a single String containing the provided list of elements. 3967 * </p> 3968 * 3969 * <p> 3970 * No delimiter is added before or after the list. Null objects or empty strings within the array are represented 3971 * by empty strings. 3972 * </p> 3973 * 3974 * <pre> 3975 * StringUtils.join(null, *) = null 3976 * StringUtils.join([], *) = "" 3977 * StringUtils.join([null], *) = "" 3978 * StringUtils.join([1, 2, 3], ';') = "1;2;3" 3979 * StringUtils.join([1, 2, 3], null) = "123" 3980 * </pre> 3981 * 3982 * @param array 3983 * the array of values to join together, may be null 3984 * @param separator 3985 * the separator character to use 3986 * @return the joined String, {@code null} if null array input 3987 * @since 3.2 3988 */ 3989 public static String join(final short[] array, final char separator) { 3990 if (array == null) { 3991 return null; 3992 } 3993 return join(array, separator, 0, array.length); 3994 } 3995 3996 /** 3997 * <p> 3998 * Joins the elements of the provided array into a single String containing the provided list of elements. 3999 * </p> 4000 * 4001 * <p> 4002 * No delimiter is added before or after the list. Null objects or empty strings within the array are represented 4003 * by empty strings. 4004 * </p> 4005 * 4006 * <pre> 4007 * StringUtils.join(null, *) = null 4008 * StringUtils.join([], *) = "" 4009 * StringUtils.join([null], *) = "" 4010 * StringUtils.join([1, 2, 3], ';') = "1;2;3" 4011 * StringUtils.join([1, 2, 3], null) = "123" 4012 * </pre> 4013 * 4014 * @param array 4015 * the array of values to join together, may be null 4016 * @param separator 4017 * the separator character to use 4018 * @return the joined String, {@code null} if null array input 4019 * @since 3.2 4020 */ 4021 public static String join(final byte[] array, final char separator) { 4022 if (array == null) { 4023 return null; 4024 } 4025 return join(array, separator, 0, array.length); 4026 } 4027 4028 /** 4029 * <p> 4030 * Joins the elements of the provided array into a single String containing the provided list of elements. 4031 * </p> 4032 * 4033 * <p> 4034 * No delimiter is added before or after the list. Null objects or empty strings within the array are represented 4035 * by empty strings. 4036 * </p> 4037 * 4038 * <pre> 4039 * StringUtils.join(null, *) = null 4040 * StringUtils.join([], *) = "" 4041 * StringUtils.join([null], *) = "" 4042 * StringUtils.join([1, 2, 3], ';') = "1;2;3" 4043 * StringUtils.join([1, 2, 3], null) = "123" 4044 * </pre> 4045 * 4046 * @param array 4047 * the array of values to join together, may be null 4048 * @param separator 4049 * the separator character to use 4050 * @return the joined String, {@code null} if null array input 4051 * @since 3.2 4052 */ 4053 public static String join(final char[] array, final char separator) { 4054 if (array == null) { 4055 return null; 4056 } 4057 return join(array, separator, 0, array.length); 4058 } 4059 4060 /** 4061 * <p> 4062 * Joins the elements of the provided array into a single String containing the provided list of elements. 4063 * </p> 4064 * 4065 * <p> 4066 * No delimiter is added before or after the list. Null objects or empty strings within the array are represented 4067 * by empty strings. 4068 * </p> 4069 * 4070 * <pre> 4071 * StringUtils.join(null, *) = null 4072 * StringUtils.join([], *) = "" 4073 * StringUtils.join([null], *) = "" 4074 * StringUtils.join([1, 2, 3], ';') = "1;2;3" 4075 * StringUtils.join([1, 2, 3], null) = "123" 4076 * </pre> 4077 * 4078 * @param array 4079 * the array of values to join together, may be null 4080 * @param separator 4081 * the separator character to use 4082 * @return the joined String, {@code null} if null array input 4083 * @since 3.2 4084 */ 4085 public static String join(final float[] array, final char separator) { 4086 if (array == null) { 4087 return null; 4088 } 4089 return join(array, separator, 0, array.length); 4090 } 4091 4092 /** 4093 * <p> 4094 * Joins the elements of the provided array into a single String containing the provided list of elements. 4095 * </p> 4096 * 4097 * <p> 4098 * No delimiter is added before or after the list. Null objects or empty strings within the array are represented 4099 * by empty strings. 4100 * </p> 4101 * 4102 * <pre> 4103 * StringUtils.join(null, *) = null 4104 * StringUtils.join([], *) = "" 4105 * StringUtils.join([null], *) = "" 4106 * StringUtils.join([1, 2, 3], ';') = "1;2;3" 4107 * StringUtils.join([1, 2, 3], null) = "123" 4108 * </pre> 4109 * 4110 * @param array 4111 * the array of values to join together, may be null 4112 * @param separator 4113 * the separator character to use 4114 * @return the joined String, {@code null} if null array input 4115 * @since 3.2 4116 */ 4117 public static String join(final double[] array, final char separator) { 4118 if (array == null) { 4119 return null; 4120 } 4121 return join(array, separator, 0, array.length); 4122 } 4123 4124 4125 /** 4126 * <p>Joins the elements of the provided array into a single String 4127 * containing the provided list of elements.</p> 4128 * 4129 * <p>No delimiter is added before or after the list. 4130 * Null objects or empty strings within the array are represented by 4131 * empty strings.</p> 4132 * 4133 * <pre> 4134 * StringUtils.join(null, *) = null 4135 * StringUtils.join([], *) = "" 4136 * StringUtils.join([null], *) = "" 4137 * StringUtils.join(["a", "b", "c"], ';') = "a;b;c" 4138 * StringUtils.join(["a", "b", "c"], null) = "abc" 4139 * StringUtils.join([null, "", "a"], ';') = ";;a" 4140 * </pre> 4141 * 4142 * @param array the array of values to join together, may be null 4143 * @param separator the separator character to use 4144 * @param startIndex the first index to start joining from. It is 4145 * an error to pass in a start index past the end of the array 4146 * @param endIndex the index to stop joining from (exclusive). It is 4147 * an error to pass in an end index past the end of the array 4148 * @return the joined String, {@code null} if null array input 4149 * @since 2.0 4150 */ 4151 public static String join(final Object[] array, final char separator, final int startIndex, final int endIndex) { 4152 if (array == null) { 4153 return null; 4154 } 4155 final int noOfItems = endIndex - startIndex; 4156 if (noOfItems <= 0) { 4157 return EMPTY; 4158 } 4159 final StringBuilder buf = newStringBuilder(noOfItems); 4160 for (int i = startIndex; i < endIndex; i++) { 4161 if (i > startIndex) { 4162 buf.append(separator); 4163 } 4164 if (array[i] != null) { 4165 buf.append(array[i]); 4166 } 4167 } 4168 return buf.toString(); 4169 } 4170 4171 /** 4172 * <p> 4173 * Joins the elements of the provided array into a single String containing the provided list of elements. 4174 * </p> 4175 * 4176 * <p> 4177 * No delimiter is added before or after the list. Null objects or empty strings within the array are represented 4178 * by empty strings. 4179 * </p> 4180 * 4181 * <pre> 4182 * StringUtils.join(null, *) = null 4183 * StringUtils.join([], *) = "" 4184 * StringUtils.join([null], *) = "" 4185 * StringUtils.join([1, 2, 3], ';') = "1;2;3" 4186 * StringUtils.join([1, 2, 3], null) = "123" 4187 * </pre> 4188 * 4189 * @param array 4190 * the array of values to join together, may be null 4191 * @param separator 4192 * the separator character to use 4193 * @param startIndex 4194 * the first index to start joining from. It is an error to pass in a start index past the end of the 4195 * array 4196 * @param endIndex 4197 * the index to stop joining from (exclusive). It is an error to pass in an end index past the end of 4198 * the array 4199 * @return the joined String, {@code null} if null array input 4200 * @since 3.2 4201 */ 4202 public static String join(final long[] array, final char separator, final int startIndex, final int endIndex) { 4203 if (array == null) { 4204 return null; 4205 } 4206 final int noOfItems = endIndex - startIndex; 4207 if (noOfItems <= 0) { 4208 return EMPTY; 4209 } 4210 final StringBuilder buf = newStringBuilder(noOfItems); 4211 for (int i = startIndex; i < endIndex; i++) { 4212 if (i > startIndex) { 4213 buf.append(separator); 4214 } 4215 buf.append(array[i]); 4216 } 4217 return buf.toString(); 4218 } 4219 4220 /** 4221 * <p> 4222 * Joins the elements of the provided array into a single String containing the provided list of elements. 4223 * </p> 4224 * 4225 * <p> 4226 * No delimiter is added before or after the list. Null objects or empty strings within the array are represented 4227 * by empty strings. 4228 * </p> 4229 * 4230 * <pre> 4231 * StringUtils.join(null, *) = null 4232 * StringUtils.join([], *) = "" 4233 * StringUtils.join([null], *) = "" 4234 * StringUtils.join([1, 2, 3], ';') = "1;2;3" 4235 * StringUtils.join([1, 2, 3], null) = "123" 4236 * </pre> 4237 * 4238 * @param array 4239 * the array of values to join together, may be null 4240 * @param separator 4241 * the separator character to use 4242 * @param startIndex 4243 * the first index to start joining from. It is an error to pass in a start index past the end of the 4244 * array 4245 * @param endIndex 4246 * the index to stop joining from (exclusive). It is an error to pass in an end index past the end of 4247 * the array 4248 * @return the joined String, {@code null} if null array input 4249 * @since 3.2 4250 */ 4251 public static String join(final int[] array, final char separator, final int startIndex, final int endIndex) { 4252 if (array == null) { 4253 return null; 4254 } 4255 final int noOfItems = endIndex - startIndex; 4256 if (noOfItems <= 0) { 4257 return EMPTY; 4258 } 4259 final StringBuilder buf = newStringBuilder(noOfItems); 4260 for (int i = startIndex; i < endIndex; i++) { 4261 if (i > startIndex) { 4262 buf.append(separator); 4263 } 4264 buf.append(array[i]); 4265 } 4266 return buf.toString(); 4267 } 4268 4269 /** 4270 * <p> 4271 * Joins the elements of the provided array into a single String containing the provided list of elements. 4272 * </p> 4273 * 4274 * <p> 4275 * No delimiter is added before or after the list. Null objects or empty strings within the array are represented 4276 * by empty strings. 4277 * </p> 4278 * 4279 * <pre> 4280 * StringUtils.join(null, *) = null 4281 * StringUtils.join([], *) = "" 4282 * StringUtils.join([null], *) = "" 4283 * StringUtils.join([1, 2, 3], ';') = "1;2;3" 4284 * StringUtils.join([1, 2, 3], null) = "123" 4285 * </pre> 4286 * 4287 * @param array 4288 * the array of values to join together, may be null 4289 * @param separator 4290 * the separator character to use 4291 * @param startIndex 4292 * the first index to start joining from. It is an error to pass in a start index past the end of the 4293 * array 4294 * @param endIndex 4295 * the index to stop joining from (exclusive). It is an error to pass in an end index past the end of 4296 * the array 4297 * @return the joined String, {@code null} if null array input 4298 * @since 3.2 4299 */ 4300 public static String join(final byte[] array, final char separator, final int startIndex, final int endIndex) { 4301 if (array == null) { 4302 return null; 4303 } 4304 final int noOfItems = endIndex - startIndex; 4305 if (noOfItems <= 0) { 4306 return EMPTY; 4307 } 4308 final StringBuilder buf = newStringBuilder(noOfItems); 4309 for (int i = startIndex; i < endIndex; i++) { 4310 if (i > startIndex) { 4311 buf.append(separator); 4312 } 4313 buf.append(array[i]); 4314 } 4315 return buf.toString(); 4316 } 4317 4318 /** 4319 * <p> 4320 * Joins the elements of the provided array into a single String containing the provided list of elements. 4321 * </p> 4322 * 4323 * <p> 4324 * No delimiter is added before or after the list. Null objects or empty strings within the array are represented 4325 * by empty strings. 4326 * </p> 4327 * 4328 * <pre> 4329 * StringUtils.join(null, *) = null 4330 * StringUtils.join([], *) = "" 4331 * StringUtils.join([null], *) = "" 4332 * StringUtils.join([1, 2, 3], ';') = "1;2;3" 4333 * StringUtils.join([1, 2, 3], null) = "123" 4334 * </pre> 4335 * 4336 * @param array 4337 * the array of values to join together, may be null 4338 * @param separator 4339 * the separator character to use 4340 * @param startIndex 4341 * the first index to start joining from. It is an error to pass in a start index past the end of the 4342 * array 4343 * @param endIndex 4344 * the index to stop joining from (exclusive). It is an error to pass in an end index past the end of 4345 * the array 4346 * @return the joined String, {@code null} if null array input 4347 * @since 3.2 4348 */ 4349 public static String join(final short[] array, final char separator, final int startIndex, final int endIndex) { 4350 if (array == null) { 4351 return null; 4352 } 4353 final int noOfItems = endIndex - startIndex; 4354 if (noOfItems <= 0) { 4355 return EMPTY; 4356 } 4357 final StringBuilder buf = newStringBuilder(noOfItems); 4358 for (int i = startIndex; i < endIndex; i++) { 4359 if (i > startIndex) { 4360 buf.append(separator); 4361 } 4362 buf.append(array[i]); 4363 } 4364 return buf.toString(); 4365 } 4366 4367 /** 4368 * <p> 4369 * Joins the elements of the provided array into a single String containing the provided list of elements. 4370 * </p> 4371 * 4372 * <p> 4373 * No delimiter is added before or after the list. Null objects or empty strings within the array are represented 4374 * by empty strings. 4375 * </p> 4376 * 4377 * <pre> 4378 * StringUtils.join(null, *) = null 4379 * StringUtils.join([], *) = "" 4380 * StringUtils.join([null], *) = "" 4381 * StringUtils.join([1, 2, 3], ';') = "1;2;3" 4382 * StringUtils.join([1, 2, 3], null) = "123" 4383 * </pre> 4384 * 4385 * @param array 4386 * the array of values to join together, may be null 4387 * @param separator 4388 * the separator character to use 4389 * @param startIndex 4390 * the first index to start joining from. It is an error to pass in a start index past the end of the 4391 * array 4392 * @param endIndex 4393 * the index to stop joining from (exclusive). It is an error to pass in an end index past the end of 4394 * the array 4395 * @return the joined String, {@code null} if null array input 4396 * @since 3.2 4397 */ 4398 public static String join(final char[] array, final char separator, final int startIndex, final int endIndex) { 4399 if (array == null) { 4400 return null; 4401 } 4402 final int noOfItems = endIndex - startIndex; 4403 if (noOfItems <= 0) { 4404 return EMPTY; 4405 } 4406 final StringBuilder buf = newStringBuilder(noOfItems); 4407 for (int i = startIndex; i < endIndex; i++) { 4408 if (i > startIndex) { 4409 buf.append(separator); 4410 } 4411 buf.append(array[i]); 4412 } 4413 return buf.toString(); 4414 } 4415 4416 /** 4417 * <p> 4418 * Joins the elements of the provided array into a single String containing the provided list of elements. 4419 * </p> 4420 * 4421 * <p> 4422 * No delimiter is added before or after the list. Null objects or empty strings within the array are represented 4423 * by empty strings. 4424 * </p> 4425 * 4426 * <pre> 4427 * StringUtils.join(null, *) = null 4428 * StringUtils.join([], *) = "" 4429 * StringUtils.join([null], *) = "" 4430 * StringUtils.join([1, 2, 3], ';') = "1;2;3" 4431 * StringUtils.join([1, 2, 3], null) = "123" 4432 * </pre> 4433 * 4434 * @param array 4435 * the array of values to join together, may be null 4436 * @param separator 4437 * the separator character to use 4438 * @param startIndex 4439 * the first index to start joining from. It is an error to pass in a start index past the end of the 4440 * array 4441 * @param endIndex 4442 * the index to stop joining from (exclusive). It is an error to pass in an end index past the end of 4443 * the array 4444 * @return the joined String, {@code null} if null array input 4445 * @since 3.2 4446 */ 4447 public static String join(final double[] array, final char separator, final int startIndex, final int endIndex) { 4448 if (array == null) { 4449 return null; 4450 } 4451 final int noOfItems = endIndex - startIndex; 4452 if (noOfItems <= 0) { 4453 return EMPTY; 4454 } 4455 final StringBuilder buf = newStringBuilder(noOfItems); 4456 for (int i = startIndex; i < endIndex; i++) { 4457 if (i > startIndex) { 4458 buf.append(separator); 4459 } 4460 buf.append(array[i]); 4461 } 4462 return buf.toString(); 4463 } 4464 4465 /** 4466 * <p> 4467 * Joins the elements of the provided array into a single String containing the provided list of elements. 4468 * </p> 4469 * 4470 * <p> 4471 * No delimiter is added before or after the list. Null objects or empty strings within the array are represented 4472 * by empty strings. 4473 * </p> 4474 * 4475 * <pre> 4476 * StringUtils.join(null, *) = null 4477 * StringUtils.join([], *) = "" 4478 * StringUtils.join([null], *) = "" 4479 * StringUtils.join([1, 2, 3], ';') = "1;2;3" 4480 * StringUtils.join([1, 2, 3], null) = "123" 4481 * </pre> 4482 * 4483 * @param array 4484 * the array of values to join together, may be null 4485 * @param separator 4486 * the separator character to use 4487 * @param startIndex 4488 * the first index to start joining from. It is an error to pass in a start index past the end of the 4489 * array 4490 * @param endIndex 4491 * the index to stop joining from (exclusive). It is an error to pass in an end index past the end of 4492 * the array 4493 * @return the joined String, {@code null} if null array input 4494 * @since 3.2 4495 */ 4496 public static String join(final float[] array, final char separator, final int startIndex, final int endIndex) { 4497 if (array == null) { 4498 return null; 4499 } 4500 final int noOfItems = endIndex - startIndex; 4501 if (noOfItems <= 0) { 4502 return EMPTY; 4503 } 4504 final StringBuilder buf = newStringBuilder(noOfItems); 4505 for (int i = startIndex; i < endIndex; i++) { 4506 if (i > startIndex) { 4507 buf.append(separator); 4508 } 4509 buf.append(array[i]); 4510 } 4511 return buf.toString(); 4512 } 4513 4514 4515 /** 4516 * <p>Joins the elements of the provided array into a single String 4517 * containing the provided list of elements.</p> 4518 * 4519 * <p>No delimiter is added before or after the list. 4520 * A {@code null} separator is the same as an empty String (""). 4521 * Null objects or empty strings within the array are represented by 4522 * empty strings.</p> 4523 * 4524 * <pre> 4525 * StringUtils.join(null, *) = null 4526 * StringUtils.join([], *) = "" 4527 * StringUtils.join([null], *) = "" 4528 * StringUtils.join(["a", "b", "c"], "--") = "a--b--c" 4529 * StringUtils.join(["a", "b", "c"], null) = "abc" 4530 * StringUtils.join(["a", "b", "c"], "") = "abc" 4531 * StringUtils.join([null, "", "a"], ',') = ",,a" 4532 * </pre> 4533 * 4534 * @param array the array of values to join together, may be null 4535 * @param separator the separator character to use, null treated as "" 4536 * @return the joined String, {@code null} if null array input 4537 */ 4538 public static String join(final Object[] array, final String separator) { 4539 if (array == null) { 4540 return null; 4541 } 4542 return join(array, separator, 0, array.length); 4543 } 4544 4545 /** 4546 * <p>Joins the elements of the provided array into a single String 4547 * containing the provided list of elements.</p> 4548 * 4549 * <p>No delimiter is added before or after the list. 4550 * A {@code null} separator is the same as an empty String (""). 4551 * Null objects or empty strings within the array are represented by 4552 * empty strings.</p> 4553 * 4554 * <pre> 4555 * StringUtils.join(null, *, *, *) = null 4556 * StringUtils.join([], *, *, *) = "" 4557 * StringUtils.join([null], *, *, *) = "" 4558 * StringUtils.join(["a", "b", "c"], "--", 0, 3) = "a--b--c" 4559 * StringUtils.join(["a", "b", "c"], "--", 1, 3) = "b--c" 4560 * StringUtils.join(["a", "b", "c"], "--", 2, 3) = "c" 4561 * StringUtils.join(["a", "b", "c"], "--", 2, 2) = "" 4562 * StringUtils.join(["a", "b", "c"], null, 0, 3) = "abc" 4563 * StringUtils.join(["a", "b", "c"], "", 0, 3) = "abc" 4564 * StringUtils.join([null, "", "a"], ',', 0, 3) = ",,a" 4565 * </pre> 4566 * 4567 * @param array the array of values to join together, may be null 4568 * @param separator the separator character to use, null treated as "" 4569 * @param startIndex the first index to start joining from. 4570 * @param endIndex the index to stop joining from (exclusive). 4571 * @return the joined String, {@code null} if null array input; or the empty string 4572 * if {@code endIndex - startIndex <= 0}. The number of joined entries is given by 4573 * {@code endIndex - startIndex} 4574 * @throws ArrayIndexOutOfBoundsException ife<br> 4575 * {@code startIndex < 0} or <br> 4576 * {@code startIndex >= array.length()} or <br> 4577 * {@code endIndex < 0} or <br> 4578 * {@code endIndex > array.length()} 4579 */ 4580 public static String join(final Object[] array, String separator, final int startIndex, final int endIndex) { 4581 if (array == null) { 4582 return null; 4583 } 4584 if (separator == null) { 4585 separator = EMPTY; 4586 } 4587 4588 // endIndex - startIndex > 0: Len = NofStrings *(len(firstString) + len(separator)) 4589 // (Assuming that all Strings are roughly equally long) 4590 final int noOfItems = endIndex - startIndex; 4591 if (noOfItems <= 0) { 4592 return EMPTY; 4593 } 4594 4595 final StringBuilder buf = newStringBuilder(noOfItems); 4596 4597 for (int i = startIndex; i < endIndex; i++) { 4598 if (i > startIndex) { 4599 buf.append(separator); 4600 } 4601 if (array[i] != null) { 4602 buf.append(array[i]); 4603 } 4604 } 4605 return buf.toString(); 4606 } 4607 4608 /** 4609 * <p>Joins the elements of the provided {@code Iterator} into 4610 * a single String containing the provided elements.</p> 4611 * 4612 * <p>No delimiter is added before or after the list. Null objects or empty 4613 * strings within the iteration are represented by empty strings.</p> 4614 * 4615 * <p>See the examples here: {@link #join(Object[],char)}. </p> 4616 * 4617 * @param iterator the {@code Iterator} of values to join together, may be null 4618 * @param separator the separator character to use 4619 * @return the joined String, {@code null} if null iterator input 4620 * @since 2.0 4621 */ 4622 public static String join(final Iterator<?> iterator, final char separator) { 4623 4624 // handle null, zero and one elements before building a buffer 4625 if (iterator == null) { 4626 return null; 4627 } 4628 if (!iterator.hasNext()) { 4629 return EMPTY; 4630 } 4631 final Object first = iterator.next(); 4632 if (!iterator.hasNext()) { 4633 return Objects.toString(first, EMPTY); 4634 } 4635 4636 // two or more elements 4637 final StringBuilder buf = new StringBuilder(STRING_BUILDER_SIZE); // Java default is 16, probably too small 4638 if (first != null) { 4639 buf.append(first); 4640 } 4641 4642 while (iterator.hasNext()) { 4643 buf.append(separator); 4644 final Object obj = iterator.next(); 4645 if (obj != null) { 4646 buf.append(obj); 4647 } 4648 } 4649 4650 return buf.toString(); 4651 } 4652 4653 /** 4654 * <p>Joins the elements of the provided {@code Iterator} into 4655 * a single String containing the provided elements.</p> 4656 * 4657 * <p>No delimiter is added before or after the list. 4658 * A {@code null} separator is the same as an empty String ("").</p> 4659 * 4660 * <p>See the examples here: {@link #join(Object[],String)}. </p> 4661 * 4662 * @param iterator the {@code Iterator} of values to join together, may be null 4663 * @param separator the separator character to use, null treated as "" 4664 * @return the joined String, {@code null} if null iterator input 4665 */ 4666 public static String join(final Iterator<?> iterator, final String separator) { 4667 4668 // handle null, zero and one elements before building a buffer 4669 if (iterator == null) { 4670 return null; 4671 } 4672 if (!iterator.hasNext()) { 4673 return EMPTY; 4674 } 4675 final Object first = iterator.next(); 4676 if (!iterator.hasNext()) { 4677 return Objects.toString(first, ""); 4678 } 4679 4680 // two or more elements 4681 final StringBuilder buf = new StringBuilder(STRING_BUILDER_SIZE); // Java default is 16, probably too small 4682 if (first != null) { 4683 buf.append(first); 4684 } 4685 4686 while (iterator.hasNext()) { 4687 if (separator != null) { 4688 buf.append(separator); 4689 } 4690 final Object obj = iterator.next(); 4691 if (obj != null) { 4692 buf.append(obj); 4693 } 4694 } 4695 return buf.toString(); 4696 } 4697 4698 /** 4699 * <p>Joins the elements of the provided {@code Iterable} into 4700 * a single String containing the provided elements.</p> 4701 * 4702 * <p>No delimiter is added before or after the list. Null objects or empty 4703 * strings within the iteration are represented by empty strings.</p> 4704 * 4705 * <p>See the examples here: {@link #join(Object[],char)}. </p> 4706 * 4707 * @param iterable the {@code Iterable} providing the values to join together, may be null 4708 * @param separator the separator character to use 4709 * @return the joined String, {@code null} if null iterator input 4710 * @since 2.3 4711 */ 4712 public static String join(final Iterable<?> iterable, final char separator) { 4713 if (iterable == null) { 4714 return null; 4715 } 4716 return join(iterable.iterator(), separator); 4717 } 4718 4719 /** 4720 * <p>Joins the elements of the provided {@code Iterable} into 4721 * a single String containing the provided elements.</p> 4722 * 4723 * <p>No delimiter is added before or after the list. 4724 * A {@code null} separator is the same as an empty String ("").</p> 4725 * 4726 * <p>See the examples here: {@link #join(Object[],String)}. </p> 4727 * 4728 * @param iterable the {@code Iterable} providing the values to join together, may be null 4729 * @param separator the separator character to use, null treated as "" 4730 * @return the joined String, {@code null} if null iterator input 4731 * @since 2.3 4732 */ 4733 public static String join(final Iterable<?> iterable, final String separator) { 4734 if (iterable == null) { 4735 return null; 4736 } 4737 return join(iterable.iterator(), separator); 4738 } 4739 4740 /** 4741 * <p>Joins the elements of the provided {@code List} into a single String 4742 * containing the provided list of elements.</p> 4743 * 4744 * <p>No delimiter is added before or after the list. 4745 * Null objects or empty strings within the array are represented by 4746 * empty strings.</p> 4747 * 4748 * <pre> 4749 * StringUtils.join(null, *) = null 4750 * StringUtils.join([], *) = "" 4751 * StringUtils.join([null], *) = "" 4752 * StringUtils.join(["a", "b", "c"], ';') = "a;b;c" 4753 * StringUtils.join(["a", "b", "c"], null) = "abc" 4754 * StringUtils.join([null, "", "a"], ';') = ";;a" 4755 * </pre> 4756 * 4757 * @param list the {@code List} of values to join together, may be null 4758 * @param separator the separator character to use 4759 * @param startIndex the first index to start joining from. It is 4760 * an error to pass in a start index past the end of the list 4761 * @param endIndex the index to stop joining from (exclusive). It is 4762 * an error to pass in an end index past the end of the list 4763 * @return the joined String, {@code null} if null list input 4764 * @since 3.8 4765 */ 4766 public static String join(final List<?> list, final char separator, final int startIndex, final int endIndex) { 4767 if (list == null) { 4768 return null; 4769 } 4770 final int noOfItems = endIndex - startIndex; 4771 if (noOfItems <= 0) { 4772 return EMPTY; 4773 } 4774 final List<?> subList = list.subList(startIndex, endIndex); 4775 return join(subList.iterator(), separator); 4776 } 4777 4778 /** 4779 * <p>Joins the elements of the provided {@code List} into a single String 4780 * containing the provided list of elements.</p> 4781 * 4782 * <p>No delimiter is added before or after the list. 4783 * Null objects or empty strings within the array are represented by 4784 * empty strings.</p> 4785 * 4786 * <pre> 4787 * StringUtils.join(null, *) = null 4788 * StringUtils.join([], *) = "" 4789 * StringUtils.join([null], *) = "" 4790 * StringUtils.join(["a", "b", "c"], ';') = "a;b;c" 4791 * StringUtils.join(["a", "b", "c"], null) = "abc" 4792 * StringUtils.join([null, "", "a"], ';') = ";;a" 4793 * </pre> 4794 * 4795 * @param list the {@code List} of values to join together, may be null 4796 * @param separator the separator character to use 4797 * @param startIndex the first index to start joining from. It is 4798 * an error to pass in a start index past the end of the list 4799 * @param endIndex the index to stop joining from (exclusive). It is 4800 * an error to pass in an end index past the end of the list 4801 * @return the joined String, {@code null} if null list input 4802 * @since 3.8 4803 */ 4804 public static String join(final List<?> list, final String separator, final int startIndex, final int endIndex) { 4805 if (list == null) { 4806 return null; 4807 } 4808 final int noOfItems = endIndex - startIndex; 4809 if (noOfItems <= 0) { 4810 return EMPTY; 4811 } 4812 final List<?> subList = list.subList(startIndex, endIndex); 4813 return join(subList.iterator(), separator); 4814 } 4815 4816 /** 4817 * <p>Joins the elements of the provided varargs into a 4818 * single String containing the provided elements.</p> 4819 * 4820 * <p>No delimiter is added before or after the list. 4821 * {@code null} elements and separator are treated as empty Strings ("").</p> 4822 * 4823 * <pre> 4824 * StringUtils.joinWith(",", {"a", "b"}) = "a,b" 4825 * StringUtils.joinWith(",", {"a", "b",""}) = "a,b," 4826 * StringUtils.joinWith(",", {"a", null, "b"}) = "a,,b" 4827 * StringUtils.joinWith(null, {"a", "b"}) = "ab" 4828 * </pre> 4829 * 4830 * @param separator the separator character to use, null treated as "" 4831 * @param objects the varargs providing the values to join together. {@code null} elements are treated as "" 4832 * @return the joined String. 4833 * @throws java.lang.IllegalArgumentException if a null varargs is provided 4834 * @since 3.5 4835 */ 4836 public static String joinWith(final String separator, final Object... objects) { 4837 if (objects == null) { 4838 throw new IllegalArgumentException("Object varargs must not be null"); 4839 } 4840 4841 final String sanitizedSeparator = defaultString(separator); 4842 4843 final StringBuilder result = new StringBuilder(); 4844 4845 final Iterator<Object> iterator = Arrays.asList(objects).iterator(); 4846 while (iterator.hasNext()) { 4847 final String value = Objects.toString(iterator.next(), ""); 4848 result.append(value); 4849 4850 if (iterator.hasNext()) { 4851 result.append(sanitizedSeparator); 4852 } 4853 } 4854 4855 return result.toString(); 4856 } 4857 4858 // Delete 4859 //----------------------------------------------------------------------- 4860 /** 4861 * <p>Deletes all whitespaces from a String as defined by 4862 * {@link Character#isWhitespace(char)}.</p> 4863 * 4864 * <pre> 4865 * StringUtils.deleteWhitespace(null) = null 4866 * StringUtils.deleteWhitespace("") = "" 4867 * StringUtils.deleteWhitespace("abc") = "abc" 4868 * StringUtils.deleteWhitespace(" ab c ") = "abc" 4869 * </pre> 4870 * 4871 * @param str the String to delete whitespace from, may be null 4872 * @return the String without whitespaces, {@code null} if null String input 4873 */ 4874 public static String deleteWhitespace(final String str) { 4875 if (isEmpty(str)) { 4876 return str; 4877 } 4878 final int sz = str.length(); 4879 final char[] chs = new char[sz]; 4880 int count = 0; 4881 for (int i = 0; i < sz; i++) { 4882 if (!Character.isWhitespace(str.charAt(i))) { 4883 chs[count++] = str.charAt(i); 4884 } 4885 } 4886 if (count == sz) { 4887 return str; 4888 } 4889 return new String(chs, 0, count); 4890 } 4891 4892 // Remove 4893 //----------------------------------------------------------------------- 4894 /** 4895 * <p>Removes a substring only if it is at the beginning of a source string, 4896 * otherwise returns the source string.</p> 4897 * 4898 * <p>A {@code null} source string will return {@code null}. 4899 * An empty ("") source string will return the empty string. 4900 * A {@code null} search string will return the source string.</p> 4901 * 4902 * <pre> 4903 * StringUtils.removeStart(null, *) = null 4904 * StringUtils.removeStart("", *) = "" 4905 * StringUtils.removeStart(*, null) = * 4906 * StringUtils.removeStart("www.domain.com", "www.") = "domain.com" 4907 * StringUtils.removeStart("domain.com", "www.") = "domain.com" 4908 * StringUtils.removeStart("www.domain.com", "domain") = "www.domain.com" 4909 * StringUtils.removeStart("abc", "") = "abc" 4910 * </pre> 4911 * 4912 * @param str the source String to search, may be null 4913 * @param remove the String to search for and remove, may be null 4914 * @return the substring with the string removed if found, 4915 * {@code null} if null String input 4916 * @since 2.1 4917 */ 4918 public static String removeStart(final String str, final String remove) { 4919 if (isEmpty(str) || isEmpty(remove)) { 4920 return str; 4921 } 4922 if (str.startsWith(remove)) { 4923 return str.substring(remove.length()); 4924 } 4925 return str; 4926 } 4927 4928 /** 4929 * <p>Case insensitive removal of a substring if it is at the beginning of a source string, 4930 * otherwise returns the source string.</p> 4931 * 4932 * <p>A {@code null} source string will return {@code null}. 4933 * An empty ("") source string will return the empty string. 4934 * A {@code null} search string will return the source string.</p> 4935 * 4936 * <pre> 4937 * StringUtils.removeStartIgnoreCase(null, *) = null 4938 * StringUtils.removeStartIgnoreCase("", *) = "" 4939 * StringUtils.removeStartIgnoreCase(*, null) = * 4940 * StringUtils.removeStartIgnoreCase("www.domain.com", "www.") = "domain.com" 4941 * StringUtils.removeStartIgnoreCase("www.domain.com", "WWW.") = "domain.com" 4942 * StringUtils.removeStartIgnoreCase("domain.com", "www.") = "domain.com" 4943 * StringUtils.removeStartIgnoreCase("www.domain.com", "domain") = "www.domain.com" 4944 * StringUtils.removeStartIgnoreCase("abc", "") = "abc" 4945 * </pre> 4946 * 4947 * @param str the source String to search, may be null 4948 * @param remove the String to search for (case insensitive) and remove, may be null 4949 * @return the substring with the string removed if found, 4950 * {@code null} if null String input 4951 * @since 2.4 4952 */ 4953 public static String removeStartIgnoreCase(final String str, final String remove) { 4954 if (isEmpty(str) || isEmpty(remove)) { 4955 return str; 4956 } 4957 if (startsWithIgnoreCase(str, remove)) { 4958 return str.substring(remove.length()); 4959 } 4960 return str; 4961 } 4962 4963 /** 4964 * <p>Removes a substring only if it is at the end of a source string, 4965 * otherwise returns the source string.</p> 4966 * 4967 * <p>A {@code null} source string will return {@code null}. 4968 * An empty ("") source string will return the empty string. 4969 * A {@code null} search string will return the source string.</p> 4970 * 4971 * <pre> 4972 * StringUtils.removeEnd(null, *) = null 4973 * StringUtils.removeEnd("", *) = "" 4974 * StringUtils.removeEnd(*, null) = * 4975 * StringUtils.removeEnd("www.domain.com", ".com.") = "www.domain.com" 4976 * StringUtils.removeEnd("www.domain.com", ".com") = "www.domain" 4977 * StringUtils.removeEnd("www.domain.com", "domain") = "www.domain.com" 4978 * StringUtils.removeEnd("abc", "") = "abc" 4979 * </pre> 4980 * 4981 * @param str the source String to search, may be null 4982 * @param remove the String to search for and remove, may be null 4983 * @return the substring with the string removed if found, 4984 * {@code null} if null String input 4985 * @since 2.1 4986 */ 4987 public static String removeEnd(final String str, final String remove) { 4988 if (isEmpty(str) || isEmpty(remove)) { 4989 return str; 4990 } 4991 if (str.endsWith(remove)) { 4992 return str.substring(0, str.length() - remove.length()); 4993 } 4994 return str; 4995 } 4996 4997 /** 4998 * <p>Case insensitive removal of a substring if it is at the end of a source string, 4999 * otherwise returns the source string.</p> 5000 * 5001 * <p>A {@code null} source string will return {@code null}. 5002 * An empty ("") source string will return the empty string. 5003 * A {@code null} search string will return the source string.</p> 5004 * 5005 * <pre> 5006 * StringUtils.removeEndIgnoreCase(null, *) = null 5007 * StringUtils.removeEndIgnoreCase("", *) = "" 5008 * StringUtils.removeEndIgnoreCase(*, null) = * 5009 * StringUtils.removeEndIgnoreCase("www.domain.com", ".com.") = "www.domain.com" 5010 * StringUtils.removeEndIgnoreCase("www.domain.com", ".com") = "www.domain" 5011 * StringUtils.removeEndIgnoreCase("www.domain.com", "domain") = "www.domain.com" 5012 * StringUtils.removeEndIgnoreCase("abc", "") = "abc" 5013 * StringUtils.removeEndIgnoreCase("www.domain.com", ".COM") = "www.domain") 5014 * StringUtils.removeEndIgnoreCase("www.domain.COM", ".com") = "www.domain") 5015 * </pre> 5016 * 5017 * @param str the source String to search, may be null 5018 * @param remove the String to search for (case insensitive) and remove, may be null 5019 * @return the substring with the string removed if found, 5020 * {@code null} if null String input 5021 * @since 2.4 5022 */ 5023 public static String removeEndIgnoreCase(final String str, final String remove) { 5024 if (isEmpty(str) || isEmpty(remove)) { 5025 return str; 5026 } 5027 if (endsWithIgnoreCase(str, remove)) { 5028 return str.substring(0, str.length() - remove.length()); 5029 } 5030 return str; 5031 } 5032 5033 /** 5034 * <p>Removes all occurrences of a substring from within the source string.</p> 5035 * 5036 * <p>A {@code null} source string will return {@code null}. 5037 * An empty ("") source string will return the empty string. 5038 * A {@code null} remove string will return the source string. 5039 * An empty ("") remove string will return the source string.</p> 5040 * 5041 * <pre> 5042 * StringUtils.remove(null, *) = null 5043 * StringUtils.remove("", *) = "" 5044 * StringUtils.remove(*, null) = * 5045 * StringUtils.remove(*, "") = * 5046 * StringUtils.remove("queued", "ue") = "qd" 5047 * StringUtils.remove("queued", "zz") = "queued" 5048 * </pre> 5049 * 5050 * @param str the source String to search, may be null 5051 * @param remove the String to search for and remove, may be null 5052 * @return the substring with the string removed if found, 5053 * {@code null} if null String input 5054 * @since 2.1 5055 */ 5056 public static String remove(final String str, final String remove) { 5057 if (isEmpty(str) || isEmpty(remove)) { 5058 return str; 5059 } 5060 return replace(str, remove, EMPTY, -1); 5061 } 5062 5063 /** 5064 * <p> 5065 * Case insensitive removal of all occurrences of a substring from within 5066 * the source string. 5067 * </p> 5068 * 5069 * <p> 5070 * A {@code null} source string will return {@code null}. An empty ("") 5071 * source string will return the empty string. A {@code null} remove string 5072 * will return the source string. An empty ("") remove string will return 5073 * the source string. 5074 * </p> 5075 * 5076 * <pre> 5077 * StringUtils.removeIgnoreCase(null, *) = null 5078 * StringUtils.removeIgnoreCase("", *) = "" 5079 * StringUtils.removeIgnoreCase(*, null) = * 5080 * StringUtils.removeIgnoreCase(*, "") = * 5081 * StringUtils.removeIgnoreCase("queued", "ue") = "qd" 5082 * StringUtils.removeIgnoreCase("queued", "zz") = "queued" 5083 * StringUtils.removeIgnoreCase("quEUed", "UE") = "qd" 5084 * StringUtils.removeIgnoreCase("queued", "zZ") = "queued" 5085 * </pre> 5086 * 5087 * @param str 5088 * the source String to search, may be null 5089 * @param remove 5090 * the String to search for (case insensitive) and remove, may be 5091 * null 5092 * @return the substring with the string removed if found, {@code null} if 5093 * null String input 5094 * @since 3.5 5095 */ 5096 public static String removeIgnoreCase(final String str, final String remove) { 5097 if (isEmpty(str) || isEmpty(remove)) { 5098 return str; 5099 } 5100 return replaceIgnoreCase(str, remove, EMPTY, -1); 5101 } 5102 5103 /** 5104 * <p>Removes all occurrences of a character from within the source string.</p> 5105 * 5106 * <p>A {@code null} source string will return {@code null}. 5107 * An empty ("") source string will return the empty string.</p> 5108 * 5109 * <pre> 5110 * StringUtils.remove(null, *) = null 5111 * StringUtils.remove("", *) = "" 5112 * StringUtils.remove("queued", 'u') = "qeed" 5113 * StringUtils.remove("queued", 'z') = "queued" 5114 * </pre> 5115 * 5116 * @param str the source String to search, may be null 5117 * @param remove the char to search for and remove, may be null 5118 * @return the substring with the char removed if found, 5119 * {@code null} if null String input 5120 * @since 2.1 5121 */ 5122 public static String remove(final String str, final char remove) { 5123 if (isEmpty(str) || str.indexOf(remove) == INDEX_NOT_FOUND) { 5124 return str; 5125 } 5126 final char[] chars = str.toCharArray(); 5127 int pos = 0; 5128 for (int i = 0; i < chars.length; i++) { 5129 if (chars[i] != remove) { 5130 chars[pos++] = chars[i]; 5131 } 5132 } 5133 return new String(chars, 0, pos); 5134 } 5135 5136 /** 5137 * <p>Removes each substring of the text String that matches the given regular expression.</p> 5138 * 5139 * This method is a {@code null} safe equivalent to: 5140 * <ul> 5141 * <li>{@code text.replaceAll(regex, StringUtils.EMPTY)}</li> 5142 * <li>{@code Pattern.compile(regex).matcher(text).replaceAll(StringUtils.EMPTY)}</li> 5143 * </ul> 5144 * 5145 * <p>A {@code null} reference passed to this method is a no-op.</p> 5146 * 5147 * <p>Unlike in the {@link #removePattern(String, String)} method, the {@link Pattern#DOTALL} option 5148 * is NOT automatically added. 5149 * To use the DOTALL option prepend <code>"(?s)"</code> to the regex. 5150 * DOTALL is also known as single-line mode in Perl.</p> 5151 * 5152 * <pre> 5153 * StringUtils.removeAll(null, *) = null 5154 * StringUtils.removeAll("any", (String) null) = "any" 5155 * StringUtils.removeAll("any", "") = "any" 5156 * StringUtils.removeAll("any", ".*") = "" 5157 * StringUtils.removeAll("any", ".+") = "" 5158 * StringUtils.removeAll("abc", ".?") = "" 5159 * StringUtils.removeAll("A<__>\n<__>B", "<.*>") = "A\nB" 5160 * StringUtils.removeAll("A<__>\n<__>B", "(?s)<.*>") = "AB" 5161 * StringUtils.removeAll("ABCabc123abc", "[a-z]") = "ABC123" 5162 * </pre> 5163 * 5164 * @param text text to remove from, may be null 5165 * @param regex the regular expression to which this string is to be matched 5166 * @return the text with any removes processed, 5167 * {@code null} if null String input 5168 * 5169 * @throws java.util.regex.PatternSyntaxException 5170 * if the regular expression's syntax is invalid 5171 * 5172 * @see #replaceAll(String, String, String) 5173 * @see #removePattern(String, String) 5174 * @see String#replaceAll(String, String) 5175 * @see java.util.regex.Pattern 5176 * @see java.util.regex.Pattern#DOTALL 5177 * @since 3.5 5178 * 5179 * @deprecated Moved to RegExUtils. 5180 */ 5181 @Deprecated 5182 public static String removeAll(final String text, final String regex) { 5183 return RegExUtils.removeAll(text, regex); 5184 } 5185 5186 /** 5187 * <p>Removes the first substring of the text string that matches the given regular expression.</p> 5188 * 5189 * This method is a {@code null} safe equivalent to: 5190 * <ul> 5191 * <li>{@code text.replaceFirst(regex, StringUtils.EMPTY)}</li> 5192 * <li>{@code Pattern.compile(regex).matcher(text).replaceFirst(StringUtils.EMPTY)}</li> 5193 * </ul> 5194 * 5195 * <p>A {@code null} reference passed to this method is a no-op.</p> 5196 * 5197 * <p>The {@link Pattern#DOTALL} option is NOT automatically added. 5198 * To use the DOTALL option prepend <code>"(?s)"</code> to the regex. 5199 * DOTALL is also known as single-line mode in Perl.</p> 5200 * 5201 * <pre> 5202 * StringUtils.removeFirst(null, *) = null 5203 * StringUtils.removeFirst("any", (String) null) = "any" 5204 * StringUtils.removeFirst("any", "") = "any" 5205 * StringUtils.removeFirst("any", ".*") = "" 5206 * StringUtils.removeFirst("any", ".+") = "" 5207 * StringUtils.removeFirst("abc", ".?") = "bc" 5208 * StringUtils.removeFirst("A<__>\n<__>B", "<.*>") = "A\n<__>B" 5209 * StringUtils.removeFirst("A<__>\n<__>B", "(?s)<.*>") = "AB" 5210 * StringUtils.removeFirst("ABCabc123", "[a-z]") = "ABCbc123" 5211 * StringUtils.removeFirst("ABCabc123abc", "[a-z]+") = "ABC123abc" 5212 * </pre> 5213 * 5214 * @param text text to remove from, may be null 5215 * @param regex the regular expression to which this string is to be matched 5216 * @return the text with the first replacement processed, 5217 * {@code null} if null String input 5218 * 5219 * @throws java.util.regex.PatternSyntaxException 5220 * if the regular expression's syntax is invalid 5221 * 5222 * @see #replaceFirst(String, String, String) 5223 * @see String#replaceFirst(String, String) 5224 * @see java.util.regex.Pattern 5225 * @see java.util.regex.Pattern#DOTALL 5226 * @since 3.5 5227 * 5228 * @deprecated Moved to RegExUtils. 5229 */ 5230 @Deprecated 5231 public static String removeFirst(final String text, final String regex) { 5232 return replaceFirst(text, regex, EMPTY); 5233 } 5234 5235 // Replacing 5236 //----------------------------------------------------------------------- 5237 /** 5238 * <p>Replaces a String with another String inside a larger String, once.</p> 5239 * 5240 * <p>A {@code null} reference passed to this method is a no-op.</p> 5241 * 5242 * <pre> 5243 * StringUtils.replaceOnce(null, *, *) = null 5244 * StringUtils.replaceOnce("", *, *) = "" 5245 * StringUtils.replaceOnce("any", null, *) = "any" 5246 * StringUtils.replaceOnce("any", *, null) = "any" 5247 * StringUtils.replaceOnce("any", "", *) = "any" 5248 * StringUtils.replaceOnce("aba", "a", null) = "aba" 5249 * StringUtils.replaceOnce("aba", "a", "") = "ba" 5250 * StringUtils.replaceOnce("aba", "a", "z") = "zba" 5251 * </pre> 5252 * 5253 * @see #replace(String text, String searchString, String replacement, int max) 5254 * @param text text to search and replace in, may be null 5255 * @param searchString the String to search for, may be null 5256 * @param replacement the String to replace with, may be null 5257 * @return the text with any replacements processed, 5258 * {@code null} if null String input 5259 */ 5260 public static String replaceOnce(final String text, final String searchString, final String replacement) { 5261 return replace(text, searchString, replacement, 1); 5262 } 5263 5264 /** 5265 * <p>Case insensitively replaces a String with another String inside a larger String, once.</p> 5266 * 5267 * <p>A {@code null} reference passed to this method is a no-op.</p> 5268 * 5269 * <pre> 5270 * StringUtils.replaceOnceIgnoreCase(null, *, *) = null 5271 * StringUtils.replaceOnceIgnoreCase("", *, *) = "" 5272 * StringUtils.replaceOnceIgnoreCase("any", null, *) = "any" 5273 * StringUtils.replaceOnceIgnoreCase("any", *, null) = "any" 5274 * StringUtils.replaceOnceIgnoreCase("any", "", *) = "any" 5275 * StringUtils.replaceOnceIgnoreCase("aba", "a", null) = "aba" 5276 * StringUtils.replaceOnceIgnoreCase("aba", "a", "") = "ba" 5277 * StringUtils.replaceOnceIgnoreCase("aba", "a", "z") = "zba" 5278 * StringUtils.replaceOnceIgnoreCase("FoOFoofoo", "foo", "") = "Foofoo" 5279 * </pre> 5280 * 5281 * @see #replaceIgnoreCase(String text, String searchString, String replacement, int max) 5282 * @param text text to search and replace in, may be null 5283 * @param searchString the String to search for (case insensitive), may be null 5284 * @param replacement the String to replace with, may be null 5285 * @return the text with any replacements processed, 5286 * {@code null} if null String input 5287 * @since 3.5 5288 */ 5289 public static String replaceOnceIgnoreCase(final String text, final String searchString, final String replacement) { 5290 return replaceIgnoreCase(text, searchString, replacement, 1); 5291 } 5292 5293 /** 5294 * <p>Replaces each substring of the source String that matches the given regular expression with the given 5295 * replacement using the {@link Pattern#DOTALL} option. DOTALL is also known as single-line mode in Perl.</p> 5296 * 5297 * This call is a {@code null} safe equivalent to: 5298 * <ul> 5299 * <li>{@code source.replaceAll("(?s)" + regex, replacement)}</li> 5300 * <li>{@code Pattern.compile(regex, Pattern.DOTALL).matcher(source).replaceAll(replacement)}</li> 5301 * </ul> 5302 * 5303 * <p>A {@code null} reference passed to this method is a no-op.</p> 5304 * 5305 * <pre> 5306 * StringUtils.replacePattern(null, *, *) = null 5307 * StringUtils.replacePattern("any", (String) null, *) = "any" 5308 * StringUtils.replacePattern("any", *, null) = "any" 5309 * StringUtils.replacePattern("", "", "zzz") = "zzz" 5310 * StringUtils.replacePattern("", ".*", "zzz") = "zzz" 5311 * StringUtils.replacePattern("", ".+", "zzz") = "" 5312 * StringUtils.replacePattern("<__>\n<__>", "<.*>", "z") = "z" 5313 * StringUtils.replacePattern("ABCabc123", "[a-z]", "_") = "ABC___123" 5314 * StringUtils.replacePattern("ABCabc123", "[^A-Z0-9]+", "_") = "ABC_123" 5315 * StringUtils.replacePattern("ABCabc123", "[^A-Z0-9]+", "") = "ABC123" 5316 * StringUtils.replacePattern("Lorem ipsum dolor sit", "( +)([a-z]+)", "_$2") = "Lorem_ipsum_dolor_sit" 5317 * </pre> 5318 * 5319 * @param source 5320 * the source string 5321 * @param regex 5322 * the regular expression to which this string is to be matched 5323 * @param replacement 5324 * the string to be substituted for each match 5325 * @return The resulting {@code String} 5326 * @see #replaceAll(String, String, String) 5327 * @see String#replaceAll(String, String) 5328 * @see Pattern#DOTALL 5329 * @since 3.2 5330 * @since 3.5 Changed {@code null} reference passed to this method is a no-op. 5331 * 5332 * @deprecated Moved to RegExUtils. 5333 */ 5334 @Deprecated 5335 public static String replacePattern(final String source, final String regex, final String replacement) { 5336 return RegExUtils.replacePattern(source, regex, replacement); 5337 } 5338 5339 /** 5340 * <p>Removes each substring of the source String that matches the given regular expression using the DOTALL option. 5341 * </p> 5342 * 5343 * This call is a {@code null} safe equivalent to: 5344 * <ul> 5345 * <li>{@code source.replaceAll("(?s)" + regex, StringUtils.EMPTY)}</li> 5346 * <li>{@code Pattern.compile(regex, Pattern.DOTALL).matcher(source).replaceAll(StringUtils.EMPTY)}</li> 5347 * </ul> 5348 * 5349 * <p>A {@code null} reference passed to this method is a no-op.</p> 5350 * 5351 * <pre> 5352 * StringUtils.removePattern(null, *) = null 5353 * StringUtils.removePattern("any", (String) null) = "any" 5354 * StringUtils.removePattern("A<__>\n<__>B", "<.*>") = "AB" 5355 * StringUtils.removePattern("ABCabc123", "[a-z]") = "ABC123" 5356 * </pre> 5357 * 5358 * @param source 5359 * the source string 5360 * @param regex 5361 * the regular expression to which this string is to be matched 5362 * @return The resulting {@code String} 5363 * @see #replacePattern(String, String, String) 5364 * @see String#replaceAll(String, String) 5365 * @see Pattern#DOTALL 5366 * @since 3.2 5367 * @since 3.5 Changed {@code null} reference passed to this method is a no-op. 5368 * 5369 * @deprecated Moved to RegExUtils. 5370 */ 5371 @Deprecated 5372 public static String removePattern(final String source, final String regex) { 5373 return RegExUtils.removePattern(source, regex); 5374 } 5375 5376 /** 5377 * <p>Replaces each substring of the text String that matches the given regular expression 5378 * with the given replacement.</p> 5379 * 5380 * This method is a {@code null} safe equivalent to: 5381 * <ul> 5382 * <li>{@code text.replaceAll(regex, replacement)}</li> 5383 * <li>{@code Pattern.compile(regex).matcher(text).replaceAll(replacement)}</li> 5384 * </ul> 5385 * 5386 * <p>A {@code null} reference passed to this method is a no-op.</p> 5387 * 5388 * <p>Unlike in the {@link #replacePattern(String, String, String)} method, the {@link Pattern#DOTALL} option 5389 * is NOT automatically added. 5390 * To use the DOTALL option prepend <code>"(?s)"</code> to the regex. 5391 * DOTALL is also known as single-line mode in Perl.</p> 5392 * 5393 * <pre> 5394 * StringUtils.replaceAll(null, *, *) = null 5395 * StringUtils.replaceAll("any", (String) null, *) = "any" 5396 * StringUtils.replaceAll("any", *, null) = "any" 5397 * StringUtils.replaceAll("", "", "zzz") = "zzz" 5398 * StringUtils.replaceAll("", ".*", "zzz") = "zzz" 5399 * StringUtils.replaceAll("", ".+", "zzz") = "" 5400 * StringUtils.replaceAll("abc", "", "ZZ") = "ZZaZZbZZcZZ" 5401 * StringUtils.replaceAll("<__>\n<__>", "<.*>", "z") = "z\nz" 5402 * StringUtils.replaceAll("<__>\n<__>", "(?s)<.*>", "z") = "z" 5403 * StringUtils.replaceAll("ABCabc123", "[a-z]", "_") = "ABC___123" 5404 * StringUtils.replaceAll("ABCabc123", "[^A-Z0-9]+", "_") = "ABC_123" 5405 * StringUtils.replaceAll("ABCabc123", "[^A-Z0-9]+", "") = "ABC123" 5406 * StringUtils.replaceAll("Lorem ipsum dolor sit", "( +)([a-z]+)", "_$2") = "Lorem_ipsum_dolor_sit" 5407 * </pre> 5408 * 5409 * @param text text to search and replace in, may be null 5410 * @param regex the regular expression to which this string is to be matched 5411 * @param replacement the string to be substituted for each match 5412 * @return the text with any replacements processed, 5413 * {@code null} if null String input 5414 * 5415 * @throws java.util.regex.PatternSyntaxException 5416 * if the regular expression's syntax is invalid 5417 * 5418 * @see #replacePattern(String, String, String) 5419 * @see String#replaceAll(String, String) 5420 * @see java.util.regex.Pattern 5421 * @see java.util.regex.Pattern#DOTALL 5422 * @since 3.5 5423 * 5424 * @deprecated Moved to RegExUtils. 5425 */ 5426 @Deprecated 5427 public static String replaceAll(final String text, final String regex, final String replacement) { 5428 return RegExUtils.replaceAll(text, regex, replacement); 5429 } 5430 5431 /** 5432 * <p>Replaces the first substring of the text string that matches the given regular expression 5433 * with the given replacement.</p> 5434 * 5435 * This method is a {@code null} safe equivalent to: 5436 * <ul> 5437 * <li>{@code text.replaceFirst(regex, replacement)}</li> 5438 * <li>{@code Pattern.compile(regex).matcher(text).replaceFirst(replacement)}</li> 5439 * </ul> 5440 * 5441 * <p>A {@code null} reference passed to this method is a no-op.</p> 5442 * 5443 * <p>The {@link Pattern#DOTALL} option is NOT automatically added. 5444 * To use the DOTALL option prepend <code>"(?s)"</code> to the regex. 5445 * DOTALL is also known as single-line mode in Perl.</p> 5446 * 5447 * <pre> 5448 * StringUtils.replaceFirst(null, *, *) = null 5449 * StringUtils.replaceFirst("any", (String) null, *) = "any" 5450 * StringUtils.replaceFirst("any", *, null) = "any" 5451 * StringUtils.replaceFirst("", "", "zzz") = "zzz" 5452 * StringUtils.replaceFirst("", ".*", "zzz") = "zzz" 5453 * StringUtils.replaceFirst("", ".+", "zzz") = "" 5454 * StringUtils.replaceFirst("abc", "", "ZZ") = "ZZabc" 5455 * StringUtils.replaceFirst("<__>\n<__>", "<.*>", "z") = "z\n<__>" 5456 * StringUtils.replaceFirst("<__>\n<__>", "(?s)<.*>", "z") = "z" 5457 * StringUtils.replaceFirst("ABCabc123", "[a-z]", "_") = "ABC_bc123" 5458 * StringUtils.replaceFirst("ABCabc123abc", "[^A-Z0-9]+", "_") = "ABC_123abc" 5459 * StringUtils.replaceFirst("ABCabc123abc", "[^A-Z0-9]+", "") = "ABC123abc" 5460 * StringUtils.replaceFirst("Lorem ipsum dolor sit", "( +)([a-z]+)", "_$2") = "Lorem_ipsum dolor sit" 5461 * </pre> 5462 * 5463 * @param text text to search and replace in, may be null 5464 * @param regex the regular expression to which this string is to be matched 5465 * @param replacement the string to be substituted for the first match 5466 * @return the text with the first replacement processed, 5467 * {@code null} if null String input 5468 * 5469 * @throws java.util.regex.PatternSyntaxException 5470 * if the regular expression's syntax is invalid 5471 * 5472 * @see String#replaceFirst(String, String) 5473 * @see java.util.regex.Pattern 5474 * @see java.util.regex.Pattern#DOTALL 5475 * @since 3.5 5476 * 5477 * @deprecated Moved to RegExUtils. 5478 */ 5479 @Deprecated 5480 public static String replaceFirst(final String text, final String regex, final String replacement) { 5481 return RegExUtils.replaceFirst(text, regex, replacement); 5482 } 5483 5484 /** 5485 * <p>Replaces all occurrences of a String within another String.</p> 5486 * 5487 * <p>A {@code null} reference passed to this method is a no-op.</p> 5488 * 5489 * <pre> 5490 * StringUtils.replace(null, *, *) = null 5491 * StringUtils.replace("", *, *) = "" 5492 * StringUtils.replace("any", null, *) = "any" 5493 * StringUtils.replace("any", *, null) = "any" 5494 * StringUtils.replace("any", "", *) = "any" 5495 * StringUtils.replace("aba", "a", null) = "aba" 5496 * StringUtils.replace("aba", "a", "") = "b" 5497 * StringUtils.replace("aba", "a", "z") = "zbz" 5498 * </pre> 5499 * 5500 * @see #replace(String text, String searchString, String replacement, int max) 5501 * @param text text to search and replace in, may be null 5502 * @param searchString the String to search for, may be null 5503 * @param replacement the String to replace it with, may be null 5504 * @return the text with any replacements processed, 5505 * {@code null} if null String input 5506 */ 5507 public static String replace(final String text, final String searchString, final String replacement) { 5508 return replace(text, searchString, replacement, -1); 5509 } 5510 5511 /** 5512 * <p>Case insensitively replaces all occurrences of a String within another String.</p> 5513 * 5514 * <p>A {@code null} reference passed to this method is a no-op.</p> 5515 * 5516 * <pre> 5517 * StringUtils.replaceIgnoreCase(null, *, *) = null 5518 * StringUtils.replaceIgnoreCase("", *, *) = "" 5519 * StringUtils.replaceIgnoreCase("any", null, *) = "any" 5520 * StringUtils.replaceIgnoreCase("any", *, null) = "any" 5521 * StringUtils.replaceIgnoreCase("any", "", *) = "any" 5522 * StringUtils.replaceIgnoreCase("aba", "a", null) = "aba" 5523 * StringUtils.replaceIgnoreCase("abA", "A", "") = "b" 5524 * StringUtils.replaceIgnoreCase("aba", "A", "z") = "zbz" 5525 * </pre> 5526 * 5527 * @see #replaceIgnoreCase(String text, String searchString, String replacement, int max) 5528 * @param text text to search and replace in, may be null 5529 * @param searchString the String to search for (case insensitive), may be null 5530 * @param replacement the String to replace it with, may be null 5531 * @return the text with any replacements processed, 5532 * {@code null} if null String input 5533 * @since 3.5 5534 */ 5535 public static String replaceIgnoreCase(final String text, final String searchString, final String replacement) { 5536 return replaceIgnoreCase(text, searchString, replacement, -1); 5537 } 5538 5539 /** 5540 * <p>Replaces a String with another String inside a larger String, 5541 * for the first {@code max} values of the search String.</p> 5542 * 5543 * <p>A {@code null} reference passed to this method is a no-op.</p> 5544 * 5545 * <pre> 5546 * StringUtils.replace(null, *, *, *) = null 5547 * StringUtils.replace("", *, *, *) = "" 5548 * StringUtils.replace("any", null, *, *) = "any" 5549 * StringUtils.replace("any", *, null, *) = "any" 5550 * StringUtils.replace("any", "", *, *) = "any" 5551 * StringUtils.replace("any", *, *, 0) = "any" 5552 * StringUtils.replace("abaa", "a", null, -1) = "abaa" 5553 * StringUtils.replace("abaa", "a", "", -1) = "b" 5554 * StringUtils.replace("abaa", "a", "z", 0) = "abaa" 5555 * StringUtils.replace("abaa", "a", "z", 1) = "zbaa" 5556 * StringUtils.replace("abaa", "a", "z", 2) = "zbza" 5557 * StringUtils.replace("abaa", "a", "z", -1) = "zbzz" 5558 * </pre> 5559 * 5560 * @param text text to search and replace in, may be null 5561 * @param searchString the String to search for, may be null 5562 * @param replacement the String to replace it with, may be null 5563 * @param max maximum number of values to replace, or {@code -1} if no maximum 5564 * @return the text with any replacements processed, 5565 * {@code null} if null String input 5566 */ 5567 public static String replace(final String text, final String searchString, final String replacement, final int max) { 5568 return replace(text, searchString, replacement, max, false); 5569 } 5570 5571 /** 5572 * <p>Replaces a String with another String inside a larger String, 5573 * for the first {@code max} values of the search String, 5574 * case sensitively/insensisitively based on {@code ignoreCase} value.</p> 5575 * 5576 * <p>A {@code null} reference passed to this method is a no-op.</p> 5577 * 5578 * <pre> 5579 * StringUtils.replace(null, *, *, *, false) = null 5580 * StringUtils.replace("", *, *, *, false) = "" 5581 * StringUtils.replace("any", null, *, *, false) = "any" 5582 * StringUtils.replace("any", *, null, *, false) = "any" 5583 * StringUtils.replace("any", "", *, *, false) = "any" 5584 * StringUtils.replace("any", *, *, 0, false) = "any" 5585 * StringUtils.replace("abaa", "a", null, -1, false) = "abaa" 5586 * StringUtils.replace("abaa", "a", "", -1, false) = "b" 5587 * StringUtils.replace("abaa", "a", "z", 0, false) = "abaa" 5588 * StringUtils.replace("abaa", "A", "z", 1, false) = "abaa" 5589 * StringUtils.replace("abaa", "A", "z", 1, true) = "zbaa" 5590 * StringUtils.replace("abAa", "a", "z", 2, true) = "zbza" 5591 * StringUtils.replace("abAa", "a", "z", -1, true) = "zbzz" 5592 * </pre> 5593 * 5594 * @param text text to search and replace in, may be null 5595 * @param searchString the String to search for (case insensitive), may be null 5596 * @param replacement the String to replace it with, may be null 5597 * @param max maximum number of values to replace, or {@code -1} if no maximum 5598 * @param ignoreCase if true replace is case insensitive, otherwise case sensitive 5599 * @return the text with any replacements processed, 5600 * {@code null} if null String input 5601 */ 5602 private static String replace(final String text, String searchString, final String replacement, int max, final boolean ignoreCase) { 5603 if (isEmpty(text) || isEmpty(searchString) || replacement == null || max == 0) { 5604 return text; 5605 } 5606 String searchText = text; 5607 if (ignoreCase) { 5608 searchText = text.toLowerCase(); 5609 searchString = searchString.toLowerCase(); 5610 } 5611 int start = 0; 5612 int end = searchText.indexOf(searchString, start); 5613 if (end == INDEX_NOT_FOUND) { 5614 return text; 5615 } 5616 final int replLength = searchString.length(); 5617 int increase = replacement.length() - replLength; 5618 increase = increase < 0 ? 0 : increase; 5619 increase *= max < 0 ? 16 : max > 64 ? 64 : max; 5620 final StringBuilder buf = new StringBuilder(text.length() + increase); 5621 while (end != INDEX_NOT_FOUND) { 5622 buf.append(text, start, end).append(replacement); 5623 start = end + replLength; 5624 if (--max == 0) { 5625 break; 5626 } 5627 end = searchText.indexOf(searchString, start); 5628 } 5629 buf.append(text, start, text.length()); 5630 return buf.toString(); 5631 } 5632 5633 /** 5634 * <p>Case insensitively replaces a String with another String inside a larger String, 5635 * for the first {@code max} values of the search String.</p> 5636 * 5637 * <p>A {@code null} reference passed to this method is a no-op.</p> 5638 * 5639 * <pre> 5640 * StringUtils.replaceIgnoreCase(null, *, *, *) = null 5641 * StringUtils.replaceIgnoreCase("", *, *, *) = "" 5642 * StringUtils.replaceIgnoreCase("any", null, *, *) = "any" 5643 * StringUtils.replaceIgnoreCase("any", *, null, *) = "any" 5644 * StringUtils.replaceIgnoreCase("any", "", *, *) = "any" 5645 * StringUtils.replaceIgnoreCase("any", *, *, 0) = "any" 5646 * StringUtils.replaceIgnoreCase("abaa", "a", null, -1) = "abaa" 5647 * StringUtils.replaceIgnoreCase("abaa", "a", "", -1) = "b" 5648 * StringUtils.replaceIgnoreCase("abaa", "a", "z", 0) = "abaa" 5649 * StringUtils.replaceIgnoreCase("abaa", "A", "z", 1) = "zbaa" 5650 * StringUtils.replaceIgnoreCase("abAa", "a", "z", 2) = "zbza" 5651 * StringUtils.replaceIgnoreCase("abAa", "a", "z", -1) = "zbzz" 5652 * </pre> 5653 * 5654 * @param text text to search and replace in, may be null 5655 * @param searchString the String to search for (case insensitive), may be null 5656 * @param replacement the String to replace it with, may be null 5657 * @param max maximum number of values to replace, or {@code -1} if no maximum 5658 * @return the text with any replacements processed, 5659 * {@code null} if null String input 5660 * @since 3.5 5661 */ 5662 public static String replaceIgnoreCase(final String text, final String searchString, final String replacement, final int max) { 5663 return replace(text, searchString, replacement, max, true); 5664 } 5665 5666 /** 5667 * <p> 5668 * Replaces all occurrences of Strings within another String. 5669 * </p> 5670 * 5671 * <p> 5672 * A {@code null} reference passed to this method is a no-op, or if 5673 * any "search string" or "string to replace" is null, that replace will be 5674 * ignored. This will not repeat. For repeating replaces, call the 5675 * overloaded method. 5676 * </p> 5677 * 5678 * <pre> 5679 * StringUtils.replaceEach(null, *, *) = null 5680 * StringUtils.replaceEach("", *, *) = "" 5681 * StringUtils.replaceEach("aba", null, null) = "aba" 5682 * StringUtils.replaceEach("aba", new String[0], null) = "aba" 5683 * StringUtils.replaceEach("aba", null, new String[0]) = "aba" 5684 * StringUtils.replaceEach("aba", new String[]{"a"}, null) = "aba" 5685 * StringUtils.replaceEach("aba", new String[]{"a"}, new String[]{""}) = "b" 5686 * StringUtils.replaceEach("aba", new String[]{null}, new String[]{"a"}) = "aba" 5687 * StringUtils.replaceEach("abcde", new String[]{"ab", "d"}, new String[]{"w", "t"}) = "wcte" 5688 * (example of how it does not repeat) 5689 * StringUtils.replaceEach("abcde", new String[]{"ab", "d"}, new String[]{"d", "t"}) = "dcte" 5690 * </pre> 5691 * 5692 * @param text 5693 * text to search and replace in, no-op if null 5694 * @param searchList 5695 * the Strings to search for, no-op if null 5696 * @param replacementList 5697 * the Strings to replace them with, no-op if null 5698 * @return the text with any replacements processed, {@code null} if 5699 * null String input 5700 * @throws IllegalArgumentException 5701 * if the lengths of the arrays are not the same (null is ok, 5702 * and/or size 0) 5703 * @since 2.4 5704 */ 5705 public static String replaceEach(final String text, final String[] searchList, final String[] replacementList) { 5706 return replaceEach(text, searchList, replacementList, false, 0); 5707 } 5708 5709 /** 5710 * <p> 5711 * Replaces all occurrences of Strings within another String. 5712 * </p> 5713 * 5714 * <p> 5715 * A {@code null} reference passed to this method is a no-op, or if 5716 * any "search string" or "string to replace" is null, that replace will be 5717 * ignored. 5718 * </p> 5719 * 5720 * <pre> 5721 * StringUtils.replaceEachRepeatedly(null, *, *) = null 5722 * StringUtils.replaceEachRepeatedly("", *, *) = "" 5723 * StringUtils.replaceEachRepeatedly("aba", null, null) = "aba" 5724 * StringUtils.replaceEachRepeatedly("aba", new String[0], null) = "aba" 5725 * StringUtils.replaceEachRepeatedly("aba", null, new String[0]) = "aba" 5726 * StringUtils.replaceEachRepeatedly("aba", new String[]{"a"}, null) = "aba" 5727 * StringUtils.replaceEachRepeatedly("aba", new String[]{"a"}, new String[]{""}) = "b" 5728 * StringUtils.replaceEachRepeatedly("aba", new String[]{null}, new String[]{"a"}) = "aba" 5729 * StringUtils.replaceEachRepeatedly("abcde", new String[]{"ab", "d"}, new String[]{"w", "t"}) = "wcte" 5730 * (example of how it repeats) 5731 * StringUtils.replaceEachRepeatedly("abcde", new String[]{"ab", "d"}, new String[]{"d", "t"}) = "tcte" 5732 * StringUtils.replaceEachRepeatedly("abcde", new String[]{"ab", "d"}, new String[]{"d", "ab"}) = IllegalStateException 5733 * </pre> 5734 * 5735 * @param text 5736 * text to search and replace in, no-op if null 5737 * @param searchList 5738 * the Strings to search for, no-op if null 5739 * @param replacementList 5740 * the Strings to replace them with, no-op if null 5741 * @return the text with any replacements processed, {@code null} if 5742 * null String input 5743 * @throws IllegalStateException 5744 * if the search is repeating and there is an endless loop due 5745 * to outputs of one being inputs to another 5746 * @throws IllegalArgumentException 5747 * if the lengths of the arrays are not the same (null is ok, 5748 * and/or size 0) 5749 * @since 2.4 5750 */ 5751 public static String replaceEachRepeatedly(final String text, final String[] searchList, final String[] replacementList) { 5752 // timeToLive should be 0 if not used or nothing to replace, else it's 5753 // the length of the replace array 5754 final int timeToLive = searchList == null ? 0 : searchList.length; 5755 return replaceEach(text, searchList, replacementList, true, timeToLive); 5756 } 5757 5758 /** 5759 * <p> 5760 * Replace all occurrences of Strings within another String. 5761 * This is a private recursive helper method for {@link #replaceEachRepeatedly(String, String[], String[])} and 5762 * {@link #replaceEach(String, String[], String[])} 5763 * </p> 5764 * 5765 * <p> 5766 * A {@code null} reference passed to this method is a no-op, or if 5767 * any "search string" or "string to replace" is null, that replace will be 5768 * ignored. 5769 * </p> 5770 * 5771 * <pre> 5772 * StringUtils.replaceEach(null, *, *, *, *) = null 5773 * StringUtils.replaceEach("", *, *, *, *) = "" 5774 * StringUtils.replaceEach("aba", null, null, *, *) = "aba" 5775 * StringUtils.replaceEach("aba", new String[0], null, *, *) = "aba" 5776 * StringUtils.replaceEach("aba", null, new String[0], *, *) = "aba" 5777 * StringUtils.replaceEach("aba", new String[]{"a"}, null, *, *) = "aba" 5778 * StringUtils.replaceEach("aba", new String[]{"a"}, new String[]{""}, *, >=0) = "b" 5779 * StringUtils.replaceEach("aba", new String[]{null}, new String[]{"a"}, *, >=0) = "aba" 5780 * StringUtils.replaceEach("abcde", new String[]{"ab", "d"}, new String[]{"w", "t"}, *, >=0) = "wcte" 5781 * (example of how it repeats) 5782 * StringUtils.replaceEach("abcde", new String[]{"ab", "d"}, new String[]{"d", "t"}, false, >=0) = "dcte" 5783 * StringUtils.replaceEach("abcde", new String[]{"ab", "d"}, new String[]{"d", "t"}, true, >=2) = "tcte" 5784 * StringUtils.replaceEach("abcde", new String[]{"ab", "d"}, new String[]{"d", "ab"}, *, *) = IllegalStateException 5785 * </pre> 5786 * 5787 * @param text 5788 * text to search and replace in, no-op if null 5789 * @param searchList 5790 * the Strings to search for, no-op if null 5791 * @param replacementList 5792 * the Strings to replace them with, no-op if null 5793 * @param repeat if true, then replace repeatedly 5794 * until there are no more possible replacements or timeToLive < 0 5795 * @param timeToLive 5796 * if less than 0 then there is a circular reference and endless 5797 * loop 5798 * @return the text with any replacements processed, {@code null} if 5799 * null String input 5800 * @throws IllegalStateException 5801 * if the search is repeating and there is an endless loop due 5802 * to outputs of one being inputs to another 5803 * @throws IllegalArgumentException 5804 * if the lengths of the arrays are not the same (null is ok, 5805 * and/or size 0) 5806 * @since 2.4 5807 */ 5808 private static String replaceEach( 5809 final String text, final String[] searchList, final String[] replacementList, final boolean repeat, final int timeToLive) { 5810 5811 // mchyzer Performance note: This creates very few new objects (one major goal) 5812 // let me know if there are performance requests, we can create a harness to measure 5813 5814 if (text == null || text.isEmpty() || searchList == null || 5815 searchList.length == 0 || replacementList == null || replacementList.length == 0) { 5816 return text; 5817 } 5818 5819 // if recursing, this shouldn't be less than 0 5820 if (timeToLive < 0) { 5821 throw new IllegalStateException("Aborting to protect against StackOverflowError - " + 5822 "output of one loop is the input of another"); 5823 } 5824 5825 final int searchLength = searchList.length; 5826 final int replacementLength = replacementList.length; 5827 5828 // make sure lengths are ok, these need to be equal 5829 if (searchLength != replacementLength) { 5830 throw new IllegalArgumentException("Search and Replace array lengths don't match: " 5831 + searchLength 5832 + " vs " 5833 + replacementLength); 5834 } 5835 5836 // keep track of which still have matches 5837 final boolean[] noMoreMatchesForReplIndex = new boolean[searchLength]; 5838 5839 // index on index that the match was found 5840 int textIndex = -1; 5841 int replaceIndex = -1; 5842 int tempIndex = -1; 5843 5844 // index of replace array that will replace the search string found 5845 // NOTE: logic duplicated below START 5846 for (int i = 0; i < searchLength; i++) { 5847 if (noMoreMatchesForReplIndex[i] || searchList[i] == null || 5848 searchList[i].isEmpty() || replacementList[i] == null) { 5849 continue; 5850 } 5851 tempIndex = text.indexOf(searchList[i]); 5852 5853 // see if we need to keep searching for this 5854 if (tempIndex == -1) { 5855 noMoreMatchesForReplIndex[i] = true; 5856 } else { 5857 if (textIndex == -1 || tempIndex < textIndex) { 5858 textIndex = tempIndex; 5859 replaceIndex = i; 5860 } 5861 } 5862 } 5863 // NOTE: logic mostly below END 5864 5865 // no search strings found, we are done 5866 if (textIndex == -1) { 5867 return text; 5868 } 5869 5870 int start = 0; 5871 5872 // get a good guess on the size of the result buffer so it doesn't have to double if it goes over a bit 5873 int increase = 0; 5874 5875 // count the replacement text elements that are larger than their corresponding text being replaced 5876 for (int i = 0; i < searchList.length; i++) { 5877 if (searchList[i] == null || replacementList[i] == null) { 5878 continue; 5879 } 5880 final int greater = replacementList[i].length() - searchList[i].length(); 5881 if (greater > 0) { 5882 increase += 3 * greater; // assume 3 matches 5883 } 5884 } 5885 // have upper-bound at 20% increase, then let Java take over 5886 increase = Math.min(increase, text.length() / 5); 5887 5888 final StringBuilder buf = new StringBuilder(text.length() + increase); 5889 5890 while (textIndex != -1) { 5891 5892 for (int i = start; i < textIndex; i++) { 5893 buf.append(text.charAt(i)); 5894 } 5895 buf.append(replacementList[replaceIndex]); 5896 5897 start = textIndex + searchList[replaceIndex].length(); 5898 5899 textIndex = -1; 5900 replaceIndex = -1; 5901 tempIndex = -1; 5902 // find the next earliest match 5903 // NOTE: logic mostly duplicated above START 5904 for (int i = 0; i < searchLength; i++) { 5905 if (noMoreMatchesForReplIndex[i] || searchList[i] == null || 5906 searchList[i].isEmpty() || replacementList[i] == null) { 5907 continue; 5908 } 5909 tempIndex = text.indexOf(searchList[i], start); 5910 5911 // see if we need to keep searching for this 5912 if (tempIndex == -1) { 5913 noMoreMatchesForReplIndex[i] = true; 5914 } else { 5915 if (textIndex == -1 || tempIndex < textIndex) { 5916 textIndex = tempIndex; 5917 replaceIndex = i; 5918 } 5919 } 5920 } 5921 // NOTE: logic duplicated above END 5922 5923 } 5924 final int textLength = text.length(); 5925 for (int i = start; i < textLength; i++) { 5926 buf.append(text.charAt(i)); 5927 } 5928 final String result = buf.toString(); 5929 if (!repeat) { 5930 return result; 5931 } 5932 5933 return replaceEach(result, searchList, replacementList, repeat, timeToLive - 1); 5934 } 5935 5936 // Replace, character based 5937 //----------------------------------------------------------------------- 5938 /** 5939 * <p>Replaces all occurrences of a character in a String with another. 5940 * This is a null-safe version of {@link String#replace(char, char)}.</p> 5941 * 5942 * <p>A {@code null} string input returns {@code null}. 5943 * An empty ("") string input returns an empty string.</p> 5944 * 5945 * <pre> 5946 * StringUtils.replaceChars(null, *, *) = null 5947 * StringUtils.replaceChars("", *, *) = "" 5948 * StringUtils.replaceChars("abcba", 'b', 'y') = "aycya" 5949 * StringUtils.replaceChars("abcba", 'z', 'y') = "abcba" 5950 * </pre> 5951 * 5952 * @param str String to replace characters in, may be null 5953 * @param searchChar the character to search for, may be null 5954 * @param replaceChar the character to replace, may be null 5955 * @return modified String, {@code null} if null string input 5956 * @since 2.0 5957 */ 5958 public static String replaceChars(final String str, final char searchChar, final char replaceChar) { 5959 if (str == null) { 5960 return null; 5961 } 5962 return str.replace(searchChar, replaceChar); 5963 } 5964 5965 /** 5966 * <p>Replaces multiple characters in a String in one go. 5967 * This method can also be used to delete characters.</p> 5968 * 5969 * <p>For example:<br> 5970 * <code>replaceChars("hello", "ho", "jy") = jelly</code>.</p> 5971 * 5972 * <p>A {@code null} string input returns {@code null}. 5973 * An empty ("") string input returns an empty string. 5974 * A null or empty set of search characters returns the input string.</p> 5975 * 5976 * <p>The length of the search characters should normally equal the length 5977 * of the replace characters. 5978 * If the search characters is longer, then the extra search characters 5979 * are deleted. 5980 * If the search characters is shorter, then the extra replace characters 5981 * are ignored.</p> 5982 * 5983 * <pre> 5984 * StringUtils.replaceChars(null, *, *) = null 5985 * StringUtils.replaceChars("", *, *) = "" 5986 * StringUtils.replaceChars("abc", null, *) = "abc" 5987 * StringUtils.replaceChars("abc", "", *) = "abc" 5988 * StringUtils.replaceChars("abc", "b", null) = "ac" 5989 * StringUtils.replaceChars("abc", "b", "") = "ac" 5990 * StringUtils.replaceChars("abcba", "bc", "yz") = "ayzya" 5991 * StringUtils.replaceChars("abcba", "bc", "y") = "ayya" 5992 * StringUtils.replaceChars("abcba", "bc", "yzx") = "ayzya" 5993 * </pre> 5994 * 5995 * @param str String to replace characters in, may be null 5996 * @param searchChars a set of characters to search for, may be null 5997 * @param replaceChars a set of characters to replace, may be null 5998 * @return modified String, {@code null} if null string input 5999 * @since 2.0 6000 */ 6001 public static String replaceChars(final String str, final String searchChars, String replaceChars) { 6002 if (isEmpty(str) || isEmpty(searchChars)) { 6003 return str; 6004 } 6005 if (replaceChars == null) { 6006 replaceChars = EMPTY; 6007 } 6008 boolean modified = false; 6009 final int replaceCharsLength = replaceChars.length(); 6010 final int strLength = str.length(); 6011 final StringBuilder buf = new StringBuilder(strLength); 6012 for (int i = 0; i < strLength; i++) { 6013 final char ch = str.charAt(i); 6014 final int index = searchChars.indexOf(ch); 6015 if (index >= 0) { 6016 modified = true; 6017 if (index < replaceCharsLength) { 6018 buf.append(replaceChars.charAt(index)); 6019 } 6020 } else { 6021 buf.append(ch); 6022 } 6023 } 6024 if (modified) { 6025 return buf.toString(); 6026 } 6027 return str; 6028 } 6029 6030 // Overlay 6031 //----------------------------------------------------------------------- 6032 /** 6033 * <p>Overlays part of a String with another String.</p> 6034 * 6035 * <p>A {@code null} string input returns {@code null}. 6036 * A negative index is treated as zero. 6037 * An index greater than the string length is treated as the string length. 6038 * The start index is always the smaller of the two indices.</p> 6039 * 6040 * <pre> 6041 * StringUtils.overlay(null, *, *, *) = null 6042 * StringUtils.overlay("", "abc", 0, 0) = "abc" 6043 * StringUtils.overlay("abcdef", null, 2, 4) = "abef" 6044 * StringUtils.overlay("abcdef", "", 2, 4) = "abef" 6045 * StringUtils.overlay("abcdef", "", 4, 2) = "abef" 6046 * StringUtils.overlay("abcdef", "zzzz", 2, 4) = "abzzzzef" 6047 * StringUtils.overlay("abcdef", "zzzz", 4, 2) = "abzzzzef" 6048 * StringUtils.overlay("abcdef", "zzzz", -1, 4) = "zzzzef" 6049 * StringUtils.overlay("abcdef", "zzzz", 2, 8) = "abzzzz" 6050 * StringUtils.overlay("abcdef", "zzzz", -2, -3) = "zzzzabcdef" 6051 * StringUtils.overlay("abcdef", "zzzz", 8, 10) = "abcdefzzzz" 6052 * </pre> 6053 * 6054 * @param str the String to do overlaying in, may be null 6055 * @param overlay the String to overlay, may be null 6056 * @param start the position to start overlaying at 6057 * @param end the position to stop overlaying before 6058 * @return overlayed String, {@code null} if null String input 6059 * @since 2.0 6060 */ 6061 public static String overlay(final String str, String overlay, int start, int end) { 6062 if (str == null) { 6063 return null; 6064 } 6065 if (overlay == null) { 6066 overlay = EMPTY; 6067 } 6068 final int len = str.length(); 6069 if (start < 0) { 6070 start = 0; 6071 } 6072 if (start > len) { 6073 start = len; 6074 } 6075 if (end < 0) { 6076 end = 0; 6077 } 6078 if (end > len) { 6079 end = len; 6080 } 6081 if (start > end) { 6082 final int temp = start; 6083 start = end; 6084 end = temp; 6085 } 6086 return str.substring(0, start) + 6087 overlay + 6088 str.substring(end); 6089 } 6090 6091 // Chomping 6092 //----------------------------------------------------------------------- 6093 /** 6094 * <p>Removes one newline from end of a String if it's there, 6095 * otherwise leave it alone. A newline is "{@code \n}", 6096 * "{@code \r}", or "{@code \r\n}".</p> 6097 * 6098 * <p>NOTE: This method changed in 2.0. 6099 * It now more closely matches Perl chomp.</p> 6100 * 6101 * <pre> 6102 * StringUtils.chomp(null) = null 6103 * StringUtils.chomp("") = "" 6104 * StringUtils.chomp("abc \r") = "abc " 6105 * StringUtils.chomp("abc\n") = "abc" 6106 * StringUtils.chomp("abc\r\n") = "abc" 6107 * StringUtils.chomp("abc\r\n\r\n") = "abc\r\n" 6108 * StringUtils.chomp("abc\n\r") = "abc\n" 6109 * StringUtils.chomp("abc\n\rabc") = "abc\n\rabc" 6110 * StringUtils.chomp("\r") = "" 6111 * StringUtils.chomp("\n") = "" 6112 * StringUtils.chomp("\r\n") = "" 6113 * </pre> 6114 * 6115 * @param str the String to chomp a newline from, may be null 6116 * @return String without newline, {@code null} if null String input 6117 */ 6118 public static String chomp(final String str) { 6119 if (isEmpty(str)) { 6120 return str; 6121 } 6122 6123 if (str.length() == 1) { 6124 final char ch = str.charAt(0); 6125 if (ch == CharUtils.CR || ch == CharUtils.LF) { 6126 return EMPTY; 6127 } 6128 return str; 6129 } 6130 6131 int lastIdx = str.length() - 1; 6132 final char last = str.charAt(lastIdx); 6133 6134 if (last == CharUtils.LF) { 6135 if (str.charAt(lastIdx - 1) == CharUtils.CR) { 6136 lastIdx--; 6137 } 6138 } else if (last != CharUtils.CR) { 6139 lastIdx++; 6140 } 6141 return str.substring(0, lastIdx); 6142 } 6143 6144 /** 6145 * <p>Removes {@code separator} from the end of 6146 * {@code str} if it's there, otherwise leave it alone.</p> 6147 * 6148 * <p>NOTE: This method changed in version 2.0. 6149 * It now more closely matches Perl chomp. 6150 * For the previous behavior, use {@link #substringBeforeLast(String, String)}. 6151 * This method uses {@link String#endsWith(String)}.</p> 6152 * 6153 * <pre> 6154 * StringUtils.chomp(null, *) = null 6155 * StringUtils.chomp("", *) = "" 6156 * StringUtils.chomp("foobar", "bar") = "foo" 6157 * StringUtils.chomp("foobar", "baz") = "foobar" 6158 * StringUtils.chomp("foo", "foo") = "" 6159 * StringUtils.chomp("foo ", "foo") = "foo " 6160 * StringUtils.chomp(" foo", "foo") = " " 6161 * StringUtils.chomp("foo", "foooo") = "foo" 6162 * StringUtils.chomp("foo", "") = "foo" 6163 * StringUtils.chomp("foo", null) = "foo" 6164 * </pre> 6165 * 6166 * @param str the String to chomp from, may be null 6167 * @param separator separator String, may be null 6168 * @return String without trailing separator, {@code null} if null String input 6169 * @deprecated This feature will be removed in Lang 4.0, use {@link StringUtils#removeEnd(String, String)} instead 6170 */ 6171 @Deprecated 6172 public static String chomp(final String str, final String separator) { 6173 return removeEnd(str, separator); 6174 } 6175 6176 // Chopping 6177 //----------------------------------------------------------------------- 6178 /** 6179 * <p>Remove the last character from a String.</p> 6180 * 6181 * <p>If the String ends in {@code \r\n}, then remove both 6182 * of them.</p> 6183 * 6184 * <pre> 6185 * StringUtils.chop(null) = null 6186 * StringUtils.chop("") = "" 6187 * StringUtils.chop("abc \r") = "abc " 6188 * StringUtils.chop("abc\n") = "abc" 6189 * StringUtils.chop("abc\r\n") = "abc" 6190 * StringUtils.chop("abc") = "ab" 6191 * StringUtils.chop("abc\nabc") = "abc\nab" 6192 * StringUtils.chop("a") = "" 6193 * StringUtils.chop("\r") = "" 6194 * StringUtils.chop("\n") = "" 6195 * StringUtils.chop("\r\n") = "" 6196 * </pre> 6197 * 6198 * @param str the String to chop last character from, may be null 6199 * @return String without last character, {@code null} if null String input 6200 */ 6201 public static String chop(final String str) { 6202 if (str == null) { 6203 return null; 6204 } 6205 final int strLen = str.length(); 6206 if (strLen < 2) { 6207 return EMPTY; 6208 } 6209 final int lastIdx = strLen - 1; 6210 final String ret = str.substring(0, lastIdx); 6211 final char last = str.charAt(lastIdx); 6212 if (last == CharUtils.LF && ret.charAt(lastIdx - 1) == CharUtils.CR) { 6213 return ret.substring(0, lastIdx - 1); 6214 } 6215 return ret; 6216 } 6217 6218 // Conversion 6219 //----------------------------------------------------------------------- 6220 6221 // Padding 6222 //----------------------------------------------------------------------- 6223 /** 6224 * <p>Repeat a String {@code repeat} times to form a 6225 * new String.</p> 6226 * 6227 * <pre> 6228 * StringUtils.repeat(null, 2) = null 6229 * StringUtils.repeat("", 0) = "" 6230 * StringUtils.repeat("", 2) = "" 6231 * StringUtils.repeat("a", 3) = "aaa" 6232 * StringUtils.repeat("ab", 2) = "abab" 6233 * StringUtils.repeat("a", -2) = "" 6234 * </pre> 6235 * 6236 * @param str the String to repeat, may be null 6237 * @param repeat number of times to repeat str, negative treated as zero 6238 * @return a new String consisting of the original String repeated, 6239 * {@code null} if null String input 6240 */ 6241 public static String repeat(final String str, final int repeat) { 6242 // Performance tuned for 2.0 (JDK1.4) 6243 6244 if (str == null) { 6245 return null; 6246 } 6247 if (repeat <= 0) { 6248 return EMPTY; 6249 } 6250 final int inputLength = str.length(); 6251 if (repeat == 1 || inputLength == 0) { 6252 return str; 6253 } 6254 if (inputLength == 1 && repeat <= PAD_LIMIT) { 6255 return repeat(str.charAt(0), repeat); 6256 } 6257 6258 final int outputLength = inputLength * repeat; 6259 switch (inputLength) { 6260 case 1 : 6261 return repeat(str.charAt(0), repeat); 6262 case 2 : 6263 final char ch0 = str.charAt(0); 6264 final char ch1 = str.charAt(1); 6265 final char[] output2 = new char[outputLength]; 6266 for (int i = repeat * 2 - 2; i >= 0; i--, i--) { 6267 output2[i] = ch0; 6268 output2[i + 1] = ch1; 6269 } 6270 return new String(output2); 6271 default : 6272 final StringBuilder buf = new StringBuilder(outputLength); 6273 for (int i = 0; i < repeat; i++) { 6274 buf.append(str); 6275 } 6276 return buf.toString(); 6277 } 6278 } 6279 6280 /** 6281 * <p>Repeat a String {@code repeat} times to form a 6282 * new String, with a String separator injected each time. </p> 6283 * 6284 * <pre> 6285 * StringUtils.repeat(null, null, 2) = null 6286 * StringUtils.repeat(null, "x", 2) = null 6287 * StringUtils.repeat("", null, 0) = "" 6288 * StringUtils.repeat("", "", 2) = "" 6289 * StringUtils.repeat("", "x", 3) = "xxx" 6290 * StringUtils.repeat("?", ", ", 3) = "?, ?, ?" 6291 * </pre> 6292 * 6293 * @param str the String to repeat, may be null 6294 * @param separator the String to inject, may be null 6295 * @param repeat number of times to repeat str, negative treated as zero 6296 * @return a new String consisting of the original String repeated, 6297 * {@code null} if null String input 6298 * @since 2.5 6299 */ 6300 public static String repeat(final String str, final String separator, final int repeat) { 6301 if (str == null || separator == null) { 6302 return repeat(str, repeat); 6303 } 6304 // given that repeat(String, int) is quite optimized, better to rely on it than try and splice this into it 6305 final String result = repeat(str + separator, repeat); 6306 return removeEnd(result, separator); 6307 } 6308 6309 /** 6310 * <p>Returns padding using the specified delimiter repeated 6311 * to a given length.</p> 6312 * 6313 * <pre> 6314 * StringUtils.repeat('e', 0) = "" 6315 * StringUtils.repeat('e', 3) = "eee" 6316 * StringUtils.repeat('e', -2) = "" 6317 * </pre> 6318 * 6319 * <p>Note: this method does not support padding with 6320 * <a href="http://www.unicode.org/glossary/#supplementary_character">Unicode Supplementary Characters</a> 6321 * as they require a pair of {@code char}s to be represented. 6322 * If you are needing to support full I18N of your applications 6323 * consider using {@link #repeat(String, int)} instead. 6324 * </p> 6325 * 6326 * @param ch character to repeat 6327 * @param repeat number of times to repeat char, negative treated as zero 6328 * @return String with repeated character 6329 * @see #repeat(String, int) 6330 */ 6331 public static String repeat(final char ch, final int repeat) { 6332 if (repeat <= 0) { 6333 return EMPTY; 6334 } 6335 final char[] buf = new char[repeat]; 6336 for (int i = repeat - 1; i >= 0; i--) { 6337 buf[i] = ch; 6338 } 6339 return new String(buf); 6340 } 6341 6342 /** 6343 * <p>Right pad a String with spaces (' ').</p> 6344 * 6345 * <p>The String is padded to the size of {@code size}.</p> 6346 * 6347 * <pre> 6348 * StringUtils.rightPad(null, *) = null 6349 * StringUtils.rightPad("", 3) = " " 6350 * StringUtils.rightPad("bat", 3) = "bat" 6351 * StringUtils.rightPad("bat", 5) = "bat " 6352 * StringUtils.rightPad("bat", 1) = "bat" 6353 * StringUtils.rightPad("bat", -1) = "bat" 6354 * </pre> 6355 * 6356 * @param str the String to pad out, may be null 6357 * @param size the size to pad to 6358 * @return right padded String or original String if no padding is necessary, 6359 * {@code null} if null String input 6360 */ 6361 public static String rightPad(final String str, final int size) { 6362 return rightPad(str, size, ' '); 6363 } 6364 6365 /** 6366 * <p>Right pad a String with a specified character.</p> 6367 * 6368 * <p>The String is padded to the size of {@code size}.</p> 6369 * 6370 * <pre> 6371 * StringUtils.rightPad(null, *, *) = null 6372 * StringUtils.rightPad("", 3, 'z') = "zzz" 6373 * StringUtils.rightPad("bat", 3, 'z') = "bat" 6374 * StringUtils.rightPad("bat", 5, 'z') = "batzz" 6375 * StringUtils.rightPad("bat", 1, 'z') = "bat" 6376 * StringUtils.rightPad("bat", -1, 'z') = "bat" 6377 * </pre> 6378 * 6379 * @param str the String to pad out, may be null 6380 * @param size the size to pad to 6381 * @param padChar the character to pad with 6382 * @return right padded String or original String if no padding is necessary, 6383 * {@code null} if null String input 6384 * @since 2.0 6385 */ 6386 public static String rightPad(final String str, final int size, final char padChar) { 6387 if (str == null) { 6388 return null; 6389 } 6390 final int pads = size - str.length(); 6391 if (pads <= 0) { 6392 return str; // returns original String when possible 6393 } 6394 if (pads > PAD_LIMIT) { 6395 return rightPad(str, size, String.valueOf(padChar)); 6396 } 6397 return str.concat(repeat(padChar, pads)); 6398 } 6399 6400 /** 6401 * <p>Right pad a String with a specified String.</p> 6402 * 6403 * <p>The String is padded to the size of {@code size}.</p> 6404 * 6405 * <pre> 6406 * StringUtils.rightPad(null, *, *) = null 6407 * StringUtils.rightPad("", 3, "z") = "zzz" 6408 * StringUtils.rightPad("bat", 3, "yz") = "bat" 6409 * StringUtils.rightPad("bat", 5, "yz") = "batyz" 6410 * StringUtils.rightPad("bat", 8, "yz") = "batyzyzy" 6411 * StringUtils.rightPad("bat", 1, "yz") = "bat" 6412 * StringUtils.rightPad("bat", -1, "yz") = "bat" 6413 * StringUtils.rightPad("bat", 5, null) = "bat " 6414 * StringUtils.rightPad("bat", 5, "") = "bat " 6415 * </pre> 6416 * 6417 * @param str the String to pad out, may be null 6418 * @param size the size to pad to 6419 * @param padStr the String to pad with, null or empty treated as single space 6420 * @return right padded String or original String if no padding is necessary, 6421 * {@code null} if null String input 6422 */ 6423 public static String rightPad(final String str, final int size, String padStr) { 6424 if (str == null) { 6425 return null; 6426 } 6427 if (isEmpty(padStr)) { 6428 padStr = SPACE; 6429 } 6430 final int padLen = padStr.length(); 6431 final int strLen = str.length(); 6432 final int pads = size - strLen; 6433 if (pads <= 0) { 6434 return str; // returns original String when possible 6435 } 6436 if (padLen == 1 && pads <= PAD_LIMIT) { 6437 return rightPad(str, size, padStr.charAt(0)); 6438 } 6439 6440 if (pads == padLen) { 6441 return str.concat(padStr); 6442 } else if (pads < padLen) { 6443 return str.concat(padStr.substring(0, pads)); 6444 } else { 6445 final char[] padding = new char[pads]; 6446 final char[] padChars = padStr.toCharArray(); 6447 for (int i = 0; i < pads; i++) { 6448 padding[i] = padChars[i % padLen]; 6449 } 6450 return str.concat(new String(padding)); 6451 } 6452 } 6453 6454 /** 6455 * <p>Left pad a String with spaces (' ').</p> 6456 * 6457 * <p>The String is padded to the size of {@code size}.</p> 6458 * 6459 * <pre> 6460 * StringUtils.leftPad(null, *) = null 6461 * StringUtils.leftPad("", 3) = " " 6462 * StringUtils.leftPad("bat", 3) = "bat" 6463 * StringUtils.leftPad("bat", 5) = " bat" 6464 * StringUtils.leftPad("bat", 1) = "bat" 6465 * StringUtils.leftPad("bat", -1) = "bat" 6466 * </pre> 6467 * 6468 * @param str the String to pad out, may be null 6469 * @param size the size to pad to 6470 * @return left padded String or original String if no padding is necessary, 6471 * {@code null} if null String input 6472 */ 6473 public static String leftPad(final String str, final int size) { 6474 return leftPad(str, size, ' '); 6475 } 6476 6477 /** 6478 * <p>Left pad a String with a specified character.</p> 6479 * 6480 * <p>Pad to a size of {@code size}.</p> 6481 * 6482 * <pre> 6483 * StringUtils.leftPad(null, *, *) = null 6484 * StringUtils.leftPad("", 3, 'z') = "zzz" 6485 * StringUtils.leftPad("bat", 3, 'z') = "bat" 6486 * StringUtils.leftPad("bat", 5, 'z') = "zzbat" 6487 * StringUtils.leftPad("bat", 1, 'z') = "bat" 6488 * StringUtils.leftPad("bat", -1, 'z') = "bat" 6489 * </pre> 6490 * 6491 * @param str the String to pad out, may be null 6492 * @param size the size to pad to 6493 * @param padChar the character to pad with 6494 * @return left padded String or original String if no padding is necessary, 6495 * {@code null} if null String input 6496 * @since 2.0 6497 */ 6498 public static String leftPad(final String str, final int size, final char padChar) { 6499 if (str == null) { 6500 return null; 6501 } 6502 final int pads = size - str.length(); 6503 if (pads <= 0) { 6504 return str; // returns original String when possible 6505 } 6506 if (pads > PAD_LIMIT) { 6507 return leftPad(str, size, String.valueOf(padChar)); 6508 } 6509 return repeat(padChar, pads).concat(str); 6510 } 6511 6512 /** 6513 * <p>Left pad a String with a specified String.</p> 6514 * 6515 * <p>Pad to a size of {@code size}.</p> 6516 * 6517 * <pre> 6518 * StringUtils.leftPad(null, *, *) = null 6519 * StringUtils.leftPad("", 3, "z") = "zzz" 6520 * StringUtils.leftPad("bat", 3, "yz") = "bat" 6521 * StringUtils.leftPad("bat", 5, "yz") = "yzbat" 6522 * StringUtils.leftPad("bat", 8, "yz") = "yzyzybat" 6523 * StringUtils.leftPad("bat", 1, "yz") = "bat" 6524 * StringUtils.leftPad("bat", -1, "yz") = "bat" 6525 * StringUtils.leftPad("bat", 5, null) = " bat" 6526 * StringUtils.leftPad("bat", 5, "") = " bat" 6527 * </pre> 6528 * 6529 * @param str the String to pad out, may be null 6530 * @param size the size to pad to 6531 * @param padStr the String to pad with, null or empty treated as single space 6532 * @return left padded String or original String if no padding is necessary, 6533 * {@code null} if null String input 6534 */ 6535 public static String leftPad(final String str, final int size, String padStr) { 6536 if (str == null) { 6537 return null; 6538 } 6539 if (isEmpty(padStr)) { 6540 padStr = SPACE; 6541 } 6542 final int padLen = padStr.length(); 6543 final int strLen = str.length(); 6544 final int pads = size - strLen; 6545 if (pads <= 0) { 6546 return str; // returns original String when possible 6547 } 6548 if (padLen == 1 && pads <= PAD_LIMIT) { 6549 return leftPad(str, size, padStr.charAt(0)); 6550 } 6551 6552 if (pads == padLen) { 6553 return padStr.concat(str); 6554 } else if (pads < padLen) { 6555 return padStr.substring(0, pads).concat(str); 6556 } else { 6557 final char[] padding = new char[pads]; 6558 final char[] padChars = padStr.toCharArray(); 6559 for (int i = 0; i < pads; i++) { 6560 padding[i] = padChars[i % padLen]; 6561 } 6562 return new String(padding).concat(str); 6563 } 6564 } 6565 6566 /** 6567 * Gets a CharSequence length or {@code 0} if the CharSequence is 6568 * {@code null}. 6569 * 6570 * @param cs 6571 * a CharSequence or {@code null} 6572 * @return CharSequence length or {@code 0} if the CharSequence is 6573 * {@code null}. 6574 * @since 2.4 6575 * @since 3.0 Changed signature from length(String) to length(CharSequence) 6576 */ 6577 public static int length(final CharSequence cs) { 6578 return cs == null ? 0 : cs.length(); 6579 } 6580 6581 // Centering 6582 //----------------------------------------------------------------------- 6583 /** 6584 * <p>Centers a String in a larger String of size {@code size} 6585 * using the space character (' ').</p> 6586 * 6587 * <p>If the size is less than the String length, the String is returned. 6588 * A {@code null} String returns {@code null}. 6589 * A negative size is treated as zero.</p> 6590 * 6591 * <p>Equivalent to {@code center(str, size, " ")}.</p> 6592 * 6593 * <pre> 6594 * StringUtils.center(null, *) = null 6595 * StringUtils.center("", 4) = " " 6596 * StringUtils.center("ab", -1) = "ab" 6597 * StringUtils.center("ab", 4) = " ab " 6598 * StringUtils.center("abcd", 2) = "abcd" 6599 * StringUtils.center("a", 4) = " a " 6600 * </pre> 6601 * 6602 * @param str the String to center, may be null 6603 * @param size the int size of new String, negative treated as zero 6604 * @return centered String, {@code null} if null String input 6605 */ 6606 public static String center(final String str, final int size) { 6607 return center(str, size, ' '); 6608 } 6609 6610 /** 6611 * <p>Centers a String in a larger String of size {@code size}. 6612 * Uses a supplied character as the value to pad the String with.</p> 6613 * 6614 * <p>If the size is less than the String length, the String is returned. 6615 * A {@code null} String returns {@code null}. 6616 * A negative size is treated as zero.</p> 6617 * 6618 * <pre> 6619 * StringUtils.center(null, *, *) = null 6620 * StringUtils.center("", 4, ' ') = " " 6621 * StringUtils.center("ab", -1, ' ') = "ab" 6622 * StringUtils.center("ab", 4, ' ') = " ab " 6623 * StringUtils.center("abcd", 2, ' ') = "abcd" 6624 * StringUtils.center("a", 4, ' ') = " a " 6625 * StringUtils.center("a", 4, 'y') = "yayy" 6626 * </pre> 6627 * 6628 * @param str the String to center, may be null 6629 * @param size the int size of new String, negative treated as zero 6630 * @param padChar the character to pad the new String with 6631 * @return centered String, {@code null} if null String input 6632 * @since 2.0 6633 */ 6634 public static String center(String str, final int size, final char padChar) { 6635 if (str == null || size <= 0) { 6636 return str; 6637 } 6638 final int strLen = str.length(); 6639 final int pads = size - strLen; 6640 if (pads <= 0) { 6641 return str; 6642 } 6643 str = leftPad(str, strLen + pads / 2, padChar); 6644 str = rightPad(str, size, padChar); 6645 return str; 6646 } 6647 6648 /** 6649 * <p>Centers a String in a larger String of size {@code size}. 6650 * Uses a supplied String as the value to pad the String with.</p> 6651 * 6652 * <p>If the size is less than the String length, the String is returned. 6653 * A {@code null} String returns {@code null}. 6654 * A negative size is treated as zero.</p> 6655 * 6656 * <pre> 6657 * StringUtils.center(null, *, *) = null 6658 * StringUtils.center("", 4, " ") = " " 6659 * StringUtils.center("ab", -1, " ") = "ab" 6660 * StringUtils.center("ab", 4, " ") = " ab " 6661 * StringUtils.center("abcd", 2, " ") = "abcd" 6662 * StringUtils.center("a", 4, " ") = " a " 6663 * StringUtils.center("a", 4, "yz") = "yayz" 6664 * StringUtils.center("abc", 7, null) = " abc " 6665 * StringUtils.center("abc", 7, "") = " abc " 6666 * </pre> 6667 * 6668 * @param str the String to center, may be null 6669 * @param size the int size of new String, negative treated as zero 6670 * @param padStr the String to pad the new String with, must not be null or empty 6671 * @return centered String, {@code null} if null String input 6672 * @throws IllegalArgumentException if padStr is {@code null} or empty 6673 */ 6674 public static String center(String str, final int size, String padStr) { 6675 if (str == null || size <= 0) { 6676 return str; 6677 } 6678 if (isEmpty(padStr)) { 6679 padStr = SPACE; 6680 } 6681 final int strLen = str.length(); 6682 final int pads = size - strLen; 6683 if (pads <= 0) { 6684 return str; 6685 } 6686 str = leftPad(str, strLen + pads / 2, padStr); 6687 str = rightPad(str, size, padStr); 6688 return str; 6689 } 6690 6691 // Case conversion 6692 //----------------------------------------------------------------------- 6693 /** 6694 * <p>Converts a String to upper case as per {@link String#toUpperCase()}.</p> 6695 * 6696 * <p>A {@code null} input String returns {@code null}.</p> 6697 * 6698 * <pre> 6699 * StringUtils.upperCase(null) = null 6700 * StringUtils.upperCase("") = "" 6701 * StringUtils.upperCase("aBc") = "ABC" 6702 * </pre> 6703 * 6704 * <p><strong>Note:</strong> As described in the documentation for {@link String#toUpperCase()}, 6705 * the result of this method is affected by the current locale. 6706 * For platform-independent case transformations, the method {@link #lowerCase(String, Locale)} 6707 * should be used with a specific locale (e.g. {@link Locale#ENGLISH}).</p> 6708 * 6709 * @param str the String to upper case, may be null 6710 * @return the upper cased String, {@code null} if null String input 6711 */ 6712 public static String upperCase(final String str) { 6713 if (str == null) { 6714 return null; 6715 } 6716 return str.toUpperCase(); 6717 } 6718 6719 /** 6720 * <p>Converts a String to upper case as per {@link String#toUpperCase(Locale)}.</p> 6721 * 6722 * <p>A {@code null} input String returns {@code null}.</p> 6723 * 6724 * <pre> 6725 * StringUtils.upperCase(null, Locale.ENGLISH) = null 6726 * StringUtils.upperCase("", Locale.ENGLISH) = "" 6727 * StringUtils.upperCase("aBc", Locale.ENGLISH) = "ABC" 6728 * </pre> 6729 * 6730 * @param str the String to upper case, may be null 6731 * @param locale the locale that defines the case transformation rules, must not be null 6732 * @return the upper cased String, {@code null} if null String input 6733 * @since 2.5 6734 */ 6735 public static String upperCase(final String str, final Locale locale) { 6736 if (str == null) { 6737 return null; 6738 } 6739 return str.toUpperCase(locale); 6740 } 6741 6742 /** 6743 * <p>Converts a String to lower case as per {@link String#toLowerCase()}.</p> 6744 * 6745 * <p>A {@code null} input String returns {@code null}.</p> 6746 * 6747 * <pre> 6748 * StringUtils.lowerCase(null) = null 6749 * StringUtils.lowerCase("") = "" 6750 * StringUtils.lowerCase("aBc") = "abc" 6751 * </pre> 6752 * 6753 * <p><strong>Note:</strong> As described in the documentation for {@link String#toLowerCase()}, 6754 * the result of this method is affected by the current locale. 6755 * For platform-independent case transformations, the method {@link #lowerCase(String, Locale)} 6756 * should be used with a specific locale (e.g. {@link Locale#ENGLISH}).</p> 6757 * 6758 * @param str the String to lower case, may be null 6759 * @return the lower cased String, {@code null} if null String input 6760 */ 6761 public static String lowerCase(final String str) { 6762 if (str == null) { 6763 return null; 6764 } 6765 return str.toLowerCase(); 6766 } 6767 6768 /** 6769 * <p>Converts a String to lower case as per {@link String#toLowerCase(Locale)}.</p> 6770 * 6771 * <p>A {@code null} input String returns {@code null}.</p> 6772 * 6773 * <pre> 6774 * StringUtils.lowerCase(null, Locale.ENGLISH) = null 6775 * StringUtils.lowerCase("", Locale.ENGLISH) = "" 6776 * StringUtils.lowerCase("aBc", Locale.ENGLISH) = "abc" 6777 * </pre> 6778 * 6779 * @param str the String to lower case, may be null 6780 * @param locale the locale that defines the case transformation rules, must not be null 6781 * @return the lower cased String, {@code null} if null String input 6782 * @since 2.5 6783 */ 6784 public static String lowerCase(final String str, final Locale locale) { 6785 if (str == null) { 6786 return null; 6787 } 6788 return str.toLowerCase(locale); 6789 } 6790 6791 /** 6792 * <p>Capitalizes a String changing the first character to title case as 6793 * per {@link Character#toTitleCase(int)}. No other characters are changed.</p> 6794 * 6795 * <p>For a word based algorithm, see {@link org.apache.commons.lang3.text.WordUtils#capitalize(String)}. 6796 * A {@code null} input String returns {@code null}.</p> 6797 * 6798 * <pre> 6799 * StringUtils.capitalize(null) = null 6800 * StringUtils.capitalize("") = "" 6801 * StringUtils.capitalize("cat") = "Cat" 6802 * StringUtils.capitalize("cAt") = "CAt" 6803 * StringUtils.capitalize("'cat'") = "'cat'" 6804 * </pre> 6805 * 6806 * @param str the String to capitalize, may be null 6807 * @return the capitalized String, {@code null} if null String input 6808 * @see org.apache.commons.lang3.text.WordUtils#capitalize(String) 6809 * @see #uncapitalize(String) 6810 * @since 2.0 6811 */ 6812 public static String capitalize(final String str) { 6813 int strLen; 6814 if (str == null || (strLen = str.length()) == 0) { 6815 return str; 6816 } 6817 6818 final int firstCodepoint = str.codePointAt(0); 6819 final int newCodePoint = Character.toTitleCase(firstCodepoint); 6820 if (firstCodepoint == newCodePoint) { 6821 // already capitalized 6822 return str; 6823 } 6824 6825 final int newCodePoints[] = new int[strLen]; // cannot be longer than the char array 6826 int outOffset = 0; 6827 newCodePoints[outOffset++] = newCodePoint; // copy the first codepoint 6828 for (int inOffset = Character.charCount(firstCodepoint); inOffset < strLen; ) { 6829 final int codepoint = str.codePointAt(inOffset); 6830 newCodePoints[outOffset++] = codepoint; // copy the remaining ones 6831 inOffset += Character.charCount(codepoint); 6832 } 6833 return new String(newCodePoints, 0, outOffset); 6834 } 6835 6836 /** 6837 * <p>Uncapitalizes a String, changing the first character to lower case as 6838 * per {@link Character#toLowerCase(int)}. No other characters are changed.</p> 6839 * 6840 * <p>For a word based algorithm, see {@link org.apache.commons.lang3.text.WordUtils#uncapitalize(String)}. 6841 * A {@code null} input String returns {@code null}.</p> 6842 * 6843 * <pre> 6844 * StringUtils.uncapitalize(null) = null 6845 * StringUtils.uncapitalize("") = "" 6846 * StringUtils.uncapitalize("cat") = "cat" 6847 * StringUtils.uncapitalize("Cat") = "cat" 6848 * StringUtils.uncapitalize("CAT") = "cAT" 6849 * </pre> 6850 * 6851 * @param str the String to uncapitalize, may be null 6852 * @return the uncapitalized String, {@code null} if null String input 6853 * @see org.apache.commons.lang3.text.WordUtils#uncapitalize(String) 6854 * @see #capitalize(String) 6855 * @since 2.0 6856 */ 6857 public static String uncapitalize(final String str) { 6858 int strLen; 6859 if (str == null || (strLen = str.length()) == 0) { 6860 return str; 6861 } 6862 6863 final int firstCodepoint = str.codePointAt(0); 6864 final int newCodePoint = Character.toLowerCase(firstCodepoint); 6865 if (firstCodepoint == newCodePoint) { 6866 // already capitalized 6867 return str; 6868 } 6869 6870 final int newCodePoints[] = new int[strLen]; // cannot be longer than the char array 6871 int outOffset = 0; 6872 newCodePoints[outOffset++] = newCodePoint; // copy the first codepoint 6873 for (int inOffset = Character.charCount(firstCodepoint); inOffset < strLen; ) { 6874 final int codepoint = str.codePointAt(inOffset); 6875 newCodePoints[outOffset++] = codepoint; // copy the remaining ones 6876 inOffset += Character.charCount(codepoint); 6877 } 6878 return new String(newCodePoints, 0, outOffset); 6879 } 6880 6881 /** 6882 * <p>Swaps the case of a String changing upper and title case to 6883 * lower case, and lower case to upper case.</p> 6884 * 6885 * <ul> 6886 * <li>Upper case character converts to Lower case</li> 6887 * <li>Title case character converts to Lower case</li> 6888 * <li>Lower case character converts to Upper case</li> 6889 * </ul> 6890 * 6891 * <p>For a word based algorithm, see {@link org.apache.commons.lang3.text.WordUtils#swapCase(String)}. 6892 * A {@code null} input String returns {@code null}.</p> 6893 * 6894 * <pre> 6895 * StringUtils.swapCase(null) = null 6896 * StringUtils.swapCase("") = "" 6897 * StringUtils.swapCase("The dog has a BONE") = "tHE DOG HAS A bone" 6898 * </pre> 6899 * 6900 * <p>NOTE: This method changed in Lang version 2.0. 6901 * It no longer performs a word based algorithm. 6902 * If you only use ASCII, you will notice no change. 6903 * That functionality is available in org.apache.commons.lang3.text.WordUtils.</p> 6904 * 6905 * @param str the String to swap case, may be null 6906 * @return the changed String, {@code null} if null String input 6907 */ 6908 public static String swapCase(final String str) { 6909 if (isEmpty(str)) { 6910 return str; 6911 } 6912 6913 final int strLen = str.length(); 6914 final int newCodePoints[] = new int[strLen]; // cannot be longer than the char array 6915 int outOffset = 0; 6916 for (int i = 0; i < strLen; ) { 6917 final int oldCodepoint = str.codePointAt(i); 6918 final int newCodePoint; 6919 if (Character.isUpperCase(oldCodepoint)) { 6920 newCodePoint = Character.toLowerCase(oldCodepoint); 6921 } else if (Character.isTitleCase(oldCodepoint)) { 6922 newCodePoint = Character.toLowerCase(oldCodepoint); 6923 } else if (Character.isLowerCase(oldCodepoint)) { 6924 newCodePoint = Character.toUpperCase(oldCodepoint); 6925 } else { 6926 newCodePoint = oldCodepoint; 6927 } 6928 newCodePoints[outOffset++] = newCodePoint; 6929 i += Character.charCount(newCodePoint); 6930 } 6931 return new String(newCodePoints, 0, outOffset); 6932 } 6933 6934 // Count matches 6935 //----------------------------------------------------------------------- 6936 /** 6937 * <p>Counts how many times the substring appears in the larger string.</p> 6938 * 6939 * <p>A {@code null} or empty ("") String input returns {@code 0}.</p> 6940 * 6941 * <pre> 6942 * StringUtils.countMatches(null, *) = 0 6943 * StringUtils.countMatches("", *) = 0 6944 * StringUtils.countMatches("abba", null) = 0 6945 * StringUtils.countMatches("abba", "") = 0 6946 * StringUtils.countMatches("abba", "a") = 2 6947 * StringUtils.countMatches("abba", "ab") = 1 6948 * StringUtils.countMatches("abba", "xxx") = 0 6949 * </pre> 6950 * 6951 * @param str the CharSequence to check, may be null 6952 * @param sub the substring to count, may be null 6953 * @return the number of occurrences, 0 if either CharSequence is {@code null} 6954 * @since 3.0 Changed signature from countMatches(String, String) to countMatches(CharSequence, CharSequence) 6955 */ 6956 public static int countMatches(final CharSequence str, final CharSequence sub) { 6957 if (isEmpty(str) || isEmpty(sub)) { 6958 return 0; 6959 } 6960 int count = 0; 6961 int idx = 0; 6962 while ((idx = CharSequenceUtils.indexOf(str, sub, idx)) != INDEX_NOT_FOUND) { 6963 count++; 6964 idx += sub.length(); 6965 } 6966 return count; 6967 } 6968 6969 /** 6970 * <p>Counts how many times the char appears in the given string.</p> 6971 * 6972 * <p>A {@code null} or empty ("") String input returns {@code 0}.</p> 6973 * 6974 * <pre> 6975 * StringUtils.countMatches(null, *) = 0 6976 * StringUtils.countMatches("", *) = 0 6977 * StringUtils.countMatches("abba", 0) = 0 6978 * StringUtils.countMatches("abba", 'a') = 2 6979 * StringUtils.countMatches("abba", 'b') = 2 6980 * StringUtils.countMatches("abba", 'x') = 0 6981 * </pre> 6982 * 6983 * @param str the CharSequence to check, may be null 6984 * @param ch the char to count 6985 * @return the number of occurrences, 0 if the CharSequence is {@code null} 6986 * @since 3.4 6987 */ 6988 public static int countMatches(final CharSequence str, final char ch) { 6989 if (isEmpty(str)) { 6990 return 0; 6991 } 6992 int count = 0; 6993 // We could also call str.toCharArray() for faster look ups but that would generate more garbage. 6994 for (int i = 0; i < str.length(); i++) { 6995 if (ch == str.charAt(i)) { 6996 count++; 6997 } 6998 } 6999 return count; 7000 } 7001 7002 // Character Tests 7003 //----------------------------------------------------------------------- 7004 /** 7005 * <p>Checks if the CharSequence contains only Unicode letters.</p> 7006 * 7007 * <p>{@code null} will return {@code false}. 7008 * An empty CharSequence (length()=0) will return {@code false}.</p> 7009 * 7010 * <pre> 7011 * StringUtils.isAlpha(null) = false 7012 * StringUtils.isAlpha("") = false 7013 * StringUtils.isAlpha(" ") = false 7014 * StringUtils.isAlpha("abc") = true 7015 * StringUtils.isAlpha("ab2c") = false 7016 * StringUtils.isAlpha("ab-c") = false 7017 * </pre> 7018 * 7019 * @param cs the CharSequence to check, may be null 7020 * @return {@code true} if only contains letters, and is non-null 7021 * @since 3.0 Changed signature from isAlpha(String) to isAlpha(CharSequence) 7022 * @since 3.0 Changed "" to return false and not true 7023 */ 7024 public static boolean isAlpha(final CharSequence cs) { 7025 if (isEmpty(cs)) { 7026 return false; 7027 } 7028 final int sz = cs.length(); 7029 for (int i = 0; i < sz; i++) { 7030 if (!Character.isLetter(cs.charAt(i))) { 7031 return false; 7032 } 7033 } 7034 return true; 7035 } 7036 7037 /** 7038 * <p>Checks if the CharSequence contains only Unicode letters and 7039 * space (' ').</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.isAlphaSpace(null) = false 7046 * StringUtils.isAlphaSpace("") = true 7047 * StringUtils.isAlphaSpace(" ") = true 7048 * StringUtils.isAlphaSpace("abc") = true 7049 * StringUtils.isAlphaSpace("ab c") = true 7050 * StringUtils.isAlphaSpace("ab2c") = false 7051 * StringUtils.isAlphaSpace("ab-c") = false 7052 * </pre> 7053 * 7054 * @param cs the CharSequence to check, may be null 7055 * @return {@code true} if only contains letters and space, 7056 * and is non-null 7057 * @since 3.0 Changed signature from isAlphaSpace(String) to isAlphaSpace(CharSequence) 7058 */ 7059 public static boolean isAlphaSpace(final CharSequence cs) { 7060 if (cs == null) { 7061 return false; 7062 } 7063 final int sz = cs.length(); 7064 for (int i = 0; i < sz; i++) { 7065 if (!Character.isLetter(cs.charAt(i)) && cs.charAt(i) != ' ') { 7066 return false; 7067 } 7068 } 7069 return true; 7070 } 7071 7072 /** 7073 * <p>Checks if the CharSequence contains only Unicode letters or digits.</p> 7074 * 7075 * <p>{@code null} will return {@code false}. 7076 * An empty CharSequence (length()=0) will return {@code false}.</p> 7077 * 7078 * <pre> 7079 * StringUtils.isAlphanumeric(null) = false 7080 * StringUtils.isAlphanumeric("") = false 7081 * StringUtils.isAlphanumeric(" ") = false 7082 * StringUtils.isAlphanumeric("abc") = true 7083 * StringUtils.isAlphanumeric("ab c") = false 7084 * StringUtils.isAlphanumeric("ab2c") = true 7085 * StringUtils.isAlphanumeric("ab-c") = false 7086 * </pre> 7087 * 7088 * @param cs the CharSequence to check, may be null 7089 * @return {@code true} if only contains letters or digits, 7090 * and is non-null 7091 * @since 3.0 Changed signature from isAlphanumeric(String) to isAlphanumeric(CharSequence) 7092 * @since 3.0 Changed "" to return false and not true 7093 */ 7094 public static boolean isAlphanumeric(final CharSequence cs) { 7095 if (isEmpty(cs)) { 7096 return false; 7097 } 7098 final int sz = cs.length(); 7099 for (int i = 0; i < sz; i++) { 7100 if (!Character.isLetterOrDigit(cs.charAt(i))) { 7101 return false; 7102 } 7103 } 7104 return true; 7105 } 7106 7107 /** 7108 * <p>Checks if the CharSequence contains only Unicode letters, digits 7109 * or space ({@code ' '}).</p> 7110 * 7111 * <p>{@code null} will return {@code false}. 7112 * An empty CharSequence (length()=0) will return {@code true}.</p> 7113 * 7114 * <pre> 7115 * StringUtils.isAlphanumericSpace(null) = false 7116 * StringUtils.isAlphanumericSpace("") = true 7117 * StringUtils.isAlphanumericSpace(" ") = true 7118 * StringUtils.isAlphanumericSpace("abc") = true 7119 * StringUtils.isAlphanumericSpace("ab c") = true 7120 * StringUtils.isAlphanumericSpace("ab2c") = true 7121 * StringUtils.isAlphanumericSpace("ab-c") = false 7122 * </pre> 7123 * 7124 * @param cs the CharSequence to check, may be null 7125 * @return {@code true} if only contains letters, digits or space, 7126 * and is non-null 7127 * @since 3.0 Changed signature from isAlphanumericSpace(String) to isAlphanumericSpace(CharSequence) 7128 */ 7129 public static boolean isAlphanumericSpace(final CharSequence cs) { 7130 if (cs == null) { 7131 return false; 7132 } 7133 final int sz = cs.length(); 7134 for (int i = 0; i < sz; i++) { 7135 if (!Character.isLetterOrDigit(cs.charAt(i)) && cs.charAt(i) != ' ') { 7136 return false; 7137 } 7138 } 7139 return true; 7140 } 7141 7142 /** 7143 * <p>Checks if the CharSequence contains only ASCII printable characters.</p> 7144 * 7145 * <p>{@code null} will return {@code false}. 7146 * An empty CharSequence (length()=0) will return {@code true}.</p> 7147 * 7148 * <pre> 7149 * StringUtils.isAsciiPrintable(null) = false 7150 * StringUtils.isAsciiPrintable("") = true 7151 * StringUtils.isAsciiPrintable(" ") = true 7152 * StringUtils.isAsciiPrintable("Ceki") = true 7153 * StringUtils.isAsciiPrintable("ab2c") = true 7154 * StringUtils.isAsciiPrintable("!ab-c~") = true 7155 * StringUtils.isAsciiPrintable("\u0020") = true 7156 * StringUtils.isAsciiPrintable("\u0021") = true 7157 * StringUtils.isAsciiPrintable("\u007e") = true 7158 * StringUtils.isAsciiPrintable("\u007f") = false 7159 * StringUtils.isAsciiPrintable("Ceki G\u00fclc\u00fc") = false 7160 * </pre> 7161 * 7162 * @param cs the CharSequence to check, may be null 7163 * @return {@code true} if every character is in the range 7164 * 32 thru 126 7165 * @since 2.1 7166 * @since 3.0 Changed signature from isAsciiPrintable(String) to isAsciiPrintable(CharSequence) 7167 */ 7168 public static boolean isAsciiPrintable(final CharSequence cs) { 7169 if (cs == null) { 7170 return false; 7171 } 7172 final int sz = cs.length(); 7173 for (int i = 0; i < sz; i++) { 7174 if (!CharUtils.isAsciiPrintable(cs.charAt(i))) { 7175 return false; 7176 } 7177 } 7178 return true; 7179 } 7180 7181 /** 7182 * <p>Checks if the CharSequence contains only Unicode digits. 7183 * A decimal point is not a Unicode digit and returns false.</p> 7184 * 7185 * <p>{@code null} will return {@code false}. 7186 * An empty CharSequence (length()=0) will return {@code false}.</p> 7187 * 7188 * <p>Note that the method does not allow for a leading sign, either positive or negative. 7189 * Also, if a String passes the numeric test, it may still generate a NumberFormatException 7190 * when parsed by Integer.parseInt or Long.parseLong, e.g. if the value is outside the range 7191 * for int or long respectively.</p> 7192 * 7193 * <pre> 7194 * StringUtils.isNumeric(null) = false 7195 * StringUtils.isNumeric("") = false 7196 * StringUtils.isNumeric(" ") = false 7197 * StringUtils.isNumeric("123") = true 7198 * StringUtils.isNumeric("\u0967\u0968\u0969") = true 7199 * StringUtils.isNumeric("12 3") = false 7200 * StringUtils.isNumeric("ab2c") = false 7201 * StringUtils.isNumeric("12-3") = false 7202 * StringUtils.isNumeric("12.3") = false 7203 * StringUtils.isNumeric("-123") = false 7204 * StringUtils.isNumeric("+123") = false 7205 * </pre> 7206 * 7207 * @param cs the CharSequence to check, may be null 7208 * @return {@code true} if only contains digits, and is non-null 7209 * @since 3.0 Changed signature from isNumeric(String) to isNumeric(CharSequence) 7210 * @since 3.0 Changed "" to return false and not true 7211 */ 7212 public static boolean isNumeric(final CharSequence cs) { 7213 if (isEmpty(cs)) { 7214 return false; 7215 } 7216 final int sz = cs.length(); 7217 for (int i = 0; i < sz; i++) { 7218 if (!Character.isDigit(cs.charAt(i))) { 7219 return false; 7220 } 7221 } 7222 return true; 7223 } 7224 7225 /** 7226 * <p>Checks if the CharSequence contains only Unicode digits or space 7227 * ({@code ' '}). 7228 * A decimal point is not a Unicode digit and returns false.</p> 7229 * 7230 * <p>{@code null} will return {@code false}. 7231 * An empty CharSequence (length()=0) will return {@code true}.</p> 7232 * 7233 * <pre> 7234 * StringUtils.isNumericSpace(null) = false 7235 * StringUtils.isNumericSpace("") = true 7236 * StringUtils.isNumericSpace(" ") = true 7237 * StringUtils.isNumericSpace("123") = true 7238 * StringUtils.isNumericSpace("12 3") = true 7239 * StringUtils.isNumeric("\u0967\u0968\u0969") = true 7240 * StringUtils.isNumeric("\u0967\u0968 \u0969") = true 7241 * StringUtils.isNumericSpace("ab2c") = false 7242 * StringUtils.isNumericSpace("12-3") = false 7243 * StringUtils.isNumericSpace("12.3") = false 7244 * </pre> 7245 * 7246 * @param cs the CharSequence to check, may be null 7247 * @return {@code true} if only contains digits or space, 7248 * and is non-null 7249 * @since 3.0 Changed signature from isNumericSpace(String) to isNumericSpace(CharSequence) 7250 */ 7251 public static boolean isNumericSpace(final CharSequence cs) { 7252 if (cs == null) { 7253 return false; 7254 } 7255 final int sz = cs.length(); 7256 for (int i = 0; i < sz; i++) { 7257 if (!Character.isDigit(cs.charAt(i)) && cs.charAt(i) != ' ') { 7258 return false; 7259 } 7260 } 7261 return true; 7262 } 7263 7264 /** 7265 * <p>Checks if a String {@code str} contains Unicode digits, 7266 * if yes then concatenate all the digits in {@code str} and return it as a String.</p> 7267 * 7268 * <p>An empty ("") String will be returned if no digits found in {@code str}.</p> 7269 * 7270 * <pre> 7271 * StringUtils.getDigits(null) = null 7272 * StringUtils.getDigits("") = "" 7273 * StringUtils.getDigits("abc") = "" 7274 * StringUtils.getDigits("1000$") = "1000" 7275 * StringUtils.getDigits("1123~45") = "112345" 7276 * StringUtils.getDigits("(541) 754-3010") = "5417543010" 7277 * StringUtils.getDigits("\u0967\u0968\u0969") = "\u0967\u0968\u0969" 7278 * </pre> 7279 * 7280 * @param str the String to extract digits from, may be null 7281 * @return String with only digits, 7282 * or an empty ("") String if no digits found, 7283 * or {@code null} String if {@code str} is null 7284 * @since 3.6 7285 */ 7286 public static String getDigits(final String str) { 7287 if (isEmpty(str)) { 7288 return str; 7289 } 7290 final int sz = str.length(); 7291 final StringBuilder strDigits = new StringBuilder(sz); 7292 for (int i = 0; i < sz; i++) { 7293 final char tempChar = str.charAt(i); 7294 if (Character.isDigit(tempChar)) { 7295 strDigits.append(tempChar); 7296 } 7297 } 7298 return strDigits.toString(); 7299 } 7300 7301 /** 7302 * <p>Checks if the CharSequence contains only whitespace.</p> 7303 * 7304 * <p>Whitespace is defined by {@link Character#isWhitespace(char)}.</p> 7305 * 7306 * <p>{@code null} will return {@code false}. 7307 * An empty CharSequence (length()=0) will return {@code true}.</p> 7308 * 7309 * <pre> 7310 * StringUtils.isWhitespace(null) = false 7311 * StringUtils.isWhitespace("") = true 7312 * StringUtils.isWhitespace(" ") = true 7313 * StringUtils.isWhitespace("abc") = false 7314 * StringUtils.isWhitespace("ab2c") = false 7315 * StringUtils.isWhitespace("ab-c") = false 7316 * </pre> 7317 * 7318 * @param cs the CharSequence to check, may be null 7319 * @return {@code true} if only contains whitespace, and is non-null 7320 * @since 2.0 7321 * @since 3.0 Changed signature from isWhitespace(String) to isWhitespace(CharSequence) 7322 */ 7323 public static boolean isWhitespace(final CharSequence cs) { 7324 if (cs == null) { 7325 return false; 7326 } 7327 final int sz = cs.length(); 7328 for (int i = 0; i < sz; i++) { 7329 if (!Character.isWhitespace(cs.charAt(i))) { 7330 return false; 7331 } 7332 } 7333 return true; 7334 } 7335 7336 /** 7337 * <p>Checks if the CharSequence contains only lowercase characters.</p> 7338 * 7339 * <p>{@code null} will return {@code false}. 7340 * An empty CharSequence (length()=0) will return {@code false}.</p> 7341 * 7342 * <pre> 7343 * StringUtils.isAllLowerCase(null) = false 7344 * StringUtils.isAllLowerCase("") = false 7345 * StringUtils.isAllLowerCase(" ") = false 7346 * StringUtils.isAllLowerCase("abc") = true 7347 * StringUtils.isAllLowerCase("abC") = false 7348 * StringUtils.isAllLowerCase("ab c") = false 7349 * StringUtils.isAllLowerCase("ab1c") = false 7350 * StringUtils.isAllLowerCase("ab/c") = false 7351 * </pre> 7352 * 7353 * @param cs the CharSequence to check, may be null 7354 * @return {@code true} if only contains lowercase characters, and is non-null 7355 * @since 2.5 7356 * @since 3.0 Changed signature from isAllLowerCase(String) to isAllLowerCase(CharSequence) 7357 */ 7358 public static boolean isAllLowerCase(final CharSequence cs) { 7359 if (cs == null || isEmpty(cs)) { 7360 return false; 7361 } 7362 final int sz = cs.length(); 7363 for (int i = 0; i < sz; i++) { 7364 if (!Character.isLowerCase(cs.charAt(i))) { 7365 return false; 7366 } 7367 } 7368 return true; 7369 } 7370 7371 /** 7372 * <p>Checks if the CharSequence contains only uppercase characters.</p> 7373 * 7374 * <p>{@code null} will return {@code false}. 7375 * An empty String (length()=0) will return {@code false}.</p> 7376 * 7377 * <pre> 7378 * StringUtils.isAllUpperCase(null) = false 7379 * StringUtils.isAllUpperCase("") = false 7380 * StringUtils.isAllUpperCase(" ") = false 7381 * StringUtils.isAllUpperCase("ABC") = true 7382 * StringUtils.isAllUpperCase("aBC") = false 7383 * StringUtils.isAllUpperCase("A C") = false 7384 * StringUtils.isAllUpperCase("A1C") = false 7385 * StringUtils.isAllUpperCase("A/C") = false 7386 * </pre> 7387 * 7388 * @param cs the CharSequence to check, may be null 7389 * @return {@code true} if only contains uppercase characters, and is non-null 7390 * @since 2.5 7391 * @since 3.0 Changed signature from isAllUpperCase(String) to isAllUpperCase(CharSequence) 7392 */ 7393 public static boolean isAllUpperCase(final CharSequence cs) { 7394 if (cs == null || isEmpty(cs)) { 7395 return false; 7396 } 7397 final int sz = cs.length(); 7398 for (int i = 0; i < sz; i++) { 7399 if (!Character.isUpperCase(cs.charAt(i))) { 7400 return false; 7401 } 7402 } 7403 return true; 7404 } 7405 7406 /** 7407 * <p>Checks if the CharSequence contains mixed casing of both uppercase and lowercase characters.</p> 7408 * 7409 * <p>{@code null} will return {@code false}. An empty CharSequence ({@code length()=0}) will return 7410 * {@code false}.</p> 7411 * 7412 * <pre> 7413 * StringUtils.isMixedCase(null) = false 7414 * StringUtils.isMixedCase("") = false 7415 * StringUtils.isMixedCase("ABC") = false 7416 * StringUtils.isMixedCase("abc") = false 7417 * StringUtils.isMixedCase("aBc") = true 7418 * StringUtils.isMixedCase("A c") = true 7419 * StringUtils.isMixedCase("A1c") = true 7420 * StringUtils.isMixedCase("a/C") = true 7421 * StringUtils.isMixedCase("aC\t") = true 7422 * </pre> 7423 * 7424 * @param cs the CharSequence to check, may be null 7425 * @return {@code true} if the CharSequence contains both uppercase and lowercase characters 7426 * @since 3.5 7427 */ 7428 public static boolean isMixedCase(final CharSequence cs) { 7429 if (isEmpty(cs) || cs.length() == 1) { 7430 return false; 7431 } 7432 boolean containsUppercase = false; 7433 boolean containsLowercase = false; 7434 final int sz = cs.length(); 7435 for (int i = 0; i < sz; i++) { 7436 if (containsUppercase && containsLowercase) { 7437 return true; 7438 } else if (Character.isUpperCase(cs.charAt(i))) { 7439 containsUppercase = true; 7440 } else if (Character.isLowerCase(cs.charAt(i))) { 7441 containsLowercase = true; 7442 } 7443 } 7444 return containsUppercase && containsLowercase; 7445 } 7446 7447 // Defaults 7448 //----------------------------------------------------------------------- 7449 /** 7450 * <p>Returns either the passed in String, 7451 * or if the String is {@code null}, an empty String ("").</p> 7452 * 7453 * <pre> 7454 * StringUtils.defaultString(null) = "" 7455 * StringUtils.defaultString("") = "" 7456 * StringUtils.defaultString("bat") = "bat" 7457 * </pre> 7458 * 7459 * @see ObjectUtils#toString(Object) 7460 * @see String#valueOf(Object) 7461 * @param str the String to check, may be null 7462 * @return the passed in String, or the empty String if it 7463 * was {@code null} 7464 */ 7465 public static String defaultString(final String str) { 7466 return defaultString(str, EMPTY); 7467 } 7468 7469 /** 7470 * <p>Returns either the passed in String, or if the String is 7471 * {@code null}, the value of {@code defaultStr}.</p> 7472 * 7473 * <pre> 7474 * StringUtils.defaultString(null, "NULL") = "NULL" 7475 * StringUtils.defaultString("", "NULL") = "" 7476 * StringUtils.defaultString("bat", "NULL") = "bat" 7477 * </pre> 7478 * 7479 * @see ObjectUtils#toString(Object,String) 7480 * @see String#valueOf(Object) 7481 * @param str the String to check, may be null 7482 * @param defaultStr the default String to return 7483 * if the input is {@code null}, may be null 7484 * @return the passed in String, or the default if it was {@code null} 7485 */ 7486 public static String defaultString(final String str, final String defaultStr) { 7487 return str == null ? defaultStr : str; 7488 } 7489 7490 /** 7491 * <p>Returns the first value in the array which is not empty (""), 7492 * {@code null} or whitespace only.</p> 7493 * 7494 * <p>Whitespace is defined by {@link Character#isWhitespace(char)}.</p> 7495 * 7496 * <p>If all values are blank or the array is {@code null} 7497 * or empty then {@code null} is returned.</p> 7498 * 7499 * <pre> 7500 * StringUtils.firstNonBlank(null, null, null) = null 7501 * StringUtils.firstNonBlank(null, "", " ") = null 7502 * StringUtils.firstNonBlank("abc") = "abc" 7503 * StringUtils.firstNonBlank(null, "xyz") = "xyz" 7504 * StringUtils.firstNonBlank(null, "", " ", "xyz") = "xyz" 7505 * StringUtils.firstNonBlank(null, "xyz", "abc") = "xyz" 7506 * StringUtils.firstNonBlank() = null 7507 * </pre> 7508 * 7509 * @param <T> the specific kind of CharSequence 7510 * @param values the values to test, may be {@code null} or empty 7511 * @return the first value from {@code values} which is not blank, 7512 * or {@code null} if there are no non-blank values 7513 * @since 3.8 7514 */ 7515 @SafeVarargs 7516 public static <T extends CharSequence> T firstNonBlank(final T... values) { 7517 if (values != null) { 7518 for (final T val : values) { 7519 if (isNotBlank(val)) { 7520 return val; 7521 } 7522 } 7523 } 7524 return null; 7525 } 7526 7527 /** 7528 * <p>Returns the first value in the array which is not empty.</p> 7529 * 7530 * <p>If all values are empty or the array is {@code null} 7531 * or empty then {@code null} is returned.</p> 7532 * 7533 * <pre> 7534 * StringUtils.firstNonEmpty(null, null, null) = null 7535 * StringUtils.firstNonEmpty(null, null, "") = null 7536 * StringUtils.firstNonEmpty(null, "", " ") = " " 7537 * StringUtils.firstNonEmpty("abc") = "abc" 7538 * StringUtils.firstNonEmpty(null, "xyz") = "xyz" 7539 * StringUtils.firstNonEmpty("", "xyz") = "xyz" 7540 * StringUtils.firstNonEmpty(null, "xyz", "abc") = "xyz" 7541 * StringUtils.firstNonEmpty() = null 7542 * </pre> 7543 * 7544 * @param <T> the specific kind of CharSequence 7545 * @param values the values to test, may be {@code null} or empty 7546 * @return the first value from {@code values} which is not empty, 7547 * or {@code null} if there are no non-empty values 7548 * @since 3.8 7549 */ 7550 @SafeVarargs 7551 public static <T extends CharSequence> T firstNonEmpty(final T... values) { 7552 if (values != null) { 7553 for (final T val : values) { 7554 if (isNotEmpty(val)) { 7555 return val; 7556 } 7557 } 7558 } 7559 return null; 7560 } 7561 7562 /** 7563 * <p>Returns either the passed in CharSequence, or if the CharSequence is 7564 * whitespace, empty ("") or {@code null}, the value of {@code defaultStr}.</p> 7565 * 7566 * <p>Whitespace is defined by {@link Character#isWhitespace(char)}.</p> 7567 * 7568 * <pre> 7569 * StringUtils.defaultIfBlank(null, "NULL") = "NULL" 7570 * StringUtils.defaultIfBlank("", "NULL") = "NULL" 7571 * StringUtils.defaultIfBlank(" ", "NULL") = "NULL" 7572 * StringUtils.defaultIfBlank("bat", "NULL") = "bat" 7573 * StringUtils.defaultIfBlank("", null) = null 7574 * </pre> 7575 * @param <T> the specific kind of CharSequence 7576 * @param str the CharSequence to check, may be null 7577 * @param defaultStr the default CharSequence to return 7578 * if the input is whitespace, empty ("") or {@code null}, may be null 7579 * @return the passed in CharSequence, or the default 7580 * @see StringUtils#defaultString(String, String) 7581 */ 7582 public static <T extends CharSequence> T defaultIfBlank(final T str, final T defaultStr) { 7583 return isBlank(str) ? defaultStr : str; 7584 } 7585 7586 /** 7587 * <p>Returns either the passed in CharSequence, or if the CharSequence is 7588 * empty or {@code null}, the value of {@code defaultStr}.</p> 7589 * 7590 * <pre> 7591 * StringUtils.defaultIfEmpty(null, "NULL") = "NULL" 7592 * StringUtils.defaultIfEmpty("", "NULL") = "NULL" 7593 * StringUtils.defaultIfEmpty(" ", "NULL") = " " 7594 * StringUtils.defaultIfEmpty("bat", "NULL") = "bat" 7595 * StringUtils.defaultIfEmpty("", null) = null 7596 * </pre> 7597 * @param <T> the specific kind of CharSequence 7598 * @param str the CharSequence to check, may be null 7599 * @param defaultStr the default CharSequence to return 7600 * if the input is empty ("") or {@code null}, may be null 7601 * @return the passed in CharSequence, or the default 7602 * @see StringUtils#defaultString(String, String) 7603 */ 7604 public static <T extends CharSequence> T defaultIfEmpty(final T str, final T defaultStr) { 7605 return isEmpty(str) ? defaultStr : str; 7606 } 7607 7608 // Rotating (circular shift) 7609 //----------------------------------------------------------------------- 7610 /** 7611 * <p>Rotate (circular shift) a String of {@code shift} characters.</p> 7612 * <ul> 7613 * <li>If {@code shift > 0}, right circular shift (ex : ABCDEF => FABCDE)</li> 7614 * <li>If {@code shift < 0}, left circular shift (ex : ABCDEF => BCDEFA)</li> 7615 * </ul> 7616 * 7617 * <pre> 7618 * StringUtils.rotate(null, *) = null 7619 * StringUtils.rotate("", *) = "" 7620 * StringUtils.rotate("abcdefg", 0) = "abcdefg" 7621 * StringUtils.rotate("abcdefg", 2) = "fgabcde" 7622 * StringUtils.rotate("abcdefg", -2) = "cdefgab" 7623 * StringUtils.rotate("abcdefg", 7) = "abcdefg" 7624 * StringUtils.rotate("abcdefg", -7) = "abcdefg" 7625 * StringUtils.rotate("abcdefg", 9) = "fgabcde" 7626 * StringUtils.rotate("abcdefg", -9) = "cdefgab" 7627 * </pre> 7628 * 7629 * @param str the String to rotate, may be null 7630 * @param shift number of time to shift (positive : right shift, negative : left shift) 7631 * @return the rotated String, 7632 * or the original String if {@code shift == 0}, 7633 * or {@code null} if null String input 7634 * @since 3.5 7635 */ 7636 public static String rotate(final String str, final int shift) { 7637 if (str == null) { 7638 return null; 7639 } 7640 7641 final int strLen = str.length(); 7642 if (shift == 0 || strLen == 0 || shift % strLen == 0) { 7643 return str; 7644 } 7645 7646 final StringBuilder builder = new StringBuilder(strLen); 7647 final int offset = - (shift % strLen); 7648 builder.append(substring(str, offset)); 7649 builder.append(substring(str, 0, offset)); 7650 return builder.toString(); 7651 } 7652 7653 // Reversing 7654 //----------------------------------------------------------------------- 7655 /** 7656 * <p>Reverses a String as per {@link StringBuilder#reverse()}.</p> 7657 * 7658 * <p>A {@code null} String returns {@code null}.</p> 7659 * 7660 * <pre> 7661 * StringUtils.reverse(null) = null 7662 * StringUtils.reverse("") = "" 7663 * StringUtils.reverse("bat") = "tab" 7664 * </pre> 7665 * 7666 * @param str the String to reverse, may be null 7667 * @return the reversed String, {@code null} if null String input 7668 */ 7669 public static String reverse(final String str) { 7670 if (str == null) { 7671 return null; 7672 } 7673 return new StringBuilder(str).reverse().toString(); 7674 } 7675 7676 /** 7677 * <p>Reverses a String that is delimited by a specific character.</p> 7678 * 7679 * <p>The Strings between the delimiters are not reversed. 7680 * Thus java.lang.String becomes String.lang.java (if the delimiter 7681 * is {@code '.'}).</p> 7682 * 7683 * <pre> 7684 * StringUtils.reverseDelimited(null, *) = null 7685 * StringUtils.reverseDelimited("", *) = "" 7686 * StringUtils.reverseDelimited("a.b.c", 'x') = "a.b.c" 7687 * StringUtils.reverseDelimited("a.b.c", ".") = "c.b.a" 7688 * </pre> 7689 * 7690 * @param str the String to reverse, may be null 7691 * @param separatorChar the separator character to use 7692 * @return the reversed String, {@code null} if null String input 7693 * @since 2.0 7694 */ 7695 public static String reverseDelimited(final String str, final char separatorChar) { 7696 if (str == null) { 7697 return null; 7698 } 7699 // could implement manually, but simple way is to reuse other, 7700 // probably slower, methods. 7701 final String[] strs = split(str, separatorChar); 7702 ArrayUtils.reverse(strs); 7703 return join(strs, separatorChar); 7704 } 7705 7706 // Abbreviating 7707 //----------------------------------------------------------------------- 7708 /** 7709 * <p>Abbreviates a String using ellipses. This will turn 7710 * "Now is the time for all good men" into "Now is the time for..."</p> 7711 * 7712 * <p>Specifically:</p> 7713 * <ul> 7714 * <li>If the number of characters in {@code str} is less than or equal to 7715 * {@code maxWidth}, return {@code str}.</li> 7716 * <li>Else abbreviate it to {@code (substring(str, 0, max-3) + "...")}.</li> 7717 * <li>If {@code maxWidth} is less than {@code 4}, throw an 7718 * {@code IllegalArgumentException}.</li> 7719 * <li>In no case will it return a String of length greater than 7720 * {@code maxWidth}.</li> 7721 * </ul> 7722 * 7723 * <pre> 7724 * StringUtils.abbreviate(null, *) = null 7725 * StringUtils.abbreviate("", 4) = "" 7726 * StringUtils.abbreviate("abcdefg", 6) = "abc..." 7727 * StringUtils.abbreviate("abcdefg", 7) = "abcdefg" 7728 * StringUtils.abbreviate("abcdefg", 8) = "abcdefg" 7729 * StringUtils.abbreviate("abcdefg", 4) = "a..." 7730 * StringUtils.abbreviate("abcdefg", 3) = IllegalArgumentException 7731 * </pre> 7732 * 7733 * @param str the String to check, may be null 7734 * @param maxWidth maximum length of result String, must be at least 4 7735 * @return abbreviated String, {@code null} if null String input 7736 * @throws IllegalArgumentException if the width is too small 7737 * @since 2.0 7738 */ 7739 public static String abbreviate(final String str, final int maxWidth) { 7740 final String defaultAbbrevMarker = "..."; 7741 return abbreviate(str, defaultAbbrevMarker, 0, maxWidth); 7742 } 7743 7744 /** 7745 * <p>Abbreviates a String using ellipses. This will turn 7746 * "Now is the time for all good men" into "...is the time for..."</p> 7747 * 7748 * <p>Works like {@code abbreviate(String, int)}, but allows you to specify 7749 * a "left edge" offset. Note that this left edge is not necessarily going to 7750 * be the leftmost character in the result, or the first character following the 7751 * ellipses, but it will appear somewhere in the result. 7752 * 7753 * <p>In no case will it return a String of length greater than 7754 * {@code maxWidth}.</p> 7755 * 7756 * <pre> 7757 * StringUtils.abbreviate(null, *, *) = null 7758 * StringUtils.abbreviate("", 0, 4) = "" 7759 * StringUtils.abbreviate("abcdefghijklmno", -1, 10) = "abcdefg..." 7760 * StringUtils.abbreviate("abcdefghijklmno", 0, 10) = "abcdefg..." 7761 * StringUtils.abbreviate("abcdefghijklmno", 1, 10) = "abcdefg..." 7762 * StringUtils.abbreviate("abcdefghijklmno", 4, 10) = "abcdefg..." 7763 * StringUtils.abbreviate("abcdefghijklmno", 5, 10) = "...fghi..." 7764 * StringUtils.abbreviate("abcdefghijklmno", 6, 10) = "...ghij..." 7765 * StringUtils.abbreviate("abcdefghijklmno", 8, 10) = "...ijklmno" 7766 * StringUtils.abbreviate("abcdefghijklmno", 10, 10) = "...ijklmno" 7767 * StringUtils.abbreviate("abcdefghijklmno", 12, 10) = "...ijklmno" 7768 * StringUtils.abbreviate("abcdefghij", 0, 3) = IllegalArgumentException 7769 * StringUtils.abbreviate("abcdefghij", 5, 6) = IllegalArgumentException 7770 * </pre> 7771 * 7772 * @param str the String to check, may be null 7773 * @param offset left edge of source String 7774 * @param maxWidth maximum length of result String, must be at least 4 7775 * @return abbreviated String, {@code null} if null String input 7776 * @throws IllegalArgumentException if the width is too small 7777 * @since 2.0 7778 */ 7779 public static String abbreviate(final String str, final int offset, final int maxWidth) { 7780 final String defaultAbbrevMarker = "..."; 7781 return abbreviate(str, defaultAbbrevMarker, offset, maxWidth); 7782 } 7783 7784 /** 7785 * <p>Abbreviates a String using another given String as replacement marker. This will turn 7786 * "Now is the time for all good men" into "Now is the time for..." if "..." was defined 7787 * as the replacement marker.</p> 7788 * 7789 * <p>Specifically:</p> 7790 * <ul> 7791 * <li>If the number of characters in {@code str} is less than or equal to 7792 * {@code maxWidth}, return {@code str}.</li> 7793 * <li>Else abbreviate it to {@code (substring(str, 0, max-abbrevMarker.length) + abbrevMarker)}.</li> 7794 * <li>If {@code maxWidth} is less than {@code abbrevMarker.length + 1}, throw an 7795 * {@code IllegalArgumentException}.</li> 7796 * <li>In no case will it return a String of length greater than 7797 * {@code maxWidth}.</li> 7798 * </ul> 7799 * 7800 * <pre> 7801 * StringUtils.abbreviate(null, "...", *) = null 7802 * StringUtils.abbreviate("abcdefg", null, *) = "abcdefg" 7803 * StringUtils.abbreviate("", "...", 4) = "" 7804 * StringUtils.abbreviate("abcdefg", ".", 5) = "abcd." 7805 * StringUtils.abbreviate("abcdefg", ".", 7) = "abcdefg" 7806 * StringUtils.abbreviate("abcdefg", ".", 8) = "abcdefg" 7807 * StringUtils.abbreviate("abcdefg", "..", 4) = "ab.." 7808 * StringUtils.abbreviate("abcdefg", "..", 3) = "a.." 7809 * StringUtils.abbreviate("abcdefg", "..", 2) = IllegalArgumentException 7810 * StringUtils.abbreviate("abcdefg", "...", 3) = IllegalArgumentException 7811 * </pre> 7812 * 7813 * @param str the String to check, may be null 7814 * @param abbrevMarker the String used as replacement marker 7815 * @param maxWidth maximum length of result String, must be at least {@code abbrevMarker.length + 1} 7816 * @return abbreviated String, {@code null} if null String input 7817 * @throws IllegalArgumentException if the width is too small 7818 * @since 3.6 7819 */ 7820 public static String abbreviate(final String str, final String abbrevMarker, final int maxWidth) { 7821 return abbreviate(str, abbrevMarker, 0, maxWidth); 7822 } 7823 7824 /** 7825 * <p>Abbreviates a String using a given replacement marker. This will turn 7826 * "Now is the time for all good men" into "...is the time for..." if "..." was defined 7827 * as the replacement marker.</p> 7828 * 7829 * <p>Works like {@code abbreviate(String, String, int)}, but allows you to specify 7830 * a "left edge" offset. Note that this left edge is not necessarily going to 7831 * be the leftmost character in the result, or the first character following the 7832 * replacement marker, but it will appear somewhere in the result. 7833 * 7834 * <p>In no case will it return a String of length greater than {@code maxWidth}.</p> 7835 * 7836 * <pre> 7837 * StringUtils.abbreviate(null, null, *, *) = null 7838 * StringUtils.abbreviate("abcdefghijklmno", null, *, *) = "abcdefghijklmno" 7839 * StringUtils.abbreviate("", "...", 0, 4) = "" 7840 * StringUtils.abbreviate("abcdefghijklmno", "---", -1, 10) = "abcdefg---" 7841 * StringUtils.abbreviate("abcdefghijklmno", ",", 0, 10) = "abcdefghi," 7842 * StringUtils.abbreviate("abcdefghijklmno", ",", 1, 10) = "abcdefghi," 7843 * StringUtils.abbreviate("abcdefghijklmno", ",", 2, 10) = "abcdefghi," 7844 * StringUtils.abbreviate("abcdefghijklmno", "::", 4, 10) = "::efghij::" 7845 * StringUtils.abbreviate("abcdefghijklmno", "...", 6, 10) = "...ghij..." 7846 * StringUtils.abbreviate("abcdefghijklmno", "*", 9, 10) = "*ghijklmno" 7847 * StringUtils.abbreviate("abcdefghijklmno", "'", 10, 10) = "'ghijklmno" 7848 * StringUtils.abbreviate("abcdefghijklmno", "!", 12, 10) = "!ghijklmno" 7849 * StringUtils.abbreviate("abcdefghij", "abra", 0, 4) = IllegalArgumentException 7850 * StringUtils.abbreviate("abcdefghij", "...", 5, 6) = IllegalArgumentException 7851 * </pre> 7852 * 7853 * @param str the String to check, may be null 7854 * @param abbrevMarker the String used as replacement marker 7855 * @param offset left edge of source String 7856 * @param maxWidth maximum length of result String, must be at least 4 7857 * @return abbreviated String, {@code null} if null String input 7858 * @throws IllegalArgumentException if the width is too small 7859 * @since 3.6 7860 */ 7861 public static String abbreviate(final String str, final String abbrevMarker, int offset, final int maxWidth) { 7862 if (isEmpty(str) || isEmpty(abbrevMarker)) { 7863 return str; 7864 } 7865 7866 final int abbrevMarkerLength = abbrevMarker.length(); 7867 final int minAbbrevWidth = abbrevMarkerLength + 1; 7868 final int minAbbrevWidthOffset = abbrevMarkerLength + abbrevMarkerLength + 1; 7869 7870 if (maxWidth < minAbbrevWidth) { 7871 throw new IllegalArgumentException(String.format("Minimum abbreviation width is %d", minAbbrevWidth)); 7872 } 7873 if (str.length() <= maxWidth) { 7874 return str; 7875 } 7876 if (offset > str.length()) { 7877 offset = str.length(); 7878 } 7879 if (str.length() - offset < maxWidth - abbrevMarkerLength) { 7880 offset = str.length() - (maxWidth - abbrevMarkerLength); 7881 } 7882 if (offset <= abbrevMarkerLength+1) { 7883 return str.substring(0, maxWidth - abbrevMarkerLength) + abbrevMarker; 7884 } 7885 if (maxWidth < minAbbrevWidthOffset) { 7886 throw new IllegalArgumentException(String.format("Minimum abbreviation width with offset is %d", minAbbrevWidthOffset)); 7887 } 7888 if (offset + maxWidth - abbrevMarkerLength < str.length()) { 7889 return abbrevMarker + abbreviate(str.substring(offset), abbrevMarker, maxWidth - abbrevMarkerLength); 7890 } 7891 return abbrevMarker + str.substring(str.length() - (maxWidth - abbrevMarkerLength)); 7892 } 7893 7894 /** 7895 * <p>Abbreviates a String to the length passed, replacing the middle characters with the supplied 7896 * replacement String.</p> 7897 * 7898 * <p>This abbreviation only occurs if the following criteria is met:</p> 7899 * <ul> 7900 * <li>Neither the String for abbreviation nor the replacement String are null or empty </li> 7901 * <li>The length to truncate to is less than the length of the supplied String</li> 7902 * <li>The length to truncate to is greater than 0</li> 7903 * <li>The abbreviated String will have enough room for the length supplied replacement String 7904 * and the first and last characters of the supplied String for abbreviation</li> 7905 * </ul> 7906 * <p>Otherwise, the returned String will be the same as the supplied String for abbreviation. 7907 * </p> 7908 * 7909 * <pre> 7910 * StringUtils.abbreviateMiddle(null, null, 0) = null 7911 * StringUtils.abbreviateMiddle("abc", null, 0) = "abc" 7912 * StringUtils.abbreviateMiddle("abc", ".", 0) = "abc" 7913 * StringUtils.abbreviateMiddle("abc", ".", 3) = "abc" 7914 * StringUtils.abbreviateMiddle("abcdef", ".", 4) = "ab.f" 7915 * </pre> 7916 * 7917 * @param str the String to abbreviate, may be null 7918 * @param middle the String to replace the middle characters with, may be null 7919 * @param length the length to abbreviate {@code str} to. 7920 * @return the abbreviated String if the above criteria is met, or the original String supplied for abbreviation. 7921 * @since 2.5 7922 */ 7923 public static String abbreviateMiddle(final String str, final String middle, final int length) { 7924 if (isEmpty(str) || isEmpty(middle)) { 7925 return str; 7926 } 7927 7928 if (length >= str.length() || length < middle.length()+2) { 7929 return str; 7930 } 7931 7932 final int targetSting = length-middle.length(); 7933 final int startOffset = targetSting/2+targetSting%2; 7934 final int endOffset = str.length()-targetSting/2; 7935 7936 return str.substring(0, startOffset) + 7937 middle + 7938 str.substring(endOffset); 7939 } 7940 7941 // Difference 7942 //----------------------------------------------------------------------- 7943 /** 7944 * <p>Compares two Strings, and returns the portion where they differ. 7945 * More precisely, return the remainder of the second String, 7946 * starting from where it's different from the first. This means that 7947 * the difference between "abc" and "ab" is the empty String and not "c". </p> 7948 * 7949 * <p>For example, 7950 * {@code difference("i am a machine", "i am a robot") -> "robot"}.</p> 7951 * 7952 * <pre> 7953 * StringUtils.difference(null, null) = null 7954 * StringUtils.difference("", "") = "" 7955 * StringUtils.difference("", "abc") = "abc" 7956 * StringUtils.difference("abc", "") = "" 7957 * StringUtils.difference("abc", "abc") = "" 7958 * StringUtils.difference("abc", "ab") = "" 7959 * StringUtils.difference("ab", "abxyz") = "xyz" 7960 * StringUtils.difference("abcde", "abxyz") = "xyz" 7961 * StringUtils.difference("abcde", "xyz") = "xyz" 7962 * </pre> 7963 * 7964 * @param str1 the first String, may be null 7965 * @param str2 the second String, may be null 7966 * @return the portion of str2 where it differs from str1; returns the 7967 * empty String if they are equal 7968 * @see #indexOfDifference(CharSequence,CharSequence) 7969 * @since 2.0 7970 */ 7971 public static String difference(final String str1, final String str2) { 7972 if (str1 == null) { 7973 return str2; 7974 } 7975 if (str2 == null) { 7976 return str1; 7977 } 7978 final int at = indexOfDifference(str1, str2); 7979 if (at == INDEX_NOT_FOUND) { 7980 return EMPTY; 7981 } 7982 return str2.substring(at); 7983 } 7984 7985 /** 7986 * <p>Compares two CharSequences, and returns the index at which the 7987 * CharSequences begin to differ.</p> 7988 * 7989 * <p>For example, 7990 * {@code indexOfDifference("i am a machine", "i am a robot") -> 7}</p> 7991 * 7992 * <pre> 7993 * StringUtils.indexOfDifference(null, null) = -1 7994 * StringUtils.indexOfDifference("", "") = -1 7995 * StringUtils.indexOfDifference("", "abc") = 0 7996 * StringUtils.indexOfDifference("abc", "") = 0 7997 * StringUtils.indexOfDifference("abc", "abc") = -1 7998 * StringUtils.indexOfDifference("ab", "abxyz") = 2 7999 * StringUtils.indexOfDifference("abcde", "abxyz") = 2 8000 * StringUtils.indexOfDifference("abcde", "xyz") = 0 8001 * </pre> 8002 * 8003 * @param cs1 the first CharSequence, may be null 8004 * @param cs2 the second CharSequence, may be null 8005 * @return the index where cs1 and cs2 begin to differ; -1 if they are equal 8006 * @since 2.0 8007 * @since 3.0 Changed signature from indexOfDifference(String, String) to 8008 * indexOfDifference(CharSequence, CharSequence) 8009 */ 8010 public static int indexOfDifference(final CharSequence cs1, final CharSequence cs2) { 8011 if (cs1 == cs2) { 8012 return INDEX_NOT_FOUND; 8013 } 8014 if (cs1 == null || cs2 == null) { 8015 return 0; 8016 } 8017 int i; 8018 for (i = 0; i < cs1.length() && i < cs2.length(); ++i) { 8019 if (cs1.charAt(i) != cs2.charAt(i)) { 8020 break; 8021 } 8022 } 8023 if (i < cs2.length() || i < cs1.length()) { 8024 return i; 8025 } 8026 return INDEX_NOT_FOUND; 8027 } 8028 8029 /** 8030 * <p>Compares all CharSequences in an array and returns the index at which the 8031 * CharSequences begin to differ.</p> 8032 * 8033 * <p>For example, 8034 * {@code indexOfDifference(new String[] {"i am a machine", "i am a robot"}) -> 7}</p> 8035 * 8036 * <pre> 8037 * StringUtils.indexOfDifference(null) = -1 8038 * StringUtils.indexOfDifference(new String[] {}) = -1 8039 * StringUtils.indexOfDifference(new String[] {"abc"}) = -1 8040 * StringUtils.indexOfDifference(new String[] {null, null}) = -1 8041 * StringUtils.indexOfDifference(new String[] {"", ""}) = -1 8042 * StringUtils.indexOfDifference(new String[] {"", null}) = 0 8043 * StringUtils.indexOfDifference(new String[] {"abc", null, null}) = 0 8044 * StringUtils.indexOfDifference(new String[] {null, null, "abc"}) = 0 8045 * StringUtils.indexOfDifference(new String[] {"", "abc"}) = 0 8046 * StringUtils.indexOfDifference(new String[] {"abc", ""}) = 0 8047 * StringUtils.indexOfDifference(new String[] {"abc", "abc"}) = -1 8048 * StringUtils.indexOfDifference(new String[] {"abc", "a"}) = 1 8049 * StringUtils.indexOfDifference(new String[] {"ab", "abxyz"}) = 2 8050 * StringUtils.indexOfDifference(new String[] {"abcde", "abxyz"}) = 2 8051 * StringUtils.indexOfDifference(new String[] {"abcde", "xyz"}) = 0 8052 * StringUtils.indexOfDifference(new String[] {"xyz", "abcde"}) = 0 8053 * StringUtils.indexOfDifference(new String[] {"i am a machine", "i am a robot"}) = 7 8054 * </pre> 8055 * 8056 * @param css array of CharSequences, entries may be null 8057 * @return the index where the strings begin to differ; -1 if they are all equal 8058 * @since 2.4 8059 * @since 3.0 Changed signature from indexOfDifference(String...) to indexOfDifference(CharSequence...) 8060 */ 8061 public static int indexOfDifference(final CharSequence... css) { 8062 if (css == null || css.length <= 1) { 8063 return INDEX_NOT_FOUND; 8064 } 8065 boolean anyStringNull = false; 8066 boolean allStringsNull = true; 8067 final int arrayLen = css.length; 8068 int shortestStrLen = Integer.MAX_VALUE; 8069 int longestStrLen = 0; 8070 8071 // find the min and max string lengths; this avoids checking to make 8072 // sure we are not exceeding the length of the string each time through 8073 // the bottom loop. 8074 for (final CharSequence cs : css) { 8075 if (cs == null) { 8076 anyStringNull = true; 8077 shortestStrLen = 0; 8078 } else { 8079 allStringsNull = false; 8080 shortestStrLen = Math.min(cs.length(), shortestStrLen); 8081 longestStrLen = Math.max(cs.length(), longestStrLen); 8082 } 8083 } 8084 8085 // handle lists containing all nulls or all empty strings 8086 if (allStringsNull || longestStrLen == 0 && !anyStringNull) { 8087 return INDEX_NOT_FOUND; 8088 } 8089 8090 // handle lists containing some nulls or some empty strings 8091 if (shortestStrLen == 0) { 8092 return 0; 8093 } 8094 8095 // find the position with the first difference across all strings 8096 int firstDiff = -1; 8097 for (int stringPos = 0; stringPos < shortestStrLen; stringPos++) { 8098 final char comparisonChar = css[0].charAt(stringPos); 8099 for (int arrayPos = 1; arrayPos < arrayLen; arrayPos++) { 8100 if (css[arrayPos].charAt(stringPos) != comparisonChar) { 8101 firstDiff = stringPos; 8102 break; 8103 } 8104 } 8105 if (firstDiff != -1) { 8106 break; 8107 } 8108 } 8109 8110 if (firstDiff == -1 && shortestStrLen != longestStrLen) { 8111 // we compared all of the characters up to the length of the 8112 // shortest string and didn't find a match, but the string lengths 8113 // vary, so return the length of the shortest string. 8114 return shortestStrLen; 8115 } 8116 return firstDiff; 8117 } 8118 8119 /** 8120 * <p>Compares all Strings in an array and returns the initial sequence of 8121 * characters that is common to all of them.</p> 8122 * 8123 * <p>For example, 8124 * <code>getCommonPrefix(new String[] {"i am a machine", "i am a robot"}) -> "i am a "</code></p> 8125 * 8126 * <pre> 8127 * StringUtils.getCommonPrefix(null) = "" 8128 * StringUtils.getCommonPrefix(new String[] {}) = "" 8129 * StringUtils.getCommonPrefix(new String[] {"abc"}) = "abc" 8130 * StringUtils.getCommonPrefix(new String[] {null, null}) = "" 8131 * StringUtils.getCommonPrefix(new String[] {"", ""}) = "" 8132 * StringUtils.getCommonPrefix(new String[] {"", null}) = "" 8133 * StringUtils.getCommonPrefix(new String[] {"abc", null, null}) = "" 8134 * StringUtils.getCommonPrefix(new String[] {null, null, "abc"}) = "" 8135 * StringUtils.getCommonPrefix(new String[] {"", "abc"}) = "" 8136 * StringUtils.getCommonPrefix(new String[] {"abc", ""}) = "" 8137 * StringUtils.getCommonPrefix(new String[] {"abc", "abc"}) = "abc" 8138 * StringUtils.getCommonPrefix(new String[] {"abc", "a"}) = "a" 8139 * StringUtils.getCommonPrefix(new String[] {"ab", "abxyz"}) = "ab" 8140 * StringUtils.getCommonPrefix(new String[] {"abcde", "abxyz"}) = "ab" 8141 * StringUtils.getCommonPrefix(new String[] {"abcde", "xyz"}) = "" 8142 * StringUtils.getCommonPrefix(new String[] {"xyz", "abcde"}) = "" 8143 * StringUtils.getCommonPrefix(new String[] {"i am a machine", "i am a robot"}) = "i am a " 8144 * </pre> 8145 * 8146 * @param strs array of String objects, entries may be null 8147 * @return the initial sequence of characters that are common to all Strings 8148 * in the array; empty String if the array is null, the elements are all null 8149 * or if there is no common prefix. 8150 * @since 2.4 8151 */ 8152 public static String getCommonPrefix(final String... strs) { 8153 if (strs == null || strs.length == 0) { 8154 return EMPTY; 8155 } 8156 final int smallestIndexOfDiff = indexOfDifference(strs); 8157 if (smallestIndexOfDiff == INDEX_NOT_FOUND) { 8158 // all strings were identical 8159 if (strs[0] == null) { 8160 return EMPTY; 8161 } 8162 return strs[0]; 8163 } else if (smallestIndexOfDiff == 0) { 8164 // there were no common initial characters 8165 return EMPTY; 8166 } else { 8167 // we found a common initial character sequence 8168 return strs[0].substring(0, smallestIndexOfDiff); 8169 } 8170 } 8171 8172 // Misc 8173 //----------------------------------------------------------------------- 8174 /** 8175 * <p>Find the Levenshtein distance between two Strings.</p> 8176 * 8177 * <p>This is the number of changes needed to change one String into 8178 * another, where each change is a single character modification (deletion, 8179 * insertion or substitution).</p> 8180 * 8181 * <p>The implementation uses a single-dimensional array of length s.length() + 1. See 8182 * <a href="http://blog.softwx.net/2014/12/optimizing-levenshtein-algorithm-in-c.html"> 8183 * http://blog.softwx.net/2014/12/optimizing-levenshtein-algorithm-in-c.html</a> for details.</p> 8184 * 8185 * <pre> 8186 * StringUtils.getLevenshteinDistance(null, *) = IllegalArgumentException 8187 * StringUtils.getLevenshteinDistance(*, null) = IllegalArgumentException 8188 * StringUtils.getLevenshteinDistance("", "") = 0 8189 * StringUtils.getLevenshteinDistance("", "a") = 1 8190 * StringUtils.getLevenshteinDistance("aaapppp", "") = 7 8191 * StringUtils.getLevenshteinDistance("frog", "fog") = 1 8192 * StringUtils.getLevenshteinDistance("fly", "ant") = 3 8193 * StringUtils.getLevenshteinDistance("elephant", "hippo") = 7 8194 * StringUtils.getLevenshteinDistance("hippo", "elephant") = 7 8195 * StringUtils.getLevenshteinDistance("hippo", "zzzzzzzz") = 8 8196 * StringUtils.getLevenshteinDistance("hello", "hallo") = 1 8197 * </pre> 8198 * 8199 * @param s the first String, must not be null 8200 * @param t the second String, must not be null 8201 * @return result distance 8202 * @throws IllegalArgumentException if either String input {@code null} 8203 * @since 3.0 Changed signature from getLevenshteinDistance(String, String) to 8204 * getLevenshteinDistance(CharSequence, CharSequence) 8205 * @deprecated as of 3.6, use commons-text 8206 * <a href="https://commons.apache.org/proper/commons-text/javadocs/api-release/org/apache/commons/text/similarity/LevenshteinDistance.html"> 8207 * LevenshteinDistance</a> instead 8208 */ 8209 @Deprecated 8210 public static int getLevenshteinDistance(CharSequence s, CharSequence t) { 8211 if (s == null || t == null) { 8212 throw new IllegalArgumentException("Strings must not be null"); 8213 } 8214 8215 int n = s.length(); 8216 int m = t.length(); 8217 8218 if (n == 0) { 8219 return m; 8220 } else if (m == 0) { 8221 return n; 8222 } 8223 8224 if (n > m) { 8225 // swap the input strings to consume less memory 8226 final CharSequence tmp = s; 8227 s = t; 8228 t = tmp; 8229 n = m; 8230 m = t.length(); 8231 } 8232 8233 final int p[] = new int[n + 1]; 8234 // indexes into strings s and t 8235 int i; // iterates through s 8236 int j; // iterates through t 8237 int upper_left; 8238 int upper; 8239 8240 char t_j; // jth character of t 8241 int cost; 8242 8243 for (i = 0; i <= n; i++) { 8244 p[i] = i; 8245 } 8246 8247 for (j = 1; j <= m; j++) { 8248 upper_left = p[0]; 8249 t_j = t.charAt(j - 1); 8250 p[0] = j; 8251 8252 for (i = 1; i <= n; i++) { 8253 upper = p[i]; 8254 cost = s.charAt(i - 1) == t_j ? 0 : 1; 8255 // minimum of cell to the left+1, to the top+1, diagonally left and up +cost 8256 p[i] = Math.min(Math.min(p[i - 1] + 1, p[i] + 1), upper_left + cost); 8257 upper_left = upper; 8258 } 8259 } 8260 8261 return p[n]; 8262 } 8263 8264 /** 8265 * <p>Find the Levenshtein distance between two Strings if it's less than or equal to a given 8266 * threshold.</p> 8267 * 8268 * <p>This is the number of changes needed to change one String into 8269 * another, where each change is a single character modification (deletion, 8270 * insertion or substitution).</p> 8271 * 8272 * <p>This implementation follows from Algorithms on Strings, Trees and Sequences by Dan Gusfield 8273 * and Chas Emerick's implementation of the Levenshtein distance algorithm from 8274 * <a href="http://www.merriampark.com/ld.htm">http://www.merriampark.com/ld.htm</a></p> 8275 * 8276 * <pre> 8277 * StringUtils.getLevenshteinDistance(null, *, *) = IllegalArgumentException 8278 * StringUtils.getLevenshteinDistance(*, null, *) = IllegalArgumentException 8279 * StringUtils.getLevenshteinDistance(*, *, -1) = IllegalArgumentException 8280 * StringUtils.getLevenshteinDistance("", "", 0) = 0 8281 * StringUtils.getLevenshteinDistance("aaapppp", "", 8) = 7 8282 * StringUtils.getLevenshteinDistance("aaapppp", "", 7) = 7 8283 * StringUtils.getLevenshteinDistance("aaapppp", "", 6)) = -1 8284 * StringUtils.getLevenshteinDistance("elephant", "hippo", 7) = 7 8285 * StringUtils.getLevenshteinDistance("elephant", "hippo", 6) = -1 8286 * StringUtils.getLevenshteinDistance("hippo", "elephant", 7) = 7 8287 * StringUtils.getLevenshteinDistance("hippo", "elephant", 6) = -1 8288 * </pre> 8289 * 8290 * @param s the first String, must not be null 8291 * @param t the second String, must not be null 8292 * @param threshold the target threshold, must not be negative 8293 * @return result distance, or {@code -1} if the distance would be greater than the threshold 8294 * @throws IllegalArgumentException if either String input {@code null} or negative threshold 8295 * @deprecated as of 3.6, use commons-text 8296 * <a href="https://commons.apache.org/proper/commons-text/javadocs/api-release/org/apache/commons/text/similarity/LevenshteinDistance.html"> 8297 * LevenshteinDistance</a> instead 8298 */ 8299 @Deprecated 8300 public static int getLevenshteinDistance(CharSequence s, CharSequence t, final int threshold) { 8301 if (s == null || t == null) { 8302 throw new IllegalArgumentException("Strings must not be null"); 8303 } 8304 if (threshold < 0) { 8305 throw new IllegalArgumentException("Threshold must not be negative"); 8306 } 8307 8308 /* 8309 This implementation only computes the distance if it's less than or equal to the 8310 threshold value, returning -1 if it's greater. The advantage is performance: unbounded 8311 distance is O(nm), but a bound of k allows us to reduce it to O(km) time by only 8312 computing a diagonal stripe of width 2k + 1 of the cost table. 8313 It is also possible to use this to compute the unbounded Levenshtein distance by starting 8314 the threshold at 1 and doubling each time until the distance is found; this is O(dm), where 8315 d is the distance. 8316 8317 One subtlety comes from needing to ignore entries on the border of our stripe 8318 eg. 8319 p[] = |#|#|#|* 8320 d[] = *|#|#|#| 8321 We must ignore the entry to the left of the leftmost member 8322 We must ignore the entry above the rightmost member 8323 8324 Another subtlety comes from our stripe running off the matrix if the strings aren't 8325 of the same size. Since string s is always swapped to be the shorter of the two, 8326 the stripe will always run off to the upper right instead of the lower left of the matrix. 8327 8328 As a concrete example, suppose s is of length 5, t is of length 7, and our threshold is 1. 8329 In this case we're going to walk a stripe of length 3. The matrix would look like so: 8330 8331 1 2 3 4 5 8332 1 |#|#| | | | 8333 2 |#|#|#| | | 8334 3 | |#|#|#| | 8335 4 | | |#|#|#| 8336 5 | | | |#|#| 8337 6 | | | | |#| 8338 7 | | | | | | 8339 8340 Note how the stripe leads off the table as there is no possible way to turn a string of length 5 8341 into one of length 7 in edit distance of 1. 8342 8343 Additionally, this implementation decreases memory usage by using two 8344 single-dimensional arrays and swapping them back and forth instead of allocating 8345 an entire n by m matrix. This requires a few minor changes, such as immediately returning 8346 when it's detected that the stripe has run off the matrix and initially filling the arrays with 8347 large values so that entries we don't compute are ignored. 8348 8349 See Algorithms on Strings, Trees and Sequences by Dan Gusfield for some discussion. 8350 */ 8351 8352 int n = s.length(); // length of s 8353 int m = t.length(); // length of t 8354 8355 // if one string is empty, the edit distance is necessarily the length of the other 8356 if (n == 0) { 8357 return m <= threshold ? m : -1; 8358 } else if (m == 0) { 8359 return n <= threshold ? n : -1; 8360 } else if (Math.abs(n - m) > threshold) { 8361 // no need to calculate the distance if the length difference is greater than the threshold 8362 return -1; 8363 } 8364 8365 if (n > m) { 8366 // swap the two strings to consume less memory 8367 final CharSequence tmp = s; 8368 s = t; 8369 t = tmp; 8370 n = m; 8371 m = t.length(); 8372 } 8373 8374 int p[] = new int[n + 1]; // 'previous' cost array, horizontally 8375 int d[] = new int[n + 1]; // cost array, horizontally 8376 int _d[]; // placeholder to assist in swapping p and d 8377 8378 // fill in starting table values 8379 final int boundary = Math.min(n, threshold) + 1; 8380 for (int i = 0; i < boundary; i++) { 8381 p[i] = i; 8382 } 8383 // these fills ensure that the value above the rightmost entry of our 8384 // stripe will be ignored in following loop iterations 8385 Arrays.fill(p, boundary, p.length, Integer.MAX_VALUE); 8386 Arrays.fill(d, Integer.MAX_VALUE); 8387 8388 // iterates through t 8389 for (int j = 1; j <= m; j++) { 8390 final char t_j = t.charAt(j - 1); // jth character of t 8391 d[0] = j; 8392 8393 // compute stripe indices, constrain to array size 8394 final int min = Math.max(1, j - threshold); 8395 final int max = j > Integer.MAX_VALUE - threshold ? n : Math.min(n, j + threshold); 8396 8397 // the stripe may lead off of the table if s and t are of different sizes 8398 if (min > max) { 8399 return -1; 8400 } 8401 8402 // ignore entry left of leftmost 8403 if (min > 1) { 8404 d[min - 1] = Integer.MAX_VALUE; 8405 } 8406 8407 // iterates through [min, max] in s 8408 for (int i = min; i <= max; i++) { 8409 if (s.charAt(i - 1) == t_j) { 8410 // diagonally left and up 8411 d[i] = p[i - 1]; 8412 } else { 8413 // 1 + minimum of cell to the left, to the top, diagonally left and up 8414 d[i] = 1 + Math.min(Math.min(d[i - 1], p[i]), p[i - 1]); 8415 } 8416 } 8417 8418 // copy current distance counts to 'previous row' distance counts 8419 _d = p; 8420 p = d; 8421 d = _d; 8422 } 8423 8424 // if p[n] is greater than the threshold, there's no guarantee on it being the correct 8425 // distance 8426 if (p[n] <= threshold) { 8427 return p[n]; 8428 } 8429 return -1; 8430 } 8431 8432 /** 8433 * <p>Find the Jaro Winkler Distance which indicates the similarity score between two Strings.</p> 8434 * 8435 * <p>The Jaro measure is the weighted sum of percentage of matched characters from each file and transposed characters. 8436 * Winkler increased this measure for matching initial characters.</p> 8437 * 8438 * <p>This implementation is based on the Jaro Winkler similarity algorithm 8439 * 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> 8440 * 8441 * <pre> 8442 * StringUtils.getJaroWinklerDistance(null, null) = IllegalArgumentException 8443 * StringUtils.getJaroWinklerDistance("", "") = 0.0 8444 * StringUtils.getJaroWinklerDistance("", "a") = 0.0 8445 * StringUtils.getJaroWinklerDistance("aaapppp", "") = 0.0 8446 * StringUtils.getJaroWinklerDistance("frog", "fog") = 0.93 8447 * StringUtils.getJaroWinklerDistance("fly", "ant") = 0.0 8448 * StringUtils.getJaroWinklerDistance("elephant", "hippo") = 0.44 8449 * StringUtils.getJaroWinklerDistance("hippo", "elephant") = 0.44 8450 * StringUtils.getJaroWinklerDistance("hippo", "zzzzzzzz") = 0.0 8451 * StringUtils.getJaroWinklerDistance("hello", "hallo") = 0.88 8452 * StringUtils.getJaroWinklerDistance("ABC Corporation", "ABC Corp") = 0.93 8453 * StringUtils.getJaroWinklerDistance("D N H Enterprises Inc", "D & H Enterprises, Inc.") = 0.95 8454 * StringUtils.getJaroWinklerDistance("My Gym Children's Fitness Center", "My Gym. Childrens Fitness") = 0.92 8455 * StringUtils.getJaroWinklerDistance("PENNSYLVANIA", "PENNCISYLVNIA") = 0.88 8456 * </pre> 8457 * 8458 * @param first the first String, must not be null 8459 * @param second the second String, must not be null 8460 * @return result distance 8461 * @throws IllegalArgumentException if either String input {@code null} 8462 * @since 3.3 8463 * @deprecated as of 3.6, use commons-text 8464 * <a href="https://commons.apache.org/proper/commons-text/javadocs/api-release/org/apache/commons/text/similarity/JaroWinklerDistance.html"> 8465 * JaroWinklerDistance</a> instead 8466 */ 8467 @Deprecated 8468 public static double getJaroWinklerDistance(final CharSequence first, final CharSequence second) { 8469 final double DEFAULT_SCALING_FACTOR = 0.1; 8470 8471 if (first == null || second == null) { 8472 throw new IllegalArgumentException("Strings must not be null"); 8473 } 8474 8475 final int[] mtp = matches(first, second); 8476 final double m = mtp[0]; 8477 if (m == 0) { 8478 return 0D; 8479 } 8480 final double j = ((m / first.length() + m / second.length() + (m - mtp[1]) / m)) / 3; 8481 final double jw = j < 0.7D ? j : j + Math.min(DEFAULT_SCALING_FACTOR, 1D / mtp[3]) * mtp[2] * (1D - j); 8482 return Math.round(jw * 100.0D) / 100.0D; 8483 } 8484 8485 private static int[] matches(final CharSequence first, final CharSequence second) { 8486 CharSequence max, min; 8487 if (first.length() > second.length()) { 8488 max = first; 8489 min = second; 8490 } else { 8491 max = second; 8492 min = first; 8493 } 8494 final int range = Math.max(max.length() / 2 - 1, 0); 8495 final int[] matchIndexes = new int[min.length()]; 8496 Arrays.fill(matchIndexes, -1); 8497 final boolean[] matchFlags = new boolean[max.length()]; 8498 int matches = 0; 8499 for (int mi = 0; mi < min.length(); mi++) { 8500 final char c1 = min.charAt(mi); 8501 for (int xi = Math.max(mi - range, 0), xn = Math.min(mi + range + 1, max.length()); xi < xn; xi++) { 8502 if (!matchFlags[xi] && c1 == max.charAt(xi)) { 8503 matchIndexes[mi] = xi; 8504 matchFlags[xi] = true; 8505 matches++; 8506 break; 8507 } 8508 } 8509 } 8510 final char[] ms1 = new char[matches]; 8511 final char[] ms2 = new char[matches]; 8512 for (int i = 0, si = 0; i < min.length(); i++) { 8513 if (matchIndexes[i] != -1) { 8514 ms1[si] = min.charAt(i); 8515 si++; 8516 } 8517 } 8518 for (int i = 0, si = 0; i < max.length(); i++) { 8519 if (matchFlags[i]) { 8520 ms2[si] = max.charAt(i); 8521 si++; 8522 } 8523 } 8524 int transpositions = 0; 8525 for (int mi = 0; mi < ms1.length; mi++) { 8526 if (ms1[mi] != ms2[mi]) { 8527 transpositions++; 8528 } 8529 } 8530 int prefix = 0; 8531 for (int mi = 0; mi < min.length(); mi++) { 8532 if (first.charAt(mi) == second.charAt(mi)) { 8533 prefix++; 8534 } else { 8535 break; 8536 } 8537 } 8538 return new int[] { matches, transpositions / 2, prefix, max.length() }; 8539 } 8540 8541 /** 8542 * <p>Find the Fuzzy Distance which indicates the similarity score between two Strings.</p> 8543 * 8544 * <p>This string matching algorithm is similar to the algorithms of editors such as Sublime Text, 8545 * TextMate, Atom and others. One point is given for every matched character. Subsequent 8546 * matches yield two bonus points. A higher score indicates a higher similarity.</p> 8547 * 8548 * <pre> 8549 * StringUtils.getFuzzyDistance(null, null, null) = IllegalArgumentException 8550 * StringUtils.getFuzzyDistance("", "", Locale.ENGLISH) = 0 8551 * StringUtils.getFuzzyDistance("Workshop", "b", Locale.ENGLISH) = 0 8552 * StringUtils.getFuzzyDistance("Room", "o", Locale.ENGLISH) = 1 8553 * StringUtils.getFuzzyDistance("Workshop", "w", Locale.ENGLISH) = 1 8554 * StringUtils.getFuzzyDistance("Workshop", "ws", Locale.ENGLISH) = 2 8555 * StringUtils.getFuzzyDistance("Workshop", "wo", Locale.ENGLISH) = 4 8556 * StringUtils.getFuzzyDistance("Apache Software Foundation", "asf", Locale.ENGLISH) = 3 8557 * </pre> 8558 * 8559 * @param term a full term that should be matched against, must not be null 8560 * @param query the query that will be matched against a term, must not be null 8561 * @param locale This string matching logic is case insensitive. A locale is necessary to normalize 8562 * both Strings to lower case. 8563 * @return result score 8564 * @throws IllegalArgumentException if either String input {@code null} or Locale input {@code null} 8565 * @since 3.4 8566 * @deprecated as of 3.6, use commons-text 8567 * <a href="https://commons.apache.org/proper/commons-text/javadocs/api-release/org/apache/commons/text/similarity/FuzzyScore.html"> 8568 * FuzzyScore</a> instead 8569 */ 8570 @Deprecated 8571 public static int getFuzzyDistance(final CharSequence term, final CharSequence query, final Locale locale) { 8572 if (term == null || query == null) { 8573 throw new IllegalArgumentException("Strings must not be null"); 8574 } else if (locale == null) { 8575 throw new IllegalArgumentException("Locale must not be null"); 8576 } 8577 8578 // fuzzy logic is case insensitive. We normalize the Strings to lower 8579 // case right from the start. Turning characters to lower case 8580 // via Character.toLowerCase(char) is unfortunately insufficient 8581 // as it does not accept a locale. 8582 final String termLowerCase = term.toString().toLowerCase(locale); 8583 final String queryLowerCase = query.toString().toLowerCase(locale); 8584 8585 // the resulting score 8586 int score = 0; 8587 8588 // the position in the term which will be scanned next for potential 8589 // query character matches 8590 int termIndex = 0; 8591 8592 // index of the previously matched character in the term 8593 int previousMatchingCharacterIndex = Integer.MIN_VALUE; 8594 8595 for (int queryIndex = 0; queryIndex < queryLowerCase.length(); queryIndex++) { 8596 final char queryChar = queryLowerCase.charAt(queryIndex); 8597 8598 boolean termCharacterMatchFound = false; 8599 for (; termIndex < termLowerCase.length() && !termCharacterMatchFound; termIndex++) { 8600 final char termChar = termLowerCase.charAt(termIndex); 8601 8602 if (queryChar == termChar) { 8603 // simple character matches result in one point 8604 score++; 8605 8606 // subsequent character matches further improve 8607 // the score. 8608 if (previousMatchingCharacterIndex + 1 == termIndex) { 8609 score += 2; 8610 } 8611 8612 previousMatchingCharacterIndex = termIndex; 8613 8614 // we can leave the nested loop. Every character in the 8615 // query can match at most one character in the term. 8616 termCharacterMatchFound = true; 8617 } 8618 } 8619 } 8620 8621 return score; 8622 } 8623 8624 // startsWith 8625 //----------------------------------------------------------------------- 8626 8627 /** 8628 * <p>Check if a CharSequence starts with a specified prefix.</p> 8629 * 8630 * <p>{@code null}s are handled without exceptions. Two {@code null} 8631 * references are considered to be equal. The comparison is case sensitive.</p> 8632 * 8633 * <pre> 8634 * StringUtils.startsWith(null, null) = true 8635 * StringUtils.startsWith(null, "abc") = false 8636 * StringUtils.startsWith("abcdef", null) = false 8637 * StringUtils.startsWith("abcdef", "abc") = true 8638 * StringUtils.startsWith("ABCDEF", "abc") = false 8639 * </pre> 8640 * 8641 * @see java.lang.String#startsWith(String) 8642 * @param str the CharSequence to check, may be null 8643 * @param prefix the prefix to find, may be null 8644 * @return {@code true} if the CharSequence starts with the prefix, case sensitive, or 8645 * both {@code null} 8646 * @since 2.4 8647 * @since 3.0 Changed signature from startsWith(String, String) to startsWith(CharSequence, CharSequence) 8648 */ 8649 public static boolean startsWith(final CharSequence str, final CharSequence prefix) { 8650 return startsWith(str, prefix, false); 8651 } 8652 8653 /** 8654 * <p>Case insensitive check if a CharSequence starts with a specified prefix.</p> 8655 * 8656 * <p>{@code null}s are handled without exceptions. Two {@code null} 8657 * references are considered to be equal. The comparison is case insensitive.</p> 8658 * 8659 * <pre> 8660 * StringUtils.startsWithIgnoreCase(null, null) = true 8661 * StringUtils.startsWithIgnoreCase(null, "abc") = false 8662 * StringUtils.startsWithIgnoreCase("abcdef", null) = false 8663 * StringUtils.startsWithIgnoreCase("abcdef", "abc") = true 8664 * StringUtils.startsWithIgnoreCase("ABCDEF", "abc") = true 8665 * </pre> 8666 * 8667 * @see java.lang.String#startsWith(String) 8668 * @param str the CharSequence to check, may be null 8669 * @param prefix the prefix to find, may be null 8670 * @return {@code true} if the CharSequence starts with the prefix, case insensitive, or 8671 * both {@code null} 8672 * @since 2.4 8673 * @since 3.0 Changed signature from startsWithIgnoreCase(String, String) to startsWithIgnoreCase(CharSequence, CharSequence) 8674 */ 8675 public static boolean startsWithIgnoreCase(final CharSequence str, final CharSequence prefix) { 8676 return startsWith(str, prefix, true); 8677 } 8678 8679 /** 8680 * <p>Check if a CharSequence starts with a specified prefix (optionally case insensitive).</p> 8681 * 8682 * @see java.lang.String#startsWith(String) 8683 * @param str the CharSequence to check, may be null 8684 * @param prefix the prefix to find, may be null 8685 * @param ignoreCase indicates whether the compare should ignore case 8686 * (case insensitive) or not. 8687 * @return {@code true} if the CharSequence starts with the prefix or 8688 * both {@code null} 8689 */ 8690 private static boolean startsWith(final CharSequence str, final CharSequence prefix, final boolean ignoreCase) { 8691 if (str == null || prefix == null) { 8692 return str == prefix; 8693 } 8694 if (prefix.length() > str.length()) { 8695 return false; 8696 } 8697 return CharSequenceUtils.regionMatches(str, ignoreCase, 0, prefix, 0, prefix.length()); 8698 } 8699 8700 /** 8701 * <p>Check if a CharSequence starts with any of the provided case-sensitive prefixes.</p> 8702 * 8703 * <pre> 8704 * StringUtils.startsWithAny(null, null) = false 8705 * StringUtils.startsWithAny(null, new String[] {"abc"}) = false 8706 * StringUtils.startsWithAny("abcxyz", null) = false 8707 * StringUtils.startsWithAny("abcxyz", new String[] {""}) = true 8708 * StringUtils.startsWithAny("abcxyz", new String[] {"abc"}) = true 8709 * StringUtils.startsWithAny("abcxyz", new String[] {null, "xyz", "abc"}) = true 8710 * StringUtils.startsWithAny("abcxyz", null, "xyz", "ABCX") = false 8711 * StringUtils.startsWithAny("ABCXYZ", null, "xyz", "abc") = false 8712 * </pre> 8713 * 8714 * @param sequence the CharSequence to check, may be null 8715 * @param searchStrings the case-sensitive CharSequence prefixes, may be empty or contain {@code null} 8716 * @see StringUtils#startsWith(CharSequence, CharSequence) 8717 * @return {@code true} if the input {@code sequence} is {@code null} AND no {@code searchStrings} are provided, or 8718 * the input {@code sequence} begins with any of the provided case-sensitive {@code searchStrings}. 8719 * @since 2.5 8720 * @since 3.0 Changed signature from startsWithAny(String, String[]) to startsWithAny(CharSequence, CharSequence...) 8721 */ 8722 public static boolean startsWithAny(final CharSequence sequence, final CharSequence... searchStrings) { 8723 if (isEmpty(sequence) || ArrayUtils.isEmpty(searchStrings)) { 8724 return false; 8725 } 8726 for (final CharSequence searchString : searchStrings) { 8727 if (startsWith(sequence, searchString)) { 8728 return true; 8729 } 8730 } 8731 return false; 8732 } 8733 8734 // endsWith 8735 //----------------------------------------------------------------------- 8736 8737 /** 8738 * <p>Check if a CharSequence ends with a specified suffix.</p> 8739 * 8740 * <p>{@code null}s are handled without exceptions. Two {@code null} 8741 * references are considered to be equal. The comparison is case sensitive.</p> 8742 * 8743 * <pre> 8744 * StringUtils.endsWith(null, null) = true 8745 * StringUtils.endsWith(null, "def") = false 8746 * StringUtils.endsWith("abcdef", null) = false 8747 * StringUtils.endsWith("abcdef", "def") = true 8748 * StringUtils.endsWith("ABCDEF", "def") = false 8749 * StringUtils.endsWith("ABCDEF", "cde") = false 8750 * StringUtils.endsWith("ABCDEF", "") = true 8751 * </pre> 8752 * 8753 * @see java.lang.String#endsWith(String) 8754 * @param str the CharSequence to check, may be null 8755 * @param suffix the suffix to find, may be null 8756 * @return {@code true} if the CharSequence ends with the suffix, case sensitive, or 8757 * both {@code null} 8758 * @since 2.4 8759 * @since 3.0 Changed signature from endsWith(String, String) to endsWith(CharSequence, CharSequence) 8760 */ 8761 public static boolean endsWith(final CharSequence str, final CharSequence suffix) { 8762 return endsWith(str, suffix, false); 8763 } 8764 8765 /** 8766 * <p>Case insensitive check if a CharSequence ends with a specified suffix.</p> 8767 * 8768 * <p>{@code null}s are handled without exceptions. Two {@code null} 8769 * references are considered to be equal. The comparison is case insensitive.</p> 8770 * 8771 * <pre> 8772 * StringUtils.endsWithIgnoreCase(null, null) = true 8773 * StringUtils.endsWithIgnoreCase(null, "def") = false 8774 * StringUtils.endsWithIgnoreCase("abcdef", null) = false 8775 * StringUtils.endsWithIgnoreCase("abcdef", "def") = true 8776 * StringUtils.endsWithIgnoreCase("ABCDEF", "def") = true 8777 * StringUtils.endsWithIgnoreCase("ABCDEF", "cde") = false 8778 * </pre> 8779 * 8780 * @see java.lang.String#endsWith(String) 8781 * @param str the CharSequence to check, may be null 8782 * @param suffix the suffix to find, may be null 8783 * @return {@code true} if the CharSequence ends with the suffix, case insensitive, or 8784 * both {@code null} 8785 * @since 2.4 8786 * @since 3.0 Changed signature from endsWithIgnoreCase(String, String) to endsWithIgnoreCase(CharSequence, CharSequence) 8787 */ 8788 public static boolean endsWithIgnoreCase(final CharSequence str, final CharSequence suffix) { 8789 return endsWith(str, suffix, true); 8790 } 8791 8792 /** 8793 * <p>Check if a CharSequence ends with a specified suffix (optionally case insensitive).</p> 8794 * 8795 * @see java.lang.String#endsWith(String) 8796 * @param str the CharSequence to check, may be null 8797 * @param suffix the suffix to find, may be null 8798 * @param ignoreCase indicates whether the compare should ignore case 8799 * (case insensitive) or not. 8800 * @return {@code true} if the CharSequence starts with the prefix or 8801 * both {@code null} 8802 */ 8803 private static boolean endsWith(final CharSequence str, final CharSequence suffix, final boolean ignoreCase) { 8804 if (str == null || suffix == null) { 8805 return str == suffix; 8806 } 8807 if (suffix.length() > str.length()) { 8808 return false; 8809 } 8810 final int strOffset = str.length() - suffix.length(); 8811 return CharSequenceUtils.regionMatches(str, ignoreCase, strOffset, suffix, 0, suffix.length()); 8812 } 8813 8814 /** 8815 * <p> 8816 * Similar to <a 8817 * href="http://www.w3.org/TR/xpath/#function-normalize-space">http://www.w3.org/TR/xpath/#function-normalize 8818 * -space</a> 8819 * </p> 8820 * <p> 8821 * The function returns the argument string with whitespace normalized by using 8822 * <code>{@link #trim(String)}</code> to remove leading and trailing whitespace 8823 * and then replacing sequences of whitespace characters by a single space. 8824 * </p> 8825 * In XML Whitespace characters are the same as those allowed by the <a 8826 * href="http://www.w3.org/TR/REC-xml/#NT-S">S</a> production, which is S ::= (#x20 | #x9 | #xD | #xA)+ 8827 * <p> 8828 * Java's regexp pattern \s defines whitespace as [ \t\n\x0B\f\r] 8829 * 8830 * <p>For reference:</p> 8831 * <ul> 8832 * <li>\x0B = vertical tab</li> 8833 * <li>\f = #xC = form feed</li> 8834 * <li>#x20 = space</li> 8835 * <li>#x9 = \t</li> 8836 * <li>#xA = \n</li> 8837 * <li>#xD = \r</li> 8838 * </ul> 8839 * 8840 * <p> 8841 * The difference is that Java's whitespace includes vertical tab and form feed, which this functional will also 8842 * normalize. Additionally <code>{@link #trim(String)}</code> removes control characters (char <= 32) from both 8843 * ends of this String. 8844 * </p> 8845 * 8846 * @see Pattern 8847 * @see #trim(String) 8848 * @see <a 8849 * href="http://www.w3.org/TR/xpath/#function-normalize-space">http://www.w3.org/TR/xpath/#function-normalize-space</a> 8850 * @param str the source String to normalize whitespaces from, may be null 8851 * @return the modified string with whitespace normalized, {@code null} if null String input 8852 * 8853 * @since 3.0 8854 */ 8855 public static String normalizeSpace(final String str) { 8856 // LANG-1020: Improved performance significantly by normalizing manually instead of using regex 8857 // See https://github.com/librucha/commons-lang-normalizespaces-benchmark for performance test 8858 if (isEmpty(str)) { 8859 return str; 8860 } 8861 final int size = str.length(); 8862 final char[] newChars = new char[size]; 8863 int count = 0; 8864 int whitespacesCount = 0; 8865 boolean startWhitespaces = true; 8866 for (int i = 0; i < size; i++) { 8867 final char actualChar = str.charAt(i); 8868 final boolean isWhitespace = Character.isWhitespace(actualChar); 8869 if (isWhitespace) { 8870 if (whitespacesCount == 0 && !startWhitespaces) { 8871 newChars[count++] = SPACE.charAt(0); 8872 } 8873 whitespacesCount++; 8874 } else { 8875 startWhitespaces = false; 8876 newChars[count++] = (actualChar == 160 ? 32 : actualChar); 8877 whitespacesCount = 0; 8878 } 8879 } 8880 if (startWhitespaces) { 8881 return EMPTY; 8882 } 8883 return new String(newChars, 0, count - (whitespacesCount > 0 ? 1 : 0)).trim(); 8884 } 8885 8886 /** 8887 * <p>Check if a CharSequence ends with any of the provided case-sensitive suffixes.</p> 8888 * 8889 * <pre> 8890 * StringUtils.endsWithAny(null, null) = false 8891 * StringUtils.endsWithAny(null, new String[] {"abc"}) = false 8892 * StringUtils.endsWithAny("abcxyz", null) = false 8893 * StringUtils.endsWithAny("abcxyz", new String[] {""}) = true 8894 * StringUtils.endsWithAny("abcxyz", new String[] {"xyz"}) = true 8895 * StringUtils.endsWithAny("abcxyz", new String[] {null, "xyz", "abc"}) = true 8896 * StringUtils.endsWithAny("abcXYZ", "def", "XYZ") = true 8897 * StringUtils.endsWithAny("abcXYZ", "def", "xyz") = false 8898 * </pre> 8899 * 8900 * @param sequence the CharSequence to check, may be null 8901 * @param searchStrings the case-sensitive CharSequences to find, may be empty or contain {@code null} 8902 * @see StringUtils#endsWith(CharSequence, CharSequence) 8903 * @return {@code true} if the input {@code sequence} is {@code null} AND no {@code searchStrings} are provided, or 8904 * the input {@code sequence} ends in any of the provided case-sensitive {@code searchStrings}. 8905 * @since 3.0 8906 */ 8907 public static boolean endsWithAny(final CharSequence sequence, final CharSequence... searchStrings) { 8908 if (isEmpty(sequence) || ArrayUtils.isEmpty(searchStrings)) { 8909 return false; 8910 } 8911 for (final CharSequence searchString : searchStrings) { 8912 if (endsWith(sequence, searchString)) { 8913 return true; 8914 } 8915 } 8916 return false; 8917 } 8918 8919 /** 8920 * Appends the suffix to the end of the string if the string does not 8921 * already end with the suffix. 8922 * 8923 * @param str The string. 8924 * @param suffix The suffix to append to the end of the string. 8925 * @param ignoreCase Indicates whether the compare should ignore case. 8926 * @param suffixes Additional suffixes that are valid terminators (optional). 8927 * 8928 * @return A new String if suffix was appended, the same string otherwise. 8929 */ 8930 private static String appendIfMissing(final String str, final CharSequence suffix, final boolean ignoreCase, final CharSequence... suffixes) { 8931 if (str == null || isEmpty(suffix) || endsWith(str, suffix, ignoreCase)) { 8932 return str; 8933 } 8934 if (suffixes != null && suffixes.length > 0) { 8935 for (final CharSequence s : suffixes) { 8936 if (endsWith(str, s, ignoreCase)) { 8937 return str; 8938 } 8939 } 8940 } 8941 return str + suffix.toString(); 8942 } 8943 8944 /** 8945 * Appends the suffix to the end of the string if the string does not 8946 * already end with any of the suffixes. 8947 * 8948 * <pre> 8949 * StringUtils.appendIfMissing(null, null) = null 8950 * StringUtils.appendIfMissing("abc", null) = "abc" 8951 * StringUtils.appendIfMissing("", "xyz") = "xyz" 8952 * StringUtils.appendIfMissing("abc", "xyz") = "abcxyz" 8953 * StringUtils.appendIfMissing("abcxyz", "xyz") = "abcxyz" 8954 * StringUtils.appendIfMissing("abcXYZ", "xyz") = "abcXYZxyz" 8955 * </pre> 8956 * <p>With additional suffixes,</p> 8957 * <pre> 8958 * StringUtils.appendIfMissing(null, null, null) = null 8959 * StringUtils.appendIfMissing("abc", null, null) = "abc" 8960 * StringUtils.appendIfMissing("", "xyz", null) = "xyz" 8961 * StringUtils.appendIfMissing("abc", "xyz", new CharSequence[]{null}) = "abcxyz" 8962 * StringUtils.appendIfMissing("abc", "xyz", "") = "abc" 8963 * StringUtils.appendIfMissing("abc", "xyz", "mno") = "abcxyz" 8964 * StringUtils.appendIfMissing("abcxyz", "xyz", "mno") = "abcxyz" 8965 * StringUtils.appendIfMissing("abcmno", "xyz", "mno") = "abcmno" 8966 * StringUtils.appendIfMissing("abcXYZ", "xyz", "mno") = "abcXYZxyz" 8967 * StringUtils.appendIfMissing("abcMNO", "xyz", "mno") = "abcMNOxyz" 8968 * </pre> 8969 * 8970 * @param str The string. 8971 * @param suffix The suffix to append to the end of the string. 8972 * @param suffixes Additional suffixes that are valid terminators. 8973 * 8974 * @return A new String if suffix was appended, the same string otherwise. 8975 * 8976 * @since 3.2 8977 */ 8978 public static String appendIfMissing(final String str, final CharSequence suffix, final CharSequence... suffixes) { 8979 return appendIfMissing(str, suffix, false, suffixes); 8980 } 8981 8982 /** 8983 * Appends the suffix to the end of the string if the string does not 8984 * already end, case insensitive, with any of the suffixes. 8985 * 8986 * <pre> 8987 * StringUtils.appendIfMissingIgnoreCase(null, null) = null 8988 * StringUtils.appendIfMissingIgnoreCase("abc", null) = "abc" 8989 * StringUtils.appendIfMissingIgnoreCase("", "xyz") = "xyz" 8990 * StringUtils.appendIfMissingIgnoreCase("abc", "xyz") = "abcxyz" 8991 * StringUtils.appendIfMissingIgnoreCase("abcxyz", "xyz") = "abcxyz" 8992 * StringUtils.appendIfMissingIgnoreCase("abcXYZ", "xyz") = "abcXYZ" 8993 * </pre> 8994 * <p>With additional suffixes,</p> 8995 * <pre> 8996 * StringUtils.appendIfMissingIgnoreCase(null, null, null) = null 8997 * StringUtils.appendIfMissingIgnoreCase("abc", null, null) = "abc" 8998 * StringUtils.appendIfMissingIgnoreCase("", "xyz", null) = "xyz" 8999 * StringUtils.appendIfMissingIgnoreCase("abc", "xyz", new CharSequence[]{null}) = "abcxyz" 9000 * StringUtils.appendIfMissingIgnoreCase("abc", "xyz", "") = "abc" 9001 * StringUtils.appendIfMissingIgnoreCase("abc", "xyz", "mno") = "axyz" 9002 * StringUtils.appendIfMissingIgnoreCase("abcxyz", "xyz", "mno") = "abcxyz" 9003 * StringUtils.appendIfMissingIgnoreCase("abcmno", "xyz", "mno") = "abcmno" 9004 * StringUtils.appendIfMissingIgnoreCase("abcXYZ", "xyz", "mno") = "abcXYZ" 9005 * StringUtils.appendIfMissingIgnoreCase("abcMNO", "xyz", "mno") = "abcMNO" 9006 * </pre> 9007 * 9008 * @param str The string. 9009 * @param suffix The suffix to append to the end of the string. 9010 * @param suffixes Additional suffixes that are valid terminators. 9011 * 9012 * @return A new String if suffix was appended, the same string otherwise. 9013 * 9014 * @since 3.2 9015 */ 9016 public static String appendIfMissingIgnoreCase(final String str, final CharSequence suffix, final CharSequence... suffixes) { 9017 return appendIfMissing(str, suffix, true, suffixes); 9018 } 9019 9020 /** 9021 * Prepends the prefix to the start of the string if the string does not 9022 * already start with any of the prefixes. 9023 * 9024 * @param str The string. 9025 * @param prefix The prefix to prepend to the start of the string. 9026 * @param ignoreCase Indicates whether the compare should ignore case. 9027 * @param prefixes Additional prefixes that are valid (optional). 9028 * 9029 * @return A new String if prefix was prepended, the same string otherwise. 9030 */ 9031 private static String prependIfMissing(final String str, final CharSequence prefix, final boolean ignoreCase, final CharSequence... prefixes) { 9032 if (str == null || isEmpty(prefix) || startsWith(str, prefix, ignoreCase)) { 9033 return str; 9034 } 9035 if (prefixes != null && prefixes.length > 0) { 9036 for (final CharSequence p : prefixes) { 9037 if (startsWith(str, p, ignoreCase)) { 9038 return str; 9039 } 9040 } 9041 } 9042 return prefix.toString() + str; 9043 } 9044 9045 /** 9046 * Prepends the prefix to the start of the string if the string does not 9047 * already start with any of the prefixes. 9048 * 9049 * <pre> 9050 * StringUtils.prependIfMissing(null, null) = null 9051 * StringUtils.prependIfMissing("abc", null) = "abc" 9052 * StringUtils.prependIfMissing("", "xyz") = "xyz" 9053 * StringUtils.prependIfMissing("abc", "xyz") = "xyzabc" 9054 * StringUtils.prependIfMissing("xyzabc", "xyz") = "xyzabc" 9055 * StringUtils.prependIfMissing("XYZabc", "xyz") = "xyzXYZabc" 9056 * </pre> 9057 * <p>With additional prefixes,</p> 9058 * <pre> 9059 * StringUtils.prependIfMissing(null, null, null) = null 9060 * StringUtils.prependIfMissing("abc", null, null) = "abc" 9061 * StringUtils.prependIfMissing("", "xyz", null) = "xyz" 9062 * StringUtils.prependIfMissing("abc", "xyz", new CharSequence[]{null}) = "xyzabc" 9063 * StringUtils.prependIfMissing("abc", "xyz", "") = "abc" 9064 * StringUtils.prependIfMissing("abc", "xyz", "mno") = "xyzabc" 9065 * StringUtils.prependIfMissing("xyzabc", "xyz", "mno") = "xyzabc" 9066 * StringUtils.prependIfMissing("mnoabc", "xyz", "mno") = "mnoabc" 9067 * StringUtils.prependIfMissing("XYZabc", "xyz", "mno") = "xyzXYZabc" 9068 * StringUtils.prependIfMissing("MNOabc", "xyz", "mno") = "xyzMNOabc" 9069 * </pre> 9070 * 9071 * @param str The string. 9072 * @param prefix The prefix to prepend to the start of the string. 9073 * @param prefixes Additional prefixes that are valid. 9074 * 9075 * @return A new String if prefix was prepended, the same string otherwise. 9076 * 9077 * @since 3.2 9078 */ 9079 public static String prependIfMissing(final String str, final CharSequence prefix, final CharSequence... prefixes) { 9080 return prependIfMissing(str, prefix, false, prefixes); 9081 } 9082 9083 /** 9084 * Prepends the prefix to the start of the string if the string does not 9085 * already start, case insensitive, with any of the prefixes. 9086 * 9087 * <pre> 9088 * StringUtils.prependIfMissingIgnoreCase(null, null) = null 9089 * StringUtils.prependIfMissingIgnoreCase("abc", null) = "abc" 9090 * StringUtils.prependIfMissingIgnoreCase("", "xyz") = "xyz" 9091 * StringUtils.prependIfMissingIgnoreCase("abc", "xyz") = "xyzabc" 9092 * StringUtils.prependIfMissingIgnoreCase("xyzabc", "xyz") = "xyzabc" 9093 * StringUtils.prependIfMissingIgnoreCase("XYZabc", "xyz") = "XYZabc" 9094 * </pre> 9095 * <p>With additional prefixes,</p> 9096 * <pre> 9097 * StringUtils.prependIfMissingIgnoreCase(null, null, null) = null 9098 * StringUtils.prependIfMissingIgnoreCase("abc", null, null) = "abc" 9099 * StringUtils.prependIfMissingIgnoreCase("", "xyz", null) = "xyz" 9100 * StringUtils.prependIfMissingIgnoreCase("abc", "xyz", new CharSequence[]{null}) = "xyzabc" 9101 * StringUtils.prependIfMissingIgnoreCase("abc", "xyz", "") = "abc" 9102 * StringUtils.prependIfMissingIgnoreCase("abc", "xyz", "mno") = "xyzabc" 9103 * StringUtils.prependIfMissingIgnoreCase("xyzabc", "xyz", "mno") = "xyzabc" 9104 * StringUtils.prependIfMissingIgnoreCase("mnoabc", "xyz", "mno") = "mnoabc" 9105 * StringUtils.prependIfMissingIgnoreCase("XYZabc", "xyz", "mno") = "XYZabc" 9106 * StringUtils.prependIfMissingIgnoreCase("MNOabc", "xyz", "mno") = "MNOabc" 9107 * </pre> 9108 * 9109 * @param str The string. 9110 * @param prefix The prefix to prepend to the start of the string. 9111 * @param prefixes Additional prefixes that are valid (optional). 9112 * 9113 * @return A new String if prefix was prepended, the same string otherwise. 9114 * 9115 * @since 3.2 9116 */ 9117 public static String prependIfMissingIgnoreCase(final String str, final CharSequence prefix, final CharSequence... prefixes) { 9118 return prependIfMissing(str, prefix, true, prefixes); 9119 } 9120 9121 /** 9122 * Converts a <code>byte[]</code> to a String using the specified character encoding. 9123 * 9124 * @param bytes 9125 * the byte array to read from 9126 * @param charsetName 9127 * the encoding to use, if null then use the platform default 9128 * @return a new String 9129 * @throws UnsupportedEncodingException 9130 * If the named charset is not supported 9131 * @throws NullPointerException 9132 * if the input is null 9133 * @deprecated use {@link StringUtils#toEncodedString(byte[], Charset)} instead of String constants in your code 9134 * @since 3.1 9135 */ 9136 @Deprecated 9137 public static String toString(final byte[] bytes, final String charsetName) throws UnsupportedEncodingException { 9138 return charsetName != null ? new String(bytes, charsetName) : new String(bytes, Charset.defaultCharset()); 9139 } 9140 9141 /** 9142 * Converts a <code>byte[]</code> to a String using the specified character encoding. 9143 * 9144 * @param bytes 9145 * the byte array to read from 9146 * @param charset 9147 * the encoding to use, if null then use the platform default 9148 * @return a new String 9149 * @throws NullPointerException 9150 * if {@code bytes} is null 9151 * @since 3.2 9152 * @since 3.3 No longer throws {@link UnsupportedEncodingException}. 9153 */ 9154 public static String toEncodedString(final byte[] bytes, final Charset charset) { 9155 return new String(bytes, charset != null ? charset : Charset.defaultCharset()); 9156 } 9157 9158 /** 9159 * <p> 9160 * Wraps a string with a char. 9161 * </p> 9162 * 9163 * <pre> 9164 * StringUtils.wrap(null, *) = null 9165 * StringUtils.wrap("", *) = "" 9166 * StringUtils.wrap("ab", '\0') = "ab" 9167 * StringUtils.wrap("ab", 'x') = "xabx" 9168 * StringUtils.wrap("ab", '\'') = "'ab'" 9169 * StringUtils.wrap("\"ab\"", '\"') = "\"\"ab\"\"" 9170 * </pre> 9171 * 9172 * @param str 9173 * the string to be wrapped, may be {@code null} 9174 * @param wrapWith 9175 * the char that will wrap {@code str} 9176 * @return the wrapped string, or {@code null} if {@code str==null} 9177 * @since 3.4 9178 */ 9179 public static String wrap(final String str, final char wrapWith) { 9180 9181 if (isEmpty(str) || wrapWith == CharUtils.NUL) { 9182 return str; 9183 } 9184 9185 return wrapWith + str + wrapWith; 9186 } 9187 9188 /** 9189 * <p> 9190 * Wraps a String with another String. 9191 * </p> 9192 * 9193 * <p> 9194 * A {@code null} input String returns {@code null}. 9195 * </p> 9196 * 9197 * <pre> 9198 * StringUtils.wrap(null, *) = null 9199 * StringUtils.wrap("", *) = "" 9200 * StringUtils.wrap("ab", null) = "ab" 9201 * StringUtils.wrap("ab", "x") = "xabx" 9202 * StringUtils.wrap("ab", "\"") = "\"ab\"" 9203 * StringUtils.wrap("\"ab\"", "\"") = "\"\"ab\"\"" 9204 * StringUtils.wrap("ab", "'") = "'ab'" 9205 * StringUtils.wrap("'abcd'", "'") = "''abcd''" 9206 * StringUtils.wrap("\"abcd\"", "'") = "'\"abcd\"'" 9207 * StringUtils.wrap("'abcd'", "\"") = "\"'abcd'\"" 9208 * </pre> 9209 * 9210 * @param str 9211 * the String to be wrapper, may be null 9212 * @param wrapWith 9213 * the String that will wrap str 9214 * @return wrapped String, {@code null} if null String input 9215 * @since 3.4 9216 */ 9217 public static String wrap(final String str, final String wrapWith) { 9218 9219 if (isEmpty(str) || isEmpty(wrapWith)) { 9220 return str; 9221 } 9222 9223 return wrapWith.concat(str).concat(wrapWith); 9224 } 9225 9226 /** 9227 * <p> 9228 * Wraps a string with a char if that char is missing from the start or end of the given string. 9229 * </p> 9230 * 9231 * <pre> 9232 * StringUtils.wrapIfMissing(null, *) = null 9233 * StringUtils.wrapIfMissing("", *) = "" 9234 * StringUtils.wrapIfMissing("ab", '\0') = "ab" 9235 * StringUtils.wrapIfMissing("ab", 'x') = "xabx" 9236 * StringUtils.wrapIfMissing("ab", '\'') = "'ab'" 9237 * StringUtils.wrapIfMissing("\"ab\"", '\"') = "\"ab\"" 9238 * StringUtils.wrapIfMissing("/", '/') = "/" 9239 * StringUtils.wrapIfMissing("a/b/c", '/') = "/a/b/c/" 9240 * StringUtils.wrapIfMissing("/a/b/c", '/') = "/a/b/c/" 9241 * StringUtils.wrapIfMissing("a/b/c/", '/') = "/a/b/c/" 9242 * </pre> 9243 * 9244 * @param str 9245 * the string to be wrapped, may be {@code null} 9246 * @param wrapWith 9247 * the char that will wrap {@code str} 9248 * @return the wrapped string, or {@code null} if {@code str==null} 9249 * @since 3.5 9250 */ 9251 public static String wrapIfMissing(final String str, final char wrapWith) { 9252 if (isEmpty(str) || wrapWith == CharUtils.NUL) { 9253 return str; 9254 } 9255 final StringBuilder builder = new StringBuilder(str.length() + 2); 9256 if (str.charAt(0) != wrapWith) { 9257 builder.append(wrapWith); 9258 } 9259 builder.append(str); 9260 if (str.charAt(str.length() - 1) != wrapWith) { 9261 builder.append(wrapWith); 9262 } 9263 return builder.toString(); 9264 } 9265 9266 /** 9267 * <p> 9268 * Wraps a string with a string if that string is missing from the start or end of the given string. 9269 * </p> 9270 * 9271 * <pre> 9272 * StringUtils.wrapIfMissing(null, *) = null 9273 * StringUtils.wrapIfMissing("", *) = "" 9274 * StringUtils.wrapIfMissing("ab", null) = "ab" 9275 * StringUtils.wrapIfMissing("ab", "x") = "xabx" 9276 * StringUtils.wrapIfMissing("ab", "\"") = "\"ab\"" 9277 * StringUtils.wrapIfMissing("\"ab\"", "\"") = "\"ab\"" 9278 * StringUtils.wrapIfMissing("ab", "'") = "'ab'" 9279 * StringUtils.wrapIfMissing("'abcd'", "'") = "'abcd'" 9280 * StringUtils.wrapIfMissing("\"abcd\"", "'") = "'\"abcd\"'" 9281 * StringUtils.wrapIfMissing("'abcd'", "\"") = "\"'abcd'\"" 9282 * StringUtils.wrapIfMissing("/", "/") = "/" 9283 * StringUtils.wrapIfMissing("a/b/c", "/") = "/a/b/c/" 9284 * StringUtils.wrapIfMissing("/a/b/c", "/") = "/a/b/c/" 9285 * StringUtils.wrapIfMissing("a/b/c/", "/") = "/a/b/c/" 9286 * </pre> 9287 * 9288 * @param str 9289 * the string to be wrapped, may be {@code null} 9290 * @param wrapWith 9291 * the char that will wrap {@code str} 9292 * @return the wrapped string, or {@code null} if {@code str==null} 9293 * @since 3.5 9294 */ 9295 public static String wrapIfMissing(final String str, final String wrapWith) { 9296 if (isEmpty(str) || isEmpty(wrapWith)) { 9297 return str; 9298 } 9299 final StringBuilder builder = new StringBuilder(str.length() + wrapWith.length() + wrapWith.length()); 9300 if (!str.startsWith(wrapWith)) { 9301 builder.append(wrapWith); 9302 } 9303 builder.append(str); 9304 if (!str.endsWith(wrapWith)) { 9305 builder.append(wrapWith); 9306 } 9307 return builder.toString(); 9308 } 9309 9310 /** 9311 * <p> 9312 * Unwraps a given string from anther string. 9313 * </p> 9314 * 9315 * <pre> 9316 * StringUtils.unwrap(null, null) = null 9317 * StringUtils.unwrap(null, "") = null 9318 * StringUtils.unwrap(null, "1") = null 9319 * StringUtils.unwrap("\'abc\'", "\'") = "abc" 9320 * StringUtils.unwrap("\"abc\"", "\"") = "abc" 9321 * StringUtils.unwrap("AABabcBAA", "AA") = "BabcB" 9322 * StringUtils.unwrap("A", "#") = "A" 9323 * StringUtils.unwrap("#A", "#") = "#A" 9324 * StringUtils.unwrap("A#", "#") = "A#" 9325 * </pre> 9326 * 9327 * @param str 9328 * the String to be unwrapped, can be null 9329 * @param wrapToken 9330 * the String used to unwrap 9331 * @return unwrapped String or the original string 9332 * if it is not quoted properly with the wrapToken 9333 * @since 3.6 9334 */ 9335 public static String unwrap(final String str, final String wrapToken) { 9336 if (isEmpty(str) || isEmpty(wrapToken)) { 9337 return str; 9338 } 9339 9340 if (startsWith(str, wrapToken) && endsWith(str, wrapToken)) { 9341 final int startIndex = str.indexOf(wrapToken); 9342 final int endIndex = str.lastIndexOf(wrapToken); 9343 final int wrapLength = wrapToken.length(); 9344 if (startIndex != -1 && endIndex != -1) { 9345 return str.substring(startIndex + wrapLength, endIndex); 9346 } 9347 } 9348 9349 return str; 9350 } 9351 9352 /** 9353 * <p> 9354 * Unwraps a given string from a character. 9355 * </p> 9356 * 9357 * <pre> 9358 * StringUtils.unwrap(null, null) = null 9359 * StringUtils.unwrap(null, '\0') = null 9360 * StringUtils.unwrap(null, '1') = null 9361 * StringUtils.unwrap("\'abc\'", '\'') = "abc" 9362 * StringUtils.unwrap("AABabcBAA", 'A') = "ABabcBA" 9363 * StringUtils.unwrap("A", '#') = "A" 9364 * StringUtils.unwrap("#A", '#') = "#A" 9365 * StringUtils.unwrap("A#", '#') = "A#" 9366 * </pre> 9367 * 9368 * @param str 9369 * the String to be unwrapped, can be null 9370 * @param wrapChar 9371 * the character used to unwrap 9372 * @return unwrapped String or the original string 9373 * if it is not quoted properly with the wrapChar 9374 * @since 3.6 9375 */ 9376 public static String unwrap(final String str, final char wrapChar) { 9377 if (isEmpty(str) || wrapChar == CharUtils.NUL) { 9378 return str; 9379 } 9380 9381 if (str.charAt(0) == wrapChar && str.charAt(str.length() - 1) == wrapChar) { 9382 final int startIndex = 0; 9383 final int endIndex = str.length() - 1; 9384 if (endIndex != -1) { 9385 return str.substring(startIndex + 1, endIndex); 9386 } 9387 } 9388 9389 return str; 9390 } 9391 9392 /** 9393 * <p>Converts a {@code CharSequence} into an array of code points.</p> 9394 * 9395 * <p>Valid pairs of surrogate code units will be converted into a single supplementary 9396 * code point. Isolated surrogate code units (i.e. a high surrogate not followed by a low surrogate or 9397 * a low surrogate not preceded by a high surrogate) will be returned as-is.</p> 9398 * 9399 * <pre> 9400 * StringUtils.toCodePoints(null) = null 9401 * StringUtils.toCodePoints("") = [] // empty array 9402 * </pre> 9403 * 9404 * @param str the character sequence to convert 9405 * @return an array of code points 9406 * @since 3.6 9407 */ 9408 public static int[] toCodePoints(final CharSequence str) { 9409 if (str == null) { 9410 return null; 9411 } 9412 if (str.length() == 0) { 9413 return ArrayUtils.EMPTY_INT_ARRAY; 9414 } 9415 9416 final String s = str.toString(); 9417 final int[] result = new int[s.codePointCount(0, s.length())]; 9418 int index = 0; 9419 for (int i = 0; i < result.length; i++) { 9420 result[i] = s.codePointAt(index); 9421 index += Character.charCount(result[i]); 9422 } 9423 return result; 9424 } 9425 9426 /** 9427 * Returns the string representation of the {@code char} array or null. 9428 * 9429 * @param value the character array. 9430 * @return a String or null 9431 * @see String#valueOf(char[]) 9432 * @since 3.9 9433 */ 9434 public static String valueOf(final char[] value) { 9435 return value == null ? null : String.valueOf(value); 9436 } 9437 9438}