001/* 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017package org.apache.commons.lang3; 018 019import java.io.UnsupportedEncodingException; 020import java.nio.charset.Charset; 021import java.text.Normalizer; 022import java.util.ArrayList; 023import java.util.Arrays; 024import java.util.Iterator; 025import java.util.List; 026import java.util.Locale; 027import java.util.Objects; 028import java.util.regex.Pattern; 029 030/** 031 * <p>Operations on {@link java.lang.String} that are 032 * {@code null} safe.</p> 033 * 034 * <ul> 035 * <li><b>IsEmpty/IsBlank</b> 036 * - checks if a String contains text</li> 037 * <li><b>Trim/Strip</b> 038 * - removes leading and trailing whitespace</li> 039 * <li><b>Equals/Compare</b> 040 * - compares two strings null-safe</li> 041 * <li><b>startsWith</b> 042 * - check if a String starts with a prefix null-safe</li> 043 * <li><b>endsWith</b> 044 * - check if a String ends with a suffix null-safe</li> 045 * <li><b>IndexOf/LastIndexOf/Contains</b> 046 * - null-safe index-of checks 047 * <li><b>IndexOfAny/LastIndexOfAny/IndexOfAnyBut/LastIndexOfAnyBut</b> 048 * - index-of any of a set of Strings</li> 049 * <li><b>ContainsOnly/ContainsNone/ContainsAny</b> 050 * - does String contains only/none/any of these characters</li> 051 * <li><b>Substring/Left/Right/Mid</b> 052 * - null-safe substring extractions</li> 053 * <li><b>SubstringBefore/SubstringAfter/SubstringBetween</b> 054 * - substring extraction relative to other strings</li> 055 * <li><b>Split/Join</b> 056 * - splits a String into an array of substrings and vice versa</li> 057 * <li><b>Remove/Delete</b> 058 * - removes part of a String</li> 059 * <li><b>Replace/Overlay</b> 060 * - Searches a String and replaces one String with another</li> 061 * <li><b>Chomp/Chop</b> 062 * - removes the last part of a String</li> 063 * <li><b>AppendIfMissing</b> 064 * - appends a suffix to the end of the String if not present</li> 065 * <li><b>PrependIfMissing</b> 066 * - prepends a prefix to the start of the String if not present</li> 067 * <li><b>LeftPad/RightPad/Center/Repeat</b> 068 * - pads a String</li> 069 * <li><b>UpperCase/LowerCase/SwapCase/Capitalize/Uncapitalize</b> 070 * - changes the case of a String</li> 071 * <li><b>CountMatches</b> 072 * - counts the number of occurrences of one String in another</li> 073 * <li><b>IsAlpha/IsNumeric/IsWhitespace/IsAsciiPrintable</b> 074 * - checks the characters in a String</li> 075 * <li><b>DefaultString</b> 076 * - protects against a null input String</li> 077 * <li><b>Rotate</b> 078 * - rotate (circular shift) a String</li> 079 * <li><b>Reverse/ReverseDelimited</b> 080 * - reverses a String</li> 081 * <li><b>Abbreviate</b> 082 * - abbreviates a string using ellipsis or another given String</li> 083 * <li><b>Difference</b> 084 * - compares Strings and reports on their differences</li> 085 * <li><b>LevenshteinDistance</b> 086 * - the number of changes needed to change one String into another</li> 087 * </ul> 088 * 089 * <p>The {@code StringUtils} class defines certain words related to 090 * String handling.</p> 091 * 092 * <ul> 093 * <li>null - {@code null}</li> 094 * <li>empty - a zero-length string ({@code ""})</li> 095 * <li>space - the space character ({@code ' '}, char 32)</li> 096 * <li>whitespace - the characters defined by {@link Character#isWhitespace(char)}</li> 097 * <li>trim - the characters <= 32 as in {@link String#trim()}</li> 098 * </ul> 099 * 100 * <p>{@code StringUtils} handles {@code null} input Strings quietly. 101 * That is to say that a {@code null} input will return {@code null}. 102 * Where a {@code boolean} or {@code int} is being returned 103 * details vary by method.</p> 104 * 105 * <p>A side effect of the {@code null} handling is that a 106 * {@code NullPointerException} should be considered a bug in 107 * {@code StringUtils}.</p> 108 * 109 * <p>Methods in this class give sample code to explain their operation. 110 * The symbol {@code *} is used to indicate any input including {@code null}.</p> 111 * 112 * <p>#ThreadSafe#</p> 113 * @see java.lang.String 114 * @since 1.0 115 */ 116//@Immutable 117public class StringUtils { 118 // Performance testing notes (JDK 1.4, Jul03, scolebourne) 119 // Whitespace: 120 // Character.isWhitespace() is faster than WHITESPACE.indexOf() 121 // where WHITESPACE is a string of all whitespace characters 122 // 123 // Character access: 124 // String.charAt(n) versus toCharArray(), then array[n] 125 // String.charAt(n) is about 15% worse for a 10K string 126 // They are about equal for a length 50 string 127 // String.charAt(n) is about 4 times better for a length 3 string 128 // String.charAt(n) is best bet overall 129 // 130 // Append: 131 // String.concat about twice as fast as StringBuffer.append 132 // (not sure who tested this) 133 134 /** 135 * A String for a space character. 136 * 137 * @since 3.2 138 */ 139 public static final String SPACE = " "; 140 141 /** 142 * The empty String {@code ""}. 143 * @since 2.0 144 */ 145 public static final String EMPTY = ""; 146 147 /** 148 * A String for linefeed LF ("\n"). 149 * 150 * @see <a href="http://docs.oracle.com/javase/specs/jls/se7/html/jls-3.html#jls-3.10.6">JLF: Escape Sequences 151 * for Character and String Literals</a> 152 * @since 3.2 153 */ 154 public static final String LF = "\n"; 155 156 /** 157 * A String for carriage return CR ("\r"). 158 * 159 * @see <a href="http://docs.oracle.com/javase/specs/jls/se7/html/jls-3.html#jls-3.10.6">JLF: Escape Sequences 160 * for Character and String Literals</a> 161 * @since 3.2 162 */ 163 public static final String CR = "\r"; 164 165 /** 166 * Represents a failed index search. 167 * @since 2.1 168 */ 169 public static final int INDEX_NOT_FOUND = -1; 170 171 /** 172 * <p>The maximum size to which the padding constant(s) can expand.</p> 173 */ 174 private static final int PAD_LIMIT = 8192; 175 176 /** 177 * <p>{@code StringUtils} instances should NOT be constructed in 178 * standard programming. Instead, the class should be used as 179 * {@code StringUtils.trim(" foo ");}.</p> 180 * 181 * <p>This constructor is public to permit tools that require a JavaBean 182 * instance to operate.</p> 183 */ 184 public StringUtils() { 185 super(); 186 } 187 188 // Empty checks 189 //----------------------------------------------------------------------- 190 /** 191 * <p>Checks if a CharSequence is empty ("") or null.</p> 192 * 193 * <pre> 194 * StringUtils.isEmpty(null) = true 195 * StringUtils.isEmpty("") = true 196 * StringUtils.isEmpty(" ") = false 197 * StringUtils.isEmpty("bob") = false 198 * StringUtils.isEmpty(" bob ") = false 199 * </pre> 200 * 201 * <p>NOTE: This method changed in Lang version 2.0. 202 * It no longer trims the CharSequence. 203 * That functionality is available in isBlank().</p> 204 * 205 * @param cs the CharSequence to check, may be null 206 * @return {@code true} if the CharSequence is empty or null 207 * @since 3.0 Changed signature from isEmpty(String) to isEmpty(CharSequence) 208 */ 209 public static boolean isEmpty(final CharSequence cs) { 210 return cs == null || cs.length() == 0; 211 } 212 213 /** 214 * <p>Checks if a CharSequence is not empty ("") and not null.</p> 215 * 216 * <pre> 217 * StringUtils.isNotEmpty(null) = false 218 * StringUtils.isNotEmpty("") = false 219 * StringUtils.isNotEmpty(" ") = true 220 * StringUtils.isNotEmpty("bob") = true 221 * StringUtils.isNotEmpty(" bob ") = true 222 * </pre> 223 * 224 * @param cs the CharSequence to check, may be null 225 * @return {@code true} if the CharSequence is not empty and not null 226 * @since 3.0 Changed signature from isNotEmpty(String) to isNotEmpty(CharSequence) 227 */ 228 public static boolean isNotEmpty(final CharSequence cs) { 229 return !isEmpty(cs); 230 } 231 232 /** 233 * <p>Checks if any of the CharSequences are empty ("") or null.</p> 234 * 235 * <pre> 236 * StringUtils.isAnyEmpty(null) = true 237 * StringUtils.isAnyEmpty(null, "foo") = true 238 * StringUtils.isAnyEmpty("", "bar") = true 239 * StringUtils.isAnyEmpty("bob", "") = true 240 * StringUtils.isAnyEmpty(" bob ", null) = true 241 * StringUtils.isAnyEmpty(" ", "bar") = false 242 * StringUtils.isAnyEmpty("foo", "bar") = false 243 * StringUtils.isAnyEmpty(new String[]{}) = false 244 * StringUtils.isAnyEmpty(new String[]{""}) = true 245 * </pre> 246 * 247 * @param css the CharSequences to check, may be null or empty 248 * @return {@code true} if any of the CharSequences are empty or null 249 * @since 3.2 250 */ 251 public static boolean isAnyEmpty(final CharSequence... css) { 252 if (ArrayUtils.isEmpty(css)) { 253 return false; 254 } 255 for (final CharSequence cs : css){ 256 if (isEmpty(cs)) { 257 return true; 258 } 259 } 260 return false; 261 } 262 263 /** 264 * <p>Checks if none of the CharSequences are empty ("") or null.</p> 265 * 266 * <pre> 267 * StringUtils.isNoneEmpty(null) = false 268 * StringUtils.isNoneEmpty(null, "foo") = false 269 * StringUtils.isNoneEmpty("", "bar") = false 270 * StringUtils.isNoneEmpty("bob", "") = false 271 * StringUtils.isNoneEmpty(" bob ", null) = false 272 * StringUtils.isNoneEmpty(new String[] {}) = true 273 * StringUtils.isNoneEmpty(new String[]{""}) = false 274 * StringUtils.isNoneEmpty(" ", "bar") = true 275 * StringUtils.isNoneEmpty("foo", "bar") = true 276 * </pre> 277 * 278 * @param css the CharSequences to check, may be null or empty 279 * @return {@code true} if none of the CharSequences are empty or null 280 * @since 3.2 281 */ 282 public static boolean isNoneEmpty(final CharSequence... css) { 283 return !isAnyEmpty(css); 284 } 285 286 /** 287 * <p>Checks if all of the CharSequences are empty ("") or null.</p> 288 * 289 * <pre> 290 * StringUtils.isAllEmpty(null) = true 291 * StringUtils.isAllEmpty(null, "") = true 292 * StringUtils.isAllEmpty(new String[] {}) = true 293 * StringUtils.isAllEmpty(null, "foo") = false 294 * StringUtils.isAllEmpty("", "bar") = false 295 * StringUtils.isAllEmpty("bob", "") = false 296 * StringUtils.isAllEmpty(" bob ", null) = false 297 * StringUtils.isAllEmpty(" ", "bar") = false 298 * StringUtils.isAllEmpty("foo", "bar") = false 299 * </pre> 300 * 301 * @param css the CharSequences to check, may be null or empty 302 * @return {@code true} if all of the CharSequences are empty or null 303 * @since 3.6 304 */ 305 public static boolean isAllEmpty(final CharSequence... css) { 306 if (ArrayUtils.isEmpty(css)) { 307 return true; 308 } 309 for (final CharSequence cs : css) { 310 if (isNotEmpty(cs)) { 311 return false; 312 } 313 } 314 return true; 315 } 316 317 /** 318 * <p>Checks if a CharSequence is empty (""), null or whitespace only.</p> 319 * 320 * <p>Whitespace is defined by {@link Character#isWhitespace(char)}.</p> 321 * 322 * <pre> 323 * StringUtils.isBlank(null) = true 324 * StringUtils.isBlank("") = true 325 * StringUtils.isBlank(" ") = true 326 * StringUtils.isBlank("bob") = false 327 * StringUtils.isBlank(" bob ") = false 328 * </pre> 329 * 330 * @param cs the CharSequence to check, may be null 331 * @return {@code true} if the CharSequence is null, empty or whitespace only 332 * @since 2.0 333 * @since 3.0 Changed signature from isBlank(String) to isBlank(CharSequence) 334 */ 335 public static boolean isBlank(final CharSequence cs) { 336 int strLen; 337 if (cs == null || (strLen = cs.length()) == 0) { 338 return true; 339 } 340 for (int i = 0; i < strLen; i++) { 341 if (Character.isWhitespace(cs.charAt(i)) == false) { 342 return false; 343 } 344 } 345 return true; 346 } 347 348 /** 349 * <p>Checks if a CharSequence is not empty (""), not null and not whitespace only.</p> 350 * 351 * <p>Whitespace is defined by {@link Character#isWhitespace(char)}.</p> 352 * 353 * <pre> 354 * StringUtils.isNotBlank(null) = false 355 * StringUtils.isNotBlank("") = false 356 * StringUtils.isNotBlank(" ") = false 357 * StringUtils.isNotBlank("bob") = true 358 * StringUtils.isNotBlank(" bob ") = true 359 * </pre> 360 * 361 * @param cs the CharSequence to check, may be null 362 * @return {@code true} if the CharSequence is 363 * not empty and not null and not whitespace only 364 * @since 2.0 365 * @since 3.0 Changed signature from isNotBlank(String) to isNotBlank(CharSequence) 366 */ 367 public static boolean isNotBlank(final CharSequence cs) { 368 return !isBlank(cs); 369 } 370 371 /** 372 * <p>Checks if any of the CharSequences are empty ("") or null or whitespace only.</p> 373 * 374 * <p>Whitespace is defined by {@link Character#isWhitespace(char)}.</p> 375 * 376 * <pre> 377 * StringUtils.isAnyBlank(null) = true 378 * StringUtils.isAnyBlank(null, "foo") = true 379 * StringUtils.isAnyBlank(null, null) = true 380 * StringUtils.isAnyBlank("", "bar") = true 381 * StringUtils.isAnyBlank("bob", "") = true 382 * StringUtils.isAnyBlank(" bob ", null) = true 383 * StringUtils.isAnyBlank(" ", "bar") = true 384 * StringUtils.isAnyBlank(new String[] {}) = false 385 * StringUtils.isAnyBlank(new String[]{""}) = true 386 * StringUtils.isAnyBlank("foo", "bar") = false 387 * </pre> 388 * 389 * @param css the CharSequences to check, may be null or empty 390 * @return {@code true} if any of the CharSequences are empty or null or whitespace only 391 * @since 3.2 392 */ 393 public static boolean isAnyBlank(final CharSequence... css) { 394 if (ArrayUtils.isEmpty(css)) { 395 return false; 396 } 397 for (final CharSequence cs : css){ 398 if (isBlank(cs)) { 399 return true; 400 } 401 } 402 return false; 403 } 404 405 /** 406 * <p>Checks if none of the CharSequences are empty (""), null or whitespace only.</p> 407 * 408 * <p>Whitespace is defined by {@link Character#isWhitespace(char)}.</p> 409 * 410 * <pre> 411 * StringUtils.isNoneBlank(null) = false 412 * StringUtils.isNoneBlank(null, "foo") = false 413 * StringUtils.isNoneBlank(null, null) = false 414 * StringUtils.isNoneBlank("", "bar") = false 415 * StringUtils.isNoneBlank("bob", "") = false 416 * StringUtils.isNoneBlank(" bob ", null) = false 417 * StringUtils.isNoneBlank(" ", "bar") = false 418 * StringUtils.isNoneBlank(new String[] {}) = true 419 * StringUtils.isNoneBlank(new String[]{""}) = false 420 * StringUtils.isNoneBlank("foo", "bar") = true 421 * </pre> 422 * 423 * @param css the CharSequences to check, may be null or empty 424 * @return {@code true} if none of the CharSequences are empty or null or whitespace only 425 * @since 3.2 426 */ 427 public static boolean isNoneBlank(final CharSequence... css) { 428 return !isAnyBlank(css); 429 } 430 431 /** 432 * <p>Checks if all of the CharSequences are empty (""), null or whitespace only.</p> 433 * 434 * <p>Whitespace is defined by {@link Character#isWhitespace(char)}.</p> 435 * 436 * <pre> 437 * StringUtils.isAllBlank(null) = true 438 * StringUtils.isAllBlank(null, "foo") = false 439 * StringUtils.isAllBlank(null, null) = true 440 * StringUtils.isAllBlank("", "bar") = false 441 * StringUtils.isAllBlank("bob", "") = false 442 * StringUtils.isAllBlank(" bob ", null) = false 443 * StringUtils.isAllBlank(" ", "bar") = false 444 * StringUtils.isAllBlank("foo", "bar") = false 445 * StringUtils.isAllBlank(new String[] {}) = true 446 * </pre> 447 * 448 * @param css the CharSequences to check, may be null or empty 449 * @return {@code true} if all of the CharSequences are empty or null or whitespace only 450 * @since 3.6 451 */ 452 public static boolean isAllBlank(final CharSequence... css) { 453 if (ArrayUtils.isEmpty(css)) { 454 return true; 455 } 456 for (final CharSequence cs : css) { 457 if (isNotBlank(cs)) { 458 return false; 459 } 460 } 461 return true; 462 } 463 464 // Trim 465 //----------------------------------------------------------------------- 466 /** 467 * <p>Removes control characters (char <= 32) from both 468 * ends of this String, handling {@code null} by returning 469 * {@code null}.</p> 470 * 471 * <p>The String is trimmed using {@link String#trim()}. 472 * Trim removes start and end characters <= 32. 473 * To strip whitespace use {@link #strip(String)}.</p> 474 * 475 * <p>To trim your choice of characters, use the 476 * {@link #strip(String, String)} methods.</p> 477 * 478 * <pre> 479 * StringUtils.trim(null) = null 480 * StringUtils.trim("") = "" 481 * StringUtils.trim(" ") = "" 482 * StringUtils.trim("abc") = "abc" 483 * StringUtils.trim(" abc ") = "abc" 484 * </pre> 485 * 486 * @param str the String to be trimmed, may be null 487 * @return the trimmed string, {@code null} if null String input 488 */ 489 public static String trim(final String str) { 490 return str == null ? null : str.trim(); 491 } 492 493 /** 494 * <p>Removes control characters (char <= 32) from both 495 * ends of this String returning {@code null} if the String is 496 * empty ("") after the trim or if it is {@code null}. 497 * 498 * <p>The String is trimmed using {@link String#trim()}. 499 * Trim removes start and end characters <= 32. 500 * To strip whitespace use {@link #stripToNull(String)}.</p> 501 * 502 * <pre> 503 * StringUtils.trimToNull(null) = null 504 * StringUtils.trimToNull("") = null 505 * StringUtils.trimToNull(" ") = null 506 * StringUtils.trimToNull("abc") = "abc" 507 * StringUtils.trimToNull(" abc ") = "abc" 508 * </pre> 509 * 510 * @param str the String to be trimmed, may be null 511 * @return the trimmed String, 512 * {@code null} if only chars <= 32, empty or null String input 513 * @since 2.0 514 */ 515 public static String trimToNull(final String str) { 516 final String ts = trim(str); 517 return isEmpty(ts) ? null : ts; 518 } 519 520 /** 521 * <p>Removes control characters (char <= 32) from both 522 * ends of this String returning an empty String ("") if the String 523 * is empty ("") after the trim or if it is {@code null}. 524 * 525 * <p>The String is trimmed using {@link String#trim()}. 526 * Trim removes start and end characters <= 32. 527 * To strip whitespace use {@link #stripToEmpty(String)}.</p> 528 * 529 * <pre> 530 * StringUtils.trimToEmpty(null) = "" 531 * StringUtils.trimToEmpty("") = "" 532 * StringUtils.trimToEmpty(" ") = "" 533 * StringUtils.trimToEmpty("abc") = "abc" 534 * StringUtils.trimToEmpty(" abc ") = "abc" 535 * </pre> 536 * 537 * @param str the String to be trimmed, may be null 538 * @return the trimmed String, or an empty String if {@code null} input 539 * @since 2.0 540 */ 541 public static String trimToEmpty(final String str) { 542 return str == null ? EMPTY : str.trim(); 543 } 544 545 /** 546 * <p>Truncates a String. This will turn 547 * "Now is the time for all good men" into "Now is the time for".</p> 548 * 549 * <p>Specifically:</p> 550 * <ul> 551 * <li>If {@code str} is less than {@code maxWidth} characters 552 * long, return it.</li> 553 * <li>Else truncate it to {@code substring(str, 0, maxWidth)}.</li> 554 * <li>If {@code maxWidth} is less than {@code 0}, throw an 555 * {@code IllegalArgumentException}.</li> 556 * <li>In no case will it return a String of length greater than 557 * {@code maxWidth}.</li> 558 * </ul> 559 * 560 * <pre> 561 * StringUtils.truncate(null, 0) = null 562 * StringUtils.truncate(null, 2) = null 563 * StringUtils.truncate("", 4) = "" 564 * StringUtils.truncate("abcdefg", 4) = "abcd" 565 * StringUtils.truncate("abcdefg", 6) = "abcdef" 566 * StringUtils.truncate("abcdefg", 7) = "abcdefg" 567 * StringUtils.truncate("abcdefg", 8) = "abcdefg" 568 * StringUtils.truncate("abcdefg", -1) = throws an IllegalArgumentException 569 * </pre> 570 * 571 * @param str the String to truncate, may be null 572 * @param maxWidth maximum length of result String, must be positive 573 * @return truncated String, {@code null} if null String input 574 * @since 3.5 575 */ 576 public static String truncate(final String str, final int maxWidth) { 577 return truncate(str, 0, maxWidth); 578 } 579 580 /** 581 * <p>Truncates a String. This will turn 582 * "Now is the time for all good men" into "is the time for all".</p> 583 * 584 * <p>Works like {@code truncate(String, int)}, but allows you to specify 585 * a "left edge" offset. 586 * 587 * <p>Specifically:</p> 588 * <ul> 589 * <li>If {@code str} is less than {@code maxWidth} characters 590 * long, return it.</li> 591 * <li>Else truncate it to {@code substring(str, offset, maxWidth)}.</li> 592 * <li>If {@code maxWidth} is less than {@code 0}, throw an 593 * {@code IllegalArgumentException}.</li> 594 * <li>If {@code offset} is less than {@code 0}, throw an 595 * {@code IllegalArgumentException}.</li> 596 * <li>In no case will it return a String of length greater than 597 * {@code maxWidth}.</li> 598 * </ul> 599 * 600 * <pre> 601 * StringUtils.truncate(null, 0, 0) = null 602 * StringUtils.truncate(null, 2, 4) = null 603 * StringUtils.truncate("", 0, 10) = "" 604 * StringUtils.truncate("", 2, 10) = "" 605 * StringUtils.truncate("abcdefghij", 0, 3) = "abc" 606 * StringUtils.truncate("abcdefghij", 5, 6) = "fghij" 607 * StringUtils.truncate("raspberry peach", 10, 15) = "peach" 608 * StringUtils.truncate("abcdefghijklmno", 0, 10) = "abcdefghij" 609 * StringUtils.truncate("abcdefghijklmno", -1, 10) = throws an IllegalArgumentException 610 * StringUtils.truncate("abcdefghijklmno", Integer.MIN_VALUE, 10) = "abcdefghij" 611 * StringUtils.truncate("abcdefghijklmno", Integer.MIN_VALUE, Integer.MAX_VALUE) = "abcdefghijklmno" 612 * StringUtils.truncate("abcdefghijklmno", 0, Integer.MAX_VALUE) = "abcdefghijklmno" 613 * StringUtils.truncate("abcdefghijklmno", 1, 10) = "bcdefghijk" 614 * StringUtils.truncate("abcdefghijklmno", 2, 10) = "cdefghijkl" 615 * StringUtils.truncate("abcdefghijklmno", 3, 10) = "defghijklm" 616 * StringUtils.truncate("abcdefghijklmno", 4, 10) = "efghijklmn" 617 * StringUtils.truncate("abcdefghijklmno", 5, 10) = "fghijklmno" 618 * StringUtils.truncate("abcdefghijklmno", 5, 5) = "fghij" 619 * StringUtils.truncate("abcdefghijklmno", 5, 3) = "fgh" 620 * StringUtils.truncate("abcdefghijklmno", 10, 3) = "klm" 621 * StringUtils.truncate("abcdefghijklmno", 10, Integer.MAX_VALUE) = "klmno" 622 * StringUtils.truncate("abcdefghijklmno", 13, 1) = "n" 623 * StringUtils.truncate("abcdefghijklmno", 13, Integer.MAX_VALUE) = "no" 624 * StringUtils.truncate("abcdefghijklmno", 14, 1) = "o" 625 * StringUtils.truncate("abcdefghijklmno", 14, Integer.MAX_VALUE) = "o" 626 * StringUtils.truncate("abcdefghijklmno", 15, 1) = "" 627 * StringUtils.truncate("abcdefghijklmno", 15, Integer.MAX_VALUE) = "" 628 * StringUtils.truncate("abcdefghijklmno", Integer.MAX_VALUE, Integer.MAX_VALUE) = "" 629 * StringUtils.truncate("abcdefghij", 3, -1) = throws an IllegalArgumentException 630 * StringUtils.truncate("abcdefghij", -2, 4) = throws an IllegalArgumentException 631 * </pre> 632 * 633 * @param str the String to check, may be null 634 * @param offset left edge of source String 635 * @param maxWidth maximum length of result String, must be positive 636 * @return truncated String, {@code null} if null String input 637 * @since 3.5 638 */ 639 public static String truncate(final String str, final int offset, final int maxWidth) { 640 if (offset < 0) { 641 throw new IllegalArgumentException("offset cannot be negative"); 642 } 643 if (maxWidth < 0) { 644 throw new IllegalArgumentException("maxWith cannot be negative"); 645 } 646 if (str == null) { 647 return null; 648 } 649 if (offset > str.length()) { 650 return EMPTY; 651 } 652 if (str.length() > maxWidth) { 653 final int ix = offset + maxWidth > str.length() ? str.length() : offset + maxWidth; 654 return str.substring(offset, ix); 655 } 656 return str.substring(offset); 657 } 658 659 // Stripping 660 //----------------------------------------------------------------------- 661 /** 662 * <p>Strips whitespace from the start and end of a String.</p> 663 * 664 * <p>This is similar to {@link #trim(String)} but removes whitespace. 665 * Whitespace is defined by {@link Character#isWhitespace(char)}.</p> 666 * 667 * <p>A {@code null} input String returns {@code null}.</p> 668 * 669 * <pre> 670 * StringUtils.strip(null) = null 671 * StringUtils.strip("") = "" 672 * StringUtils.strip(" ") = "" 673 * StringUtils.strip("abc") = "abc" 674 * StringUtils.strip(" abc") = "abc" 675 * StringUtils.strip("abc ") = "abc" 676 * StringUtils.strip(" abc ") = "abc" 677 * StringUtils.strip(" ab c ") = "ab c" 678 * </pre> 679 * 680 * @param str the String to remove whitespace from, may be null 681 * @return the stripped String, {@code null} if null String input 682 */ 683 public static String strip(final String str) { 684 return strip(str, null); 685 } 686 687 /** 688 * <p>Strips whitespace from the start and end of a String returning 689 * {@code null} if the String is empty ("") after the strip.</p> 690 * 691 * <p>This is similar to {@link #trimToNull(String)} but removes whitespace. 692 * Whitespace is defined by {@link Character#isWhitespace(char)}.</p> 693 * 694 * <pre> 695 * StringUtils.stripToNull(null) = null 696 * StringUtils.stripToNull("") = null 697 * StringUtils.stripToNull(" ") = null 698 * StringUtils.stripToNull("abc") = "abc" 699 * StringUtils.stripToNull(" abc") = "abc" 700 * StringUtils.stripToNull("abc ") = "abc" 701 * StringUtils.stripToNull(" abc ") = "abc" 702 * StringUtils.stripToNull(" ab c ") = "ab c" 703 * </pre> 704 * 705 * @param str the String to be stripped, may be null 706 * @return the stripped String, 707 * {@code null} if whitespace, empty or null String input 708 * @since 2.0 709 */ 710 public static String stripToNull(String str) { 711 if (str == null) { 712 return null; 713 } 714 str = strip(str, null); 715 return str.isEmpty() ? null : str; 716 } 717 718 /** 719 * <p>Strips whitespace from the start and end of a String returning 720 * an empty String if {@code null} input.</p> 721 * 722 * <p>This is similar to {@link #trimToEmpty(String)} but removes whitespace. 723 * Whitespace is defined by {@link Character#isWhitespace(char)}.</p> 724 * 725 * <pre> 726 * StringUtils.stripToEmpty(null) = "" 727 * StringUtils.stripToEmpty("") = "" 728 * StringUtils.stripToEmpty(" ") = "" 729 * StringUtils.stripToEmpty("abc") = "abc" 730 * StringUtils.stripToEmpty(" abc") = "abc" 731 * StringUtils.stripToEmpty("abc ") = "abc" 732 * StringUtils.stripToEmpty(" abc ") = "abc" 733 * StringUtils.stripToEmpty(" ab c ") = "ab c" 734 * </pre> 735 * 736 * @param str the String to be stripped, may be null 737 * @return the trimmed String, or an empty String if {@code null} input 738 * @since 2.0 739 */ 740 public static String stripToEmpty(final String str) { 741 return str == null ? EMPTY : strip(str, null); 742 } 743 744 /** 745 * <p>Strips any of a set of characters from the start and end of a String. 746 * This is similar to {@link String#trim()} but allows the characters 747 * to be stripped to be controlled.</p> 748 * 749 * <p>A {@code null} input String returns {@code null}. 750 * An empty string ("") input returns the empty string.</p> 751 * 752 * <p>If the stripChars String is {@code null}, whitespace is 753 * stripped as defined by {@link Character#isWhitespace(char)}. 754 * Alternatively use {@link #strip(String)}.</p> 755 * 756 * <pre> 757 * StringUtils.strip(null, *) = null 758 * StringUtils.strip("", *) = "" 759 * StringUtils.strip("abc", null) = "abc" 760 * StringUtils.strip(" abc", null) = "abc" 761 * StringUtils.strip("abc ", null) = "abc" 762 * StringUtils.strip(" abc ", null) = "abc" 763 * StringUtils.strip(" abcyx", "xyz") = " abc" 764 * </pre> 765 * 766 * @param str the String to remove characters from, may be null 767 * @param stripChars the characters to remove, null treated as whitespace 768 * @return the stripped String, {@code null} if null String input 769 */ 770 public static String strip(String str, final String stripChars) { 771 if (isEmpty(str)) { 772 return str; 773 } 774 str = stripStart(str, stripChars); 775 return stripEnd(str, stripChars); 776 } 777 778 /** 779 * <p>Strips any of a set of characters from the start of a String.</p> 780 * 781 * <p>A {@code null} input String returns {@code null}. 782 * An empty string ("") input returns the empty string.</p> 783 * 784 * <p>If the stripChars String is {@code null}, whitespace is 785 * stripped as defined by {@link Character#isWhitespace(char)}.</p> 786 * 787 * <pre> 788 * StringUtils.stripStart(null, *) = null 789 * StringUtils.stripStart("", *) = "" 790 * StringUtils.stripStart("abc", "") = "abc" 791 * StringUtils.stripStart("abc", null) = "abc" 792 * StringUtils.stripStart(" abc", null) = "abc" 793 * StringUtils.stripStart("abc ", null) = "abc " 794 * StringUtils.stripStart(" abc ", null) = "abc " 795 * StringUtils.stripStart("yxabc ", "xyz") = "abc " 796 * </pre> 797 * 798 * @param str the String to remove characters from, may be null 799 * @param stripChars the characters to remove, null treated as whitespace 800 * @return the stripped String, {@code null} if null String input 801 */ 802 public static String stripStart(final String str, final String stripChars) { 803 int strLen; 804 if (str == null || (strLen = str.length()) == 0) { 805 return str; 806 } 807 int start = 0; 808 if (stripChars == null) { 809 while (start != strLen && Character.isWhitespace(str.charAt(start))) { 810 start++; 811 } 812 } else if (stripChars.isEmpty()) { 813 return str; 814 } else { 815 while (start != strLen && stripChars.indexOf(str.charAt(start)) != INDEX_NOT_FOUND) { 816 start++; 817 } 818 } 819 return str.substring(start); 820 } 821 822 /** 823 * <p>Strips any of a set of characters from the end of a String.</p> 824 * 825 * <p>A {@code null} input String returns {@code null}. 826 * An empty string ("") input returns the empty string.</p> 827 * 828 * <p>If the stripChars String is {@code null}, whitespace is 829 * stripped as defined by {@link Character#isWhitespace(char)}.</p> 830 * 831 * <pre> 832 * StringUtils.stripEnd(null, *) = null 833 * StringUtils.stripEnd("", *) = "" 834 * StringUtils.stripEnd("abc", "") = "abc" 835 * StringUtils.stripEnd("abc", null) = "abc" 836 * StringUtils.stripEnd(" abc", null) = " abc" 837 * StringUtils.stripEnd("abc ", null) = "abc" 838 * StringUtils.stripEnd(" abc ", null) = " abc" 839 * StringUtils.stripEnd(" abcyx", "xyz") = " abc" 840 * StringUtils.stripEnd("120.00", ".0") = "12" 841 * </pre> 842 * 843 * @param str the String to remove characters from, may be null 844 * @param stripChars the set of characters to remove, null treated as whitespace 845 * @return the stripped String, {@code null} if null String input 846 */ 847 public static String stripEnd(final String str, final String stripChars) { 848 int end; 849 if (str == null || (end = str.length()) == 0) { 850 return str; 851 } 852 853 if (stripChars == null) { 854 while (end != 0 && Character.isWhitespace(str.charAt(end - 1))) { 855 end--; 856 } 857 } else if (stripChars.isEmpty()) { 858 return str; 859 } else { 860 while (end != 0 && stripChars.indexOf(str.charAt(end - 1)) != INDEX_NOT_FOUND) { 861 end--; 862 } 863 } 864 return str.substring(0, end); 865 } 866 867 // StripAll 868 //----------------------------------------------------------------------- 869 /** 870 * <p>Strips whitespace from the start and end of every String in an array. 871 * Whitespace is defined by {@link Character#isWhitespace(char)}.</p> 872 * 873 * <p>A new array is returned each time, except for length zero. 874 * A {@code null} array will return {@code null}. 875 * An empty array will return itself. 876 * A {@code null} array entry will be ignored.</p> 877 * 878 * <pre> 879 * StringUtils.stripAll(null) = null 880 * StringUtils.stripAll([]) = [] 881 * StringUtils.stripAll(["abc", " abc"]) = ["abc", "abc"] 882 * StringUtils.stripAll(["abc ", null]) = ["abc", null] 883 * </pre> 884 * 885 * @param strs the array to remove whitespace from, may be null 886 * @return the stripped Strings, {@code null} if null array input 887 */ 888 public static String[] stripAll(final String... strs) { 889 return stripAll(strs, null); 890 } 891 892 /** 893 * <p>Strips any of a set of characters from the start and end of every 894 * String in an array.</p> 895 * <p>Whitespace is defined by {@link Character#isWhitespace(char)}.</p> 896 * 897 * <p>A new array is returned each time, except for length zero. 898 * A {@code null} array will return {@code null}. 899 * An empty array will return itself. 900 * A {@code null} array entry will be ignored. 901 * A {@code null} stripChars will strip whitespace as defined by 902 * {@link Character#isWhitespace(char)}.</p> 903 * 904 * <pre> 905 * StringUtils.stripAll(null, *) = null 906 * StringUtils.stripAll([], *) = [] 907 * StringUtils.stripAll(["abc", " abc"], null) = ["abc", "abc"] 908 * StringUtils.stripAll(["abc ", null], null) = ["abc", null] 909 * StringUtils.stripAll(["abc ", null], "yz") = ["abc ", null] 910 * StringUtils.stripAll(["yabcz", null], "yz") = ["abc", null] 911 * </pre> 912 * 913 * @param strs the array to remove characters from, may be null 914 * @param stripChars the characters to remove, null treated as whitespace 915 * @return the stripped Strings, {@code null} if null array input 916 */ 917 public static String[] stripAll(final String[] strs, final String stripChars) { 918 int strsLen; 919 if (strs == null || (strsLen = strs.length) == 0) { 920 return strs; 921 } 922 final String[] newArr = new String[strsLen]; 923 for (int i = 0; i < strsLen; i++) { 924 newArr[i] = strip(strs[i], stripChars); 925 } 926 return newArr; 927 } 928 929 /** 930 * <p>Removes diacritics (~= accents) from a string. The case will not be altered.</p> 931 * <p>For instance, 'à' will be replaced by 'a'.</p> 932 * <p>Note that ligatures will be left as is.</p> 933 * 934 * <pre> 935 * StringUtils.stripAccents(null) = null 936 * StringUtils.stripAccents("") = "" 937 * StringUtils.stripAccents("control") = "control" 938 * StringUtils.stripAccents("éclair") = "eclair" 939 * </pre> 940 * 941 * @param input String to be stripped 942 * @return input text with diacritics removed 943 * 944 * @since 3.0 945 */ 946 // See also Lucene's ASCIIFoldingFilter (Lucene 2.9) that replaces accented characters by their unaccented equivalent (and uncommitted bug fix: https://issues.apache.org/jira/browse/LUCENE-1343?focusedCommentId=12858907&page=com.atlassian.jira.plugin.system.issuetabpanels%3Acomment-tabpanel#action_12858907). 947 public static String stripAccents(final String input) { 948 if(input == null) { 949 return null; 950 } 951 final Pattern pattern = Pattern.compile("\\p{InCombiningDiacriticalMarks}+");//$NON-NLS-1$ 952 final StringBuilder decomposed = new StringBuilder(Normalizer.normalize(input, Normalizer.Form.NFD)); 953 convertRemainingAccentCharacters(decomposed); 954 // Note that this doesn't correctly remove ligatures... 955 return pattern.matcher(decomposed).replaceAll(StringUtils.EMPTY); 956 } 957 958 private static void convertRemainingAccentCharacters(final StringBuilder decomposed) { 959 for (int i = 0; i < decomposed.length(); i++) { 960 if (decomposed.charAt(i) == '\u0141') { 961 decomposed.deleteCharAt(i); 962 decomposed.insert(i, 'L'); 963 } else if (decomposed.charAt(i) == '\u0142') { 964 decomposed.deleteCharAt(i); 965 decomposed.insert(i, 'l'); 966 } 967 } 968 } 969 970 // Equals 971 //----------------------------------------------------------------------- 972 /** 973 * <p>Compares two CharSequences, returning {@code true} if they represent 974 * equal sequences of characters.</p> 975 * 976 * <p>{@code null}s are handled without exceptions. Two {@code null} 977 * references are considered to be equal. The comparison is case sensitive.</p> 978 * 979 * <pre> 980 * StringUtils.equals(null, null) = true 981 * StringUtils.equals(null, "abc") = false 982 * StringUtils.equals("abc", null) = false 983 * StringUtils.equals("abc", "abc") = true 984 * StringUtils.equals("abc", "ABC") = false 985 * </pre> 986 * 987 * @see Object#equals(Object) 988 * @param cs1 the first CharSequence, may be {@code null} 989 * @param cs2 the second CharSequence, may be {@code null} 990 * @return {@code true} if the CharSequences are equal (case-sensitive), or both {@code null} 991 * @since 3.0 Changed signature from equals(String, String) to equals(CharSequence, CharSequence) 992 */ 993 public static boolean equals(final CharSequence cs1, final CharSequence cs2) { 994 if (cs1 == cs2) { 995 return true; 996 } 997 if (cs1 == null || cs2 == null) { 998 return false; 999 } 1000 if (cs1.length() != cs2.length()) { 1001 return false; 1002 } 1003 if (cs1 instanceof String && cs2 instanceof String) { 1004 return cs1.equals(cs2); 1005 } 1006 return CharSequenceUtils.regionMatches(cs1, false, 0, cs2, 0, cs1.length()); 1007 } 1008 1009 /** 1010 * <p>Compares two CharSequences, returning {@code true} if they represent 1011 * equal sequences of characters, ignoring case.</p> 1012 * 1013 * <p>{@code null}s are handled without exceptions. Two {@code null} 1014 * references are considered equal. Comparison is case insensitive.</p> 1015 * 1016 * <pre> 1017 * StringUtils.equalsIgnoreCase(null, null) = true 1018 * StringUtils.equalsIgnoreCase(null, "abc") = false 1019 * StringUtils.equalsIgnoreCase("abc", null) = false 1020 * StringUtils.equalsIgnoreCase("abc", "abc") = true 1021 * StringUtils.equalsIgnoreCase("abc", "ABC") = true 1022 * </pre> 1023 * 1024 * @param str1 the first CharSequence, may be null 1025 * @param str2 the second CharSequence, may be null 1026 * @return {@code true} if the CharSequence are equal, case insensitive, or 1027 * both {@code null} 1028 * @since 3.0 Changed signature from equalsIgnoreCase(String, String) to equalsIgnoreCase(CharSequence, CharSequence) 1029 */ 1030 public static boolean equalsIgnoreCase(final CharSequence str1, final CharSequence str2) { 1031 if (str1 == null || str2 == null) { 1032 return str1 == str2; 1033 } else if (str1 == str2) { 1034 return true; 1035 } else if (str1.length() != str2.length()) { 1036 return false; 1037 } else { 1038 return CharSequenceUtils.regionMatches(str1, true, 0, str2, 0, str1.length()); 1039 } 1040 } 1041 1042 // Compare 1043 //----------------------------------------------------------------------- 1044 /** 1045 * <p>Compare two Strings lexicographically, as per {@link String#compareTo(String)}, returning :</p> 1046 * <ul> 1047 * <li>{@code int = 0}, if {@code str1} is equal to {@code str2} (or both {@code null})</li> 1048 * <li>{@code int < 0}, if {@code str1} is less than {@code str2}</li> 1049 * <li>{@code int > 0}, if {@code str1} is greater than {@code str2}</li> 1050 * </ul> 1051 * 1052 * <p>This is a {@code null} safe version of :</p> 1053 * <blockquote><pre>str1.compareTo(str2)</pre></blockquote> 1054 * 1055 * <p>{@code null} value is considered less than non-{@code null} value. 1056 * Two {@code null} references are considered equal.</p> 1057 * 1058 * <pre> 1059 * StringUtils.compare(null, null) = 0 1060 * StringUtils.compare(null , "a") < 0 1061 * StringUtils.compare("a", null) > 0 1062 * StringUtils.compare("abc", "abc") = 0 1063 * StringUtils.compare("a", "b") < 0 1064 * StringUtils.compare("b", "a") > 0 1065 * StringUtils.compare("a", "B") > 0 1066 * StringUtils.compare("ab", "abc") < 0 1067 * </pre> 1068 * 1069 * @see #compare(String, String, boolean) 1070 * @see String#compareTo(String) 1071 * @param str1 the String to compare from 1072 * @param str2 the String to compare to 1073 * @return < 0, 0, > 0, if {@code str1} is respectively less, equal or greater than {@code str2} 1074 * @since 3.5 1075 */ 1076 public static int compare(final String str1, final String str2) { 1077 return compare(str1, str2, true); 1078 } 1079 1080 /** 1081 * <p>Compare two Strings lexicographically, as per {@link String#compareTo(String)}, returning :</p> 1082 * <ul> 1083 * <li>{@code int = 0}, if {@code str1} is equal to {@code str2} (or both {@code null})</li> 1084 * <li>{@code int < 0}, if {@code str1} is less than {@code str2}</li> 1085 * <li>{@code int > 0}, if {@code str1} is greater than {@code str2}</li> 1086 * </ul> 1087 * 1088 * <p>This is a {@code null} safe version of :</p> 1089 * <blockquote><pre>str1.compareTo(str2)</pre></blockquote> 1090 * 1091 * <p>{@code null} inputs are handled according to the {@code nullIsLess} parameter. 1092 * Two {@code null} references are considered equal.</p> 1093 * 1094 * <pre> 1095 * StringUtils.compare(null, null, *) = 0 1096 * StringUtils.compare(null , "a", true) < 0 1097 * StringUtils.compare(null , "a", false) > 0 1098 * StringUtils.compare("a", null, true) > 0 1099 * StringUtils.compare("a", null, false) < 0 1100 * StringUtils.compare("abc", "abc", *) = 0 1101 * StringUtils.compare("a", "b", *) < 0 1102 * StringUtils.compare("b", "a", *) > 0 1103 * StringUtils.compare("a", "B", *) > 0 1104 * StringUtils.compare("ab", "abc", *) < 0 1105 * </pre> 1106 * 1107 * @see String#compareTo(String) 1108 * @param str1 the String to compare from 1109 * @param str2 the String to compare to 1110 * @param nullIsLess whether consider {@code null} value less than non-{@code null} value 1111 * @return < 0, 0, > 0, if {@code str1} is respectively less, equal ou greater than {@code str2} 1112 * @since 3.5 1113 */ 1114 public static int compare(final String str1, final String str2, final boolean nullIsLess) { 1115 if (str1 == str2) { 1116 return 0; 1117 } 1118 if (str1 == null) { 1119 return nullIsLess ? -1 : 1; 1120 } 1121 if (str2 == null) { 1122 return nullIsLess ? 1 : - 1; 1123 } 1124 return str1.compareTo(str2); 1125 } 1126 1127 /** 1128 * <p>Compare two Strings lexicographically, ignoring case differences, 1129 * as per {@link String#compareToIgnoreCase(String)}, returning :</p> 1130 * <ul> 1131 * <li>{@code int = 0}, if {@code str1} is equal to {@code str2} (or both {@code null})</li> 1132 * <li>{@code int < 0}, if {@code str1} is less than {@code str2}</li> 1133 * <li>{@code int > 0}, if {@code str1} is greater than {@code str2}</li> 1134 * </ul> 1135 * 1136 * <p>This is a {@code null} safe version of :</p> 1137 * <blockquote><pre>str1.compareToIgnoreCase(str2)</pre></blockquote> 1138 * 1139 * <p>{@code null} value is considered less than non-{@code null} value. 1140 * Two {@code null} references are considered equal. 1141 * Comparison is case insensitive.</p> 1142 * 1143 * <pre> 1144 * StringUtils.compareIgnoreCase(null, null) = 0 1145 * StringUtils.compareIgnoreCase(null , "a") < 0 1146 * StringUtils.compareIgnoreCase("a", null) > 0 1147 * StringUtils.compareIgnoreCase("abc", "abc") = 0 1148 * StringUtils.compareIgnoreCase("abc", "ABC") = 0 1149 * StringUtils.compareIgnoreCase("a", "b") < 0 1150 * StringUtils.compareIgnoreCase("b", "a") > 0 1151 * StringUtils.compareIgnoreCase("a", "B") < 0 1152 * StringUtils.compareIgnoreCase("A", "b") < 0 1153 * StringUtils.compareIgnoreCase("ab", "ABC") < 0 1154 * </pre> 1155 * 1156 * @see #compareIgnoreCase(String, String, boolean) 1157 * @see String#compareToIgnoreCase(String) 1158 * @param str1 the String to compare from 1159 * @param str2 the String to compare to 1160 * @return < 0, 0, > 0, if {@code str1} is respectively less, equal ou greater than {@code str2}, 1161 * ignoring case differences. 1162 * @since 3.5 1163 */ 1164 public static int compareIgnoreCase(final String str1, final String str2) { 1165 return compareIgnoreCase(str1, str2, true); 1166 } 1167 1168 /** 1169 * <p>Compare two Strings lexicographically, ignoring case differences, 1170 * as per {@link String#compareToIgnoreCase(String)}, returning :</p> 1171 * <ul> 1172 * <li>{@code int = 0}, if {@code str1} is equal to {@code str2} (or both {@code null})</li> 1173 * <li>{@code int < 0}, if {@code str1} is less than {@code str2}</li> 1174 * <li>{@code int > 0}, if {@code str1} is greater than {@code str2}</li> 1175 * </ul> 1176 * 1177 * <p>This is a {@code null} safe version of :</p> 1178 * <blockquote><pre>str1.compareToIgnoreCase(str2)</pre></blockquote> 1179 * 1180 * <p>{@code null} inputs are handled according to the {@code nullIsLess} parameter. 1181 * Two {@code null} references are considered equal. 1182 * Comparison is case insensitive.</p> 1183 * 1184 * <pre> 1185 * StringUtils.compareIgnoreCase(null, null, *) = 0 1186 * StringUtils.compareIgnoreCase(null , "a", true) < 0 1187 * StringUtils.compareIgnoreCase(null , "a", false) > 0 1188 * StringUtils.compareIgnoreCase("a", null, true) > 0 1189 * StringUtils.compareIgnoreCase("a", null, false) < 0 1190 * StringUtils.compareIgnoreCase("abc", "abc", *) = 0 1191 * StringUtils.compareIgnoreCase("abc", "ABC", *) = 0 1192 * StringUtils.compareIgnoreCase("a", "b", *) < 0 1193 * StringUtils.compareIgnoreCase("b", "a", *) > 0 1194 * StringUtils.compareIgnoreCase("a", "B", *) < 0 1195 * StringUtils.compareIgnoreCase("A", "b", *) < 0 1196 * StringUtils.compareIgnoreCase("ab", "abc", *) < 0 1197 * </pre> 1198 * 1199 * @see String#compareToIgnoreCase(String) 1200 * @param str1 the String to compare from 1201 * @param str2 the String to compare to 1202 * @param nullIsLess whether consider {@code null} value less than non-{@code null} value 1203 * @return < 0, 0, > 0, if {@code str1} is respectively less, equal ou greater than {@code str2}, 1204 * ignoring case differences. 1205 * @since 3.5 1206 */ 1207 public static int compareIgnoreCase(final String str1, final String str2, final boolean nullIsLess) { 1208 if (str1 == str2) { 1209 return 0; 1210 } 1211 if (str1 == null) { 1212 return nullIsLess ? -1 : 1; 1213 } 1214 if (str2 == null) { 1215 return nullIsLess ? 1 : - 1; 1216 } 1217 return str1.compareToIgnoreCase(str2); 1218 } 1219 1220 /** 1221 * <p>Compares given <code>string</code> to a CharSequences vararg of <code>searchStrings</code>, 1222 * returning {@code true} if the <code>string</code> is equal to any of the <code>searchStrings</code>.</p> 1223 * 1224 * <pre> 1225 * StringUtils.equalsAny(null, (CharSequence[]) null) = false 1226 * StringUtils.equalsAny(null, null, null) = true 1227 * StringUtils.equalsAny(null, "abc", "def") = false 1228 * StringUtils.equalsAny("abc", null, "def") = false 1229 * StringUtils.equalsAny("abc", "abc", "def") = true 1230 * StringUtils.equalsAny("abc", "ABC", "DEF") = false 1231 * </pre> 1232 * 1233 * @param string to compare, may be {@code null}. 1234 * @param searchStrings a vararg of strings, may be {@code null}. 1235 * @return {@code true} if the string is equal (case-sensitive) to any other element of <code>searchStrings</code>; 1236 * {@code false} if <code>searchStrings</code> is null or contains no matches. 1237 * @since 3.5 1238 */ 1239 public static boolean equalsAny(final CharSequence string, final CharSequence... searchStrings) { 1240 if (ArrayUtils.isNotEmpty(searchStrings)) { 1241 for (final CharSequence next : searchStrings) { 1242 if (equals(string, next)) { 1243 return true; 1244 } 1245 } 1246 } 1247 return false; 1248 } 1249 1250 1251 /** 1252 * <p>Compares given <code>string</code> to a CharSequences vararg of <code>searchStrings</code>, 1253 * returning {@code true} if the <code>string</code> is equal to any of the <code>searchStrings</code>, ignoring case.</p> 1254 * 1255 * <pre> 1256 * StringUtils.equalsAnyIgnoreCase(null, (CharSequence[]) null) = false 1257 * StringUtils.equalsAnyIgnoreCase(null, null, null) = true 1258 * StringUtils.equalsAnyIgnoreCase(null, "abc", "def") = false 1259 * StringUtils.equalsAnyIgnoreCase("abc", null, "def") = false 1260 * StringUtils.equalsAnyIgnoreCase("abc", "abc", "def") = true 1261 * StringUtils.equalsAnyIgnoreCase("abc", "ABC", "DEF") = true 1262 * </pre> 1263 * 1264 * @param string to compare, may be {@code null}. 1265 * @param searchStrings a vararg of strings, may be {@code null}. 1266 * @return {@code true} if the string is equal (case-insensitive) to any other element of <code>searchStrings</code>; 1267 * {@code false} if <code>searchStrings</code> is null or contains no matches. 1268 * @since 3.5 1269 */ 1270 public static boolean equalsAnyIgnoreCase(final CharSequence string, final CharSequence...searchStrings) { 1271 if (ArrayUtils.isNotEmpty(searchStrings)) { 1272 for (final CharSequence next : searchStrings) { 1273 if (equalsIgnoreCase(string, next)) { 1274 return true; 1275 } 1276 } 1277 } 1278 return false; 1279 } 1280 1281 // IndexOf 1282 //----------------------------------------------------------------------- 1283 /** 1284 * Returns the index within <code>seq</code> of the first occurrence of 1285 * the specified character. If a character with value 1286 * <code>searchChar</code> occurs in the character sequence represented by 1287 * <code>seq</code> <code>CharSequence</code> object, then the index (in Unicode 1288 * code units) of the first such occurrence is returned. For 1289 * values of <code>searchChar</code> in the range from 0 to 0xFFFF 1290 * (inclusive), this is the smallest value <i>k</i> such that: 1291 * <blockquote><pre> 1292 * this.charAt(<i>k</i>) == searchChar 1293 * </pre></blockquote> 1294 * is true. For other values of <code>searchChar</code>, it is the 1295 * smallest value <i>k</i> such that: 1296 * <blockquote><pre> 1297 * this.codePointAt(<i>k</i>) == searchChar 1298 * </pre></blockquote> 1299 * is true. In either case, if no such character occurs in <code>seq</code>, 1300 * then {@code INDEX_NOT_FOUND (-1)} is returned. 1301 * 1302 * <p>Furthermore, a {@code null} or empty ("") CharSequence will 1303 * return {@code INDEX_NOT_FOUND (-1)}.</p> 1304 * 1305 * <pre> 1306 * StringUtils.indexOf(null, *) = -1 1307 * StringUtils.indexOf("", *) = -1 1308 * StringUtils.indexOf("aabaabaa", 'a') = 0 1309 * StringUtils.indexOf("aabaabaa", 'b') = 2 1310 * </pre> 1311 * 1312 * @param seq the CharSequence to check, may be null 1313 * @param searchChar the character to find 1314 * @return the first index of the search character, 1315 * -1 if no match or {@code null} string input 1316 * @since 2.0 1317 * @since 3.0 Changed signature from indexOf(String, int) to indexOf(CharSequence, int) 1318 * @since 3.6 Updated {@link CharSequenceUtils} call to behave more like <code>String</code> 1319 */ 1320 public static int indexOf(final CharSequence seq, final int searchChar) { 1321 if (isEmpty(seq)) { 1322 return INDEX_NOT_FOUND; 1323 } 1324 return CharSequenceUtils.indexOf(seq, searchChar, 0); 1325 } 1326 1327 /** 1328 * 1329 * Returns the index within <code>seq</code> of the first occurrence of the 1330 * specified character, starting the search at the specified index. 1331 * <p> 1332 * If a character with value <code>searchChar</code> occurs in the 1333 * character sequence represented by the <code>seq</code> <code>CharSequence</code> 1334 * object at an index no smaller than <code>startPos</code>, then 1335 * the index of the first such occurrence is returned. For values 1336 * of <code>searchChar</code> in the range from 0 to 0xFFFF (inclusive), 1337 * this is the smallest value <i>k</i> such that: 1338 * <blockquote><pre> 1339 * (this.charAt(<i>k</i>) == searchChar) && (<i>k</i> >= startPos) 1340 * </pre></blockquote> 1341 * is true. For other values of <code>searchChar</code>, it is the 1342 * smallest value <i>k</i> such that: 1343 * <blockquote><pre> 1344 * (this.codePointAt(<i>k</i>) == searchChar) && (<i>k</i> >= startPos) 1345 * </pre></blockquote> 1346 * is true. In either case, if no such character occurs in <code>seq</code> 1347 * at or after position <code>startPos</code>, then 1348 * <code>-1</code> is returned. 1349 * 1350 * <p> 1351 * There is no restriction on the value of <code>startPos</code>. If it 1352 * is negative, it has the same effect as if it were zero: this entire 1353 * string may be searched. If it is greater than the length of this 1354 * string, it has the same effect as if it were equal to the length of 1355 * this string: {@code (INDEX_NOT_FOUND) -1} is returned. Furthermore, a 1356 * {@code null} or empty ("") CharSequence will 1357 * return {@code (INDEX_NOT_FOUND) -1}. 1358 * 1359 * <p>All indices are specified in <code>char</code> values 1360 * (Unicode code units). 1361 * 1362 * <pre> 1363 * StringUtils.indexOf(null, *, *) = -1 1364 * StringUtils.indexOf("", *, *) = -1 1365 * StringUtils.indexOf("aabaabaa", 'b', 0) = 2 1366 * StringUtils.indexOf("aabaabaa", 'b', 3) = 5 1367 * StringUtils.indexOf("aabaabaa", 'b', 9) = -1 1368 * StringUtils.indexOf("aabaabaa", 'b', -1) = 2 1369 * </pre> 1370 * 1371 * @param seq the CharSequence to check, may be null 1372 * @param searchChar the character to find 1373 * @param startPos the start position, negative treated as zero 1374 * @return the first index of the search character (always ≥ startPos), 1375 * -1 if no match or {@code null} string input 1376 * @since 2.0 1377 * @since 3.0 Changed signature from indexOf(String, int, int) to indexOf(CharSequence, int, int) 1378 * @since 3.6 Updated {@link CharSequenceUtils} call to behave more like <code>String</code> 1379 */ 1380 public static int indexOf(final CharSequence seq, final int searchChar, final int startPos) { 1381 if (isEmpty(seq)) { 1382 return INDEX_NOT_FOUND; 1383 } 1384 return CharSequenceUtils.indexOf(seq, searchChar, startPos); 1385 } 1386 1387 /** 1388 * <p>Finds the first index within a CharSequence, handling {@code null}. 1389 * This method uses {@link String#indexOf(String, int)} if possible.</p> 1390 * 1391 * <p>A {@code null} CharSequence will return {@code -1}.</p> 1392 * 1393 * <pre> 1394 * StringUtils.indexOf(null, *) = -1 1395 * StringUtils.indexOf(*, null) = -1 1396 * StringUtils.indexOf("", "") = 0 1397 * StringUtils.indexOf("", *) = -1 (except when * = "") 1398 * StringUtils.indexOf("aabaabaa", "a") = 0 1399 * StringUtils.indexOf("aabaabaa", "b") = 2 1400 * StringUtils.indexOf("aabaabaa", "ab") = 1 1401 * StringUtils.indexOf("aabaabaa", "") = 0 1402 * </pre> 1403 * 1404 * @param seq the CharSequence to check, may be null 1405 * @param searchSeq the CharSequence to find, may be null 1406 * @return the first index of the search CharSequence, 1407 * -1 if no match or {@code null} string input 1408 * @since 2.0 1409 * @since 3.0 Changed signature from indexOf(String, String) to indexOf(CharSequence, CharSequence) 1410 */ 1411 public static int indexOf(final CharSequence seq, final CharSequence searchSeq) { 1412 if (seq == null || searchSeq == null) { 1413 return INDEX_NOT_FOUND; 1414 } 1415 return CharSequenceUtils.indexOf(seq, searchSeq, 0); 1416 } 1417 1418 /** 1419 * <p>Finds the first index within a CharSequence, handling {@code null}. 1420 * This method uses {@link String#indexOf(String, int)} if possible.</p> 1421 * 1422 * <p>A {@code null} CharSequence will return {@code -1}. 1423 * A negative start position is treated as zero. 1424 * An empty ("") search CharSequence always matches. 1425 * A start position greater than the string length only matches 1426 * an empty search CharSequence.</p> 1427 * 1428 * <pre> 1429 * StringUtils.indexOf(null, *, *) = -1 1430 * StringUtils.indexOf(*, null, *) = -1 1431 * StringUtils.indexOf("", "", 0) = 0 1432 * StringUtils.indexOf("", *, 0) = -1 (except when * = "") 1433 * StringUtils.indexOf("aabaabaa", "a", 0) = 0 1434 * StringUtils.indexOf("aabaabaa", "b", 0) = 2 1435 * StringUtils.indexOf("aabaabaa", "ab", 0) = 1 1436 * StringUtils.indexOf("aabaabaa", "b", 3) = 5 1437 * StringUtils.indexOf("aabaabaa", "b", 9) = -1 1438 * StringUtils.indexOf("aabaabaa", "b", -1) = 2 1439 * StringUtils.indexOf("aabaabaa", "", 2) = 2 1440 * StringUtils.indexOf("abc", "", 9) = 3 1441 * </pre> 1442 * 1443 * @param seq the CharSequence to check, may be null 1444 * @param searchSeq the CharSequence to find, may be null 1445 * @param startPos the start position, negative treated as zero 1446 * @return the first index of the search CharSequence (always ≥ startPos), 1447 * -1 if no match or {@code null} string input 1448 * @since 2.0 1449 * @since 3.0 Changed signature from indexOf(String, String, int) to indexOf(CharSequence, CharSequence, int) 1450 */ 1451 public static int indexOf(final CharSequence seq, final CharSequence searchSeq, final int startPos) { 1452 if (seq == null || searchSeq == null) { 1453 return INDEX_NOT_FOUND; 1454 } 1455 return CharSequenceUtils.indexOf(seq, searchSeq, startPos); 1456 } 1457 1458 /** 1459 * <p>Finds the n-th index within a CharSequence, handling {@code null}. 1460 * This method uses {@link String#indexOf(String)} if possible.</p> 1461 * <p><b>Note:</b> The code starts looking for a match at the start of the target, 1462 * incrementing the starting index by one after each successful match 1463 * (unless {@code searchStr} is an empty string in which case the position 1464 * is never incremented and {@code 0} is returned immediately). 1465 * This means that matches may overlap.</p> 1466 * <p>A {@code null} CharSequence will return {@code -1}.</p> 1467 * 1468 * <pre> 1469 * StringUtils.ordinalIndexOf(null, *, *) = -1 1470 * StringUtils.ordinalIndexOf(*, null, *) = -1 1471 * StringUtils.ordinalIndexOf("", "", *) = 0 1472 * StringUtils.ordinalIndexOf("aabaabaa", "a", 1) = 0 1473 * StringUtils.ordinalIndexOf("aabaabaa", "a", 2) = 1 1474 * StringUtils.ordinalIndexOf("aabaabaa", "b", 1) = 2 1475 * StringUtils.ordinalIndexOf("aabaabaa", "b", 2) = 5 1476 * StringUtils.ordinalIndexOf("aabaabaa", "ab", 1) = 1 1477 * StringUtils.ordinalIndexOf("aabaabaa", "ab", 2) = 4 1478 * StringUtils.ordinalIndexOf("aabaabaa", "", 1) = 0 1479 * StringUtils.ordinalIndexOf("aabaabaa", "", 2) = 0 1480 * </pre> 1481 * 1482 * <p>Matches may overlap:</p> 1483 * <pre> 1484 * StringUtils.ordinalIndexOf("ababab","aba", 1) = 0 1485 * StringUtils.ordinalIndexOf("ababab","aba", 2) = 2 1486 * StringUtils.ordinalIndexOf("ababab","aba", 3) = -1 1487 * 1488 * StringUtils.ordinalIndexOf("abababab", "abab", 1) = 0 1489 * StringUtils.ordinalIndexOf("abababab", "abab", 2) = 2 1490 * StringUtils.ordinalIndexOf("abababab", "abab", 3) = 4 1491 * StringUtils.ordinalIndexOf("abababab", "abab", 4) = -1 1492 * </pre> 1493 * 1494 * <p>Note that 'head(CharSequence str, int n)' may be implemented as: </p> 1495 * 1496 * <pre> 1497 * str.substring(0, lastOrdinalIndexOf(str, "\n", n)) 1498 * </pre> 1499 * 1500 * @param str the CharSequence to check, may be null 1501 * @param searchStr the CharSequence to find, may be null 1502 * @param ordinal the n-th {@code searchStr} to find 1503 * @return the n-th index of the search CharSequence, 1504 * {@code -1} ({@code INDEX_NOT_FOUND}) if no match or {@code null} string input 1505 * @since 2.1 1506 * @since 3.0 Changed signature from ordinalIndexOf(String, String, int) to ordinalIndexOf(CharSequence, CharSequence, int) 1507 */ 1508 public static int ordinalIndexOf(final CharSequence str, final CharSequence searchStr, final int ordinal) { 1509 return ordinalIndexOf(str, searchStr, ordinal, false); 1510 } 1511 1512 /** 1513 * <p>Finds the n-th index within a String, handling {@code null}. 1514 * This method uses {@link String#indexOf(String)} if possible.</p> 1515 * <p>Note that matches may overlap<p> 1516 * 1517 * <p>A {@code null} CharSequence will return {@code -1}.</p> 1518 * 1519 * @param str the CharSequence to check, may be null 1520 * @param searchStr the CharSequence to find, may be null 1521 * @param ordinal the n-th {@code searchStr} to find, overlapping matches are allowed. 1522 * @param lastIndex true if lastOrdinalIndexOf() otherwise false if ordinalIndexOf() 1523 * @return the n-th index of the search CharSequence, 1524 * {@code -1} ({@code INDEX_NOT_FOUND}) if no match or {@code null} string input 1525 */ 1526 // Shared code between ordinalIndexOf(String,String,int) and lastOrdinalIndexOf(String,String,int) 1527 private static int ordinalIndexOf(final CharSequence str, final CharSequence searchStr, final int ordinal, final boolean lastIndex) { 1528 if (str == null || searchStr == null || ordinal <= 0) { 1529 return INDEX_NOT_FOUND; 1530 } 1531 if (searchStr.length() == 0) { 1532 return lastIndex ? str.length() : 0; 1533 } 1534 int found = 0; 1535 // set the initial index beyond the end of the string 1536 // this is to allow for the initial index decrement/increment 1537 int index = lastIndex ? str.length() : INDEX_NOT_FOUND; 1538 do { 1539 if (lastIndex) { 1540 index = CharSequenceUtils.lastIndexOf(str, searchStr, index - 1); // step backwards thru string 1541 } else { 1542 index = CharSequenceUtils.indexOf(str, searchStr, index + 1); // step forwards through string 1543 } 1544 if (index < 0) { 1545 return index; 1546 } 1547 found++; 1548 } while (found < ordinal); 1549 return index; 1550 } 1551 1552 /** 1553 * <p>Case in-sensitive find of the first index within a CharSequence.</p> 1554 * 1555 * <p>A {@code null} CharSequence will return {@code -1}. 1556 * A negative start position is treated as zero. 1557 * An empty ("") search CharSequence always matches. 1558 * A start position greater than the string length only matches 1559 * an empty search CharSequence.</p> 1560 * 1561 * <pre> 1562 * StringUtils.indexOfIgnoreCase(null, *) = -1 1563 * StringUtils.indexOfIgnoreCase(*, null) = -1 1564 * StringUtils.indexOfIgnoreCase("", "") = 0 1565 * StringUtils.indexOfIgnoreCase("aabaabaa", "a") = 0 1566 * StringUtils.indexOfIgnoreCase("aabaabaa", "b") = 2 1567 * StringUtils.indexOfIgnoreCase("aabaabaa", "ab") = 1 1568 * </pre> 1569 * 1570 * @param str the CharSequence to check, may be null 1571 * @param searchStr the CharSequence to find, may be null 1572 * @return the first index of the search CharSequence, 1573 * -1 if no match or {@code null} string input 1574 * @since 2.5 1575 * @since 3.0 Changed signature from indexOfIgnoreCase(String, String) to indexOfIgnoreCase(CharSequence, CharSequence) 1576 */ 1577 public static int indexOfIgnoreCase(final CharSequence str, final CharSequence searchStr) { 1578 return indexOfIgnoreCase(str, searchStr, 0); 1579 } 1580 1581 /** 1582 * <p>Case in-sensitive find of the first index within a CharSequence 1583 * from the specified position.</p> 1584 * 1585 * <p>A {@code null} CharSequence will return {@code -1}. 1586 * A negative start position is treated as zero. 1587 * An empty ("") search CharSequence always matches. 1588 * A start position greater than the string length only matches 1589 * an empty search CharSequence.</p> 1590 * 1591 * <pre> 1592 * StringUtils.indexOfIgnoreCase(null, *, *) = -1 1593 * StringUtils.indexOfIgnoreCase(*, null, *) = -1 1594 * StringUtils.indexOfIgnoreCase("", "", 0) = 0 1595 * StringUtils.indexOfIgnoreCase("aabaabaa", "A", 0) = 0 1596 * StringUtils.indexOfIgnoreCase("aabaabaa", "B", 0) = 2 1597 * StringUtils.indexOfIgnoreCase("aabaabaa", "AB", 0) = 1 1598 * StringUtils.indexOfIgnoreCase("aabaabaa", "B", 3) = 5 1599 * StringUtils.indexOfIgnoreCase("aabaabaa", "B", 9) = -1 1600 * StringUtils.indexOfIgnoreCase("aabaabaa", "B", -1) = 2 1601 * StringUtils.indexOfIgnoreCase("aabaabaa", "", 2) = 2 1602 * StringUtils.indexOfIgnoreCase("abc", "", 9) = -1 1603 * </pre> 1604 * 1605 * @param str the CharSequence to check, may be null 1606 * @param searchStr the CharSequence to find, may be null 1607 * @param startPos the start position, negative treated as zero 1608 * @return the first index of the search CharSequence (always ≥ startPos), 1609 * -1 if no match or {@code null} string input 1610 * @since 2.5 1611 * @since 3.0 Changed signature from indexOfIgnoreCase(String, String, int) to indexOfIgnoreCase(CharSequence, CharSequence, int) 1612 */ 1613 public static int indexOfIgnoreCase(final CharSequence str, final CharSequence searchStr, int startPos) { 1614 if (str == null || searchStr == null) { 1615 return INDEX_NOT_FOUND; 1616 } 1617 if (startPos < 0) { 1618 startPos = 0; 1619 } 1620 final int endLimit = str.length() - searchStr.length() + 1; 1621 if (startPos > endLimit) { 1622 return INDEX_NOT_FOUND; 1623 } 1624 if (searchStr.length() == 0) { 1625 return startPos; 1626 } 1627 for (int i = startPos; i < endLimit; i++) { 1628 if (CharSequenceUtils.regionMatches(str, true, i, searchStr, 0, searchStr.length())) { 1629 return i; 1630 } 1631 } 1632 return INDEX_NOT_FOUND; 1633 } 1634 1635 // LastIndexOf 1636 //----------------------------------------------------------------------- 1637 /** 1638 * Returns the index within <code>seq</code> of the last occurrence of 1639 * the specified character. For values of <code>searchChar</code> in the 1640 * range from 0 to 0xFFFF (inclusive), the index (in Unicode code 1641 * units) returned is the largest value <i>k</i> such that: 1642 * <blockquote><pre> 1643 * this.charAt(<i>k</i>) == searchChar 1644 * </pre></blockquote> 1645 * is true. For other values of <code>searchChar</code>, it is the 1646 * largest value <i>k</i> such that: 1647 * <blockquote><pre> 1648 * this.codePointAt(<i>k</i>) == searchChar 1649 * </pre></blockquote> 1650 * is true. In either case, if no such character occurs in this 1651 * string, then <code>-1</code> is returned. Furthermore, a {@code null} or empty ("") 1652 * <code>CharSequence</code> will return {@code -1}. The 1653 * <code>seq</code> <code>CharSequence</code> object is searched backwards 1654 * starting at the last character. 1655 * 1656 * <pre> 1657 * StringUtils.lastIndexOf(null, *) = -1 1658 * StringUtils.lastIndexOf("", *) = -1 1659 * StringUtils.lastIndexOf("aabaabaa", 'a') = 7 1660 * StringUtils.lastIndexOf("aabaabaa", 'b') = 5 1661 * </pre> 1662 * 1663 * @param seq the <code>CharSequence</code> to check, may be null 1664 * @param searchChar the character to find 1665 * @return the last index of the search character, 1666 * -1 if no match or {@code null} string input 1667 * @since 2.0 1668 * @since 3.0 Changed signature from lastIndexOf(String, int) to lastIndexOf(CharSequence, int) 1669 * @since 3.6 Updated {@link CharSequenceUtils} call to behave more like <code>String</code> 1670 */ 1671 public static int lastIndexOf(final CharSequence seq, final int searchChar) { 1672 if (isEmpty(seq)) { 1673 return INDEX_NOT_FOUND; 1674 } 1675 return CharSequenceUtils.lastIndexOf(seq, searchChar, seq.length()); 1676 } 1677 1678 /** 1679 * Returns the index within <code>seq</code> of the last occurrence of 1680 * the specified character, searching backward starting at the 1681 * specified index. For values of <code>searchChar</code> in the range 1682 * from 0 to 0xFFFF (inclusive), the index returned is the largest 1683 * value <i>k</i> such that: 1684 * <blockquote><pre> 1685 * (this.charAt(<i>k</i>) == searchChar) && (<i>k</i> <= startPos) 1686 * </pre></blockquote> 1687 * is true. For other values of <code>searchChar</code>, it is the 1688 * largest value <i>k</i> such that: 1689 * <blockquote><pre> 1690 * (this.codePointAt(<i>k</i>) == searchChar) && (<i>k</i> <= startPos) 1691 * </pre></blockquote> 1692 * is true. In either case, if no such character occurs in <code>seq</code> 1693 * at or before position <code>startPos</code>, then 1694 * <code>-1</code> is returned. Furthermore, a {@code null} or empty ("") 1695 * <code>CharSequence</code> will return {@code -1}. A start position greater 1696 * than the string length searches the whole string. 1697 * The search starts at the <code>startPos</code> and works backwards; 1698 * matches starting after the start position are ignored. 1699 * 1700 * <p>All indices are specified in <code>char</code> values 1701 * (Unicode code units). 1702 * 1703 * <pre> 1704 * StringUtils.lastIndexOf(null, *, *) = -1 1705 * StringUtils.lastIndexOf("", *, *) = -1 1706 * StringUtils.lastIndexOf("aabaabaa", 'b', 8) = 5 1707 * StringUtils.lastIndexOf("aabaabaa", 'b', 4) = 2 1708 * StringUtils.lastIndexOf("aabaabaa", 'b', 0) = -1 1709 * StringUtils.lastIndexOf("aabaabaa", 'b', 9) = 5 1710 * StringUtils.lastIndexOf("aabaabaa", 'b', -1) = -1 1711 * StringUtils.lastIndexOf("aabaabaa", 'a', 0) = 0 1712 * </pre> 1713 * 1714 * @param seq the CharSequence to check, may be null 1715 * @param searchChar the character to find 1716 * @param startPos the start position 1717 * @return the last index of the search character (always ≤ startPos), 1718 * -1 if no match or {@code null} string input 1719 * @since 2.0 1720 * @since 3.0 Changed signature from lastIndexOf(String, int, int) to lastIndexOf(CharSequence, int, int) 1721 */ 1722 public static int lastIndexOf(final CharSequence seq, final int searchChar, final int startPos) { 1723 if (isEmpty(seq)) { 1724 return INDEX_NOT_FOUND; 1725 } 1726 return CharSequenceUtils.lastIndexOf(seq, searchChar, startPos); 1727 } 1728 1729 /** 1730 * <p>Finds the last index within a CharSequence, handling {@code null}. 1731 * This method uses {@link String#lastIndexOf(String)} if possible.</p> 1732 * 1733 * <p>A {@code null} CharSequence will return {@code -1}.</p> 1734 * 1735 * <pre> 1736 * StringUtils.lastIndexOf(null, *) = -1 1737 * StringUtils.lastIndexOf(*, null) = -1 1738 * StringUtils.lastIndexOf("", "") = 0 1739 * StringUtils.lastIndexOf("aabaabaa", "a") = 7 1740 * StringUtils.lastIndexOf("aabaabaa", "b") = 5 1741 * StringUtils.lastIndexOf("aabaabaa", "ab") = 4 1742 * StringUtils.lastIndexOf("aabaabaa", "") = 8 1743 * </pre> 1744 * 1745 * @param seq the CharSequence to check, may be null 1746 * @param searchSeq the CharSequence to find, may be null 1747 * @return the last index of the search String, 1748 * -1 if no match or {@code null} string input 1749 * @since 2.0 1750 * @since 3.0 Changed signature from lastIndexOf(String, String) to lastIndexOf(CharSequence, CharSequence) 1751 */ 1752 public static int lastIndexOf(final CharSequence seq, final CharSequence searchSeq) { 1753 if (seq == null || searchSeq == null) { 1754 return INDEX_NOT_FOUND; 1755 } 1756 return CharSequenceUtils.lastIndexOf(seq, searchSeq, seq.length()); 1757 } 1758 1759 /** 1760 * <p>Finds the n-th last index within a String, handling {@code null}. 1761 * This method uses {@link String#lastIndexOf(String)}.</p> 1762 * 1763 * <p>A {@code null} String will return {@code -1}.</p> 1764 * 1765 * <pre> 1766 * StringUtils.lastOrdinalIndexOf(null, *, *) = -1 1767 * StringUtils.lastOrdinalIndexOf(*, null, *) = -1 1768 * StringUtils.lastOrdinalIndexOf("", "", *) = 0 1769 * StringUtils.lastOrdinalIndexOf("aabaabaa", "a", 1) = 7 1770 * StringUtils.lastOrdinalIndexOf("aabaabaa", "a", 2) = 6 1771 * StringUtils.lastOrdinalIndexOf("aabaabaa", "b", 1) = 5 1772 * StringUtils.lastOrdinalIndexOf("aabaabaa", "b", 2) = 2 1773 * StringUtils.lastOrdinalIndexOf("aabaabaa", "ab", 1) = 4 1774 * StringUtils.lastOrdinalIndexOf("aabaabaa", "ab", 2) = 1 1775 * StringUtils.lastOrdinalIndexOf("aabaabaa", "", 1) = 8 1776 * StringUtils.lastOrdinalIndexOf("aabaabaa", "", 2) = 8 1777 * </pre> 1778 * 1779 * <p>Note that 'tail(CharSequence str, int n)' may be implemented as: </p> 1780 * 1781 * <pre> 1782 * str.substring(lastOrdinalIndexOf(str, "\n", n) + 1) 1783 * </pre> 1784 * 1785 * @param str the CharSequence to check, may be null 1786 * @param searchStr the CharSequence to find, may be null 1787 * @param ordinal the n-th last {@code searchStr} to find 1788 * @return the n-th last index of the search CharSequence, 1789 * {@code -1} ({@code INDEX_NOT_FOUND}) if no match or {@code null} string input 1790 * @since 2.5 1791 * @since 3.0 Changed signature from lastOrdinalIndexOf(String, String, int) to lastOrdinalIndexOf(CharSequence, CharSequence, int) 1792 */ 1793 public static int lastOrdinalIndexOf(final CharSequence str, final CharSequence searchStr, final int ordinal) { 1794 return ordinalIndexOf(str, searchStr, ordinal, true); 1795 } 1796 1797 /** 1798 * <p>Finds the last index within a CharSequence, handling {@code null}. 1799 * This method uses {@link String#lastIndexOf(String, int)} if possible.</p> 1800 * 1801 * <p>A {@code null} CharSequence will return {@code -1}. 1802 * A negative start position returns {@code -1}. 1803 * An empty ("") search CharSequence always matches unless the start position is negative. 1804 * A start position greater than the string length searches the whole string. 1805 * The search starts at the startPos and works backwards; matches starting after the start 1806 * position are ignored. 1807 * </p> 1808 * 1809 * <pre> 1810 * StringUtils.lastIndexOf(null, *, *) = -1 1811 * StringUtils.lastIndexOf(*, null, *) = -1 1812 * StringUtils.lastIndexOf("aabaabaa", "a", 8) = 7 1813 * StringUtils.lastIndexOf("aabaabaa", "b", 8) = 5 1814 * StringUtils.lastIndexOf("aabaabaa", "ab", 8) = 4 1815 * StringUtils.lastIndexOf("aabaabaa", "b", 9) = 5 1816 * StringUtils.lastIndexOf("aabaabaa", "b", -1) = -1 1817 * StringUtils.lastIndexOf("aabaabaa", "a", 0) = 0 1818 * StringUtils.lastIndexOf("aabaabaa", "b", 0) = -1 1819 * StringUtils.lastIndexOf("aabaabaa", "b", 1) = -1 1820 * StringUtils.lastIndexOf("aabaabaa", "b", 2) = 2 1821 * StringUtils.lastIndexOf("aabaabaa", "ba", 2) = -1 1822 * StringUtils.lastIndexOf("aabaabaa", "ba", 2) = 2 1823 * </pre> 1824 * 1825 * @param seq the CharSequence to check, may be null 1826 * @param searchSeq the CharSequence to find, may be null 1827 * @param startPos the start position, negative treated as zero 1828 * @return the last index of the search CharSequence (always ≤ startPos), 1829 * -1 if no match or {@code null} string input 1830 * @since 2.0 1831 * @since 3.0 Changed signature from lastIndexOf(String, String, int) to lastIndexOf(CharSequence, CharSequence, int) 1832 */ 1833 public static int lastIndexOf(final CharSequence seq, final CharSequence searchSeq, final int startPos) { 1834 if (seq == null || searchSeq == null) { 1835 return INDEX_NOT_FOUND; 1836 } 1837 return CharSequenceUtils.lastIndexOf(seq, searchSeq, startPos); 1838 } 1839 1840 /** 1841 * <p>Case in-sensitive find of the last index within a CharSequence.</p> 1842 * 1843 * <p>A {@code null} CharSequence will return {@code -1}. 1844 * A negative start position returns {@code -1}. 1845 * An empty ("") search CharSequence always matches unless the start position is negative. 1846 * A start position greater than the string length searches the whole string.</p> 1847 * 1848 * <pre> 1849 * StringUtils.lastIndexOfIgnoreCase(null, *) = -1 1850 * StringUtils.lastIndexOfIgnoreCase(*, null) = -1 1851 * StringUtils.lastIndexOfIgnoreCase("aabaabaa", "A") = 7 1852 * StringUtils.lastIndexOfIgnoreCase("aabaabaa", "B") = 5 1853 * StringUtils.lastIndexOfIgnoreCase("aabaabaa", "AB") = 4 1854 * </pre> 1855 * 1856 * @param str the CharSequence to check, may be null 1857 * @param searchStr the CharSequence to find, may be null 1858 * @return the first index of the search CharSequence, 1859 * -1 if no match or {@code null} string input 1860 * @since 2.5 1861 * @since 3.0 Changed signature from lastIndexOfIgnoreCase(String, String) to lastIndexOfIgnoreCase(CharSequence, CharSequence) 1862 */ 1863 public static int lastIndexOfIgnoreCase(final CharSequence str, final CharSequence searchStr) { 1864 if (str == null || searchStr == null) { 1865 return INDEX_NOT_FOUND; 1866 } 1867 return lastIndexOfIgnoreCase(str, searchStr, str.length()); 1868 } 1869 1870 /** 1871 * <p>Case in-sensitive find of the last index within a CharSequence 1872 * from the specified position.</p> 1873 * 1874 * <p>A {@code null} CharSequence will return {@code -1}. 1875 * A negative start position returns {@code -1}. 1876 * An empty ("") search CharSequence always matches unless the start position is negative. 1877 * A start position greater than the string length searches the whole string. 1878 * The search starts at the startPos and works backwards; matches starting after the start 1879 * position are ignored. 1880 * </p> 1881 * 1882 * <pre> 1883 * StringUtils.lastIndexOfIgnoreCase(null, *, *) = -1 1884 * StringUtils.lastIndexOfIgnoreCase(*, null, *) = -1 1885 * StringUtils.lastIndexOfIgnoreCase("aabaabaa", "A", 8) = 7 1886 * StringUtils.lastIndexOfIgnoreCase("aabaabaa", "B", 8) = 5 1887 * StringUtils.lastIndexOfIgnoreCase("aabaabaa", "AB", 8) = 4 1888 * StringUtils.lastIndexOfIgnoreCase("aabaabaa", "B", 9) = 5 1889 * StringUtils.lastIndexOfIgnoreCase("aabaabaa", "B", -1) = -1 1890 * StringUtils.lastIndexOfIgnoreCase("aabaabaa", "A", 0) = 0 1891 * StringUtils.lastIndexOfIgnoreCase("aabaabaa", "B", 0) = -1 1892 * </pre> 1893 * 1894 * @param str the CharSequence to check, may be null 1895 * @param searchStr the CharSequence to find, may be null 1896 * @param startPos the start position 1897 * @return the last index of the search CharSequence (always ≤ startPos), 1898 * -1 if no match or {@code null} input 1899 * @since 2.5 1900 * @since 3.0 Changed signature from lastIndexOfIgnoreCase(String, String, int) to lastIndexOfIgnoreCase(CharSequence, CharSequence, int) 1901 */ 1902 public static int lastIndexOfIgnoreCase(final CharSequence str, final CharSequence searchStr, int startPos) { 1903 if (str == null || searchStr == null) { 1904 return INDEX_NOT_FOUND; 1905 } 1906 if (startPos > str.length() - searchStr.length()) { 1907 startPos = str.length() - searchStr.length(); 1908 } 1909 if (startPos < 0) { 1910 return INDEX_NOT_FOUND; 1911 } 1912 if (searchStr.length() == 0) { 1913 return startPos; 1914 } 1915 1916 for (int i = startPos; i >= 0; i--) { 1917 if (CharSequenceUtils.regionMatches(str, true, i, searchStr, 0, searchStr.length())) { 1918 return i; 1919 } 1920 } 1921 return INDEX_NOT_FOUND; 1922 } 1923 1924 // Contains 1925 //----------------------------------------------------------------------- 1926 /** 1927 * <p>Checks if CharSequence contains a search character, handling {@code null}. 1928 * This method uses {@link String#indexOf(int)} if possible.</p> 1929 * 1930 * <p>A {@code null} or empty ("") CharSequence will return {@code false}.</p> 1931 * 1932 * <pre> 1933 * StringUtils.contains(null, *) = false 1934 * StringUtils.contains("", *) = false 1935 * StringUtils.contains("abc", 'a') = true 1936 * StringUtils.contains("abc", 'z') = false 1937 * </pre> 1938 * 1939 * @param seq the CharSequence to check, may be null 1940 * @param searchChar the character to find 1941 * @return true if the CharSequence contains the search character, 1942 * false if not or {@code null} string input 1943 * @since 2.0 1944 * @since 3.0 Changed signature from contains(String, int) to contains(CharSequence, int) 1945 */ 1946 public static boolean contains(final CharSequence seq, final int searchChar) { 1947 if (isEmpty(seq)) { 1948 return false; 1949 } 1950 return CharSequenceUtils.indexOf(seq, searchChar, 0) >= 0; 1951 } 1952 1953 /** 1954 * <p>Checks if CharSequence contains a search CharSequence, handling {@code null}. 1955 * This method uses {@link String#indexOf(String)} if possible.</p> 1956 * 1957 * <p>A {@code null} CharSequence will return {@code false}.</p> 1958 * 1959 * <pre> 1960 * StringUtils.contains(null, *) = false 1961 * StringUtils.contains(*, null) = false 1962 * StringUtils.contains("", "") = true 1963 * StringUtils.contains("abc", "") = true 1964 * StringUtils.contains("abc", "a") = true 1965 * StringUtils.contains("abc", "z") = false 1966 * </pre> 1967 * 1968 * @param seq the CharSequence to check, may be null 1969 * @param searchSeq the CharSequence to find, may be null 1970 * @return true if the CharSequence contains the search CharSequence, 1971 * false if not or {@code null} string input 1972 * @since 2.0 1973 * @since 3.0 Changed signature from contains(String, String) to contains(CharSequence, CharSequence) 1974 */ 1975 public static boolean contains(final CharSequence seq, final CharSequence searchSeq) { 1976 if (seq == null || searchSeq == null) { 1977 return false; 1978 } 1979 return CharSequenceUtils.indexOf(seq, searchSeq, 0) >= 0; 1980 } 1981 1982 /** 1983 * <p>Checks if CharSequence contains a search CharSequence irrespective of case, 1984 * handling {@code null}. Case-insensitivity is defined as by 1985 * {@link String#equalsIgnoreCase(String)}. 1986 * 1987 * <p>A {@code null} CharSequence will return {@code false}.</p> 1988 * 1989 * <pre> 1990 * StringUtils.containsIgnoreCase(null, *) = false 1991 * StringUtils.containsIgnoreCase(*, null) = false 1992 * StringUtils.containsIgnoreCase("", "") = true 1993 * StringUtils.containsIgnoreCase("abc", "") = true 1994 * StringUtils.containsIgnoreCase("abc", "a") = true 1995 * StringUtils.containsIgnoreCase("abc", "z") = false 1996 * StringUtils.containsIgnoreCase("abc", "A") = true 1997 * StringUtils.containsIgnoreCase("abc", "Z") = false 1998 * </pre> 1999 * 2000 * @param str the CharSequence to check, may be null 2001 * @param searchStr the CharSequence to find, may be null 2002 * @return true if the CharSequence contains the search CharSequence irrespective of 2003 * case or false if not or {@code null} string input 2004 * @since 3.0 Changed signature from containsIgnoreCase(String, String) to containsIgnoreCase(CharSequence, CharSequence) 2005 */ 2006 public static boolean containsIgnoreCase(final CharSequence str, final CharSequence searchStr) { 2007 if (str == null || searchStr == null) { 2008 return false; 2009 } 2010 final int len = searchStr.length(); 2011 final int max = str.length() - len; 2012 for (int i = 0; i <= max; i++) { 2013 if (CharSequenceUtils.regionMatches(str, true, i, searchStr, 0, len)) { 2014 return true; 2015 } 2016 } 2017 return false; 2018 } 2019 2020 /** 2021 * <p>Check whether the given CharSequence contains any whitespace characters.</p> 2022 * 2023 * <p>Whitespace is defined by {@link Character#isWhitespace(char)}.</p> 2024 * 2025 * @param seq the CharSequence to check (may be {@code null}) 2026 * @return {@code true} if the CharSequence is not empty and 2027 * contains at least 1 (breaking) whitespace character 2028 * @since 3.0 2029 */ 2030 // From org.springframework.util.StringUtils, under Apache License 2.0 2031 public static boolean containsWhitespace(final CharSequence seq) { 2032 if (isEmpty(seq)) { 2033 return false; 2034 } 2035 final int strLen = seq.length(); 2036 for (int i = 0; i < strLen; i++) { 2037 if (Character.isWhitespace(seq.charAt(i))) { 2038 return true; 2039 } 2040 } 2041 return false; 2042 } 2043 2044 // IndexOfAny chars 2045 //----------------------------------------------------------------------- 2046 /** 2047 * <p>Search a CharSequence to find the first index of any 2048 * character in the given set of characters.</p> 2049 * 2050 * <p>A {@code null} String will return {@code -1}. 2051 * A {@code null} or zero length search array will return {@code -1}.</p> 2052 * 2053 * <pre> 2054 * StringUtils.indexOfAny(null, *) = -1 2055 * StringUtils.indexOfAny("", *) = -1 2056 * StringUtils.indexOfAny(*, null) = -1 2057 * StringUtils.indexOfAny(*, []) = -1 2058 * StringUtils.indexOfAny("zzabyycdxx",['z','a']) = 0 2059 * StringUtils.indexOfAny("zzabyycdxx",['b','y']) = 3 2060 * StringUtils.indexOfAny("aba", ['z']) = -1 2061 * </pre> 2062 * 2063 * @param cs the CharSequence to check, may be null 2064 * @param searchChars the chars to search for, may be null 2065 * @return the index of any of the chars, -1 if no match or null input 2066 * @since 2.0 2067 * @since 3.0 Changed signature from indexOfAny(String, char[]) to indexOfAny(CharSequence, char...) 2068 */ 2069 public static int indexOfAny(final CharSequence cs, final char... searchChars) { 2070 if (isEmpty(cs) || ArrayUtils.isEmpty(searchChars)) { 2071 return INDEX_NOT_FOUND; 2072 } 2073 final int csLen = cs.length(); 2074 final int csLast = csLen - 1; 2075 final int searchLen = searchChars.length; 2076 final int searchLast = searchLen - 1; 2077 for (int i = 0; i < csLen; i++) { 2078 final char ch = cs.charAt(i); 2079 for (int j = 0; j < searchLen; j++) { 2080 if (searchChars[j] == ch) { 2081 if (i < csLast && j < searchLast && Character.isHighSurrogate(ch)) { 2082 // ch is a supplementary character 2083 if (searchChars[j + 1] == cs.charAt(i + 1)) { 2084 return i; 2085 } 2086 } else { 2087 return i; 2088 } 2089 } 2090 } 2091 } 2092 return INDEX_NOT_FOUND; 2093 } 2094 2095 /** 2096 * <p>Search a CharSequence to find the first index of any 2097 * character in the given set of characters.</p> 2098 * 2099 * <p>A {@code null} String will return {@code -1}. 2100 * A {@code null} search string will return {@code -1}.</p> 2101 * 2102 * <pre> 2103 * StringUtils.indexOfAny(null, *) = -1 2104 * StringUtils.indexOfAny("", *) = -1 2105 * StringUtils.indexOfAny(*, null) = -1 2106 * StringUtils.indexOfAny(*, "") = -1 2107 * StringUtils.indexOfAny("zzabyycdxx", "za") = 0 2108 * StringUtils.indexOfAny("zzabyycdxx", "by") = 3 2109 * StringUtils.indexOfAny("aba","z") = -1 2110 * </pre> 2111 * 2112 * @param cs the CharSequence to check, may be null 2113 * @param searchChars the chars to search for, may be null 2114 * @return the index of any of the chars, -1 if no match or null input 2115 * @since 2.0 2116 * @since 3.0 Changed signature from indexOfAny(String, String) to indexOfAny(CharSequence, String) 2117 */ 2118 public static int indexOfAny(final CharSequence cs, final String searchChars) { 2119 if (isEmpty(cs) || isEmpty(searchChars)) { 2120 return INDEX_NOT_FOUND; 2121 } 2122 return indexOfAny(cs, searchChars.toCharArray()); 2123 } 2124 2125 // ContainsAny 2126 //----------------------------------------------------------------------- 2127 /** 2128 * <p>Checks if the CharSequence contains any character in the given 2129 * set of characters.</p> 2130 * 2131 * <p>A {@code null} CharSequence will return {@code false}. 2132 * A {@code null} or zero length search array will return {@code false}.</p> 2133 * 2134 * <pre> 2135 * StringUtils.containsAny(null, *) = false 2136 * StringUtils.containsAny("", *) = false 2137 * StringUtils.containsAny(*, null) = false 2138 * StringUtils.containsAny(*, []) = false 2139 * StringUtils.containsAny("zzabyycdxx",['z','a']) = true 2140 * StringUtils.containsAny("zzabyycdxx",['b','y']) = true 2141 * StringUtils.containsAny("zzabyycdxx",['z','y']) = true 2142 * StringUtils.containsAny("aba", ['z']) = false 2143 * </pre> 2144 * 2145 * @param cs the CharSequence to check, may be null 2146 * @param searchChars the chars to search for, may be null 2147 * @return the {@code true} if any of the chars are found, 2148 * {@code false} if no match or null input 2149 * @since 2.4 2150 * @since 3.0 Changed signature from containsAny(String, char[]) to containsAny(CharSequence, char...) 2151 */ 2152 public static boolean containsAny(final CharSequence cs, final char... searchChars) { 2153 if (isEmpty(cs) || ArrayUtils.isEmpty(searchChars)) { 2154 return false; 2155 } 2156 final int csLength = cs.length(); 2157 final int searchLength = searchChars.length; 2158 final int csLast = csLength - 1; 2159 final int searchLast = searchLength - 1; 2160 for (int i = 0; i < csLength; i++) { 2161 final char ch = cs.charAt(i); 2162 for (int j = 0; j < searchLength; j++) { 2163 if (searchChars[j] == ch) { 2164 if (Character.isHighSurrogate(ch)) { 2165 if (j == searchLast) { 2166 // missing low surrogate, fine, like String.indexOf(String) 2167 return true; 2168 } 2169 if (i < csLast && searchChars[j + 1] == cs.charAt(i + 1)) { 2170 return true; 2171 } 2172 } else { 2173 // ch is in the Basic Multilingual Plane 2174 return true; 2175 } 2176 } 2177 } 2178 } 2179 return false; 2180 } 2181 2182 /** 2183 * <p> 2184 * Checks if the CharSequence contains any character in the given set of characters. 2185 * </p> 2186 * 2187 * <p> 2188 * A {@code null} CharSequence will return {@code false}. A {@code null} search CharSequence will return 2189 * {@code false}. 2190 * </p> 2191 * 2192 * <pre> 2193 * StringUtils.containsAny(null, *) = false 2194 * StringUtils.containsAny("", *) = false 2195 * StringUtils.containsAny(*, null) = false 2196 * StringUtils.containsAny(*, "") = false 2197 * StringUtils.containsAny("zzabyycdxx", "za") = true 2198 * StringUtils.containsAny("zzabyycdxx", "by") = true 2199 * StringUtils.containsAny("zzabyycdxx", "zy") = true 2200 * StringUtils.containsAny("zzabyycdxx", "\tx") = true 2201 * StringUtils.containsAny("zzabyycdxx", "$.#yF") = true 2202 * StringUtils.containsAny("aba","z") = false 2203 * </pre> 2204 * 2205 * @param cs 2206 * the CharSequence to check, may be null 2207 * @param searchChars 2208 * the chars to search for, may be null 2209 * @return the {@code true} if any of the chars are found, {@code false} if no match or null input 2210 * @since 2.4 2211 * @since 3.0 Changed signature from containsAny(String, String) to containsAny(CharSequence, CharSequence) 2212 */ 2213 public static boolean containsAny(final CharSequence cs, final CharSequence searchChars) { 2214 if (searchChars == null) { 2215 return false; 2216 } 2217 return containsAny(cs, CharSequenceUtils.toCharArray(searchChars)); 2218 } 2219 2220 /** 2221 * <p>Checks if the CharSequence contains any of the CharSequences in the given array.</p> 2222 * 2223 * <p> 2224 * A {@code null} {@code cs} CharSequence will return {@code false}. A {@code null} or zero 2225 * length search array will return {@code false}. 2226 * </p> 2227 * 2228 * <pre> 2229 * StringUtils.containsAny(null, *) = false 2230 * StringUtils.containsAny("", *) = false 2231 * StringUtils.containsAny(*, null) = false 2232 * StringUtils.containsAny(*, []) = false 2233 * StringUtils.containsAny("abcd", "ab", null) = true 2234 * StringUtils.containsAny("abcd", "ab", "cd") = true 2235 * StringUtils.containsAny("abc", "d", "abc") = true 2236 * </pre> 2237 * 2238 * 2239 * @param cs The CharSequence to check, may be null 2240 * @param searchCharSequences The array of CharSequences to search for, may be null. 2241 * Individual CharSequences may be null as well. 2242 * @return {@code true} if any of the search CharSequences are found, {@code false} otherwise 2243 * @since 3.4 2244 */ 2245 public static boolean containsAny(final CharSequence cs, final CharSequence... searchCharSequences) { 2246 if (isEmpty(cs) || ArrayUtils.isEmpty(searchCharSequences)) { 2247 return false; 2248 } 2249 for (final CharSequence searchCharSequence : searchCharSequences) { 2250 if (contains(cs, searchCharSequence)) { 2251 return true; 2252 } 2253 } 2254 return false; 2255 } 2256 2257 // IndexOfAnyBut chars 2258 //----------------------------------------------------------------------- 2259 /** 2260 * <p>Searches a CharSequence to find the first index of any 2261 * character not in the given set of characters.</p> 2262 * 2263 * <p>A {@code null} CharSequence will return {@code -1}. 2264 * A {@code null} or zero length search array will return {@code -1}.</p> 2265 * 2266 * <pre> 2267 * StringUtils.indexOfAnyBut(null, *) = -1 2268 * StringUtils.indexOfAnyBut("", *) = -1 2269 * StringUtils.indexOfAnyBut(*, null) = -1 2270 * StringUtils.indexOfAnyBut(*, []) = -1 2271 * StringUtils.indexOfAnyBut("zzabyycdxx", new char[] {'z', 'a'} ) = 3 2272 * StringUtils.indexOfAnyBut("aba", new char[] {'z'} ) = 0 2273 * StringUtils.indexOfAnyBut("aba", new char[] {'a', 'b'} ) = -1 2274 2275 * </pre> 2276 * 2277 * @param cs the CharSequence to check, may be null 2278 * @param searchChars the chars to search for, may be null 2279 * @return the index of any of the chars, -1 if no match or null input 2280 * @since 2.0 2281 * @since 3.0 Changed signature from indexOfAnyBut(String, char[]) to indexOfAnyBut(CharSequence, char...) 2282 */ 2283 public static int indexOfAnyBut(final CharSequence cs, final char... searchChars) { 2284 if (isEmpty(cs) || ArrayUtils.isEmpty(searchChars)) { 2285 return INDEX_NOT_FOUND; 2286 } 2287 final int csLen = cs.length(); 2288 final int csLast = csLen - 1; 2289 final int searchLen = searchChars.length; 2290 final int searchLast = searchLen - 1; 2291 outer: 2292 for (int i = 0; i < csLen; i++) { 2293 final char ch = cs.charAt(i); 2294 for (int j = 0; j < searchLen; j++) { 2295 if (searchChars[j] == ch) { 2296 if (i < csLast && j < searchLast && Character.isHighSurrogate(ch)) { 2297 if (searchChars[j + 1] == cs.charAt(i + 1)) { 2298 continue outer; 2299 } 2300 } else { 2301 continue outer; 2302 } 2303 } 2304 } 2305 return i; 2306 } 2307 return INDEX_NOT_FOUND; 2308 } 2309 2310 /** 2311 * <p>Search a CharSequence to find the first index of any 2312 * character not in the given set of characters.</p> 2313 * 2314 * <p>A {@code null} CharSequence will return {@code -1}. 2315 * A {@code null} or empty search string will return {@code -1}.</p> 2316 * 2317 * <pre> 2318 * StringUtils.indexOfAnyBut(null, *) = -1 2319 * StringUtils.indexOfAnyBut("", *) = -1 2320 * StringUtils.indexOfAnyBut(*, null) = -1 2321 * StringUtils.indexOfAnyBut(*, "") = -1 2322 * StringUtils.indexOfAnyBut("zzabyycdxx", "za") = 3 2323 * StringUtils.indexOfAnyBut("zzabyycdxx", "") = -1 2324 * StringUtils.indexOfAnyBut("aba","ab") = -1 2325 * </pre> 2326 * 2327 * @param seq the CharSequence to check, may be null 2328 * @param searchChars the chars to search for, may be null 2329 * @return the index of any of the chars, -1 if no match or null input 2330 * @since 2.0 2331 * @since 3.0 Changed signature from indexOfAnyBut(String, String) to indexOfAnyBut(CharSequence, CharSequence) 2332 */ 2333 public static int indexOfAnyBut(final CharSequence seq, final CharSequence searchChars) { 2334 if (isEmpty(seq) || isEmpty(searchChars)) { 2335 return INDEX_NOT_FOUND; 2336 } 2337 final int strLen = seq.length(); 2338 for (int i = 0; i < strLen; i++) { 2339 final char ch = seq.charAt(i); 2340 final boolean chFound = CharSequenceUtils.indexOf(searchChars, ch, 0) >= 0; 2341 if (i + 1 < strLen && Character.isHighSurrogate(ch)) { 2342 final char ch2 = seq.charAt(i + 1); 2343 if (chFound && CharSequenceUtils.indexOf(searchChars, ch2, 0) < 0) { 2344 return i; 2345 } 2346 } else { 2347 if (!chFound) { 2348 return i; 2349 } 2350 } 2351 } 2352 return INDEX_NOT_FOUND; 2353 } 2354 2355 // ContainsOnly 2356 //----------------------------------------------------------------------- 2357 /** 2358 * <p>Checks if the CharSequence contains only certain characters.</p> 2359 * 2360 * <p>A {@code null} CharSequence will return {@code false}. 2361 * A {@code null} valid character array will return {@code false}. 2362 * An empty CharSequence (length()=0) always returns {@code true}.</p> 2363 * 2364 * <pre> 2365 * StringUtils.containsOnly(null, *) = false 2366 * StringUtils.containsOnly(*, null) = false 2367 * StringUtils.containsOnly("", *) = true 2368 * StringUtils.containsOnly("ab", '') = false 2369 * StringUtils.containsOnly("abab", 'abc') = true 2370 * StringUtils.containsOnly("ab1", 'abc') = false 2371 * StringUtils.containsOnly("abz", 'abc') = false 2372 * </pre> 2373 * 2374 * @param cs the String to check, may be null 2375 * @param valid an array of valid chars, may be null 2376 * @return true if it only contains valid chars and is non-null 2377 * @since 3.0 Changed signature from containsOnly(String, char[]) to containsOnly(CharSequence, char...) 2378 */ 2379 public static boolean containsOnly(final CharSequence cs, final char... valid) { 2380 // All these pre-checks are to maintain API with an older version 2381 if (valid == null || cs == null) { 2382 return false; 2383 } 2384 if (cs.length() == 0) { 2385 return true; 2386 } 2387 if (valid.length == 0) { 2388 return false; 2389 } 2390 return indexOfAnyBut(cs, valid) == INDEX_NOT_FOUND; 2391 } 2392 2393 /** 2394 * <p>Checks if the CharSequence contains only certain characters.</p> 2395 * 2396 * <p>A {@code null} CharSequence will return {@code false}. 2397 * A {@code null} valid character String will return {@code false}. 2398 * An empty String (length()=0) always returns {@code true}.</p> 2399 * 2400 * <pre> 2401 * StringUtils.containsOnly(null, *) = false 2402 * StringUtils.containsOnly(*, null) = false 2403 * StringUtils.containsOnly("", *) = true 2404 * StringUtils.containsOnly("ab", "") = false 2405 * StringUtils.containsOnly("abab", "abc") = true 2406 * StringUtils.containsOnly("ab1", "abc") = false 2407 * StringUtils.containsOnly("abz", "abc") = false 2408 * </pre> 2409 * 2410 * @param cs the CharSequence to check, may be null 2411 * @param validChars a String of valid chars, may be null 2412 * @return true if it only contains valid chars and is non-null 2413 * @since 2.0 2414 * @since 3.0 Changed signature from containsOnly(String, String) to containsOnly(CharSequence, String) 2415 */ 2416 public static boolean containsOnly(final CharSequence cs, final String validChars) { 2417 if (cs == null || validChars == null) { 2418 return false; 2419 } 2420 return containsOnly(cs, validChars.toCharArray()); 2421 } 2422 2423 // ContainsNone 2424 //----------------------------------------------------------------------- 2425 /** 2426 * <p>Checks that the CharSequence does not contain certain characters.</p> 2427 * 2428 * <p>A {@code null} CharSequence will return {@code true}. 2429 * A {@code null} invalid character array will return {@code true}. 2430 * An empty CharSequence (length()=0) always returns true.</p> 2431 * 2432 * <pre> 2433 * StringUtils.containsNone(null, *) = true 2434 * StringUtils.containsNone(*, null) = true 2435 * StringUtils.containsNone("", *) = true 2436 * StringUtils.containsNone("ab", '') = true 2437 * StringUtils.containsNone("abab", 'xyz') = true 2438 * StringUtils.containsNone("ab1", 'xyz') = true 2439 * StringUtils.containsNone("abz", 'xyz') = false 2440 * </pre> 2441 * 2442 * @param cs the CharSequence to check, may be null 2443 * @param searchChars an array of invalid chars, may be null 2444 * @return true if it contains none of the invalid chars, or is null 2445 * @since 2.0 2446 * @since 3.0 Changed signature from containsNone(String, char[]) to containsNone(CharSequence, char...) 2447 */ 2448 public static boolean containsNone(final CharSequence cs, final char... searchChars) { 2449 if (cs == null || searchChars == null) { 2450 return true; 2451 } 2452 final int csLen = cs.length(); 2453 final int csLast = csLen - 1; 2454 final int searchLen = searchChars.length; 2455 final int searchLast = searchLen - 1; 2456 for (int i = 0; i < csLen; i++) { 2457 final char ch = cs.charAt(i); 2458 for (int j = 0; j < searchLen; j++) { 2459 if (searchChars[j] == ch) { 2460 if (Character.isHighSurrogate(ch)) { 2461 if (j == searchLast) { 2462 // missing low surrogate, fine, like String.indexOf(String) 2463 return false; 2464 } 2465 if (i < csLast && searchChars[j + 1] == cs.charAt(i + 1)) { 2466 return false; 2467 } 2468 } else { 2469 // ch is in the Basic Multilingual Plane 2470 return false; 2471 } 2472 } 2473 } 2474 } 2475 return true; 2476 } 2477 2478 /** 2479 * <p>Checks that the CharSequence does not contain certain characters.</p> 2480 * 2481 * <p>A {@code null} CharSequence will return {@code true}. 2482 * A {@code null} invalid character array will return {@code true}. 2483 * An empty String ("") always returns true.</p> 2484 * 2485 * <pre> 2486 * StringUtils.containsNone(null, *) = true 2487 * StringUtils.containsNone(*, null) = true 2488 * StringUtils.containsNone("", *) = true 2489 * StringUtils.containsNone("ab", "") = true 2490 * StringUtils.containsNone("abab", "xyz") = true 2491 * StringUtils.containsNone("ab1", "xyz") = true 2492 * StringUtils.containsNone("abz", "xyz") = false 2493 * </pre> 2494 * 2495 * @param cs the CharSequence to check, may be null 2496 * @param invalidChars a String of invalid chars, may be null 2497 * @return true if it contains none of the invalid chars, or is null 2498 * @since 2.0 2499 * @since 3.0 Changed signature from containsNone(String, String) to containsNone(CharSequence, String) 2500 */ 2501 public static boolean containsNone(final CharSequence cs, final String invalidChars) { 2502 if (cs == null || invalidChars == null) { 2503 return true; 2504 } 2505 return containsNone(cs, invalidChars.toCharArray()); 2506 } 2507 2508 // IndexOfAny strings 2509 //----------------------------------------------------------------------- 2510 /** 2511 * <p>Find the first index of any of a set of potential substrings.</p> 2512 * 2513 * <p>A {@code null} CharSequence will return {@code -1}. 2514 * A {@code null} or zero length search array will return {@code -1}. 2515 * A {@code null} search array entry will be ignored, but a search 2516 * array containing "" will return {@code 0} if {@code str} is not 2517 * null. This method uses {@link String#indexOf(String)} if possible.</p> 2518 * 2519 * <pre> 2520 * StringUtils.indexOfAny(null, *) = -1 2521 * StringUtils.indexOfAny(*, null) = -1 2522 * StringUtils.indexOfAny(*, []) = -1 2523 * StringUtils.indexOfAny("zzabyycdxx", ["ab","cd"]) = 2 2524 * StringUtils.indexOfAny("zzabyycdxx", ["cd","ab"]) = 2 2525 * StringUtils.indexOfAny("zzabyycdxx", ["mn","op"]) = -1 2526 * StringUtils.indexOfAny("zzabyycdxx", ["zab","aby"]) = 1 2527 * StringUtils.indexOfAny("zzabyycdxx", [""]) = 0 2528 * StringUtils.indexOfAny("", [""]) = 0 2529 * StringUtils.indexOfAny("", ["a"]) = -1 2530 * </pre> 2531 * 2532 * @param str the CharSequence to check, may be null 2533 * @param searchStrs the CharSequences to search for, may be null 2534 * @return the first index of any of the searchStrs in str, -1 if no match 2535 * @since 3.0 Changed signature from indexOfAny(String, String[]) to indexOfAny(CharSequence, CharSequence...) 2536 */ 2537 public static int indexOfAny(final CharSequence str, final CharSequence... searchStrs) { 2538 if (str == null || searchStrs == null) { 2539 return INDEX_NOT_FOUND; 2540 } 2541 2542 // String's can't have a MAX_VALUEth index. 2543 int ret = Integer.MAX_VALUE; 2544 2545 int tmp = 0; 2546 for (final CharSequence search : searchStrs) { 2547 if (search == null) { 2548 continue; 2549 } 2550 tmp = CharSequenceUtils.indexOf(str, search, 0); 2551 if (tmp == INDEX_NOT_FOUND) { 2552 continue; 2553 } 2554 2555 if (tmp < ret) { 2556 ret = tmp; 2557 } 2558 } 2559 2560 return ret == Integer.MAX_VALUE ? INDEX_NOT_FOUND : ret; 2561 } 2562 2563 /** 2564 * <p>Find the latest index of any of a set of potential substrings.</p> 2565 * 2566 * <p>A {@code null} CharSequence will return {@code -1}. 2567 * A {@code null} search array will return {@code -1}. 2568 * A {@code null} or zero length search array entry will be ignored, 2569 * but a search array containing "" will return the length of {@code str} 2570 * if {@code str} is not null. This method uses {@link String#indexOf(String)} if possible</p> 2571 * 2572 * <pre> 2573 * StringUtils.lastIndexOfAny(null, *) = -1 2574 * StringUtils.lastIndexOfAny(*, null) = -1 2575 * StringUtils.lastIndexOfAny(*, []) = -1 2576 * StringUtils.lastIndexOfAny(*, [null]) = -1 2577 * StringUtils.lastIndexOfAny("zzabyycdxx", ["ab","cd"]) = 6 2578 * StringUtils.lastIndexOfAny("zzabyycdxx", ["cd","ab"]) = 6 2579 * StringUtils.lastIndexOfAny("zzabyycdxx", ["mn","op"]) = -1 2580 * StringUtils.lastIndexOfAny("zzabyycdxx", ["mn","op"]) = -1 2581 * StringUtils.lastIndexOfAny("zzabyycdxx", ["mn",""]) = 10 2582 * </pre> 2583 * 2584 * @param str the CharSequence to check, may be null 2585 * @param searchStrs the CharSequences to search for, may be null 2586 * @return the last index of any of the CharSequences, -1 if no match 2587 * @since 3.0 Changed signature from lastIndexOfAny(String, String[]) to lastIndexOfAny(CharSequence, CharSequence) 2588 */ 2589 public static int lastIndexOfAny(final CharSequence str, final CharSequence... searchStrs) { 2590 if (str == null || searchStrs == null) { 2591 return INDEX_NOT_FOUND; 2592 } 2593 int ret = INDEX_NOT_FOUND; 2594 int tmp = 0; 2595 for (final CharSequence search : searchStrs) { 2596 if (search == null) { 2597 continue; 2598 } 2599 tmp = CharSequenceUtils.lastIndexOf(str, search, str.length()); 2600 if (tmp > ret) { 2601 ret = tmp; 2602 } 2603 } 2604 return ret; 2605 } 2606 2607 // Substring 2608 //----------------------------------------------------------------------- 2609 /** 2610 * <p>Gets a substring from the specified String avoiding exceptions.</p> 2611 * 2612 * <p>A negative start position can be used to start {@code n} 2613 * characters from the end of the String.</p> 2614 * 2615 * <p>A {@code null} String will return {@code null}. 2616 * An empty ("") String will return "".</p> 2617 * 2618 * <pre> 2619 * StringUtils.substring(null, *) = null 2620 * StringUtils.substring("", *) = "" 2621 * StringUtils.substring("abc", 0) = "abc" 2622 * StringUtils.substring("abc", 2) = "c" 2623 * StringUtils.substring("abc", 4) = "" 2624 * StringUtils.substring("abc", -2) = "bc" 2625 * StringUtils.substring("abc", -4) = "abc" 2626 * </pre> 2627 * 2628 * @param str the String to get the substring from, may be null 2629 * @param start the position to start from, negative means 2630 * count back from the end of the String by this many characters 2631 * @return substring from start position, {@code null} if null String input 2632 */ 2633 public static String substring(final String str, int start) { 2634 if (str == null) { 2635 return null; 2636 } 2637 2638 // handle negatives, which means last n characters 2639 if (start < 0) { 2640 start = str.length() + start; // remember start is negative 2641 } 2642 2643 if (start < 0) { 2644 start = 0; 2645 } 2646 if (start > str.length()) { 2647 return EMPTY; 2648 } 2649 2650 return str.substring(start); 2651 } 2652 2653 /** 2654 * <p>Gets a substring from the specified String avoiding exceptions.</p> 2655 * 2656 * <p>A negative start position can be used to start/end {@code n} 2657 * characters from the end of the String.</p> 2658 * 2659 * <p>The returned substring starts with the character in the {@code start} 2660 * position and ends before the {@code end} position. All position counting is 2661 * zero-based -- i.e., to start at the beginning of the string use 2662 * {@code start = 0}. Negative start and end positions can be used to 2663 * specify offsets relative to the end of the String.</p> 2664 * 2665 * <p>If {@code start} is not strictly to the left of {@code end}, "" 2666 * is returned.</p> 2667 * 2668 * <pre> 2669 * StringUtils.substring(null, *, *) = null 2670 * StringUtils.substring("", * , *) = ""; 2671 * StringUtils.substring("abc", 0, 2) = "ab" 2672 * StringUtils.substring("abc", 2, 0) = "" 2673 * StringUtils.substring("abc", 2, 4) = "c" 2674 * StringUtils.substring("abc", 4, 6) = "" 2675 * StringUtils.substring("abc", 2, 2) = "" 2676 * StringUtils.substring("abc", -2, -1) = "b" 2677 * StringUtils.substring("abc", -4, 2) = "ab" 2678 * </pre> 2679 * 2680 * @param str the String to get the substring from, may be null 2681 * @param start the position to start from, negative means 2682 * count back from the end of the String by this many characters 2683 * @param end the position to end at (exclusive), negative means 2684 * count back from the end of the String by this many characters 2685 * @return substring from start position to end position, 2686 * {@code null} if null String input 2687 */ 2688 public static String substring(final String str, int start, int end) { 2689 if (str == null) { 2690 return null; 2691 } 2692 2693 // handle negatives 2694 if (end < 0) { 2695 end = str.length() + end; // remember end is negative 2696 } 2697 if (start < 0) { 2698 start = str.length() + start; // remember start is negative 2699 } 2700 2701 // check length next 2702 if (end > str.length()) { 2703 end = str.length(); 2704 } 2705 2706 // if start is greater than end, return "" 2707 if (start > end) { 2708 return EMPTY; 2709 } 2710 2711 if (start < 0) { 2712 start = 0; 2713 } 2714 if (end < 0) { 2715 end = 0; 2716 } 2717 2718 return str.substring(start, end); 2719 } 2720 2721 // Left/Right/Mid 2722 //----------------------------------------------------------------------- 2723 /** 2724 * <p>Gets the leftmost {@code len} characters of a String.</p> 2725 * 2726 * <p>If {@code len} characters are not available, or the 2727 * String is {@code null}, the String will be returned without 2728 * an exception. An empty String is returned if len is negative.</p> 2729 * 2730 * <pre> 2731 * StringUtils.left(null, *) = null 2732 * StringUtils.left(*, -ve) = "" 2733 * StringUtils.left("", *) = "" 2734 * StringUtils.left("abc", 0) = "" 2735 * StringUtils.left("abc", 2) = "ab" 2736 * StringUtils.left("abc", 4) = "abc" 2737 * </pre> 2738 * 2739 * @param str the String to get the leftmost characters from, may be null 2740 * @param len the length of the required String 2741 * @return the leftmost characters, {@code null} if null String input 2742 */ 2743 public static String left(final String str, final int len) { 2744 if (str == null) { 2745 return null; 2746 } 2747 if (len < 0) { 2748 return EMPTY; 2749 } 2750 if (str.length() <= len) { 2751 return str; 2752 } 2753 return str.substring(0, len); 2754 } 2755 2756 /** 2757 * <p>Gets the rightmost {@code len} characters of a String.</p> 2758 * 2759 * <p>If {@code len} characters are not available, or the String 2760 * is {@code null}, the String will be returned without an 2761 * an exception. An empty String is returned if len is negative.</p> 2762 * 2763 * <pre> 2764 * StringUtils.right(null, *) = null 2765 * StringUtils.right(*, -ve) = "" 2766 * StringUtils.right("", *) = "" 2767 * StringUtils.right("abc", 0) = "" 2768 * StringUtils.right("abc", 2) = "bc" 2769 * StringUtils.right("abc", 4) = "abc" 2770 * </pre> 2771 * 2772 * @param str the String to get the rightmost characters from, may be null 2773 * @param len the length of the required String 2774 * @return the rightmost characters, {@code null} if null String input 2775 */ 2776 public static String right(final String str, final int len) { 2777 if (str == null) { 2778 return null; 2779 } 2780 if (len < 0) { 2781 return EMPTY; 2782 } 2783 if (str.length() <= len) { 2784 return str; 2785 } 2786 return str.substring(str.length() - len); 2787 } 2788 2789 /** 2790 * <p>Gets {@code len} characters from the middle of a String.</p> 2791 * 2792 * <p>If {@code len} characters are not available, the remainder 2793 * of the String will be returned without an exception. If the 2794 * String is {@code null}, {@code null} will be returned. 2795 * An empty String is returned if len is negative or exceeds the 2796 * length of {@code str}.</p> 2797 * 2798 * <pre> 2799 * StringUtils.mid(null, *, *) = null 2800 * StringUtils.mid(*, *, -ve) = "" 2801 * StringUtils.mid("", 0, *) = "" 2802 * StringUtils.mid("abc", 0, 2) = "ab" 2803 * StringUtils.mid("abc", 0, 4) = "abc" 2804 * StringUtils.mid("abc", 2, 4) = "c" 2805 * StringUtils.mid("abc", 4, 2) = "" 2806 * StringUtils.mid("abc", -2, 2) = "ab" 2807 * </pre> 2808 * 2809 * @param str the String to get the characters from, may be null 2810 * @param pos the position to start from, negative treated as zero 2811 * @param len the length of the required String 2812 * @return the middle characters, {@code null} if null String input 2813 */ 2814 public static String mid(final String str, int pos, final int len) { 2815 if (str == null) { 2816 return null; 2817 } 2818 if (len < 0 || pos > str.length()) { 2819 return EMPTY; 2820 } 2821 if (pos < 0) { 2822 pos = 0; 2823 } 2824 if (str.length() <= pos + len) { 2825 return str.substring(pos); 2826 } 2827 return str.substring(pos, pos + len); 2828 } 2829 2830 // SubStringAfter/SubStringBefore 2831 //----------------------------------------------------------------------- 2832 /** 2833 * <p>Gets the substring before the first occurrence of a separator. 2834 * The separator is not returned.</p> 2835 * 2836 * <p>A {@code null} string input will return {@code null}. 2837 * An empty ("") string input will return the empty string. 2838 * A {@code null} separator will return the input string.</p> 2839 * 2840 * <p>If nothing is found, the string input is returned.</p> 2841 * 2842 * <pre> 2843 * StringUtils.substringBefore(null, *) = null 2844 * StringUtils.substringBefore("", *) = "" 2845 * StringUtils.substringBefore("abc", "a") = "" 2846 * StringUtils.substringBefore("abcba", "b") = "a" 2847 * StringUtils.substringBefore("abc", "c") = "ab" 2848 * StringUtils.substringBefore("abc", "d") = "abc" 2849 * StringUtils.substringBefore("abc", "") = "" 2850 * StringUtils.substringBefore("abc", null) = "abc" 2851 * </pre> 2852 * 2853 * @param str the String to get a substring from, may be null 2854 * @param separator the String to search for, may be null 2855 * @return the substring before the first occurrence of the separator, 2856 * {@code null} if null String input 2857 * @since 2.0 2858 */ 2859 public static String substringBefore(final String str, final String separator) { 2860 if (isEmpty(str) || separator == null) { 2861 return str; 2862 } 2863 if (separator.isEmpty()) { 2864 return EMPTY; 2865 } 2866 final int pos = str.indexOf(separator); 2867 if (pos == INDEX_NOT_FOUND) { 2868 return str; 2869 } 2870 return str.substring(0, pos); 2871 } 2872 2873 /** 2874 * <p>Gets the substring after the first occurrence of a separator. 2875 * The separator is not returned.</p> 2876 * 2877 * <p>A {@code null} string input will return {@code null}. 2878 * An empty ("") string input will return the empty string. 2879 * A {@code null} separator will return the empty string if the 2880 * input string is not {@code null}.</p> 2881 * 2882 * <p>If nothing is found, the empty string is returned.</p> 2883 * 2884 * <pre> 2885 * StringUtils.substringAfter(null, *) = null 2886 * StringUtils.substringAfter("", *) = "" 2887 * StringUtils.substringAfter(*, null) = "" 2888 * StringUtils.substringAfter("abc", "a") = "bc" 2889 * StringUtils.substringAfter("abcba", "b") = "cba" 2890 * StringUtils.substringAfter("abc", "c") = "" 2891 * StringUtils.substringAfter("abc", "d") = "" 2892 * StringUtils.substringAfter("abc", "") = "abc" 2893 * </pre> 2894 * 2895 * @param str the String to get a substring from, may be null 2896 * @param separator the String to search for, may be null 2897 * @return the substring after the first occurrence of the separator, 2898 * {@code null} if null String input 2899 * @since 2.0 2900 */ 2901 public static String substringAfter(final String str, final String separator) { 2902 if (isEmpty(str)) { 2903 return str; 2904 } 2905 if (separator == null) { 2906 return EMPTY; 2907 } 2908 final int pos = str.indexOf(separator); 2909 if (pos == INDEX_NOT_FOUND) { 2910 return EMPTY; 2911 } 2912 return str.substring(pos + separator.length()); 2913 } 2914 2915 /** 2916 * <p>Gets the substring before the last occurrence of a separator. 2917 * The separator is not returned.</p> 2918 * 2919 * <p>A {@code null} string input will return {@code null}. 2920 * An empty ("") string input will return the empty string. 2921 * An empty or {@code null} separator will return the input string.</p> 2922 * 2923 * <p>If nothing is found, the string input is returned.</p> 2924 * 2925 * <pre> 2926 * StringUtils.substringBeforeLast(null, *) = null 2927 * StringUtils.substringBeforeLast("", *) = "" 2928 * StringUtils.substringBeforeLast("abcba", "b") = "abc" 2929 * StringUtils.substringBeforeLast("abc", "c") = "ab" 2930 * StringUtils.substringBeforeLast("a", "a") = "" 2931 * StringUtils.substringBeforeLast("a", "z") = "a" 2932 * StringUtils.substringBeforeLast("a", null) = "a" 2933 * StringUtils.substringBeforeLast("a", "") = "a" 2934 * </pre> 2935 * 2936 * @param str the String to get a substring from, may be null 2937 * @param separator the String to search for, may be null 2938 * @return the substring before the last occurrence of the separator, 2939 * {@code null} if null String input 2940 * @since 2.0 2941 */ 2942 public static String substringBeforeLast(final String str, final String separator) { 2943 if (isEmpty(str) || isEmpty(separator)) { 2944 return str; 2945 } 2946 final int pos = str.lastIndexOf(separator); 2947 if (pos == INDEX_NOT_FOUND) { 2948 return str; 2949 } 2950 return str.substring(0, pos); 2951 } 2952 2953 /** 2954 * <p>Gets the substring after the last occurrence of a separator. 2955 * The separator is not returned.</p> 2956 * 2957 * <p>A {@code null} string input will return {@code null}. 2958 * An empty ("") string input will return the empty string. 2959 * An empty or {@code null} separator will return the empty string if 2960 * the input string is not {@code null}.</p> 2961 * 2962 * <p>If nothing is found, the empty string is returned.</p> 2963 * 2964 * <pre> 2965 * StringUtils.substringAfterLast(null, *) = null 2966 * StringUtils.substringAfterLast("", *) = "" 2967 * StringUtils.substringAfterLast(*, "") = "" 2968 * StringUtils.substringAfterLast(*, null) = "" 2969 * StringUtils.substringAfterLast("abc", "a") = "bc" 2970 * StringUtils.substringAfterLast("abcba", "b") = "a" 2971 * StringUtils.substringAfterLast("abc", "c") = "" 2972 * StringUtils.substringAfterLast("a", "a") = "" 2973 * StringUtils.substringAfterLast("a", "z") = "" 2974 * </pre> 2975 * 2976 * @param str the String to get a substring from, may be null 2977 * @param separator the String to search for, may be null 2978 * @return the substring after the last occurrence of the separator, 2979 * {@code null} if null String input 2980 * @since 2.0 2981 */ 2982 public static String substringAfterLast(final String str, final String separator) { 2983 if (isEmpty(str)) { 2984 return str; 2985 } 2986 if (isEmpty(separator)) { 2987 return EMPTY; 2988 } 2989 final int pos = str.lastIndexOf(separator); 2990 if (pos == INDEX_NOT_FOUND || pos == str.length() - separator.length()) { 2991 return EMPTY; 2992 } 2993 return str.substring(pos + separator.length()); 2994 } 2995 2996 // Substring between 2997 //----------------------------------------------------------------------- 2998 /** 2999 * <p>Gets the String that is nested in between two instances of the 3000 * same String.</p> 3001 * 3002 * <p>A {@code null} input String returns {@code null}. 3003 * A {@code null} tag returns {@code null}.</p> 3004 * 3005 * <pre> 3006 * StringUtils.substringBetween(null, *) = null 3007 * StringUtils.substringBetween("", "") = "" 3008 * StringUtils.substringBetween("", "tag") = null 3009 * StringUtils.substringBetween("tagabctag", null) = null 3010 * StringUtils.substringBetween("tagabctag", "") = "" 3011 * StringUtils.substringBetween("tagabctag", "tag") = "abc" 3012 * </pre> 3013 * 3014 * @param str the String containing the substring, may be null 3015 * @param tag the String before and after the substring, may be null 3016 * @return the substring, {@code null} if no match 3017 * @since 2.0 3018 */ 3019 public static String substringBetween(final String str, final String tag) { 3020 return substringBetween(str, tag, tag); 3021 } 3022 3023 /** 3024 * <p>Gets the String that is nested in between two Strings. 3025 * Only the first match is returned.</p> 3026 * 3027 * <p>A {@code null} input String returns {@code null}. 3028 * A {@code null} open/close returns {@code null} (no match). 3029 * An empty ("") open and close returns an empty string.</p> 3030 * 3031 * <pre> 3032 * StringUtils.substringBetween("wx[b]yz", "[", "]") = "b" 3033 * StringUtils.substringBetween(null, *, *) = null 3034 * StringUtils.substringBetween(*, null, *) = null 3035 * StringUtils.substringBetween(*, *, null) = null 3036 * StringUtils.substringBetween("", "", "") = "" 3037 * StringUtils.substringBetween("", "", "]") = null 3038 * StringUtils.substringBetween("", "[", "]") = null 3039 * StringUtils.substringBetween("yabcz", "", "") = "" 3040 * StringUtils.substringBetween("yabcz", "y", "z") = "abc" 3041 * StringUtils.substringBetween("yabczyabcz", "y", "z") = "abc" 3042 * </pre> 3043 * 3044 * @param str the String containing the substring, may be null 3045 * @param open the String before the substring, may be null 3046 * @param close the String after the substring, may be null 3047 * @return the substring, {@code null} if no match 3048 * @since 2.0 3049 */ 3050 public static String substringBetween(final String str, final String open, final String close) { 3051 if (str == null || open == null || close == null) { 3052 return null; 3053 } 3054 final int start = str.indexOf(open); 3055 if (start != INDEX_NOT_FOUND) { 3056 final int end = str.indexOf(close, start + open.length()); 3057 if (end != INDEX_NOT_FOUND) { 3058 return str.substring(start + open.length(), end); 3059 } 3060 } 3061 return null; 3062 } 3063 3064 /** 3065 * <p>Searches a String for substrings delimited by a start and end tag, 3066 * returning all matching substrings in an array.</p> 3067 * 3068 * <p>A {@code null} input String returns {@code null}. 3069 * A {@code null} open/close returns {@code null} (no match). 3070 * An empty ("") open/close returns {@code null} (no match).</p> 3071 * 3072 * <pre> 3073 * StringUtils.substringsBetween("[a][b][c]", "[", "]") = ["a","b","c"] 3074 * StringUtils.substringsBetween(null, *, *) = null 3075 * StringUtils.substringsBetween(*, null, *) = null 3076 * StringUtils.substringsBetween(*, *, null) = null 3077 * StringUtils.substringsBetween("", "[", "]") = [] 3078 * </pre> 3079 * 3080 * @param str the String containing the substrings, null returns null, empty returns empty 3081 * @param open the String identifying the start of the substring, empty returns null 3082 * @param close the String identifying the end of the substring, empty returns null 3083 * @return a String Array of substrings, or {@code null} if no match 3084 * @since 2.3 3085 */ 3086 public static String[] substringsBetween(final String str, final String open, final String close) { 3087 if (str == null || isEmpty(open) || isEmpty(close)) { 3088 return null; 3089 } 3090 final int strLen = str.length(); 3091 if (strLen == 0) { 3092 return ArrayUtils.EMPTY_STRING_ARRAY; 3093 } 3094 final int closeLen = close.length(); 3095 final int openLen = open.length(); 3096 final List<String> list = new ArrayList<>(); 3097 int pos = 0; 3098 while (pos < strLen - closeLen) { 3099 int start = str.indexOf(open, pos); 3100 if (start < 0) { 3101 break; 3102 } 3103 start += openLen; 3104 final int end = str.indexOf(close, start); 3105 if (end < 0) { 3106 break; 3107 } 3108 list.add(str.substring(start, end)); 3109 pos = end + closeLen; 3110 } 3111 if (list.isEmpty()) { 3112 return null; 3113 } 3114 return list.toArray(new String [list.size()]); 3115 } 3116 3117 // Nested extraction 3118 //----------------------------------------------------------------------- 3119 3120 // Splitting 3121 //----------------------------------------------------------------------- 3122 /** 3123 * <p>Splits the provided text into an array, using whitespace as the 3124 * separator. 3125 * Whitespace is defined by {@link Character#isWhitespace(char)}.</p> 3126 * 3127 * <p>The separator is not included in the returned String array. 3128 * Adjacent separators are treated as one separator. 3129 * For more control over the split use the StrTokenizer class.</p> 3130 * 3131 * <p>A {@code null} input String returns {@code null}.</p> 3132 * 3133 * <pre> 3134 * StringUtils.split(null) = null 3135 * StringUtils.split("") = [] 3136 * StringUtils.split("abc def") = ["abc", "def"] 3137 * StringUtils.split("abc def") = ["abc", "def"] 3138 * StringUtils.split(" abc ") = ["abc"] 3139 * </pre> 3140 * 3141 * @param str the String to parse, may be null 3142 * @return an array of parsed Strings, {@code null} if null String input 3143 */ 3144 public static String[] split(final String str) { 3145 return split(str, null, -1); 3146 } 3147 3148 /** 3149 * <p>Splits the provided text into an array, separator specified. 3150 * This is an alternative to using StringTokenizer.</p> 3151 * 3152 * <p>The separator is not included in the returned String array. 3153 * Adjacent separators are treated as one separator. 3154 * For more control over the split use the StrTokenizer class.</p> 3155 * 3156 * <p>A {@code null} input String returns {@code null}.</p> 3157 * 3158 * <pre> 3159 * StringUtils.split(null, *) = null 3160 * StringUtils.split("", *) = [] 3161 * StringUtils.split("a.b.c", '.') = ["a", "b", "c"] 3162 * StringUtils.split("a..b.c", '.') = ["a", "b", "c"] 3163 * StringUtils.split("a:b:c", '.') = ["a:b:c"] 3164 * StringUtils.split("a b c", ' ') = ["a", "b", "c"] 3165 * </pre> 3166 * 3167 * @param str the String to parse, may be null 3168 * @param separatorChar the character used as the delimiter 3169 * @return an array of parsed Strings, {@code null} if null String input 3170 * @since 2.0 3171 */ 3172 public static String[] split(final String str, final char separatorChar) { 3173 return splitWorker(str, separatorChar, false); 3174 } 3175 3176 /** 3177 * <p>Splits the provided text into an array, separators specified. 3178 * This is an alternative to using StringTokenizer.</p> 3179 * 3180 * <p>The separator is not included in the returned String array. 3181 * Adjacent separators are treated as one separator. 3182 * For more control over the split use the StrTokenizer class.</p> 3183 * 3184 * <p>A {@code null} input String returns {@code null}. 3185 * A {@code null} separatorChars splits on whitespace.</p> 3186 * 3187 * <pre> 3188 * StringUtils.split(null, *) = null 3189 * StringUtils.split("", *) = [] 3190 * StringUtils.split("abc def", null) = ["abc", "def"] 3191 * StringUtils.split("abc def", " ") = ["abc", "def"] 3192 * StringUtils.split("abc def", " ") = ["abc", "def"] 3193 * StringUtils.split("ab:cd:ef", ":") = ["ab", "cd", "ef"] 3194 * </pre> 3195 * 3196 * @param str the String to parse, may be null 3197 * @param separatorChars the characters used as the delimiters, 3198 * {@code null} splits on whitespace 3199 * @return an array of parsed Strings, {@code null} if null String input 3200 */ 3201 public static String[] split(final String str, final String separatorChars) { 3202 return splitWorker(str, separatorChars, -1, false); 3203 } 3204 3205 /** 3206 * <p>Splits the provided text into an array with a maximum length, 3207 * separators specified.</p> 3208 * 3209 * <p>The separator is not included in the returned String array. 3210 * Adjacent separators are treated as one separator.</p> 3211 * 3212 * <p>A {@code null} input String returns {@code null}. 3213 * A {@code null} separatorChars splits on whitespace.</p> 3214 * 3215 * <p>If more than {@code max} delimited substrings are found, the last 3216 * returned string includes all characters after the first {@code max - 1} 3217 * returned strings (including separator characters).</p> 3218 * 3219 * <pre> 3220 * StringUtils.split(null, *, *) = null 3221 * StringUtils.split("", *, *) = [] 3222 * StringUtils.split("ab cd ef", null, 0) = ["ab", "cd", "ef"] 3223 * StringUtils.split("ab cd ef", null, 0) = ["ab", "cd", "ef"] 3224 * StringUtils.split("ab:cd:ef", ":", 0) = ["ab", "cd", "ef"] 3225 * StringUtils.split("ab:cd:ef", ":", 2) = ["ab", "cd:ef"] 3226 * </pre> 3227 * 3228 * @param str the String to parse, may be null 3229 * @param separatorChars the characters used as the delimiters, 3230 * {@code null} splits on whitespace 3231 * @param max the maximum number of elements to include in the 3232 * array. A zero or negative value implies no limit 3233 * @return an array of parsed Strings, {@code null} if null String input 3234 */ 3235 public static String[] split(final String str, final String separatorChars, final int max) { 3236 return splitWorker(str, separatorChars, max, false); 3237 } 3238 3239 /** 3240 * <p>Splits the provided text into an array, separator string specified.</p> 3241 * 3242 * <p>The separator(s) will not be included in the returned String array. 3243 * Adjacent separators are treated as one separator.</p> 3244 * 3245 * <p>A {@code null} input String returns {@code null}. 3246 * A {@code null} separator splits on whitespace.</p> 3247 * 3248 * <pre> 3249 * StringUtils.splitByWholeSeparator(null, *) = null 3250 * StringUtils.splitByWholeSeparator("", *) = [] 3251 * StringUtils.splitByWholeSeparator("ab de fg", null) = ["ab", "de", "fg"] 3252 * StringUtils.splitByWholeSeparator("ab de fg", null) = ["ab", "de", "fg"] 3253 * StringUtils.splitByWholeSeparator("ab:cd:ef", ":") = ["ab", "cd", "ef"] 3254 * StringUtils.splitByWholeSeparator("ab-!-cd-!-ef", "-!-") = ["ab", "cd", "ef"] 3255 * </pre> 3256 * 3257 * @param str the String to parse, may be null 3258 * @param separator String containing the String to be used as a delimiter, 3259 * {@code null} splits on whitespace 3260 * @return an array of parsed Strings, {@code null} if null String was input 3261 */ 3262 public static String[] splitByWholeSeparator(final String str, final String separator) { 3263 return splitByWholeSeparatorWorker( str, separator, -1, false ) ; 3264 } 3265 3266 /** 3267 * <p>Splits the provided text into an array, separator string specified. 3268 * Returns a maximum of {@code max} substrings.</p> 3269 * 3270 * <p>The separator(s) will not be included in the returned String array. 3271 * Adjacent separators are treated as one separator.</p> 3272 * 3273 * <p>A {@code null} input String returns {@code null}. 3274 * A {@code null} separator splits on whitespace.</p> 3275 * 3276 * <pre> 3277 * StringUtils.splitByWholeSeparator(null, *, *) = null 3278 * StringUtils.splitByWholeSeparator("", *, *) = [] 3279 * StringUtils.splitByWholeSeparator("ab de fg", null, 0) = ["ab", "de", "fg"] 3280 * StringUtils.splitByWholeSeparator("ab de fg", null, 0) = ["ab", "de", "fg"] 3281 * StringUtils.splitByWholeSeparator("ab:cd:ef", ":", 2) = ["ab", "cd:ef"] 3282 * StringUtils.splitByWholeSeparator("ab-!-cd-!-ef", "-!-", 5) = ["ab", "cd", "ef"] 3283 * StringUtils.splitByWholeSeparator("ab-!-cd-!-ef", "-!-", 2) = ["ab", "cd-!-ef"] 3284 * </pre> 3285 * 3286 * @param str the String to parse, may be null 3287 * @param separator String containing the String to be used as a delimiter, 3288 * {@code null} splits on whitespace 3289 * @param max the maximum number of elements to include in the returned 3290 * array. A zero or negative value implies no limit. 3291 * @return an array of parsed Strings, {@code null} if null String was input 3292 */ 3293 public static String[] splitByWholeSeparator( final String str, final String separator, final int max) { 3294 return splitByWholeSeparatorWorker(str, separator, max, false); 3295 } 3296 3297 /** 3298 * <p>Splits the provided text into an array, separator string specified. </p> 3299 * 3300 * <p>The separator is not included in the returned String array. 3301 * Adjacent separators are treated as separators for empty tokens. 3302 * For more control over the split use the StrTokenizer class.</p> 3303 * 3304 * <p>A {@code null} input String returns {@code null}. 3305 * A {@code null} separator splits on whitespace.</p> 3306 * 3307 * <pre> 3308 * StringUtils.splitByWholeSeparatorPreserveAllTokens(null, *) = null 3309 * StringUtils.splitByWholeSeparatorPreserveAllTokens("", *) = [] 3310 * StringUtils.splitByWholeSeparatorPreserveAllTokens("ab de fg", null) = ["ab", "de", "fg"] 3311 * StringUtils.splitByWholeSeparatorPreserveAllTokens("ab de fg", null) = ["ab", "", "", "de", "fg"] 3312 * StringUtils.splitByWholeSeparatorPreserveAllTokens("ab:cd:ef", ":") = ["ab", "cd", "ef"] 3313 * StringUtils.splitByWholeSeparatorPreserveAllTokens("ab-!-cd-!-ef", "-!-") = ["ab", "cd", "ef"] 3314 * </pre> 3315 * 3316 * @param str the String to parse, may be null 3317 * @param separator String containing the String to be used as a delimiter, 3318 * {@code null} splits on whitespace 3319 * @return an array of parsed Strings, {@code null} if null String was input 3320 * @since 2.4 3321 */ 3322 public static String[] splitByWholeSeparatorPreserveAllTokens(final String str, final String separator) { 3323 return splitByWholeSeparatorWorker(str, separator, -1, true); 3324 } 3325 3326 /** 3327 * <p>Splits the provided text into an array, separator string specified. 3328 * Returns a maximum of {@code max} substrings.</p> 3329 * 3330 * <p>The separator is not included in the returned String array. 3331 * Adjacent separators are treated as separators for empty tokens. 3332 * For more control over the split use the StrTokenizer class.</p> 3333 * 3334 * <p>A {@code null} input String returns {@code null}. 3335 * A {@code null} separator splits on whitespace.</p> 3336 * 3337 * <pre> 3338 * StringUtils.splitByWholeSeparatorPreserveAllTokens(null, *, *) = null 3339 * StringUtils.splitByWholeSeparatorPreserveAllTokens("", *, *) = [] 3340 * StringUtils.splitByWholeSeparatorPreserveAllTokens("ab de fg", null, 0) = ["ab", "de", "fg"] 3341 * StringUtils.splitByWholeSeparatorPreserveAllTokens("ab de fg", null, 0) = ["ab", "", "", "de", "fg"] 3342 * StringUtils.splitByWholeSeparatorPreserveAllTokens("ab:cd:ef", ":", 2) = ["ab", "cd:ef"] 3343 * StringUtils.splitByWholeSeparatorPreserveAllTokens("ab-!-cd-!-ef", "-!-", 5) = ["ab", "cd", "ef"] 3344 * StringUtils.splitByWholeSeparatorPreserveAllTokens("ab-!-cd-!-ef", "-!-", 2) = ["ab", "cd-!-ef"] 3345 * </pre> 3346 * 3347 * @param str the String to parse, may be null 3348 * @param separator String containing the String to be used as a delimiter, 3349 * {@code null} splits on whitespace 3350 * @param max the maximum number of elements to include in the returned 3351 * array. A zero or negative value implies no limit. 3352 * @return an array of parsed Strings, {@code null} if null String was input 3353 * @since 2.4 3354 */ 3355 public static String[] splitByWholeSeparatorPreserveAllTokens(final String str, final String separator, final int max) { 3356 return splitByWholeSeparatorWorker(str, separator, max, true); 3357 } 3358 3359 /** 3360 * Performs the logic for the {@code splitByWholeSeparatorPreserveAllTokens} methods. 3361 * 3362 * @param str the String to parse, may be {@code null} 3363 * @param separator String containing the String to be used as a delimiter, 3364 * {@code null} splits on whitespace 3365 * @param max the maximum number of elements to include in the returned 3366 * array. A zero or negative value implies no limit. 3367 * @param preserveAllTokens if {@code true}, adjacent separators are 3368 * treated as empty token separators; if {@code false}, adjacent 3369 * separators are treated as one separator. 3370 * @return an array of parsed Strings, {@code null} if null String input 3371 * @since 2.4 3372 */ 3373 private static String[] splitByWholeSeparatorWorker( 3374 final String str, final String separator, final int max, final boolean preserveAllTokens) { 3375 if (str == null) { 3376 return null; 3377 } 3378 3379 final int len = str.length(); 3380 3381 if (len == 0) { 3382 return ArrayUtils.EMPTY_STRING_ARRAY; 3383 } 3384 3385 if (separator == null || EMPTY.equals(separator)) { 3386 // Split on whitespace. 3387 return splitWorker(str, null, max, preserveAllTokens); 3388 } 3389 3390 final int separatorLength = separator.length(); 3391 3392 final ArrayList<String> substrings = new ArrayList<>(); 3393 int numberOfSubstrings = 0; 3394 int beg = 0; 3395 int end = 0; 3396 while (end < len) { 3397 end = str.indexOf(separator, beg); 3398 3399 if (end > -1) { 3400 if (end > beg) { 3401 numberOfSubstrings += 1; 3402 3403 if (numberOfSubstrings == max) { 3404 end = len; 3405 substrings.add(str.substring(beg)); 3406 } else { 3407 // The following is OK, because String.substring( beg, end ) excludes 3408 // the character at the position 'end'. 3409 substrings.add(str.substring(beg, end)); 3410 3411 // Set the starting point for the next search. 3412 // The following is equivalent to beg = end + (separatorLength - 1) + 1, 3413 // which is the right calculation: 3414 beg = end + separatorLength; 3415 } 3416 } else { 3417 // We found a consecutive occurrence of the separator, so skip it. 3418 if (preserveAllTokens) { 3419 numberOfSubstrings += 1; 3420 if (numberOfSubstrings == max) { 3421 end = len; 3422 substrings.add(str.substring(beg)); 3423 } else { 3424 substrings.add(EMPTY); 3425 } 3426 } 3427 beg = end + separatorLength; 3428 } 3429 } else { 3430 // String.substring( beg ) goes from 'beg' to the end of the String. 3431 substrings.add(str.substring(beg)); 3432 end = len; 3433 } 3434 } 3435 3436 return substrings.toArray(new String[substrings.size()]); 3437 } 3438 3439 // ----------------------------------------------------------------------- 3440 /** 3441 * <p>Splits the provided text into an array, using whitespace as the 3442 * separator, preserving all tokens, including empty tokens created by 3443 * adjacent separators. This is an alternative to using StringTokenizer. 3444 * Whitespace is defined by {@link Character#isWhitespace(char)}.</p> 3445 * 3446 * <p>The separator is not included in the returned String array. 3447 * Adjacent separators are treated as separators for empty tokens. 3448 * For more control over the split use the StrTokenizer class.</p> 3449 * 3450 * <p>A {@code null} input String returns {@code null}.</p> 3451 * 3452 * <pre> 3453 * StringUtils.splitPreserveAllTokens(null) = null 3454 * StringUtils.splitPreserveAllTokens("") = [] 3455 * StringUtils.splitPreserveAllTokens("abc def") = ["abc", "def"] 3456 * StringUtils.splitPreserveAllTokens("abc def") = ["abc", "", "def"] 3457 * StringUtils.splitPreserveAllTokens(" abc ") = ["", "abc", ""] 3458 * </pre> 3459 * 3460 * @param str the String to parse, may be {@code null} 3461 * @return an array of parsed Strings, {@code null} if null String input 3462 * @since 2.1 3463 */ 3464 public static String[] splitPreserveAllTokens(final String str) { 3465 return splitWorker(str, null, -1, true); 3466 } 3467 3468 /** 3469 * <p>Splits the provided text into an array, separator specified, 3470 * preserving all tokens, including empty tokens created by adjacent 3471 * separators. This is an alternative to using StringTokenizer.</p> 3472 * 3473 * <p>The separator is not included in the returned String array. 3474 * Adjacent separators are treated as separators for empty tokens. 3475 * For more control over the split use the StrTokenizer class.</p> 3476 * 3477 * <p>A {@code null} input String returns {@code null}.</p> 3478 * 3479 * <pre> 3480 * StringUtils.splitPreserveAllTokens(null, *) = null 3481 * StringUtils.splitPreserveAllTokens("", *) = [] 3482 * StringUtils.splitPreserveAllTokens("a.b.c", '.') = ["a", "b", "c"] 3483 * StringUtils.splitPreserveAllTokens("a..b.c", '.') = ["a", "", "b", "c"] 3484 * StringUtils.splitPreserveAllTokens("a:b:c", '.') = ["a:b:c"] 3485 * StringUtils.splitPreserveAllTokens("a\tb\nc", null) = ["a", "b", "c"] 3486 * StringUtils.splitPreserveAllTokens("a b c", ' ') = ["a", "b", "c"] 3487 * StringUtils.splitPreserveAllTokens("a b c ", ' ') = ["a", "b", "c", ""] 3488 * StringUtils.splitPreserveAllTokens("a b c ", ' ') = ["a", "b", "c", "", ""] 3489 * StringUtils.splitPreserveAllTokens(" a b c", ' ') = ["", a", "b", "c"] 3490 * StringUtils.splitPreserveAllTokens(" a b c", ' ') = ["", "", a", "b", "c"] 3491 * StringUtils.splitPreserveAllTokens(" a b c ", ' ') = ["", a", "b", "c", ""] 3492 * </pre> 3493 * 3494 * @param str the String to parse, may be {@code null} 3495 * @param separatorChar the character used as the delimiter, 3496 * {@code null} splits on whitespace 3497 * @return an array of parsed Strings, {@code null} if null String input 3498 * @since 2.1 3499 */ 3500 public static String[] splitPreserveAllTokens(final String str, final char separatorChar) { 3501 return splitWorker(str, separatorChar, true); 3502 } 3503 3504 /** 3505 * Performs the logic for the {@code split} and 3506 * {@code splitPreserveAllTokens} methods that do not return a 3507 * maximum array length. 3508 * 3509 * @param str the String to parse, may be {@code null} 3510 * @param separatorChar the separate character 3511 * @param preserveAllTokens if {@code true}, adjacent separators are 3512 * treated as empty token separators; if {@code false}, adjacent 3513 * separators are treated as one separator. 3514 * @return an array of parsed Strings, {@code null} if null String input 3515 */ 3516 private static String[] splitWorker(final String str, final char separatorChar, final boolean preserveAllTokens) { 3517 // Performance tuned for 2.0 (JDK1.4) 3518 3519 if (str == null) { 3520 return null; 3521 } 3522 final int len = str.length(); 3523 if (len == 0) { 3524 return ArrayUtils.EMPTY_STRING_ARRAY; 3525 } 3526 final List<String> list = new ArrayList<>(); 3527 int i = 0, start = 0; 3528 boolean match = false; 3529 boolean lastMatch = false; 3530 while (i < len) { 3531 if (str.charAt(i) == separatorChar) { 3532 if (match || preserveAllTokens) { 3533 list.add(str.substring(start, i)); 3534 match = false; 3535 lastMatch = true; 3536 } 3537 start = ++i; 3538 continue; 3539 } 3540 lastMatch = false; 3541 match = true; 3542 i++; 3543 } 3544 if (match || preserveAllTokens && lastMatch) { 3545 list.add(str.substring(start, i)); 3546 } 3547 return list.toArray(new String[list.size()]); 3548 } 3549 3550 /** 3551 * <p>Splits the provided text into an array, separators specified, 3552 * preserving all tokens, including empty tokens created by adjacent 3553 * separators. This is an alternative to using StringTokenizer.</p> 3554 * 3555 * <p>The separator is not included in the returned String array. 3556 * Adjacent separators are treated as separators for empty tokens. 3557 * For more control over the split use the StrTokenizer class.</p> 3558 * 3559 * <p>A {@code null} input String returns {@code null}. 3560 * A {@code null} separatorChars splits on whitespace.</p> 3561 * 3562 * <pre> 3563 * StringUtils.splitPreserveAllTokens(null, *) = null 3564 * StringUtils.splitPreserveAllTokens("", *) = [] 3565 * StringUtils.splitPreserveAllTokens("abc def", null) = ["abc", "def"] 3566 * StringUtils.splitPreserveAllTokens("abc def", " ") = ["abc", "def"] 3567 * StringUtils.splitPreserveAllTokens("abc def", " ") = ["abc", "", def"] 3568 * StringUtils.splitPreserveAllTokens("ab:cd:ef", ":") = ["ab", "cd", "ef"] 3569 * StringUtils.splitPreserveAllTokens("ab:cd:ef:", ":") = ["ab", "cd", "ef", ""] 3570 * StringUtils.splitPreserveAllTokens("ab:cd:ef::", ":") = ["ab", "cd", "ef", "", ""] 3571 * StringUtils.splitPreserveAllTokens("ab::cd:ef", ":") = ["ab", "", cd", "ef"] 3572 * StringUtils.splitPreserveAllTokens(":cd:ef", ":") = ["", cd", "ef"] 3573 * StringUtils.splitPreserveAllTokens("::cd:ef", ":") = ["", "", cd", "ef"] 3574 * StringUtils.splitPreserveAllTokens(":cd:ef:", ":") = ["", cd", "ef", ""] 3575 * </pre> 3576 * 3577 * @param str the String to parse, may be {@code null} 3578 * @param separatorChars the characters used as the delimiters, 3579 * {@code null} splits on whitespace 3580 * @return an array of parsed Strings, {@code null} if null String input 3581 * @since 2.1 3582 */ 3583 public static String[] splitPreserveAllTokens(final String str, final String separatorChars) { 3584 return splitWorker(str, separatorChars, -1, true); 3585 } 3586 3587 /** 3588 * <p>Splits the provided text into an array with a maximum length, 3589 * separators specified, preserving all tokens, including empty tokens 3590 * created by adjacent separators.</p> 3591 * 3592 * <p>The separator is not included in the returned String array. 3593 * Adjacent separators are treated as separators for empty tokens. 3594 * Adjacent separators are treated as one separator.</p> 3595 * 3596 * <p>A {@code null} input String returns {@code null}. 3597 * A {@code null} separatorChars splits on whitespace.</p> 3598 * 3599 * <p>If more than {@code max} delimited substrings are found, the last 3600 * returned string includes all characters after the first {@code max - 1} 3601 * returned strings (including separator characters).</p> 3602 * 3603 * <pre> 3604 * StringUtils.splitPreserveAllTokens(null, *, *) = null 3605 * StringUtils.splitPreserveAllTokens("", *, *) = [] 3606 * StringUtils.splitPreserveAllTokens("ab de fg", null, 0) = ["ab", "cd", "ef"] 3607 * StringUtils.splitPreserveAllTokens("ab de fg", null, 0) = ["ab", "cd", "ef"] 3608 * StringUtils.splitPreserveAllTokens("ab:cd:ef", ":", 0) = ["ab", "cd", "ef"] 3609 * StringUtils.splitPreserveAllTokens("ab:cd:ef", ":", 2) = ["ab", "cd:ef"] 3610 * StringUtils.splitPreserveAllTokens("ab de fg", null, 2) = ["ab", " de fg"] 3611 * StringUtils.splitPreserveAllTokens("ab de fg", null, 3) = ["ab", "", " de fg"] 3612 * StringUtils.splitPreserveAllTokens("ab de fg", null, 4) = ["ab", "", "", "de fg"] 3613 * </pre> 3614 * 3615 * @param str the String to parse, may be {@code null} 3616 * @param separatorChars the characters used as the delimiters, 3617 * {@code null} splits on whitespace 3618 * @param max the maximum number of elements to include in the 3619 * array. A zero or negative value implies no limit 3620 * @return an array of parsed Strings, {@code null} if null String input 3621 * @since 2.1 3622 */ 3623 public static String[] splitPreserveAllTokens(final String str, final String separatorChars, final int max) { 3624 return splitWorker(str, separatorChars, max, true); 3625 } 3626 3627 /** 3628 * Performs the logic for the {@code split} and 3629 * {@code splitPreserveAllTokens} methods that return a maximum array 3630 * length. 3631 * 3632 * @param str the String to parse, may be {@code null} 3633 * @param separatorChars the separate character 3634 * @param max the maximum number of elements to include in the 3635 * array. A zero or negative value implies no limit. 3636 * @param preserveAllTokens if {@code true}, adjacent separators are 3637 * treated as empty token separators; if {@code false}, adjacent 3638 * separators are treated as one separator. 3639 * @return an array of parsed Strings, {@code null} if null String input 3640 */ 3641 private static String[] splitWorker(final String str, final String separatorChars, final int max, final boolean preserveAllTokens) { 3642 // Performance tuned for 2.0 (JDK1.4) 3643 // Direct code is quicker than StringTokenizer. 3644 // Also, StringTokenizer uses isSpace() not isWhitespace() 3645 3646 if (str == null) { 3647 return null; 3648 } 3649 final int len = str.length(); 3650 if (len == 0) { 3651 return ArrayUtils.EMPTY_STRING_ARRAY; 3652 } 3653 final List<String> list = new ArrayList<>(); 3654 int sizePlus1 = 1; 3655 int i = 0, start = 0; 3656 boolean match = false; 3657 boolean lastMatch = false; 3658 if (separatorChars == null) { 3659 // Null separator means use whitespace 3660 while (i < len) { 3661 if (Character.isWhitespace(str.charAt(i))) { 3662 if (match || preserveAllTokens) { 3663 lastMatch = true; 3664 if (sizePlus1++ == max) { 3665 i = len; 3666 lastMatch = false; 3667 } 3668 list.add(str.substring(start, i)); 3669 match = false; 3670 } 3671 start = ++i; 3672 continue; 3673 } 3674 lastMatch = false; 3675 match = true; 3676 i++; 3677 } 3678 } else if (separatorChars.length() == 1) { 3679 // Optimise 1 character case 3680 final char sep = separatorChars.charAt(0); 3681 while (i < len) { 3682 if (str.charAt(i) == sep) { 3683 if (match || preserveAllTokens) { 3684 lastMatch = true; 3685 if (sizePlus1++ == max) { 3686 i = len; 3687 lastMatch = false; 3688 } 3689 list.add(str.substring(start, i)); 3690 match = false; 3691 } 3692 start = ++i; 3693 continue; 3694 } 3695 lastMatch = false; 3696 match = true; 3697 i++; 3698 } 3699 } else { 3700 // standard case 3701 while (i < len) { 3702 if (separatorChars.indexOf(str.charAt(i)) >= 0) { 3703 if (match || preserveAllTokens) { 3704 lastMatch = true; 3705 if (sizePlus1++ == max) { 3706 i = len; 3707 lastMatch = false; 3708 } 3709 list.add(str.substring(start, i)); 3710 match = false; 3711 } 3712 start = ++i; 3713 continue; 3714 } 3715 lastMatch = false; 3716 match = true; 3717 i++; 3718 } 3719 } 3720 if (match || preserveAllTokens && lastMatch) { 3721 list.add(str.substring(start, i)); 3722 } 3723 return list.toArray(new String[list.size()]); 3724 } 3725 3726 /** 3727 * <p>Splits a String by Character type as returned by 3728 * {@code java.lang.Character.getType(char)}. Groups of contiguous 3729 * characters of the same type are returned as complete tokens. 3730 * <pre> 3731 * StringUtils.splitByCharacterType(null) = null 3732 * StringUtils.splitByCharacterType("") = [] 3733 * StringUtils.splitByCharacterType("ab de fg") = ["ab", " ", "de", " ", "fg"] 3734 * StringUtils.splitByCharacterType("ab de fg") = ["ab", " ", "de", " ", "fg"] 3735 * StringUtils.splitByCharacterType("ab:cd:ef") = ["ab", ":", "cd", ":", "ef"] 3736 * StringUtils.splitByCharacterType("number5") = ["number", "5"] 3737 * StringUtils.splitByCharacterType("fooBar") = ["foo", "B", "ar"] 3738 * StringUtils.splitByCharacterType("foo200Bar") = ["foo", "200", "B", "ar"] 3739 * StringUtils.splitByCharacterType("ASFRules") = ["ASFR", "ules"] 3740 * </pre> 3741 * @param str the String to split, may be {@code null} 3742 * @return an array of parsed Strings, {@code null} if null String input 3743 * @since 2.4 3744 */ 3745 public static String[] splitByCharacterType(final String str) { 3746 return splitByCharacterType(str, false); 3747 } 3748 3749 /** 3750 * <p>Splits a String by Character type as returned by 3751 * {@code java.lang.Character.getType(char)}. Groups of contiguous 3752 * characters of the same type are returned as complete tokens, with the 3753 * following exception: the character of type 3754 * {@code Character.UPPERCASE_LETTER}, if any, immediately 3755 * preceding a token of type {@code Character.LOWERCASE_LETTER} 3756 * will belong to the following token rather than to the preceding, if any, 3757 * {@code Character.UPPERCASE_LETTER} token. 3758 * <pre> 3759 * StringUtils.splitByCharacterTypeCamelCase(null) = null 3760 * StringUtils.splitByCharacterTypeCamelCase("") = [] 3761 * StringUtils.splitByCharacterTypeCamelCase("ab de fg") = ["ab", " ", "de", " ", "fg"] 3762 * StringUtils.splitByCharacterTypeCamelCase("ab de fg") = ["ab", " ", "de", " ", "fg"] 3763 * StringUtils.splitByCharacterTypeCamelCase("ab:cd:ef") = ["ab", ":", "cd", ":", "ef"] 3764 * StringUtils.splitByCharacterTypeCamelCase("number5") = ["number", "5"] 3765 * StringUtils.splitByCharacterTypeCamelCase("fooBar") = ["foo", "Bar"] 3766 * StringUtils.splitByCharacterTypeCamelCase("foo200Bar") = ["foo", "200", "Bar"] 3767 * StringUtils.splitByCharacterTypeCamelCase("ASFRules") = ["ASF", "Rules"] 3768 * </pre> 3769 * @param str the String to split, may be {@code null} 3770 * @return an array of parsed Strings, {@code null} if null String input 3771 * @since 2.4 3772 */ 3773 public static String[] splitByCharacterTypeCamelCase(final String str) { 3774 return splitByCharacterType(str, true); 3775 } 3776 3777 /** 3778 * <p>Splits a String by Character type as returned by 3779 * {@code java.lang.Character.getType(char)}. Groups of contiguous 3780 * characters of the same type are returned as complete tokens, with the 3781 * following exception: if {@code camelCase} is {@code true}, 3782 * the character of type {@code Character.UPPERCASE_LETTER}, if any, 3783 * immediately preceding a token of type {@code Character.LOWERCASE_LETTER} 3784 * will belong to the following token rather than to the preceding, if any, 3785 * {@code Character.UPPERCASE_LETTER} token. 3786 * @param str the String to split, may be {@code null} 3787 * @param camelCase whether to use so-called "camel-case" for letter types 3788 * @return an array of parsed Strings, {@code null} if null String input 3789 * @since 2.4 3790 */ 3791 private static String[] splitByCharacterType(final String str, final boolean camelCase) { 3792 if (str == null) { 3793 return null; 3794 } 3795 if (str.isEmpty()) { 3796 return ArrayUtils.EMPTY_STRING_ARRAY; 3797 } 3798 final char[] c = str.toCharArray(); 3799 final List<String> list = new ArrayList<>(); 3800 int tokenStart = 0; 3801 int currentType = Character.getType(c[tokenStart]); 3802 for (int pos = tokenStart + 1; pos < c.length; pos++) { 3803 final int type = Character.getType(c[pos]); 3804 if (type == currentType) { 3805 continue; 3806 } 3807 if (camelCase && type == Character.LOWERCASE_LETTER && currentType == Character.UPPERCASE_LETTER) { 3808 final int newTokenStart = pos - 1; 3809 if (newTokenStart != tokenStart) { 3810 list.add(new String(c, tokenStart, newTokenStart - tokenStart)); 3811 tokenStart = newTokenStart; 3812 } 3813 } else { 3814 list.add(new String(c, tokenStart, pos - tokenStart)); 3815 tokenStart = pos; 3816 } 3817 currentType = type; 3818 } 3819 list.add(new String(c, tokenStart, c.length - tokenStart)); 3820 return list.toArray(new String[list.size()]); 3821 } 3822 3823 // Joining 3824 //----------------------------------------------------------------------- 3825 /** 3826 * <p>Joins the elements of the provided array into a single String 3827 * containing the provided list of elements.</p> 3828 * 3829 * <p>No separator is added to the joined String. 3830 * Null objects or empty strings within the array are represented by 3831 * empty strings.</p> 3832 * 3833 * <pre> 3834 * StringUtils.join(null) = null 3835 * StringUtils.join([]) = "" 3836 * StringUtils.join([null]) = "" 3837 * StringUtils.join(["a", "b", "c"]) = "abc" 3838 * StringUtils.join([null, "", "a"]) = "a" 3839 * </pre> 3840 * 3841 * @param <T> the specific type of values to join together 3842 * @param elements the values to join together, may be null 3843 * @return the joined String, {@code null} if null array input 3844 * @since 2.0 3845 * @since 3.0 Changed signature to use varargs 3846 */ 3847 @SafeVarargs 3848 public static <T> String join(final T... elements) { 3849 return join(elements, null); 3850 } 3851 3852 /** 3853 * <p>Joins the elements of the provided array into a single String 3854 * containing the provided list of elements.</p> 3855 * 3856 * <p>No delimiter is added before or after the list. 3857 * Null objects or empty strings within the array are represented by 3858 * empty strings.</p> 3859 * 3860 * <pre> 3861 * StringUtils.join(null, *) = null 3862 * StringUtils.join([], *) = "" 3863 * StringUtils.join([null], *) = "" 3864 * StringUtils.join(["a", "b", "c"], ';') = "a;b;c" 3865 * StringUtils.join(["a", "b", "c"], null) = "abc" 3866 * StringUtils.join([null, "", "a"], ';') = ";;a" 3867 * </pre> 3868 * 3869 * @param array the array of values to join together, may be null 3870 * @param separator the separator character to use 3871 * @return the joined String, {@code null} if null array input 3872 * @since 2.0 3873 */ 3874 public static String join(final Object[] array, final char separator) { 3875 if (array == null) { 3876 return null; 3877 } 3878 return join(array, separator, 0, array.length); 3879 } 3880 3881 /** 3882 * <p> 3883 * Joins the elements of the provided array into a single String containing the provided list of elements. 3884 * </p> 3885 * 3886 * <p> 3887 * No delimiter is added before or after the list. Null objects or empty strings within the array are represented 3888 * by empty strings. 3889 * </p> 3890 * 3891 * <pre> 3892 * StringUtils.join(null, *) = null 3893 * StringUtils.join([], *) = "" 3894 * StringUtils.join([null], *) = "" 3895 * StringUtils.join([1, 2, 3], ';') = "1;2;3" 3896 * StringUtils.join([1, 2, 3], null) = "123" 3897 * </pre> 3898 * 3899 * @param array 3900 * the array of values to join together, may be null 3901 * @param separator 3902 * the separator character to use 3903 * @return the joined String, {@code null} if null array input 3904 * @since 3.2 3905 */ 3906 public static String join(final long[] array, final char separator) { 3907 if (array == null) { 3908 return null; 3909 } 3910 return join(array, separator, 0, array.length); 3911 } 3912 3913 /** 3914 * <p> 3915 * Joins the elements of the provided array into a single String containing the provided list of elements. 3916 * </p> 3917 * 3918 * <p> 3919 * No delimiter is added before or after the list. Null objects or empty strings within the array are represented 3920 * by empty strings. 3921 * </p> 3922 * 3923 * <pre> 3924 * StringUtils.join(null, *) = null 3925 * StringUtils.join([], *) = "" 3926 * StringUtils.join([null], *) = "" 3927 * StringUtils.join([1, 2, 3], ';') = "1;2;3" 3928 * StringUtils.join([1, 2, 3], null) = "123" 3929 * </pre> 3930 * 3931 * @param array 3932 * the array of values to join together, may be null 3933 * @param separator 3934 * the separator character to use 3935 * @return the joined String, {@code null} if null array input 3936 * @since 3.2 3937 */ 3938 public static String join(final int[] array, final char separator) { 3939 if (array == null) { 3940 return null; 3941 } 3942 return join(array, separator, 0, array.length); 3943 } 3944 3945 /** 3946 * <p> 3947 * Joins the elements of the provided array into a single String containing the provided list of elements. 3948 * </p> 3949 * 3950 * <p> 3951 * No delimiter is added before or after the list. Null objects or empty strings within the array are represented 3952 * by empty strings. 3953 * </p> 3954 * 3955 * <pre> 3956 * StringUtils.join(null, *) = null 3957 * StringUtils.join([], *) = "" 3958 * StringUtils.join([null], *) = "" 3959 * StringUtils.join([1, 2, 3], ';') = "1;2;3" 3960 * StringUtils.join([1, 2, 3], null) = "123" 3961 * </pre> 3962 * 3963 * @param array 3964 * the array of values to join together, may be null 3965 * @param separator 3966 * the separator character to use 3967 * @return the joined String, {@code null} if null array input 3968 * @since 3.2 3969 */ 3970 public static String join(final short[] array, final char separator) { 3971 if (array == null) { 3972 return null; 3973 } 3974 return join(array, separator, 0, array.length); 3975 } 3976 3977 /** 3978 * <p> 3979 * Joins the elements of the provided array into a single String containing the provided list of elements. 3980 * </p> 3981 * 3982 * <p> 3983 * No delimiter is added before or after the list. Null objects or empty strings within the array are represented 3984 * by empty strings. 3985 * </p> 3986 * 3987 * <pre> 3988 * StringUtils.join(null, *) = null 3989 * StringUtils.join([], *) = "" 3990 * StringUtils.join([null], *) = "" 3991 * StringUtils.join([1, 2, 3], ';') = "1;2;3" 3992 * StringUtils.join([1, 2, 3], null) = "123" 3993 * </pre> 3994 * 3995 * @param array 3996 * the array of values to join together, may be null 3997 * @param separator 3998 * the separator character to use 3999 * @return the joined String, {@code null} if null array input 4000 * @since 3.2 4001 */ 4002 public static String join(final byte[] array, final char separator) { 4003 if (array == null) { 4004 return null; 4005 } 4006 return join(array, separator, 0, array.length); 4007 } 4008 4009 /** 4010 * <p> 4011 * Joins the elements of the provided array into a single String containing the provided list of elements. 4012 * </p> 4013 * 4014 * <p> 4015 * No delimiter is added before or after the list. Null objects or empty strings within the array are represented 4016 * by empty strings. 4017 * </p> 4018 * 4019 * <pre> 4020 * StringUtils.join(null, *) = null 4021 * StringUtils.join([], *) = "" 4022 * StringUtils.join([null], *) = "" 4023 * StringUtils.join([1, 2, 3], ';') = "1;2;3" 4024 * StringUtils.join([1, 2, 3], null) = "123" 4025 * </pre> 4026 * 4027 * @param array 4028 * the array of values to join together, may be null 4029 * @param separator 4030 * the separator character to use 4031 * @return the joined String, {@code null} if null array input 4032 * @since 3.2 4033 */ 4034 public static String join(final char[] array, final char separator) { 4035 if (array == null) { 4036 return null; 4037 } 4038 return join(array, separator, 0, array.length); 4039 } 4040 4041 /** 4042 * <p> 4043 * Joins the elements of the provided array into a single String containing the provided list of elements. 4044 * </p> 4045 * 4046 * <p> 4047 * No delimiter is added before or after the list. Null objects or empty strings within the array are represented 4048 * by empty strings. 4049 * </p> 4050 * 4051 * <pre> 4052 * StringUtils.join(null, *) = null 4053 * StringUtils.join([], *) = "" 4054 * StringUtils.join([null], *) = "" 4055 * StringUtils.join([1, 2, 3], ';') = "1;2;3" 4056 * StringUtils.join([1, 2, 3], null) = "123" 4057 * </pre> 4058 * 4059 * @param array 4060 * the array of values to join together, may be null 4061 * @param separator 4062 * the separator character to use 4063 * @return the joined String, {@code null} if null array input 4064 * @since 3.2 4065 */ 4066 public static String join(final float[] array, final char separator) { 4067 if (array == null) { 4068 return null; 4069 } 4070 return join(array, separator, 0, array.length); 4071 } 4072 4073 /** 4074 * <p> 4075 * Joins the elements of the provided array into a single String containing the provided list of elements. 4076 * </p> 4077 * 4078 * <p> 4079 * No delimiter is added before or after the list. Null objects or empty strings within the array are represented 4080 * by empty strings. 4081 * </p> 4082 * 4083 * <pre> 4084 * StringUtils.join(null, *) = null 4085 * StringUtils.join([], *) = "" 4086 * StringUtils.join([null], *) = "" 4087 * StringUtils.join([1, 2, 3], ';') = "1;2;3" 4088 * StringUtils.join([1, 2, 3], null) = "123" 4089 * </pre> 4090 * 4091 * @param array 4092 * the array of values to join together, may be null 4093 * @param separator 4094 * the separator character to use 4095 * @return the joined String, {@code null} if null array input 4096 * @since 3.2 4097 */ 4098 public static String join(final double[] array, final char separator) { 4099 if (array == null) { 4100 return null; 4101 } 4102 return join(array, separator, 0, array.length); 4103 } 4104 4105 4106 /** 4107 * <p>Joins the elements of the provided array into a single String 4108 * containing the provided list of elements.</p> 4109 * 4110 * <p>No delimiter is added before or after the list. 4111 * Null objects or empty strings within the array are represented by 4112 * empty strings.</p> 4113 * 4114 * <pre> 4115 * StringUtils.join(null, *) = null 4116 * StringUtils.join([], *) = "" 4117 * StringUtils.join([null], *) = "" 4118 * StringUtils.join(["a", "b", "c"], ';') = "a;b;c" 4119 * StringUtils.join(["a", "b", "c"], null) = "abc" 4120 * StringUtils.join([null, "", "a"], ';') = ";;a" 4121 * </pre> 4122 * 4123 * @param array the array of values to join together, may be null 4124 * @param separator the separator character to use 4125 * @param startIndex the first index to start joining from. It is 4126 * an error to pass in an end index past the end of the array 4127 * @param endIndex the index to stop joining from (exclusive). It is 4128 * an error to pass in an end index past the end of the array 4129 * @return the joined String, {@code null} if null array input 4130 * @since 2.0 4131 */ 4132 public static String join(final Object[] array, final char separator, final int startIndex, final int endIndex) { 4133 if (array == null) { 4134 return null; 4135 } 4136 final int noOfItems = endIndex - startIndex; 4137 if (noOfItems <= 0) { 4138 return EMPTY; 4139 } 4140 final StringBuilder buf = new StringBuilder(noOfItems * 16); 4141 for (int i = startIndex; i < endIndex; i++) { 4142 if (i > startIndex) { 4143 buf.append(separator); 4144 } 4145 if (array[i] != null) { 4146 buf.append(array[i]); 4147 } 4148 } 4149 return buf.toString(); 4150 } 4151 4152 /** 4153 * <p> 4154 * Joins the elements of the provided array into a single String containing the provided list of elements. 4155 * </p> 4156 * 4157 * <p> 4158 * No delimiter is added before or after the list. Null objects or empty strings within the array are represented 4159 * by empty strings. 4160 * </p> 4161 * 4162 * <pre> 4163 * StringUtils.join(null, *) = null 4164 * StringUtils.join([], *) = "" 4165 * StringUtils.join([null], *) = "" 4166 * StringUtils.join([1, 2, 3], ';') = "1;2;3" 4167 * StringUtils.join([1, 2, 3], null) = "123" 4168 * </pre> 4169 * 4170 * @param array 4171 * the array of values to join together, may be null 4172 * @param separator 4173 * the separator character to use 4174 * @param startIndex 4175 * the first index to start joining from. It is an error to pass in an end index past the end of the 4176 * array 4177 * @param endIndex 4178 * the index to stop joining from (exclusive). It is an error to pass in an end index past the end of 4179 * the array 4180 * @return the joined String, {@code null} if null array input 4181 * @since 3.2 4182 */ 4183 public static String join(final long[] array, final char separator, final int startIndex, final int endIndex) { 4184 if (array == null) { 4185 return null; 4186 } 4187 final int noOfItems = endIndex - startIndex; 4188 if (noOfItems <= 0) { 4189 return EMPTY; 4190 } 4191 final StringBuilder buf = new StringBuilder(noOfItems * 16); 4192 for (int i = startIndex; i < endIndex; i++) { 4193 if (i > startIndex) { 4194 buf.append(separator); 4195 } 4196 buf.append(array[i]); 4197 } 4198 return buf.toString(); 4199 } 4200 4201 /** 4202 * <p> 4203 * Joins the elements of the provided array into a single String containing the provided list of elements. 4204 * </p> 4205 * 4206 * <p> 4207 * No delimiter is added before or after the list. Null objects or empty strings within the array are represented 4208 * by empty strings. 4209 * </p> 4210 * 4211 * <pre> 4212 * StringUtils.join(null, *) = null 4213 * StringUtils.join([], *) = "" 4214 * StringUtils.join([null], *) = "" 4215 * StringUtils.join([1, 2, 3], ';') = "1;2;3" 4216 * StringUtils.join([1, 2, 3], null) = "123" 4217 * </pre> 4218 * 4219 * @param array 4220 * the array of values to join together, may be null 4221 * @param separator 4222 * the separator character to use 4223 * @param startIndex 4224 * the first index to start joining from. It is an error to pass in an end index past the end of the 4225 * array 4226 * @param endIndex 4227 * the index to stop joining from (exclusive). It is an error to pass in an end index past the end of 4228 * the array 4229 * @return the joined String, {@code null} if null array input 4230 * @since 3.2 4231 */ 4232 public static String join(final int[] array, final char separator, final int startIndex, final int endIndex) { 4233 if (array == null) { 4234 return null; 4235 } 4236 final int noOfItems = endIndex - startIndex; 4237 if (noOfItems <= 0) { 4238 return EMPTY; 4239 } 4240 final StringBuilder buf = new StringBuilder(noOfItems * 16); 4241 for (int i = startIndex; i < endIndex; i++) { 4242 if (i > startIndex) { 4243 buf.append(separator); 4244 } 4245 buf.append(array[i]); 4246 } 4247 return buf.toString(); 4248 } 4249 4250 /** 4251 * <p> 4252 * Joins the elements of the provided array into a single String containing the provided list of elements. 4253 * </p> 4254 * 4255 * <p> 4256 * No delimiter is added before or after the list. Null objects or empty strings within the array are represented 4257 * by empty strings. 4258 * </p> 4259 * 4260 * <pre> 4261 * StringUtils.join(null, *) = null 4262 * StringUtils.join([], *) = "" 4263 * StringUtils.join([null], *) = "" 4264 * StringUtils.join([1, 2, 3], ';') = "1;2;3" 4265 * StringUtils.join([1, 2, 3], null) = "123" 4266 * </pre> 4267 * 4268 * @param array 4269 * the array of values to join together, may be null 4270 * @param separator 4271 * the separator character to use 4272 * @param startIndex 4273 * the first index to start joining from. It is an error to pass in an end index past the end of the 4274 * array 4275 * @param endIndex 4276 * the index to stop joining from (exclusive). It is an error to pass in an end index past the end of 4277 * the array 4278 * @return the joined String, {@code null} if null array input 4279 * @since 3.2 4280 */ 4281 public static String join(final byte[] array, final char separator, final int startIndex, final int endIndex) { 4282 if (array == null) { 4283 return null; 4284 } 4285 final int noOfItems = endIndex - startIndex; 4286 if (noOfItems <= 0) { 4287 return EMPTY; 4288 } 4289 final StringBuilder buf = new StringBuilder(noOfItems * 16); 4290 for (int i = startIndex; i < endIndex; i++) { 4291 if (i > startIndex) { 4292 buf.append(separator); 4293 } 4294 buf.append(array[i]); 4295 } 4296 return buf.toString(); 4297 } 4298 4299 /** 4300 * <p> 4301 * Joins the elements of the provided array into a single String containing the provided list of elements. 4302 * </p> 4303 * 4304 * <p> 4305 * No delimiter is added before or after the list. Null objects or empty strings within the array are represented 4306 * by empty strings. 4307 * </p> 4308 * 4309 * <pre> 4310 * StringUtils.join(null, *) = null 4311 * StringUtils.join([], *) = "" 4312 * StringUtils.join([null], *) = "" 4313 * StringUtils.join([1, 2, 3], ';') = "1;2;3" 4314 * StringUtils.join([1, 2, 3], null) = "123" 4315 * </pre> 4316 * 4317 * @param array 4318 * the array of values to join together, may be null 4319 * @param separator 4320 * the separator character to use 4321 * @param startIndex 4322 * the first index to start joining from. It is an error to pass in an end index past the end of the 4323 * array 4324 * @param endIndex 4325 * the index to stop joining from (exclusive). It is an error to pass in an end index past the end of 4326 * the array 4327 * @return the joined String, {@code null} if null array input 4328 * @since 3.2 4329 */ 4330 public static String join(final short[] array, final char separator, final int startIndex, final int endIndex) { 4331 if (array == null) { 4332 return null; 4333 } 4334 final int noOfItems = endIndex - startIndex; 4335 if (noOfItems <= 0) { 4336 return EMPTY; 4337 } 4338 final StringBuilder buf = new StringBuilder(noOfItems * 16); 4339 for (int i = startIndex; i < endIndex; i++) { 4340 if (i > startIndex) { 4341 buf.append(separator); 4342 } 4343 buf.append(array[i]); 4344 } 4345 return buf.toString(); 4346 } 4347 4348 /** 4349 * <p> 4350 * Joins the elements of the provided array into a single String containing the provided list of elements. 4351 * </p> 4352 * 4353 * <p> 4354 * No delimiter is added before or after the list. Null objects or empty strings within the array are represented 4355 * by empty strings. 4356 * </p> 4357 * 4358 * <pre> 4359 * StringUtils.join(null, *) = null 4360 * StringUtils.join([], *) = "" 4361 * StringUtils.join([null], *) = "" 4362 * StringUtils.join([1, 2, 3], ';') = "1;2;3" 4363 * StringUtils.join([1, 2, 3], null) = "123" 4364 * </pre> 4365 * 4366 * @param array 4367 * the array of values to join together, may be null 4368 * @param separator 4369 * the separator character to use 4370 * @param startIndex 4371 * the first index to start joining from. It is an error to pass in an end index past the end of the 4372 * array 4373 * @param endIndex 4374 * the index to stop joining from (exclusive). It is an error to pass in an end index past the end of 4375 * the array 4376 * @return the joined String, {@code null} if null array input 4377 * @since 3.2 4378 */ 4379 public static String join(final char[] array, final char separator, final int startIndex, final int endIndex) { 4380 if (array == null) { 4381 return null; 4382 } 4383 final int noOfItems = endIndex - startIndex; 4384 if (noOfItems <= 0) { 4385 return EMPTY; 4386 } 4387 final StringBuilder buf = new StringBuilder(noOfItems * 16); 4388 for (int i = startIndex; i < endIndex; i++) { 4389 if (i > startIndex) { 4390 buf.append(separator); 4391 } 4392 buf.append(array[i]); 4393 } 4394 return buf.toString(); 4395 } 4396 4397 /** 4398 * <p> 4399 * Joins the elements of the provided array into a single String containing the provided list of elements. 4400 * </p> 4401 * 4402 * <p> 4403 * No delimiter is added before or after the list. Null objects or empty strings within the array are represented 4404 * by empty strings. 4405 * </p> 4406 * 4407 * <pre> 4408 * StringUtils.join(null, *) = null 4409 * StringUtils.join([], *) = "" 4410 * StringUtils.join([null], *) = "" 4411 * StringUtils.join([1, 2, 3], ';') = "1;2;3" 4412 * StringUtils.join([1, 2, 3], null) = "123" 4413 * </pre> 4414 * 4415 * @param array 4416 * the array of values to join together, may be null 4417 * @param separator 4418 * the separator character to use 4419 * @param startIndex 4420 * the first index to start joining from. It is an error to pass in an end index past the end of the 4421 * array 4422 * @param endIndex 4423 * the index to stop joining from (exclusive). It is an error to pass in an end index past the end of 4424 * the array 4425 * @return the joined String, {@code null} if null array input 4426 * @since 3.2 4427 */ 4428 public static String join(final double[] array, final char separator, final int startIndex, final int endIndex) { 4429 if (array == null) { 4430 return null; 4431 } 4432 final int noOfItems = endIndex - startIndex; 4433 if (noOfItems <= 0) { 4434 return EMPTY; 4435 } 4436 final StringBuilder buf = new StringBuilder(noOfItems * 16); 4437 for (int i = startIndex; i < endIndex; i++) { 4438 if (i > startIndex) { 4439 buf.append(separator); 4440 } 4441 buf.append(array[i]); 4442 } 4443 return buf.toString(); 4444 } 4445 4446 /** 4447 * <p> 4448 * Joins the elements of the provided array into a single String containing the provided list of elements. 4449 * </p> 4450 * 4451 * <p> 4452 * No delimiter is added before or after the list. Null objects or empty strings within the array are represented 4453 * by empty strings. 4454 * </p> 4455 * 4456 * <pre> 4457 * StringUtils.join(null, *) = null 4458 * StringUtils.join([], *) = "" 4459 * StringUtils.join([null], *) = "" 4460 * StringUtils.join([1, 2, 3], ';') = "1;2;3" 4461 * StringUtils.join([1, 2, 3], null) = "123" 4462 * </pre> 4463 * 4464 * @param array 4465 * the array of values to join together, may be null 4466 * @param separator 4467 * the separator character to use 4468 * @param startIndex 4469 * the first index to start joining from. It is an error to pass in an end index past the end of the 4470 * array 4471 * @param endIndex 4472 * the index to stop joining from (exclusive). It is an error to pass in an end index past the end of 4473 * the array 4474 * @return the joined String, {@code null} if null array input 4475 * @since 3.2 4476 */ 4477 public static String join(final float[] array, final char separator, final int startIndex, final int endIndex) { 4478 if (array == null) { 4479 return null; 4480 } 4481 final int noOfItems = endIndex - startIndex; 4482 if (noOfItems <= 0) { 4483 return EMPTY; 4484 } 4485 final StringBuilder buf = new StringBuilder(noOfItems * 16); 4486 for (int i = startIndex; i < endIndex; i++) { 4487 if (i > startIndex) { 4488 buf.append(separator); 4489 } 4490 buf.append(array[i]); 4491 } 4492 return buf.toString(); 4493 } 4494 4495 4496 /** 4497 * <p>Joins the elements of the provided array into a single String 4498 * containing the provided list of elements.</p> 4499 * 4500 * <p>No delimiter is added before or after the list. 4501 * A {@code null} separator is the same as an empty String (""). 4502 * Null objects or empty strings within the array are represented by 4503 * empty strings.</p> 4504 * 4505 * <pre> 4506 * StringUtils.join(null, *) = null 4507 * StringUtils.join([], *) = "" 4508 * StringUtils.join([null], *) = "" 4509 * StringUtils.join(["a", "b", "c"], "--") = "a--b--c" 4510 * StringUtils.join(["a", "b", "c"], null) = "abc" 4511 * StringUtils.join(["a", "b", "c"], "") = "abc" 4512 * StringUtils.join([null, "", "a"], ',') = ",,a" 4513 * </pre> 4514 * 4515 * @param array the array of values to join together, may be null 4516 * @param separator the separator character to use, null treated as "" 4517 * @return the joined String, {@code null} if null array input 4518 */ 4519 public static String join(final Object[] array, final String separator) { 4520 if (array == null) { 4521 return null; 4522 } 4523 return join(array, separator, 0, array.length); 4524 } 4525 4526 /** 4527 * <p>Joins the elements of the provided array into a single String 4528 * containing the provided list of elements.</p> 4529 * 4530 * <p>No delimiter is added before or after the list. 4531 * A {@code null} separator is the same as an empty String (""). 4532 * Null objects or empty strings within the array are represented by 4533 * empty strings.</p> 4534 * 4535 * <pre> 4536 * StringUtils.join(null, *, *, *) = null 4537 * StringUtils.join([], *, *, *) = "" 4538 * StringUtils.join([null], *, *, *) = "" 4539 * StringUtils.join(["a", "b", "c"], "--", 0, 3) = "a--b--c" 4540 * StringUtils.join(["a", "b", "c"], "--", 1, 3) = "b--c" 4541 * StringUtils.join(["a", "b", "c"], "--", 2, 3) = "c" 4542 * StringUtils.join(["a", "b", "c"], "--", 2, 2) = "" 4543 * StringUtils.join(["a", "b", "c"], null, 0, 3) = "abc" 4544 * StringUtils.join(["a", "b", "c"], "", 0, 3) = "abc" 4545 * StringUtils.join([null, "", "a"], ',', 0, 3) = ",,a" 4546 * </pre> 4547 * 4548 * @param array the array of values to join together, may be null 4549 * @param separator the separator character to use, null treated as "" 4550 * @param startIndex the first index to start joining from. 4551 * @param endIndex the index to stop joining from (exclusive). 4552 * @return the joined String, {@code null} if null array input; or the empty string 4553 * if {@code endIndex - startIndex <= 0}. The number of joined entries is given by 4554 * {@code endIndex - startIndex} 4555 * @throws ArrayIndexOutOfBoundsException ife<br> 4556 * {@code startIndex < 0} or <br> 4557 * {@code startIndex >= array.length()} or <br> 4558 * {@code endIndex < 0} or <br> 4559 * {@code endIndex > array.length()} 4560 */ 4561 public static String join(final Object[] array, String separator, final int startIndex, final int endIndex) { 4562 if (array == null) { 4563 return null; 4564 } 4565 if (separator == null) { 4566 separator = EMPTY; 4567 } 4568 4569 // endIndex - startIndex > 0: Len = NofStrings *(len(firstString) + len(separator)) 4570 // (Assuming that all Strings are roughly equally long) 4571 final int noOfItems = endIndex - startIndex; 4572 if (noOfItems <= 0) { 4573 return EMPTY; 4574 } 4575 4576 final StringBuilder buf = new StringBuilder(noOfItems * 16); 4577 4578 for (int i = startIndex; i < endIndex; i++) { 4579 if (i > startIndex) { 4580 buf.append(separator); 4581 } 4582 if (array[i] != null) { 4583 buf.append(array[i]); 4584 } 4585 } 4586 return buf.toString(); 4587 } 4588 4589 /** 4590 * <p>Joins the elements of the provided {@code Iterator} into 4591 * a single String containing the provided elements.</p> 4592 * 4593 * <p>No delimiter is added before or after the list. Null objects or empty 4594 * strings within the iteration are represented by empty strings.</p> 4595 * 4596 * <p>See the examples here: {@link #join(Object[],char)}. </p> 4597 * 4598 * @param iterator the {@code Iterator} of values to join together, may be null 4599 * @param separator the separator character to use 4600 * @return the joined String, {@code null} if null iterator input 4601 * @since 2.0 4602 */ 4603 public static String join(final Iterator<?> iterator, final char separator) { 4604 4605 // handle null, zero and one elements before building a buffer 4606 if (iterator == null) { 4607 return null; 4608 } 4609 if (!iterator.hasNext()) { 4610 return EMPTY; 4611 } 4612 final Object first = iterator.next(); 4613 if (!iterator.hasNext()) { 4614 final String result = Objects.toString(first, ""); 4615 return result; 4616 } 4617 4618 // two or more elements 4619 final StringBuilder buf = new StringBuilder(256); // Java default is 16, probably too small 4620 if (first != null) { 4621 buf.append(first); 4622 } 4623 4624 while (iterator.hasNext()) { 4625 buf.append(separator); 4626 final Object obj = iterator.next(); 4627 if (obj != null) { 4628 buf.append(obj); 4629 } 4630 } 4631 4632 return buf.toString(); 4633 } 4634 4635 /** 4636 * <p>Joins the elements of the provided {@code Iterator} into 4637 * a single String containing the provided elements.</p> 4638 * 4639 * <p>No delimiter is added before or after the list. 4640 * A {@code null} separator is the same as an empty String ("").</p> 4641 * 4642 * <p>See the examples here: {@link #join(Object[],String)}. </p> 4643 * 4644 * @param iterator the {@code Iterator} of values to join together, may be null 4645 * @param separator the separator character to use, null treated as "" 4646 * @return the joined String, {@code null} if null iterator input 4647 */ 4648 public static String join(final Iterator<?> iterator, final String separator) { 4649 4650 // handle null, zero and one elements before building a buffer 4651 if (iterator == null) { 4652 return null; 4653 } 4654 if (!iterator.hasNext()) { 4655 return EMPTY; 4656 } 4657 final Object first = iterator.next(); 4658 if (!iterator.hasNext()) { 4659 final String result = Objects.toString(first, ""); 4660 return result; 4661 } 4662 4663 // two or more elements 4664 final StringBuilder buf = new StringBuilder(256); // Java default is 16, probably too small 4665 if (first != null) { 4666 buf.append(first); 4667 } 4668 4669 while (iterator.hasNext()) { 4670 if (separator != null) { 4671 buf.append(separator); 4672 } 4673 final Object obj = iterator.next(); 4674 if (obj != null) { 4675 buf.append(obj); 4676 } 4677 } 4678 return buf.toString(); 4679 } 4680 4681 /** 4682 * <p>Joins the elements of the provided {@code Iterable} into 4683 * a single String containing the provided elements.</p> 4684 * 4685 * <p>No delimiter is added before or after the list. Null objects or empty 4686 * strings within the iteration are represented by empty strings.</p> 4687 * 4688 * <p>See the examples here: {@link #join(Object[],char)}. </p> 4689 * 4690 * @param iterable the {@code Iterable} providing the values to join together, may be null 4691 * @param separator the separator character to use 4692 * @return the joined String, {@code null} if null iterator input 4693 * @since 2.3 4694 */ 4695 public static String join(final Iterable<?> iterable, final char separator) { 4696 if (iterable == null) { 4697 return null; 4698 } 4699 return join(iterable.iterator(), separator); 4700 } 4701 4702 /** 4703 * <p>Joins the elements of the provided {@code Iterable} into 4704 * a single String containing the provided elements.</p> 4705 * 4706 * <p>No delimiter is added before or after the list. 4707 * A {@code null} separator is the same as an empty String ("").</p> 4708 * 4709 * <p>See the examples here: {@link #join(Object[],String)}. </p> 4710 * 4711 * @param iterable the {@code Iterable} providing the values to join together, may be null 4712 * @param separator the separator character to use, null treated as "" 4713 * @return the joined String, {@code null} if null iterator input 4714 * @since 2.3 4715 */ 4716 public static String join(final Iterable<?> iterable, final String separator) { 4717 if (iterable == null) { 4718 return null; 4719 } 4720 return join(iterable.iterator(), separator); 4721 } 4722 4723 /** 4724 * <p>Joins the elements of the provided varargs into a 4725 * single String containing the provided elements.</p> 4726 * 4727 * <p>No delimiter is added before or after the list. 4728 * {@code null} elements and separator are treated as empty Strings ("").</p> 4729 * 4730 * <pre> 4731 * StringUtils.joinWith(",", {"a", "b"}) = "a,b" 4732 * StringUtils.joinWith(",", {"a", "b",""}) = "a,b," 4733 * StringUtils.joinWith(",", {"a", null, "b"}) = "a,,b" 4734 * StringUtils.joinWith(null, {"a", "b"}) = "ab" 4735 * </pre> 4736 * 4737 * @param separator the separator character to use, null treated as "" 4738 * @param objects the varargs providing the values to join together. {@code null} elements are treated as "" 4739 * @return the joined String. 4740 * @throws java.lang.IllegalArgumentException if a null varargs is provided 4741 * @since 3.5 4742 */ 4743 public static String joinWith(final String separator, final Object... objects) { 4744 if (objects == null) { 4745 throw new IllegalArgumentException("Object varargs must not be null"); 4746 } 4747 4748 final String sanitizedSeparator = defaultString(separator, StringUtils.EMPTY); 4749 4750 final StringBuilder result = new StringBuilder(); 4751 4752 final Iterator<Object> iterator = Arrays.asList(objects).iterator(); 4753 while (iterator.hasNext()) { 4754 final String value = Objects.toString(iterator.next(), ""); 4755 result.append(value); 4756 4757 if (iterator.hasNext()) { 4758 result.append(sanitizedSeparator); 4759 } 4760 } 4761 4762 return result.toString(); 4763 } 4764 4765 // Delete 4766 //----------------------------------------------------------------------- 4767 /** 4768 * <p>Deletes all whitespaces from a String as defined by 4769 * {@link Character#isWhitespace(char)}.</p> 4770 * 4771 * <pre> 4772 * StringUtils.deleteWhitespace(null) = null 4773 * StringUtils.deleteWhitespace("") = "" 4774 * StringUtils.deleteWhitespace("abc") = "abc" 4775 * StringUtils.deleteWhitespace(" ab c ") = "abc" 4776 * </pre> 4777 * 4778 * @param str the String to delete whitespace from, may be null 4779 * @return the String without whitespaces, {@code null} if null String input 4780 */ 4781 public static String deleteWhitespace(final String str) { 4782 if (isEmpty(str)) { 4783 return str; 4784 } 4785 final int sz = str.length(); 4786 final char[] chs = new char[sz]; 4787 int count = 0; 4788 for (int i = 0; i < sz; i++) { 4789 if (!Character.isWhitespace(str.charAt(i))) { 4790 chs[count++] = str.charAt(i); 4791 } 4792 } 4793 if (count == sz) { 4794 return str; 4795 } 4796 return new String(chs, 0, count); 4797 } 4798 4799 // Remove 4800 //----------------------------------------------------------------------- 4801 /** 4802 * <p>Removes a substring only if it is at the beginning of a source string, 4803 * otherwise returns the source string.</p> 4804 * 4805 * <p>A {@code null} source string will return {@code null}. 4806 * An empty ("") source string will return the empty string. 4807 * A {@code null} search string will return the source string.</p> 4808 * 4809 * <pre> 4810 * StringUtils.removeStart(null, *) = null 4811 * StringUtils.removeStart("", *) = "" 4812 * StringUtils.removeStart(*, null) = * 4813 * StringUtils.removeStart("www.domain.com", "www.") = "domain.com" 4814 * StringUtils.removeStart("domain.com", "www.") = "domain.com" 4815 * StringUtils.removeStart("www.domain.com", "domain") = "www.domain.com" 4816 * StringUtils.removeStart("abc", "") = "abc" 4817 * </pre> 4818 * 4819 * @param str the source String to search, may be null 4820 * @param remove the String to search for and remove, may be null 4821 * @return the substring with the string removed if found, 4822 * {@code null} if null String input 4823 * @since 2.1 4824 */ 4825 public static String removeStart(final String str, final String remove) { 4826 if (isEmpty(str) || isEmpty(remove)) { 4827 return str; 4828 } 4829 if (str.startsWith(remove)){ 4830 return str.substring(remove.length()); 4831 } 4832 return str; 4833 } 4834 4835 /** 4836 * <p>Case insensitive removal of a substring if it is at the beginning of a source string, 4837 * otherwise returns the source string.</p> 4838 * 4839 * <p>A {@code null} source string will return {@code null}. 4840 * An empty ("") source string will return the empty string. 4841 * A {@code null} search string will return the source string.</p> 4842 * 4843 * <pre> 4844 * StringUtils.removeStartIgnoreCase(null, *) = null 4845 * StringUtils.removeStartIgnoreCase("", *) = "" 4846 * StringUtils.removeStartIgnoreCase(*, null) = * 4847 * StringUtils.removeStartIgnoreCase("www.domain.com", "www.") = "domain.com" 4848 * StringUtils.removeStartIgnoreCase("www.domain.com", "WWW.") = "domain.com" 4849 * StringUtils.removeStartIgnoreCase("domain.com", "www.") = "domain.com" 4850 * StringUtils.removeStartIgnoreCase("www.domain.com", "domain") = "www.domain.com" 4851 * StringUtils.removeStartIgnoreCase("abc", "") = "abc" 4852 * </pre> 4853 * 4854 * @param str the source String to search, may be null 4855 * @param remove the String to search for (case insensitive) and remove, may be null 4856 * @return the substring with the string removed if found, 4857 * {@code null} if null String input 4858 * @since 2.4 4859 */ 4860 public static String removeStartIgnoreCase(final String str, final String remove) { 4861 if (isEmpty(str) || isEmpty(remove)) { 4862 return str; 4863 } 4864 if (startsWithIgnoreCase(str, remove)) { 4865 return str.substring(remove.length()); 4866 } 4867 return str; 4868 } 4869 4870 /** 4871 * <p>Removes a substring only if it is at the end of a source string, 4872 * otherwise returns the source string.</p> 4873 * 4874 * <p>A {@code null} source string will return {@code null}. 4875 * An empty ("") source string will return the empty string. 4876 * A {@code null} search string will return the source string.</p> 4877 * 4878 * <pre> 4879 * StringUtils.removeEnd(null, *) = null 4880 * StringUtils.removeEnd("", *) = "" 4881 * StringUtils.removeEnd(*, null) = * 4882 * StringUtils.removeEnd("www.domain.com", ".com.") = "www.domain.com" 4883 * StringUtils.removeEnd("www.domain.com", ".com") = "www.domain" 4884 * StringUtils.removeEnd("www.domain.com", "domain") = "www.domain.com" 4885 * StringUtils.removeEnd("abc", "") = "abc" 4886 * </pre> 4887 * 4888 * @param str the source String to search, may be null 4889 * @param remove the String to search for and remove, may be null 4890 * @return the substring with the string removed if found, 4891 * {@code null} if null String input 4892 * @since 2.1 4893 */ 4894 public static String removeEnd(final String str, final String remove) { 4895 if (isEmpty(str) || isEmpty(remove)) { 4896 return str; 4897 } 4898 if (str.endsWith(remove)) { 4899 return str.substring(0, str.length() - remove.length()); 4900 } 4901 return str; 4902 } 4903 4904 /** 4905 * <p>Case insensitive removal of a substring if it is at the end of a source string, 4906 * otherwise returns the source string.</p> 4907 * 4908 * <p>A {@code null} source string will return {@code null}. 4909 * An empty ("") source string will return the empty string. 4910 * A {@code null} search string will return the source string.</p> 4911 * 4912 * <pre> 4913 * StringUtils.removeEndIgnoreCase(null, *) = null 4914 * StringUtils.removeEndIgnoreCase("", *) = "" 4915 * StringUtils.removeEndIgnoreCase(*, null) = * 4916 * StringUtils.removeEndIgnoreCase("www.domain.com", ".com.") = "www.domain.com" 4917 * StringUtils.removeEndIgnoreCase("www.domain.com", ".com") = "www.domain" 4918 * StringUtils.removeEndIgnoreCase("www.domain.com", "domain") = "www.domain.com" 4919 * StringUtils.removeEndIgnoreCase("abc", "") = "abc" 4920 * StringUtils.removeEndIgnoreCase("www.domain.com", ".COM") = "www.domain") 4921 * StringUtils.removeEndIgnoreCase("www.domain.COM", ".com") = "www.domain") 4922 * </pre> 4923 * 4924 * @param str the source String to search, may be null 4925 * @param remove the String to search for (case insensitive) and remove, may be null 4926 * @return the substring with the string removed if found, 4927 * {@code null} if null String input 4928 * @since 2.4 4929 */ 4930 public static String removeEndIgnoreCase(final String str, final String remove) { 4931 if (isEmpty(str) || isEmpty(remove)) { 4932 return str; 4933 } 4934 if (endsWithIgnoreCase(str, remove)) { 4935 return str.substring(0, str.length() - remove.length()); 4936 } 4937 return str; 4938 } 4939 4940 /** 4941 * <p>Removes all occurrences of a substring from within the source string.</p> 4942 * 4943 * <p>A {@code null} source string will return {@code null}. 4944 * An empty ("") source string will return the empty string. 4945 * A {@code null} remove string will return the source string. 4946 * An empty ("") remove string will return the source string.</p> 4947 * 4948 * <pre> 4949 * StringUtils.remove(null, *) = null 4950 * StringUtils.remove("", *) = "" 4951 * StringUtils.remove(*, null) = * 4952 * StringUtils.remove(*, "") = * 4953 * StringUtils.remove("queued", "ue") = "qd" 4954 * StringUtils.remove("queued", "zz") = "queued" 4955 * </pre> 4956 * 4957 * @param str the source String to search, may be null 4958 * @param remove the String to search for and remove, may be null 4959 * @return the substring with the string removed if found, 4960 * {@code null} if null String input 4961 * @since 2.1 4962 */ 4963 public static String remove(final String str, final String remove) { 4964 if (isEmpty(str) || isEmpty(remove)) { 4965 return str; 4966 } 4967 return replace(str, remove, EMPTY, -1); 4968 } 4969 4970 /** 4971 * <p> 4972 * Case insensitive removal of all occurrences of a substring from within 4973 * the source string. 4974 * </p> 4975 * 4976 * <p> 4977 * A {@code null} source string will return {@code null}. An empty ("") 4978 * source string will return the empty string. A {@code null} remove string 4979 * will return the source string. An empty ("") remove string will return 4980 * the source string. 4981 * </p> 4982 * 4983 * <pre> 4984 * StringUtils.removeIgnoreCase(null, *) = null 4985 * StringUtils.removeIgnoreCase("", *) = "" 4986 * StringUtils.removeIgnoreCase(*, null) = * 4987 * StringUtils.removeIgnoreCase(*, "") = * 4988 * StringUtils.removeIgnoreCase("queued", "ue") = "qd" 4989 * StringUtils.removeIgnoreCase("queued", "zz") = "queued" 4990 * StringUtils.removeIgnoreCase("quEUed", "UE") = "qd" 4991 * StringUtils.removeIgnoreCase("queued", "zZ") = "queued" 4992 * </pre> 4993 * 4994 * @param str 4995 * the source String to search, may be null 4996 * @param remove 4997 * the String to search for (case insensitive) and remove, may be 4998 * null 4999 * @return the substring with the string removed if found, {@code null} if 5000 * null String input 5001 * @since 3.5 5002 */ 5003 public static String removeIgnoreCase(final String str, final String remove) { 5004 if (isEmpty(str) || isEmpty(remove)) { 5005 return str; 5006 } 5007 return replaceIgnoreCase(str, remove, EMPTY, -1); 5008 } 5009 5010 /** 5011 * <p>Removes all occurrences of a character from within the source string.</p> 5012 * 5013 * <p>A {@code null} source string will return {@code null}. 5014 * An empty ("") source string will return the empty string.</p> 5015 * 5016 * <pre> 5017 * StringUtils.remove(null, *) = null 5018 * StringUtils.remove("", *) = "" 5019 * StringUtils.remove("queued", 'u') = "qeed" 5020 * StringUtils.remove("queued", 'z') = "queued" 5021 * </pre> 5022 * 5023 * @param str the source String to search, may be null 5024 * @param remove the char to search for and remove, may be null 5025 * @return the substring with the char removed if found, 5026 * {@code null} if null String input 5027 * @since 2.1 5028 */ 5029 public static String remove(final String str, final char remove) { 5030 if (isEmpty(str) || str.indexOf(remove) == INDEX_NOT_FOUND) { 5031 return str; 5032 } 5033 final char[] chars = str.toCharArray(); 5034 int pos = 0; 5035 for (int i = 0; i < chars.length; i++) { 5036 if (chars[i] != remove) { 5037 chars[pos++] = chars[i]; 5038 } 5039 } 5040 return new String(chars, 0, pos); 5041 } 5042 5043 /** 5044 * <p>Removes each substring of the text String that matches the given regular expression.</p> 5045 * 5046 * This method is a {@code null} safe equivalent to: 5047 * <ul> 5048 * <li>{@code text.replaceAll(regex, StringUtils.EMPTY)}</li> 5049 * <li>{@code Pattern.compile(regex).matcher(text).replaceAll(StringUtils.EMPTY)}</li> 5050 * </ul> 5051 * 5052 * <p>A {@code null} reference passed to this method is a no-op.</p> 5053 * 5054 * <p>Unlike in the {@link #removePattern(String, String)} method, the {@link Pattern#DOTALL} option 5055 * is NOT automatically added. 5056 * To use the DOTALL option prepend <code>"(?s)"</code> to the regex. 5057 * DOTALL is also know as single-line mode in Perl.</p> 5058 * 5059 * <pre> 5060 * StringUtils.removeAll(null, *) = null 5061 * StringUtils.removeAll("any", null) = "any" 5062 * StringUtils.removeAll("any", "") = "any" 5063 * StringUtils.removeAll("any", ".*") = "" 5064 * StringUtils.removeAll("any", ".+") = "" 5065 * StringUtils.removeAll("abc", ".?") = "" 5066 * StringUtils.removeAll("A<__>\n<__>B", "<.*>") = "A\nB" 5067 * StringUtils.removeAll("A<__>\n<__>B", "(?s)<.*>") = "AB" 5068 * StringUtils.removeAll("ABCabc123abc", "[a-z]") = "ABC123" 5069 * </pre> 5070 * 5071 * @param text text to remove from, may be null 5072 * @param regex the regular expression to which this string is to be matched 5073 * @return the text with any removes processed, 5074 * {@code null} if null String input 5075 * 5076 * @throws java.util.regex.PatternSyntaxException 5077 * if the regular expression's syntax is invalid 5078 * 5079 * @see #replaceAll(String, String, String) 5080 * @see #removePattern(String, String) 5081 * @see String#replaceAll(String, String) 5082 * @see java.util.regex.Pattern 5083 * @see java.util.regex.Pattern#DOTALL 5084 * @since 3.5 5085 */ 5086 public static String removeAll(final String text, final String regex) { 5087 return replaceAll(text, regex, StringUtils.EMPTY); 5088 } 5089 5090 /** 5091 * <p>Removes the first substring of the text string that matches the given regular expression.</p> 5092 * 5093 * This method is a {@code null} safe equivalent to: 5094 * <ul> 5095 * <li>{@code text.replaceFirst(regex, StringUtils.EMPTY)}</li> 5096 * <li>{@code Pattern.compile(regex).matcher(text).replaceFirst(StringUtils.EMPTY)}</li> 5097 * </ul> 5098 * 5099 * <p>A {@code null} reference passed to this method is a no-op.</p> 5100 * 5101 * <p>The {@link Pattern#DOTALL} option is NOT automatically added. 5102 * To use the DOTALL option prepend <code>"(?s)"</code> to the regex. 5103 * DOTALL is also know as single-line mode in Perl.</p> 5104 * 5105 * <pre> 5106 * StringUtils.removeFirst(null, *) = null 5107 * StringUtils.removeFirst("any", null) = "any" 5108 * StringUtils.removeFirst("any", "") = "any" 5109 * StringUtils.removeFirst("any", ".*") = "" 5110 * StringUtils.removeFirst("any", ".+") = "" 5111 * StringUtils.removeFirst("abc", ".?") = "bc" 5112 * StringUtils.removeFirst("A<__>\n<__>B", "<.*>") = "A\n<__>B" 5113 * StringUtils.removeFirst("A<__>\n<__>B", "(?s)<.*>") = "AB" 5114 * StringUtils.removeFirst("ABCabc123", "[a-z]") = "ABCbc123" 5115 * StringUtils.removeFirst("ABCabc123abc", "[a-z]+") = "ABC123abc" 5116 * </pre> 5117 * 5118 * @param text text to remove from, may be null 5119 * @param regex the regular expression to which this string is to be matched 5120 * @return the text with the first replacement processed, 5121 * {@code null} if null String input 5122 * 5123 * @throws java.util.regex.PatternSyntaxException 5124 * if the regular expression's syntax is invalid 5125 * 5126 * @see #replaceFirst(String, String, String) 5127 * @see String#replaceFirst(String, String) 5128 * @see java.util.regex.Pattern 5129 * @see java.util.regex.Pattern#DOTALL 5130 * @since 3.5 5131 */ 5132 public static String removeFirst(final String text, final String regex) { 5133 return replaceFirst(text, regex, StringUtils.EMPTY); 5134 } 5135 5136 // Replacing 5137 //----------------------------------------------------------------------- 5138 /** 5139 * <p>Replaces a String with another String inside a larger String, once.</p> 5140 * 5141 * <p>A {@code null} reference passed to this method is a no-op.</p> 5142 * 5143 * <pre> 5144 * StringUtils.replaceOnce(null, *, *) = null 5145 * StringUtils.replaceOnce("", *, *) = "" 5146 * StringUtils.replaceOnce("any", null, *) = "any" 5147 * StringUtils.replaceOnce("any", *, null) = "any" 5148 * StringUtils.replaceOnce("any", "", *) = "any" 5149 * StringUtils.replaceOnce("aba", "a", null) = "aba" 5150 * StringUtils.replaceOnce("aba", "a", "") = "ba" 5151 * StringUtils.replaceOnce("aba", "a", "z") = "zba" 5152 * </pre> 5153 * 5154 * @see #replace(String text, String searchString, String replacement, int max) 5155 * @param text text to search and replace in, may be null 5156 * @param searchString the String to search for, may be null 5157 * @param replacement the String to replace with, may be null 5158 * @return the text with any replacements processed, 5159 * {@code null} if null String input 5160 */ 5161 public static String replaceOnce(final String text, final String searchString, final String replacement) { 5162 return replace(text, searchString, replacement, 1); 5163 } 5164 5165 /** 5166 * <p>Case insensitively replaces a String with another String inside a larger String, once.</p> 5167 * 5168 * <p>A {@code null} reference passed to this method is a no-op.</p> 5169 * 5170 * <pre> 5171 * StringUtils.replaceOnceIgnoreCase(null, *, *) = null 5172 * StringUtils.replaceOnceIgnoreCase("", *, *) = "" 5173 * StringUtils.replaceOnceIgnoreCase("any", null, *) = "any" 5174 * StringUtils.replaceOnceIgnoreCase("any", *, null) = "any" 5175 * StringUtils.replaceOnceIgnoreCase("any", "", *) = "any" 5176 * StringUtils.replaceOnceIgnoreCase("aba", "a", null) = "aba" 5177 * StringUtils.replaceOnceIgnoreCase("aba", "a", "") = "ba" 5178 * StringUtils.replaceOnceIgnoreCase("aba", "a", "z") = "zba" 5179 * StringUtils.replaceOnceIgnoreCase("FoOFoofoo", "foo", "") = "Foofoo" 5180 * </pre> 5181 * 5182 * @see #replaceIgnoreCase(String text, String searchString, String replacement, int max) 5183 * @param text text to search and replace in, may be null 5184 * @param searchString the String to search for (case insensitive), may be null 5185 * @param replacement the String to replace with, may be null 5186 * @return the text with any replacements processed, 5187 * {@code null} if null String input 5188 * @since 3.5 5189 */ 5190 public static String replaceOnceIgnoreCase(final String text, final String searchString, final String replacement) { 5191 return replaceIgnoreCase(text, searchString, replacement, 1); 5192 } 5193 5194 /** 5195 * <p>Replaces each substring of the source String that matches the given regular expression with the given 5196 * replacement using the {@link Pattern#DOTALL} option. DOTALL is also know as single-line mode in Perl.</p> 5197 * 5198 * This call is a {@code null} safe equivalent to: 5199 * <ul> 5200 * <li>{@code source.replaceAll("(?s)" + regex, replacement)}</li> 5201 * <li>{@code Pattern.compile(regex, Pattern.DOTALL).matcher(source).replaceAll(replacement)}</li> 5202 * </ul> 5203 * 5204 * <p>A {@code null} reference passed to this method is a no-op.</p> 5205 * 5206 * <pre> 5207 * StringUtils.replacePattern(null, *, *) = null 5208 * StringUtils.replacePattern("any", null, *) = "any" 5209 * StringUtils.replacePattern("any", *, null) = "any" 5210 * StringUtils.replacePattern("", "", "zzz") = "zzz" 5211 * StringUtils.replacePattern("", ".*", "zzz") = "zzz" 5212 * StringUtils.replacePattern("", ".+", "zzz") = "" 5213 * StringUtils.replacePattern("<__>\n<__>", "<.*>", "z") = "z" 5214 * StringUtils.replacePattern("ABCabc123", "[a-z]", "_") = "ABC___123" 5215 * StringUtils.replacePattern("ABCabc123", "[^A-Z0-9]+", "_") = "ABC_123" 5216 * StringUtils.replacePattern("ABCabc123", "[^A-Z0-9]+", "") = "ABC123" 5217 * StringUtils.replacePattern("Lorem ipsum dolor sit", "( +)([a-z]+)", "_$2") = "Lorem_ipsum_dolor_sit" 5218 * </pre> 5219 * 5220 * @param source 5221 * the source string 5222 * @param regex 5223 * the regular expression to which this string is to be matched 5224 * @param replacement 5225 * the string to be substituted for each match 5226 * @return The resulting {@code String} 5227 * @see #replaceAll(String, String, String) 5228 * @see String#replaceAll(String, String) 5229 * @see Pattern#DOTALL 5230 * @since 3.2 5231 * @since 3.5 Changed {@code null} reference passed to this method is a no-op. 5232 */ 5233 public static String replacePattern(final String source, final String regex, final String replacement) { 5234 if (source == null || regex == null || replacement == null) { 5235 return source; 5236 } 5237 return Pattern.compile(regex, Pattern.DOTALL).matcher(source).replaceAll(replacement); 5238 } 5239 5240 /** 5241 * <p>Removes each substring of the source String that matches the given regular expression using the DOTALL option. 5242 * </p> 5243 * 5244 * This call is a {@code null} safe equivalent to: 5245 * <ul> 5246 * <li>{@code source.replaceAll("(?s)" + regex, StringUtils.EMPTY)}</li> 5247 * <li>{@code Pattern.compile(regex, Pattern.DOTALL).matcher(source).replaceAll(StringUtils.EMPTY)}</li> 5248 * </ul> 5249 * 5250 * <p>A {@code null} reference passed to this method is a no-op.</p> 5251 * 5252 * <pre> 5253 * StringUtils.removePattern(null, *) = null 5254 * StringUtils.removePattern("any", null) = "any" 5255 * StringUtils.removePattern("A<__>\n<__>B", "<.*>") = "AB" 5256 * StringUtils.removePattern("ABCabc123", "[a-z]") = "ABC123" 5257 * </pre> 5258 * 5259 * @param source 5260 * the source string 5261 * @param regex 5262 * the regular expression to which this string is to be matched 5263 * @return The resulting {@code String} 5264 * @see #replacePattern(String, String, String) 5265 * @see String#replaceAll(String, String) 5266 * @see Pattern#DOTALL 5267 * @since 3.2 5268 * @since 3.5 Changed {@code null} reference passed to this method is a no-op. 5269 */ 5270 public static String removePattern(final String source, final String regex) { 5271 return replacePattern(source, regex, StringUtils.EMPTY); 5272 } 5273 5274 /** 5275 * <p>Replaces each substring of the text String that matches the given regular expression 5276 * with the given replacement.</p> 5277 * 5278 * This method is a {@code null} safe equivalent to: 5279 * <ul> 5280 * <li>{@code text.replaceAll(regex, replacement)}</li> 5281 * <li>{@code Pattern.compile(regex).matcher(text).replaceAll(replacement)}</li> 5282 * </ul> 5283 * 5284 * <p>A {@code null} reference passed to this method is a no-op.</p> 5285 * 5286 * <p>Unlike in the {@link #replacePattern(String, String, String)} method, the {@link Pattern#DOTALL} option 5287 * is NOT automatically added. 5288 * To use the DOTALL option prepend <code>"(?s)"</code> to the regex. 5289 * DOTALL is also know as single-line mode in Perl.</p> 5290 * 5291 * <pre> 5292 * StringUtils.replaceAll(null, *, *) = null 5293 * StringUtils.replaceAll("any", null, *) = "any" 5294 * StringUtils.replaceAll("any", *, null) = "any" 5295 * StringUtils.replaceAll("", "", "zzz") = "zzz" 5296 * StringUtils.replaceAll("", ".*", "zzz") = "zzz" 5297 * StringUtils.replaceAll("", ".+", "zzz") = "" 5298 * StringUtils.replaceAll("abc", "", "ZZ") = "ZZaZZbZZcZZ" 5299 * StringUtils.replaceAll("<__>\n<__>", "<.*>", "z") = "z\nz" 5300 * StringUtils.replaceAll("<__>\n<__>", "(?s)<.*>", "z") = "z" 5301 * StringUtils.replaceAll("ABCabc123", "[a-z]", "_") = "ABC___123" 5302 * StringUtils.replaceAll("ABCabc123", "[^A-Z0-9]+", "_") = "ABC_123" 5303 * StringUtils.replaceAll("ABCabc123", "[^A-Z0-9]+", "") = "ABC123" 5304 * StringUtils.replaceAll("Lorem ipsum dolor sit", "( +)([a-z]+)", "_$2") = "Lorem_ipsum_dolor_sit" 5305 * </pre> 5306 * 5307 * @param text text to search and replace in, may be null 5308 * @param regex the regular expression to which this string is to be matched 5309 * @param replacement the string to be substituted for each match 5310 * @return the text with any replacements processed, 5311 * {@code null} if null String input 5312 * 5313 * @throws java.util.regex.PatternSyntaxException 5314 * if the regular expression's syntax is invalid 5315 * 5316 * @see #replacePattern(String, String, String) 5317 * @see String#replaceAll(String, String) 5318 * @see java.util.regex.Pattern 5319 * @see java.util.regex.Pattern#DOTALL 5320 * @since 3.5 5321 */ 5322 public static String replaceAll(final String text, final String regex, final String replacement) { 5323 if (text == null || regex == null|| replacement == null ) { 5324 return text; 5325 } 5326 return text.replaceAll(regex, replacement); 5327 } 5328 5329 /** 5330 * <p>Replaces the first substring of the text string that matches the given regular expression 5331 * with the given replacement.</p> 5332 * 5333 * This method is a {@code null} safe equivalent to: 5334 * <ul> 5335 * <li>{@code text.replaceFirst(regex, replacement)}</li> 5336 * <li>{@code Pattern.compile(regex).matcher(text).replaceFirst(replacement)}</li> 5337 * </ul> 5338 * 5339 * <p>A {@code null} reference passed to this method is a no-op.</p> 5340 * 5341 * <p>The {@link Pattern#DOTALL} option is NOT automatically added. 5342 * To use the DOTALL option prepend <code>"(?s)"</code> to the regex. 5343 * DOTALL is also know as single-line mode in Perl.</p> 5344 * 5345 * <pre> 5346 * StringUtils.replaceFirst(null, *, *) = null 5347 * StringUtils.replaceFirst("any", null, *) = "any" 5348 * StringUtils.replaceFirst("any", *, null) = "any" 5349 * StringUtils.replaceFirst("", "", "zzz") = "zzz" 5350 * StringUtils.replaceFirst("", ".*", "zzz") = "zzz" 5351 * StringUtils.replaceFirst("", ".+", "zzz") = "" 5352 * StringUtils.replaceFirst("abc", "", "ZZ") = "ZZabc" 5353 * StringUtils.replaceFirst("<__>\n<__>", "<.*>", "z") = "z\n<__>" 5354 * StringUtils.replaceFirst("<__>\n<__>", "(?s)<.*>", "z") = "z" 5355 * StringUtils.replaceFirst("ABCabc123", "[a-z]", "_") = "ABC_bc123" 5356 * StringUtils.replaceFirst("ABCabc123abc", "[^A-Z0-9]+", "_") = "ABC_123abc" 5357 * StringUtils.replaceFirst("ABCabc123abc", "[^A-Z0-9]+", "") = "ABC123abc" 5358 * StringUtils.replaceFirst("Lorem ipsum dolor sit", "( +)([a-z]+)", "_$2") = "Lorem_ipsum dolor sit" 5359 * </pre> 5360 * 5361 * @param text text to search and replace in, may be null 5362 * @param regex the regular expression to which this string is to be matched 5363 * @param replacement the string to be substituted for the first match 5364 * @return the text with the first replacement processed, 5365 * {@code null} if null String input 5366 * 5367 * @throws java.util.regex.PatternSyntaxException 5368 * if the regular expression's syntax is invalid 5369 * 5370 * @see String#replaceFirst(String, String) 5371 * @see java.util.regex.Pattern 5372 * @see java.util.regex.Pattern#DOTALL 5373 * @since 3.5 5374 */ 5375 public static String replaceFirst(final String text, final String regex, final String replacement) { 5376 if (text == null || regex == null|| replacement == null ) { 5377 return text; 5378 } 5379 return text.replaceFirst(regex, replacement); 5380 } 5381 5382 /** 5383 * <p>Replaces all occurrences of a String within another String.</p> 5384 * 5385 * <p>A {@code null} reference passed to this method is a no-op.</p> 5386 * 5387 * <pre> 5388 * StringUtils.replace(null, *, *) = null 5389 * StringUtils.replace("", *, *) = "" 5390 * StringUtils.replace("any", null, *) = "any" 5391 * StringUtils.replace("any", *, null) = "any" 5392 * StringUtils.replace("any", "", *) = "any" 5393 * StringUtils.replace("aba", "a", null) = "aba" 5394 * StringUtils.replace("aba", "a", "") = "b" 5395 * StringUtils.replace("aba", "a", "z") = "zbz" 5396 * </pre> 5397 * 5398 * @see #replace(String text, String searchString, String replacement, int max) 5399 * @param text text to search and replace in, may be null 5400 * @param searchString the String to search for, may be null 5401 * @param replacement the String to replace it with, may be null 5402 * @return the text with any replacements processed, 5403 * {@code null} if null String input 5404 */ 5405 public static String replace(final String text, final String searchString, final String replacement) { 5406 return replace(text, searchString, replacement, -1); 5407 } 5408 5409 /** 5410 * <p>Case insensitively replaces all occurrences of a String within another String.</p> 5411 * 5412 * <p>A {@code null} reference passed to this method is a no-op.</p> 5413 * 5414 * <pre> 5415 * StringUtils.replaceIgnoreCase(null, *, *) = null 5416 * StringUtils.replaceIgnoreCase("", *, *) = "" 5417 * StringUtils.replaceIgnoreCase("any", null, *) = "any" 5418 * StringUtils.replaceIgnoreCase("any", *, null) = "any" 5419 * StringUtils.replaceIgnoreCase("any", "", *) = "any" 5420 * StringUtils.replaceIgnoreCase("aba", "a", null) = "aba" 5421 * StringUtils.replaceIgnoreCase("abA", "A", "") = "b" 5422 * StringUtils.replaceIgnoreCase("aba", "A", "z") = "zbz" 5423 * </pre> 5424 * 5425 * @see #replaceIgnoreCase(String text, String searchString, String replacement, int max) 5426 * @param text text to search and replace in, may be null 5427 * @param searchString the String to search for (case insensitive), may be null 5428 * @param replacement the String to replace it with, may be null 5429 * @return the text with any replacements processed, 5430 * {@code null} if null String input 5431 * @since 3.5 5432 */ 5433 public static String replaceIgnoreCase(final String text, final String searchString, final String replacement) { 5434 return replaceIgnoreCase(text, searchString, replacement, -1); 5435 } 5436 5437 /** 5438 * <p>Replaces a String with another String inside a larger String, 5439 * for the first {@code max} values of the search String.</p> 5440 * 5441 * <p>A {@code null} reference passed to this method is a no-op.</p> 5442 * 5443 * <pre> 5444 * StringUtils.replace(null, *, *, *) = null 5445 * StringUtils.replace("", *, *, *) = "" 5446 * StringUtils.replace("any", null, *, *) = "any" 5447 * StringUtils.replace("any", *, null, *) = "any" 5448 * StringUtils.replace("any", "", *, *) = "any" 5449 * StringUtils.replace("any", *, *, 0) = "any" 5450 * StringUtils.replace("abaa", "a", null, -1) = "abaa" 5451 * StringUtils.replace("abaa", "a", "", -1) = "b" 5452 * StringUtils.replace("abaa", "a", "z", 0) = "abaa" 5453 * StringUtils.replace("abaa", "a", "z", 1) = "zbaa" 5454 * StringUtils.replace("abaa", "a", "z", 2) = "zbza" 5455 * StringUtils.replace("abaa", "a", "z", -1) = "zbzz" 5456 * </pre> 5457 * 5458 * @param text text to search and replace in, may be null 5459 * @param searchString the String to search for, may be null 5460 * @param replacement the String to replace it with, may be null 5461 * @param max maximum number of values to replace, or {@code -1} if no maximum 5462 * @return the text with any replacements processed, 5463 * {@code null} if null String input 5464 */ 5465 public static String replace(final String text, final String searchString, final String replacement, final int max) { 5466 return replace(text, searchString, replacement, max, false); 5467 } 5468 5469 /** 5470 * <p>Replaces a String with another String inside a larger String, 5471 * for the first {@code max} values of the search String, 5472 * case sensitively/insensisitively based on {@code ignoreCase} value.</p> 5473 * 5474 * <p>A {@code null} reference passed to this method is a no-op.</p> 5475 * 5476 * <pre> 5477 * StringUtils.replace(null, *, *, *, false) = null 5478 * StringUtils.replace("", *, *, *, false) = "" 5479 * StringUtils.replace("any", null, *, *, false) = "any" 5480 * StringUtils.replace("any", *, null, *, false) = "any" 5481 * StringUtils.replace("any", "", *, *, false) = "any" 5482 * StringUtils.replace("any", *, *, 0, false) = "any" 5483 * StringUtils.replace("abaa", "a", null, -1, false) = "abaa" 5484 * StringUtils.replace("abaa", "a", "", -1, false) = "b" 5485 * StringUtils.replace("abaa", "a", "z", 0, false) = "abaa" 5486 * StringUtils.replace("abaa", "A", "z", 1, false) = "abaa" 5487 * StringUtils.replace("abaa", "A", "z", 1, true) = "zbaa" 5488 * StringUtils.replace("abAa", "a", "z", 2, true) = "zbza" 5489 * StringUtils.replace("abAa", "a", "z", -1, true) = "zbzz" 5490 * </pre> 5491 * 5492 * @param text text to search and replace in, may be null 5493 * @param searchString the String to search for (case insensitive), may be null 5494 * @param replacement the String to replace it with, may be null 5495 * @param max maximum number of values to replace, or {@code -1} if no maximum 5496 * @param ignoreCase if true replace is case insensitive, otherwise case sensitive 5497 * @return the text with any replacements processed, 5498 * {@code null} if null String input 5499 */ 5500 private static String replace(final String text, String searchString, final String replacement, int max, final boolean ignoreCase) { 5501 if (isEmpty(text) || isEmpty(searchString) || replacement == null || max == 0) { 5502 return text; 5503 } 5504 String searchText = text; 5505 if (ignoreCase) { 5506 searchText = text.toLowerCase(); 5507 searchString = searchString.toLowerCase(); 5508 } 5509 int start = 0; 5510 int end = searchText.indexOf(searchString, start); 5511 if (end == INDEX_NOT_FOUND) { 5512 return text; 5513 } 5514 final int replLength = searchString.length(); 5515 int increase = replacement.length() - replLength; 5516 increase = increase < 0 ? 0 : increase; 5517 increase *= max < 0 ? 16 : max > 64 ? 64 : max; 5518 final StringBuilder buf = new StringBuilder(text.length() + increase); 5519 while (end != INDEX_NOT_FOUND) { 5520 buf.append(text.substring(start, end)).append(replacement); 5521 start = end + replLength; 5522 if (--max == 0) { 5523 break; 5524 } 5525 end = searchText.indexOf(searchString, start); 5526 } 5527 buf.append(text.substring(start)); 5528 return buf.toString(); 5529 } 5530 5531 /** 5532 * <p>Case insensitively replaces a String with another String inside a larger String, 5533 * for the first {@code max} values of the search String.</p> 5534 * 5535 * <p>A {@code null} reference passed to this method is a no-op.</p> 5536 * 5537 * <pre> 5538 * StringUtils.replaceIgnoreCase(null, *, *, *) = null 5539 * StringUtils.replaceIgnoreCase("", *, *, *) = "" 5540 * StringUtils.replaceIgnoreCase("any", null, *, *) = "any" 5541 * StringUtils.replaceIgnoreCase("any", *, null, *) = "any" 5542 * StringUtils.replaceIgnoreCase("any", "", *, *) = "any" 5543 * StringUtils.replaceIgnoreCase("any", *, *, 0) = "any" 5544 * StringUtils.replaceIgnoreCase("abaa", "a", null, -1) = "abaa" 5545 * StringUtils.replaceIgnoreCase("abaa", "a", "", -1) = "b" 5546 * StringUtils.replaceIgnoreCase("abaa", "a", "z", 0) = "abaa" 5547 * StringUtils.replaceIgnoreCase("abaa", "A", "z", 1) = "zbaa" 5548 * StringUtils.replaceIgnoreCase("abAa", "a", "z", 2) = "zbza" 5549 * StringUtils.replaceIgnoreCase("abAa", "a", "z", -1) = "zbzz" 5550 * </pre> 5551 * 5552 * @param text text to search and replace in, may be null 5553 * @param searchString the String to search for (case insensitive), may be null 5554 * @param replacement the String to replace it with, may be null 5555 * @param max maximum number of values to replace, or {@code -1} if no maximum 5556 * @return the text with any replacements processed, 5557 * {@code null} if null String input 5558 * @since 3.5 5559 */ 5560 public static String replaceIgnoreCase(final String text, final String searchString, final String replacement, final int max) { 5561 return replace(text, searchString, replacement, max, true); 5562 } 5563 5564 /** 5565 * <p> 5566 * Replaces all occurrences of Strings within another String. 5567 * </p> 5568 * 5569 * <p> 5570 * A {@code null} reference passed to this method is a no-op, or if 5571 * any "search string" or "string to replace" is null, that replace will be 5572 * ignored. This will not repeat. For repeating replaces, call the 5573 * overloaded method. 5574 * </p> 5575 * 5576 * <pre> 5577 * StringUtils.replaceEach(null, *, *) = null 5578 * StringUtils.replaceEach("", *, *) = "" 5579 * StringUtils.replaceEach("aba", null, null) = "aba" 5580 * StringUtils.replaceEach("aba", new String[0], null) = "aba" 5581 * StringUtils.replaceEach("aba", null, new String[0]) = "aba" 5582 * StringUtils.replaceEach("aba", new String[]{"a"}, null) = "aba" 5583 * StringUtils.replaceEach("aba", new String[]{"a"}, new String[]{""}) = "b" 5584 * StringUtils.replaceEach("aba", new String[]{null}, new String[]{"a"}) = "aba" 5585 * StringUtils.replaceEach("abcde", new String[]{"ab", "d"}, new String[]{"w", "t"}) = "wcte" 5586 * (example of how it does not repeat) 5587 * StringUtils.replaceEach("abcde", new String[]{"ab", "d"}, new String[]{"d", "t"}) = "dcte" 5588 * </pre> 5589 * 5590 * @param text 5591 * text to search and replace in, no-op if null 5592 * @param searchList 5593 * the Strings to search for, no-op if null 5594 * @param replacementList 5595 * the Strings to replace them with, no-op if null 5596 * @return the text with any replacements processed, {@code null} if 5597 * null String input 5598 * @throws IllegalArgumentException 5599 * if the lengths of the arrays are not the same (null is ok, 5600 * and/or size 0) 5601 * @since 2.4 5602 */ 5603 public static String replaceEach(final String text, final String[] searchList, final String[] replacementList) { 5604 return replaceEach(text, searchList, replacementList, false, 0); 5605 } 5606 5607 /** 5608 * <p> 5609 * Replaces all occurrences of Strings within another String. 5610 * </p> 5611 * 5612 * <p> 5613 * A {@code null} reference passed to this method is a no-op, or if 5614 * any "search string" or "string to replace" is null, that replace will be 5615 * ignored. 5616 * </p> 5617 * 5618 * <pre> 5619 * StringUtils.replaceEachRepeatedly(null, *, *) = null 5620 * StringUtils.replaceEachRepeatedly("", *, *) = "" 5621 * StringUtils.replaceEachRepeatedly("aba", null, null) = "aba" 5622 * StringUtils.replaceEachRepeatedly("aba", new String[0], null) = "aba" 5623 * StringUtils.replaceEachRepeatedly("aba", null, new String[0]) = "aba" 5624 * StringUtils.replaceEachRepeatedly("aba", new String[]{"a"}, null) = "aba" 5625 * StringUtils.replaceEachRepeatedly("aba", new String[]{"a"}, new String[]{""}) = "b" 5626 * StringUtils.replaceEachRepeatedly("aba", new String[]{null}, new String[]{"a"}) = "aba" 5627 * StringUtils.replaceEachRepeatedly("abcde", new String[]{"ab", "d"}, new String[]{"w", "t"}) = "wcte" 5628 * (example of how it repeats) 5629 * StringUtils.replaceEachRepeatedly("abcde", new String[]{"ab", "d"}, new String[]{"d", "t"}) = "tcte" 5630 * StringUtils.replaceEachRepeatedly("abcde", new String[]{"ab", "d"}, new String[]{"d", "ab"}) = IllegalStateException 5631 * </pre> 5632 * 5633 * @param text 5634 * text to search and replace in, no-op if null 5635 * @param searchList 5636 * the Strings to search for, no-op if null 5637 * @param replacementList 5638 * the Strings to replace them with, no-op if null 5639 * @return the text with any replacements processed, {@code null} if 5640 * null String input 5641 * @throws IllegalStateException 5642 * if the search is repeating and there is an endless loop due 5643 * to outputs of one being inputs to another 5644 * @throws IllegalArgumentException 5645 * if the lengths of the arrays are not the same (null is ok, 5646 * and/or size 0) 5647 * @since 2.4 5648 */ 5649 public static String replaceEachRepeatedly(final String text, final String[] searchList, final String[] replacementList) { 5650 // timeToLive should be 0 if not used or nothing to replace, else it's 5651 // the length of the replace array 5652 final int timeToLive = searchList == null ? 0 : searchList.length; 5653 return replaceEach(text, searchList, replacementList, true, timeToLive); 5654 } 5655 5656 /** 5657 * <p> 5658 * Replace all occurrences of Strings within another String. 5659 * This is a private recursive helper method for {@link #replaceEachRepeatedly(String, String[], String[])} and 5660 * {@link #replaceEach(String, String[], String[])} 5661 * </p> 5662 * 5663 * <p> 5664 * A {@code null} reference passed to this method is a no-op, or if 5665 * any "search string" or "string to replace" is null, that replace will be 5666 * ignored. 5667 * </p> 5668 * 5669 * <pre> 5670 * StringUtils.replaceEach(null, *, *, *, *) = null 5671 * StringUtils.replaceEach("", *, *, *, *) = "" 5672 * StringUtils.replaceEach("aba", null, null, *, *) = "aba" 5673 * StringUtils.replaceEach("aba", new String[0], null, *, *) = "aba" 5674 * StringUtils.replaceEach("aba", null, new String[0], *, *) = "aba" 5675 * StringUtils.replaceEach("aba", new String[]{"a"}, null, *, *) = "aba" 5676 * StringUtils.replaceEach("aba", new String[]{"a"}, new String[]{""}, *, >=0) = "b" 5677 * StringUtils.replaceEach("aba", new String[]{null}, new String[]{"a"}, *, >=0) = "aba" 5678 * StringUtils.replaceEach("abcde", new String[]{"ab", "d"}, new String[]{"w", "t"}, *, >=0) = "wcte" 5679 * (example of how it repeats) 5680 * StringUtils.replaceEach("abcde", new String[]{"ab", "d"}, new String[]{"d", "t"}, false, >=0) = "dcte" 5681 * StringUtils.replaceEach("abcde", new String[]{"ab", "d"}, new String[]{"d", "t"}, true, >=2) = "tcte" 5682 * StringUtils.replaceEach("abcde", new String[]{"ab", "d"}, new String[]{"d", "ab"}, *, *) = IllegalStateException 5683 * </pre> 5684 * 5685 * @param text 5686 * text to search and replace in, no-op if null 5687 * @param searchList 5688 * the Strings to search for, no-op if null 5689 * @param replacementList 5690 * the Strings to replace them with, no-op if null 5691 * @param repeat if true, then replace repeatedly 5692 * until there are no more possible replacements or timeToLive < 0 5693 * @param timeToLive 5694 * if less than 0 then there is a circular reference and endless 5695 * loop 5696 * @return the text with any replacements processed, {@code null} if 5697 * null String input 5698 * @throws IllegalStateException 5699 * if the search is repeating and there is an endless loop due 5700 * to outputs of one being inputs to another 5701 * @throws IllegalArgumentException 5702 * if the lengths of the arrays are not the same (null is ok, 5703 * and/or size 0) 5704 * @since 2.4 5705 */ 5706 private static String replaceEach( 5707 final String text, final String[] searchList, final String[] replacementList, final boolean repeat, final int timeToLive) { 5708 5709 // mchyzer Performance note: This creates very few new objects (one major goal) 5710 // let me know if there are performance requests, we can create a harness to measure 5711 5712 if (text == null || text.isEmpty() || searchList == null || 5713 searchList.length == 0 || replacementList == null || replacementList.length == 0) { 5714 return text; 5715 } 5716 5717 // if recursing, this shouldn't be less than 0 5718 if (timeToLive < 0) { 5719 throw new IllegalStateException("Aborting to protect against StackOverflowError - " + 5720 "output of one loop is the input of another"); 5721 } 5722 5723 final int searchLength = searchList.length; 5724 final int replacementLength = replacementList.length; 5725 5726 // make sure lengths are ok, these need to be equal 5727 if (searchLength != replacementLength) { 5728 throw new IllegalArgumentException("Search and Replace array lengths don't match: " 5729 + searchLength 5730 + " vs " 5731 + replacementLength); 5732 } 5733 5734 // keep track of which still have matches 5735 final boolean[] noMoreMatchesForReplIndex = new boolean[searchLength]; 5736 5737 // index on index that the match was found 5738 int textIndex = -1; 5739 int replaceIndex = -1; 5740 int tempIndex = -1; 5741 5742 // index of replace array that will replace the search string found 5743 // NOTE: logic duplicated below START 5744 for (int i = 0; i < searchLength; i++) { 5745 if (noMoreMatchesForReplIndex[i] || searchList[i] == null || 5746 searchList[i].isEmpty() || replacementList[i] == null) { 5747 continue; 5748 } 5749 tempIndex = text.indexOf(searchList[i]); 5750 5751 // see if we need to keep searching for this 5752 if (tempIndex == -1) { 5753 noMoreMatchesForReplIndex[i] = true; 5754 } else { 5755 if (textIndex == -1 || tempIndex < textIndex) { 5756 textIndex = tempIndex; 5757 replaceIndex = i; 5758 } 5759 } 5760 } 5761 // NOTE: logic mostly below END 5762 5763 // no search strings found, we are done 5764 if (textIndex == -1) { 5765 return text; 5766 } 5767 5768 int start = 0; 5769 5770 // get a good guess on the size of the result buffer so it doesn't have to double if it goes over a bit 5771 int increase = 0; 5772 5773 // count the replacement text elements that are larger than their corresponding text being replaced 5774 for (int i = 0; i < searchList.length; i++) { 5775 if (searchList[i] == null || replacementList[i] == null) { 5776 continue; 5777 } 5778 final int greater = replacementList[i].length() - searchList[i].length(); 5779 if (greater > 0) { 5780 increase += 3 * greater; // assume 3 matches 5781 } 5782 } 5783 // have upper-bound at 20% increase, then let Java take over 5784 increase = Math.min(increase, text.length() / 5); 5785 5786 final StringBuilder buf = new StringBuilder(text.length() + increase); 5787 5788 while (textIndex != -1) { 5789 5790 for (int i = start; i < textIndex; i++) { 5791 buf.append(text.charAt(i)); 5792 } 5793 buf.append(replacementList[replaceIndex]); 5794 5795 start = textIndex + searchList[replaceIndex].length(); 5796 5797 textIndex = -1; 5798 replaceIndex = -1; 5799 tempIndex = -1; 5800 // find the next earliest match 5801 // NOTE: logic mostly duplicated above START 5802 for (int i = 0; i < searchLength; i++) { 5803 if (noMoreMatchesForReplIndex[i] || searchList[i] == null || 5804 searchList[i].isEmpty() || replacementList[i] == null) { 5805 continue; 5806 } 5807 tempIndex = text.indexOf(searchList[i], start); 5808 5809 // see if we need to keep searching for this 5810 if (tempIndex == -1) { 5811 noMoreMatchesForReplIndex[i] = true; 5812 } else { 5813 if (textIndex == -1 || tempIndex < textIndex) { 5814 textIndex = tempIndex; 5815 replaceIndex = i; 5816 } 5817 } 5818 } 5819 // NOTE: logic duplicated above END 5820 5821 } 5822 final int textLength = text.length(); 5823 for (int i = start; i < textLength; i++) { 5824 buf.append(text.charAt(i)); 5825 } 5826 final String result = buf.toString(); 5827 if (!repeat) { 5828 return result; 5829 } 5830 5831 return replaceEach(result, searchList, replacementList, repeat, timeToLive - 1); 5832 } 5833 5834 // Replace, character based 5835 //----------------------------------------------------------------------- 5836 /** 5837 * <p>Replaces all occurrences of a character in a String with another. 5838 * This is a null-safe version of {@link String#replace(char, char)}.</p> 5839 * 5840 * <p>A {@code null} string input returns {@code null}. 5841 * An empty ("") string input returns an empty string.</p> 5842 * 5843 * <pre> 5844 * StringUtils.replaceChars(null, *, *) = null 5845 * StringUtils.replaceChars("", *, *) = "" 5846 * StringUtils.replaceChars("abcba", 'b', 'y') = "aycya" 5847 * StringUtils.replaceChars("abcba", 'z', 'y') = "abcba" 5848 * </pre> 5849 * 5850 * @param str String to replace characters in, may be null 5851 * @param searchChar the character to search for, may be null 5852 * @param replaceChar the character to replace, may be null 5853 * @return modified String, {@code null} if null string input 5854 * @since 2.0 5855 */ 5856 public static String replaceChars(final String str, final char searchChar, final char replaceChar) { 5857 if (str == null) { 5858 return null; 5859 } 5860 return str.replace(searchChar, replaceChar); 5861 } 5862 5863 /** 5864 * <p>Replaces multiple characters in a String in one go. 5865 * This method can also be used to delete characters.</p> 5866 * 5867 * <p>For example:<br> 5868 * <code>replaceChars("hello", "ho", "jy") = jelly</code>.</p> 5869 * 5870 * <p>A {@code null} string input returns {@code null}. 5871 * An empty ("") string input returns an empty string. 5872 * A null or empty set of search characters returns the input string.</p> 5873 * 5874 * <p>The length of the search characters should normally equal the length 5875 * of the replace characters. 5876 * If the search characters is longer, then the extra search characters 5877 * are deleted. 5878 * If the search characters is shorter, then the extra replace characters 5879 * are ignored.</p> 5880 * 5881 * <pre> 5882 * StringUtils.replaceChars(null, *, *) = null 5883 * StringUtils.replaceChars("", *, *) = "" 5884 * StringUtils.replaceChars("abc", null, *) = "abc" 5885 * StringUtils.replaceChars("abc", "", *) = "abc" 5886 * StringUtils.replaceChars("abc", "b", null) = "ac" 5887 * StringUtils.replaceChars("abc", "b", "") = "ac" 5888 * StringUtils.replaceChars("abcba", "bc", "yz") = "ayzya" 5889 * StringUtils.replaceChars("abcba", "bc", "y") = "ayya" 5890 * StringUtils.replaceChars("abcba", "bc", "yzx") = "ayzya" 5891 * </pre> 5892 * 5893 * @param str String to replace characters in, may be null 5894 * @param searchChars a set of characters to search for, may be null 5895 * @param replaceChars a set of characters to replace, may be null 5896 * @return modified String, {@code null} if null string input 5897 * @since 2.0 5898 */ 5899 public static String replaceChars(final String str, final String searchChars, String replaceChars) { 5900 if (isEmpty(str) || isEmpty(searchChars)) { 5901 return str; 5902 } 5903 if (replaceChars == null) { 5904 replaceChars = EMPTY; 5905 } 5906 boolean modified = false; 5907 final int replaceCharsLength = replaceChars.length(); 5908 final int strLength = str.length(); 5909 final StringBuilder buf = new StringBuilder(strLength); 5910 for (int i = 0; i < strLength; i++) { 5911 final char ch = str.charAt(i); 5912 final int index = searchChars.indexOf(ch); 5913 if (index >= 0) { 5914 modified = true; 5915 if (index < replaceCharsLength) { 5916 buf.append(replaceChars.charAt(index)); 5917 } 5918 } else { 5919 buf.append(ch); 5920 } 5921 } 5922 if (modified) { 5923 return buf.toString(); 5924 } 5925 return str; 5926 } 5927 5928 // Overlay 5929 //----------------------------------------------------------------------- 5930 /** 5931 * <p>Overlays part of a String with another String.</p> 5932 * 5933 * <p>A {@code null} string input returns {@code null}. 5934 * A negative index is treated as zero. 5935 * An index greater than the string length is treated as the string length. 5936 * The start index is always the smaller of the two indices.</p> 5937 * 5938 * <pre> 5939 * StringUtils.overlay(null, *, *, *) = null 5940 * StringUtils.overlay("", "abc", 0, 0) = "abc" 5941 * StringUtils.overlay("abcdef", null, 2, 4) = "abef" 5942 * StringUtils.overlay("abcdef", "", 2, 4) = "abef" 5943 * StringUtils.overlay("abcdef", "", 4, 2) = "abef" 5944 * StringUtils.overlay("abcdef", "zzzz", 2, 4) = "abzzzzef" 5945 * StringUtils.overlay("abcdef", "zzzz", 4, 2) = "abzzzzef" 5946 * StringUtils.overlay("abcdef", "zzzz", -1, 4) = "zzzzef" 5947 * StringUtils.overlay("abcdef", "zzzz", 2, 8) = "abzzzz" 5948 * StringUtils.overlay("abcdef", "zzzz", -2, -3) = "zzzzabcdef" 5949 * StringUtils.overlay("abcdef", "zzzz", 8, 10) = "abcdefzzzz" 5950 * </pre> 5951 * 5952 * @param str the String to do overlaying in, may be null 5953 * @param overlay the String to overlay, may be null 5954 * @param start the position to start overlaying at 5955 * @param end the position to stop overlaying before 5956 * @return overlayed String, {@code null} if null String input 5957 * @since 2.0 5958 */ 5959 public static String overlay(final String str, String overlay, int start, int end) { 5960 if (str == null) { 5961 return null; 5962 } 5963 if (overlay == null) { 5964 overlay = EMPTY; 5965 } 5966 final int len = str.length(); 5967 if (start < 0) { 5968 start = 0; 5969 } 5970 if (start > len) { 5971 start = len; 5972 } 5973 if (end < 0) { 5974 end = 0; 5975 } 5976 if (end > len) { 5977 end = len; 5978 } 5979 if (start > end) { 5980 final int temp = start; 5981 start = end; 5982 end = temp; 5983 } 5984 return new StringBuilder(len + start - end + overlay.length() + 1) 5985 .append(str.substring(0, start)) 5986 .append(overlay) 5987 .append(str.substring(end)) 5988 .toString(); 5989 } 5990 5991 // Chomping 5992 //----------------------------------------------------------------------- 5993 /** 5994 * <p>Removes one newline from end of a String if it's there, 5995 * otherwise leave it alone. A newline is "{@code \n}", 5996 * "{@code \r}", or "{@code \r\n}".</p> 5997 * 5998 * <p>NOTE: This method changed in 2.0. 5999 * It now more closely matches Perl chomp.</p> 6000 * 6001 * <pre> 6002 * StringUtils.chomp(null) = null 6003 * StringUtils.chomp("") = "" 6004 * StringUtils.chomp("abc \r") = "abc " 6005 * StringUtils.chomp("abc\n") = "abc" 6006 * StringUtils.chomp("abc\r\n") = "abc" 6007 * StringUtils.chomp("abc\r\n\r\n") = "abc\r\n" 6008 * StringUtils.chomp("abc\n\r") = "abc\n" 6009 * StringUtils.chomp("abc\n\rabc") = "abc\n\rabc" 6010 * StringUtils.chomp("\r") = "" 6011 * StringUtils.chomp("\n") = "" 6012 * StringUtils.chomp("\r\n") = "" 6013 * </pre> 6014 * 6015 * @param str the String to chomp a newline from, may be null 6016 * @return String without newline, {@code null} if null String input 6017 */ 6018 public static String chomp(final String str) { 6019 if (isEmpty(str)) { 6020 return str; 6021 } 6022 6023 if (str.length() == 1) { 6024 final char ch = str.charAt(0); 6025 if (ch == CharUtils.CR || ch == CharUtils.LF) { 6026 return EMPTY; 6027 } 6028 return str; 6029 } 6030 6031 int lastIdx = str.length() - 1; 6032 final char last = str.charAt(lastIdx); 6033 6034 if (last == CharUtils.LF) { 6035 if (str.charAt(lastIdx - 1) == CharUtils.CR) { 6036 lastIdx--; 6037 } 6038 } else if (last != CharUtils.CR) { 6039 lastIdx++; 6040 } 6041 return str.substring(0, lastIdx); 6042 } 6043 6044 /** 6045 * <p>Removes {@code separator} from the end of 6046 * {@code str} if it's there, otherwise leave it alone.</p> 6047 * 6048 * <p>NOTE: This method changed in version 2.0. 6049 * It now more closely matches Perl chomp. 6050 * For the previous behavior, use {@link #substringBeforeLast(String, String)}. 6051 * This method uses {@link String#endsWith(String)}.</p> 6052 * 6053 * <pre> 6054 * StringUtils.chomp(null, *) = null 6055 * StringUtils.chomp("", *) = "" 6056 * StringUtils.chomp("foobar", "bar") = "foo" 6057 * StringUtils.chomp("foobar", "baz") = "foobar" 6058 * StringUtils.chomp("foo", "foo") = "" 6059 * StringUtils.chomp("foo ", "foo") = "foo " 6060 * StringUtils.chomp(" foo", "foo") = " " 6061 * StringUtils.chomp("foo", "foooo") = "foo" 6062 * StringUtils.chomp("foo", "") = "foo" 6063 * StringUtils.chomp("foo", null) = "foo" 6064 * </pre> 6065 * 6066 * @param str the String to chomp from, may be null 6067 * @param separator separator String, may be null 6068 * @return String without trailing separator, {@code null} if null String input 6069 * @deprecated This feature will be removed in Lang 4.0, use {@link StringUtils#removeEnd(String, String)} instead 6070 */ 6071 @Deprecated 6072 public static String chomp(final String str, final String separator) { 6073 return removeEnd(str,separator); 6074 } 6075 6076 // Chopping 6077 //----------------------------------------------------------------------- 6078 /** 6079 * <p>Remove the last character from a String.</p> 6080 * 6081 * <p>If the String ends in {@code \r\n}, then remove both 6082 * of them.</p> 6083 * 6084 * <pre> 6085 * StringUtils.chop(null) = null 6086 * StringUtils.chop("") = "" 6087 * StringUtils.chop("abc \r") = "abc " 6088 * StringUtils.chop("abc\n") = "abc" 6089 * StringUtils.chop("abc\r\n") = "abc" 6090 * StringUtils.chop("abc") = "ab" 6091 * StringUtils.chop("abc\nabc") = "abc\nab" 6092 * StringUtils.chop("a") = "" 6093 * StringUtils.chop("\r") = "" 6094 * StringUtils.chop("\n") = "" 6095 * StringUtils.chop("\r\n") = "" 6096 * </pre> 6097 * 6098 * @param str the String to chop last character from, may be null 6099 * @return String without last character, {@code null} if null String input 6100 */ 6101 public static String chop(final String str) { 6102 if (str == null) { 6103 return null; 6104 } 6105 final int strLen = str.length(); 6106 if (strLen < 2) { 6107 return EMPTY; 6108 } 6109 final int lastIdx = strLen - 1; 6110 final String ret = str.substring(0, lastIdx); 6111 final char last = str.charAt(lastIdx); 6112 if (last == CharUtils.LF && ret.charAt(lastIdx - 1) == CharUtils.CR) { 6113 return ret.substring(0, lastIdx - 1); 6114 } 6115 return ret; 6116 } 6117 6118 // Conversion 6119 //----------------------------------------------------------------------- 6120 6121 // Padding 6122 //----------------------------------------------------------------------- 6123 /** 6124 * <p>Repeat a String {@code repeat} times to form a 6125 * new String.</p> 6126 * 6127 * <pre> 6128 * StringUtils.repeat(null, 2) = null 6129 * StringUtils.repeat("", 0) = "" 6130 * StringUtils.repeat("", 2) = "" 6131 * StringUtils.repeat("a", 3) = "aaa" 6132 * StringUtils.repeat("ab", 2) = "abab" 6133 * StringUtils.repeat("a", -2) = "" 6134 * </pre> 6135 * 6136 * @param str the String to repeat, may be null 6137 * @param repeat number of times to repeat str, negative treated as zero 6138 * @return a new String consisting of the original String repeated, 6139 * {@code null} if null String input 6140 */ 6141 public static String repeat(final String str, final int repeat) { 6142 // Performance tuned for 2.0 (JDK1.4) 6143 6144 if (str == null) { 6145 return null; 6146 } 6147 if (repeat <= 0) { 6148 return EMPTY; 6149 } 6150 final int inputLength = str.length(); 6151 if (repeat == 1 || inputLength == 0) { 6152 return str; 6153 } 6154 if (inputLength == 1 && repeat <= PAD_LIMIT) { 6155 return repeat(str.charAt(0), repeat); 6156 } 6157 6158 final int outputLength = inputLength * repeat; 6159 switch (inputLength) { 6160 case 1 : 6161 return repeat(str.charAt(0), repeat); 6162 case 2 : 6163 final char ch0 = str.charAt(0); 6164 final char ch1 = str.charAt(1); 6165 final char[] output2 = new char[outputLength]; 6166 for (int i = repeat * 2 - 2; i >= 0; i--, i--) { 6167 output2[i] = ch0; 6168 output2[i + 1] = ch1; 6169 } 6170 return new String(output2); 6171 default : 6172 final StringBuilder buf = new StringBuilder(outputLength); 6173 for (int i = 0; i < repeat; i++) { 6174 buf.append(str); 6175 } 6176 return buf.toString(); 6177 } 6178 } 6179 6180 /** 6181 * <p>Repeat a String {@code repeat} times to form a 6182 * new String, with a String separator injected each time. </p> 6183 * 6184 * <pre> 6185 * StringUtils.repeat(null, null, 2) = null 6186 * StringUtils.repeat(null, "x", 2) = null 6187 * StringUtils.repeat("", null, 0) = "" 6188 * StringUtils.repeat("", "", 2) = "" 6189 * StringUtils.repeat("", "x", 3) = "xxx" 6190 * StringUtils.repeat("?", ", ", 3) = "?, ?, ?" 6191 * </pre> 6192 * 6193 * @param str the String to repeat, may be null 6194 * @param separator the String to inject, may be null 6195 * @param repeat number of times to repeat str, negative treated as zero 6196 * @return a new String consisting of the original String repeated, 6197 * {@code null} if null String input 6198 * @since 2.5 6199 */ 6200 public static String repeat(final String str, final String separator, final int repeat) { 6201 if(str == null || separator == null) { 6202 return repeat(str, repeat); 6203 } 6204 // given that repeat(String, int) is quite optimized, better to rely on it than try and splice this into it 6205 final String result = repeat(str + separator, repeat); 6206 return removeEnd(result, separator); 6207 } 6208 6209 /** 6210 * <p>Returns padding using the specified delimiter repeated 6211 * to a given length.</p> 6212 * 6213 * <pre> 6214 * StringUtils.repeat('e', 0) = "" 6215 * StringUtils.repeat('e', 3) = "eee" 6216 * StringUtils.repeat('e', -2) = "" 6217 * </pre> 6218 * 6219 * <p>Note: this method doesn't not support padding with 6220 * <a href="http://www.unicode.org/glossary/#supplementary_character">Unicode Supplementary Characters</a> 6221 * as they require a pair of {@code char}s to be represented. 6222 * If you are needing to support full I18N of your applications 6223 * consider using {@link #repeat(String, int)} instead. 6224 * </p> 6225 * 6226 * @param ch character to repeat 6227 * @param repeat number of times to repeat char, negative treated as zero 6228 * @return String with repeated character 6229 * @see #repeat(String, int) 6230 */ 6231 public static String repeat(final char ch, final int repeat) { 6232 if (repeat <= 0) { 6233 return EMPTY; 6234 } 6235 final char[] buf = new char[repeat]; 6236 for (int i = repeat - 1; i >= 0; i--) { 6237 buf[i] = ch; 6238 } 6239 return new String(buf); 6240 } 6241 6242 /** 6243 * <p>Right pad a String with spaces (' ').</p> 6244 * 6245 * <p>The String is padded to the size of {@code size}.</p> 6246 * 6247 * <pre> 6248 * StringUtils.rightPad(null, *) = null 6249 * StringUtils.rightPad("", 3) = " " 6250 * StringUtils.rightPad("bat", 3) = "bat" 6251 * StringUtils.rightPad("bat", 5) = "bat " 6252 * StringUtils.rightPad("bat", 1) = "bat" 6253 * StringUtils.rightPad("bat", -1) = "bat" 6254 * </pre> 6255 * 6256 * @param str the String to pad out, may be null 6257 * @param size the size to pad to 6258 * @return right padded String or original String if no padding is necessary, 6259 * {@code null} if null String input 6260 */ 6261 public static String rightPad(final String str, final int size) { 6262 return rightPad(str, size, ' '); 6263 } 6264 6265 /** 6266 * <p>Right pad a String with a specified character.</p> 6267 * 6268 * <p>The String is padded to the size of {@code size}.</p> 6269 * 6270 * <pre> 6271 * StringUtils.rightPad(null, *, *) = null 6272 * StringUtils.rightPad("", 3, 'z') = "zzz" 6273 * StringUtils.rightPad("bat", 3, 'z') = "bat" 6274 * StringUtils.rightPad("bat", 5, 'z') = "batzz" 6275 * StringUtils.rightPad("bat", 1, 'z') = "bat" 6276 * StringUtils.rightPad("bat", -1, 'z') = "bat" 6277 * </pre> 6278 * 6279 * @param str the String to pad out, may be null 6280 * @param size the size to pad to 6281 * @param padChar the character to pad with 6282 * @return right padded String or original String if no padding is necessary, 6283 * {@code null} if null String input 6284 * @since 2.0 6285 */ 6286 public static String rightPad(final String str, final int size, final char padChar) { 6287 if (str == null) { 6288 return null; 6289 } 6290 final int pads = size - str.length(); 6291 if (pads <= 0) { 6292 return str; // returns original String when possible 6293 } 6294 if (pads > PAD_LIMIT) { 6295 return rightPad(str, size, String.valueOf(padChar)); 6296 } 6297 return str.concat(repeat(padChar, pads)); 6298 } 6299 6300 /** 6301 * <p>Right pad a String with a specified String.</p> 6302 * 6303 * <p>The String is padded to the size of {@code size}.</p> 6304 * 6305 * <pre> 6306 * StringUtils.rightPad(null, *, *) = null 6307 * StringUtils.rightPad("", 3, "z") = "zzz" 6308 * StringUtils.rightPad("bat", 3, "yz") = "bat" 6309 * StringUtils.rightPad("bat", 5, "yz") = "batyz" 6310 * StringUtils.rightPad("bat", 8, "yz") = "batyzyzy" 6311 * StringUtils.rightPad("bat", 1, "yz") = "bat" 6312 * StringUtils.rightPad("bat", -1, "yz") = "bat" 6313 * StringUtils.rightPad("bat", 5, null) = "bat " 6314 * StringUtils.rightPad("bat", 5, "") = "bat " 6315 * </pre> 6316 * 6317 * @param str the String to pad out, may be null 6318 * @param size the size to pad to 6319 * @param padStr the String to pad with, null or empty treated as single space 6320 * @return right padded String or original String if no padding is necessary, 6321 * {@code null} if null String input 6322 */ 6323 public static String rightPad(final String str, final int size, String padStr) { 6324 if (str == null) { 6325 return null; 6326 } 6327 if (isEmpty(padStr)) { 6328 padStr = SPACE; 6329 } 6330 final int padLen = padStr.length(); 6331 final int strLen = str.length(); 6332 final int pads = size - strLen; 6333 if (pads <= 0) { 6334 return str; // returns original String when possible 6335 } 6336 if (padLen == 1 && pads <= PAD_LIMIT) { 6337 return rightPad(str, size, padStr.charAt(0)); 6338 } 6339 6340 if (pads == padLen) { 6341 return str.concat(padStr); 6342 } else if (pads < padLen) { 6343 return str.concat(padStr.substring(0, pads)); 6344 } else { 6345 final char[] padding = new char[pads]; 6346 final char[] padChars = padStr.toCharArray(); 6347 for (int i = 0; i < pads; i++) { 6348 padding[i] = padChars[i % padLen]; 6349 } 6350 return str.concat(new String(padding)); 6351 } 6352 } 6353 6354 /** 6355 * <p>Left pad a String with spaces (' ').</p> 6356 * 6357 * <p>The String is padded to the size of {@code size}.</p> 6358 * 6359 * <pre> 6360 * StringUtils.leftPad(null, *) = null 6361 * StringUtils.leftPad("", 3) = " " 6362 * StringUtils.leftPad("bat", 3) = "bat" 6363 * StringUtils.leftPad("bat", 5) = " bat" 6364 * StringUtils.leftPad("bat", 1) = "bat" 6365 * StringUtils.leftPad("bat", -1) = "bat" 6366 * </pre> 6367 * 6368 * @param str the String to pad out, may be null 6369 * @param size the size to pad to 6370 * @return left padded String or original String if no padding is necessary, 6371 * {@code null} if null String input 6372 */ 6373 public static String leftPad(final String str, final int size) { 6374 return leftPad(str, size, ' '); 6375 } 6376 6377 /** 6378 * <p>Left pad a String with a specified character.</p> 6379 * 6380 * <p>Pad to a size of {@code size}.</p> 6381 * 6382 * <pre> 6383 * StringUtils.leftPad(null, *, *) = null 6384 * StringUtils.leftPad("", 3, 'z') = "zzz" 6385 * StringUtils.leftPad("bat", 3, 'z') = "bat" 6386 * StringUtils.leftPad("bat", 5, 'z') = "zzbat" 6387 * StringUtils.leftPad("bat", 1, 'z') = "bat" 6388 * StringUtils.leftPad("bat", -1, 'z') = "bat" 6389 * </pre> 6390 * 6391 * @param str the String to pad out, may be null 6392 * @param size the size to pad to 6393 * @param padChar the character to pad with 6394 * @return left padded String or original String if no padding is necessary, 6395 * {@code null} if null String input 6396 * @since 2.0 6397 */ 6398 public static String leftPad(final String str, final int size, final char padChar) { 6399 if (str == null) { 6400 return null; 6401 } 6402 final int pads = size - str.length(); 6403 if (pads <= 0) { 6404 return str; // returns original String when possible 6405 } 6406 if (pads > PAD_LIMIT) { 6407 return leftPad(str, size, String.valueOf(padChar)); 6408 } 6409 return repeat(padChar, pads).concat(str); 6410 } 6411 6412 /** 6413 * <p>Left pad a String with a specified String.</p> 6414 * 6415 * <p>Pad to a size of {@code size}.</p> 6416 * 6417 * <pre> 6418 * StringUtils.leftPad(null, *, *) = null 6419 * StringUtils.leftPad("", 3, "z") = "zzz" 6420 * StringUtils.leftPad("bat", 3, "yz") = "bat" 6421 * StringUtils.leftPad("bat", 5, "yz") = "yzbat" 6422 * StringUtils.leftPad("bat", 8, "yz") = "yzyzybat" 6423 * StringUtils.leftPad("bat", 1, "yz") = "bat" 6424 * StringUtils.leftPad("bat", -1, "yz") = "bat" 6425 * StringUtils.leftPad("bat", 5, null) = " bat" 6426 * StringUtils.leftPad("bat", 5, "") = " bat" 6427 * </pre> 6428 * 6429 * @param str the String to pad out, may be null 6430 * @param size the size to pad to 6431 * @param padStr the String to pad with, null or empty treated as single space 6432 * @return left padded String or original String if no padding is necessary, 6433 * {@code null} if null String input 6434 */ 6435 public static String leftPad(final String str, final int size, String padStr) { 6436 if (str == null) { 6437 return null; 6438 } 6439 if (isEmpty(padStr)) { 6440 padStr = SPACE; 6441 } 6442 final int padLen = padStr.length(); 6443 final int strLen = str.length(); 6444 final int pads = size - strLen; 6445 if (pads <= 0) { 6446 return str; // returns original String when possible 6447 } 6448 if (padLen == 1 && pads <= PAD_LIMIT) { 6449 return leftPad(str, size, padStr.charAt(0)); 6450 } 6451 6452 if (pads == padLen) { 6453 return padStr.concat(str); 6454 } else if (pads < padLen) { 6455 return padStr.substring(0, pads).concat(str); 6456 } else { 6457 final char[] padding = new char[pads]; 6458 final char[] padChars = padStr.toCharArray(); 6459 for (int i = 0; i < pads; i++) { 6460 padding[i] = padChars[i % padLen]; 6461 } 6462 return new String(padding).concat(str); 6463 } 6464 } 6465 6466 /** 6467 * Gets a CharSequence length or {@code 0} if the CharSequence is 6468 * {@code null}. 6469 * 6470 * @param cs 6471 * a CharSequence or {@code null} 6472 * @return CharSequence length or {@code 0} if the CharSequence is 6473 * {@code null}. 6474 * @since 2.4 6475 * @since 3.0 Changed signature from length(String) to length(CharSequence) 6476 */ 6477 public static int length(final CharSequence cs) { 6478 return cs == null ? 0 : cs.length(); 6479 } 6480 6481 // Centering 6482 //----------------------------------------------------------------------- 6483 /** 6484 * <p>Centers a String in a larger String of size {@code size} 6485 * using the space character (' ').</p> 6486 * 6487 * <p>If the size is less than the String length, the String is returned. 6488 * A {@code null} String returns {@code null}. 6489 * A negative size is treated as zero.</p> 6490 * 6491 * <p>Equivalent to {@code center(str, size, " ")}.</p> 6492 * 6493 * <pre> 6494 * StringUtils.center(null, *) = null 6495 * StringUtils.center("", 4) = " " 6496 * StringUtils.center("ab", -1) = "ab" 6497 * StringUtils.center("ab", 4) = " ab " 6498 * StringUtils.center("abcd", 2) = "abcd" 6499 * StringUtils.center("a", 4) = " a " 6500 * </pre> 6501 * 6502 * @param str the String to center, may be null 6503 * @param size the int size of new String, negative treated as zero 6504 * @return centered String, {@code null} if null String input 6505 */ 6506 public static String center(final String str, final int size) { 6507 return center(str, size, ' '); 6508 } 6509 6510 /** 6511 * <p>Centers a String in a larger String of size {@code size}. 6512 * Uses a supplied character as the value to pad the String with.</p> 6513 * 6514 * <p>If the size is less than the String length, the String is returned. 6515 * A {@code null} String returns {@code null}. 6516 * A negative size is treated as zero.</p> 6517 * 6518 * <pre> 6519 * StringUtils.center(null, *, *) = null 6520 * StringUtils.center("", 4, ' ') = " " 6521 * StringUtils.center("ab", -1, ' ') = "ab" 6522 * StringUtils.center("ab", 4, ' ') = " ab " 6523 * StringUtils.center("abcd", 2, ' ') = "abcd" 6524 * StringUtils.center("a", 4, ' ') = " a " 6525 * StringUtils.center("a", 4, 'y') = "yayy" 6526 * </pre> 6527 * 6528 * @param str the String to center, may be null 6529 * @param size the int size of new String, negative treated as zero 6530 * @param padChar the character to pad the new String with 6531 * @return centered String, {@code null} if null String input 6532 * @since 2.0 6533 */ 6534 public static String center(String str, final int size, final char padChar) { 6535 if (str == null || size <= 0) { 6536 return str; 6537 } 6538 final int strLen = str.length(); 6539 final int pads = size - strLen; 6540 if (pads <= 0) { 6541 return str; 6542 } 6543 str = leftPad(str, strLen + pads / 2, padChar); 6544 str = rightPad(str, size, padChar); 6545 return str; 6546 } 6547 6548 /** 6549 * <p>Centers a String in a larger String of size {@code size}. 6550 * Uses a supplied String as the value to pad the String with.</p> 6551 * 6552 * <p>If the size is less than the String length, the String is returned. 6553 * A {@code null} String returns {@code null}. 6554 * A negative size is treated as zero.</p> 6555 * 6556 * <pre> 6557 * StringUtils.center(null, *, *) = null 6558 * StringUtils.center("", 4, " ") = " " 6559 * StringUtils.center("ab", -1, " ") = "ab" 6560 * StringUtils.center("ab", 4, " ") = " ab " 6561 * StringUtils.center("abcd", 2, " ") = "abcd" 6562 * StringUtils.center("a", 4, " ") = " a " 6563 * StringUtils.center("a", 4, "yz") = "yayz" 6564 * StringUtils.center("abc", 7, null) = " abc " 6565 * StringUtils.center("abc", 7, "") = " abc " 6566 * </pre> 6567 * 6568 * @param str the String to center, may be null 6569 * @param size the int size of new String, negative treated as zero 6570 * @param padStr the String to pad the new String with, must not be null or empty 6571 * @return centered String, {@code null} if null String input 6572 * @throws IllegalArgumentException if padStr is {@code null} or empty 6573 */ 6574 public static String center(String str, final int size, String padStr) { 6575 if (str == null || size <= 0) { 6576 return str; 6577 } 6578 if (isEmpty(padStr)) { 6579 padStr = SPACE; 6580 } 6581 final int strLen = str.length(); 6582 final int pads = size - strLen; 6583 if (pads <= 0) { 6584 return str; 6585 } 6586 str = leftPad(str, strLen + pads / 2, padStr); 6587 str = rightPad(str, size, padStr); 6588 return str; 6589 } 6590 6591 // Case conversion 6592 //----------------------------------------------------------------------- 6593 /** 6594 * <p>Converts a String to upper case as per {@link String#toUpperCase()}.</p> 6595 * 6596 * <p>A {@code null} input String returns {@code null}.</p> 6597 * 6598 * <pre> 6599 * StringUtils.upperCase(null) = null 6600 * StringUtils.upperCase("") = "" 6601 * StringUtils.upperCase("aBc") = "ABC" 6602 * </pre> 6603 * 6604 * <p><strong>Note:</strong> As described in the documentation for {@link String#toUpperCase()}, 6605 * the result of this method is affected by the current locale. 6606 * For platform-independent case transformations, the method {@link #lowerCase(String, Locale)} 6607 * should be used with a specific locale (e.g. {@link Locale#ENGLISH}).</p> 6608 * 6609 * @param str the String to upper case, may be null 6610 * @return the upper cased String, {@code null} if null String input 6611 */ 6612 public static String upperCase(final String str) { 6613 if (str == null) { 6614 return null; 6615 } 6616 return str.toUpperCase(); 6617 } 6618 6619 /** 6620 * <p>Converts a String to upper case as per {@link String#toUpperCase(Locale)}.</p> 6621 * 6622 * <p>A {@code null} input String returns {@code null}.</p> 6623 * 6624 * <pre> 6625 * StringUtils.upperCase(null, Locale.ENGLISH) = null 6626 * StringUtils.upperCase("", Locale.ENGLISH) = "" 6627 * StringUtils.upperCase("aBc", Locale.ENGLISH) = "ABC" 6628 * </pre> 6629 * 6630 * @param str the String to upper case, may be null 6631 * @param locale the locale that defines the case transformation rules, must not be null 6632 * @return the upper cased String, {@code null} if null String input 6633 * @since 2.5 6634 */ 6635 public static String upperCase(final String str, final Locale locale) { 6636 if (str == null) { 6637 return null; 6638 } 6639 return str.toUpperCase(locale); 6640 } 6641 6642 /** 6643 * <p>Converts a String to lower case as per {@link String#toLowerCase()}.</p> 6644 * 6645 * <p>A {@code null} input String returns {@code null}.</p> 6646 * 6647 * <pre> 6648 * StringUtils.lowerCase(null) = null 6649 * StringUtils.lowerCase("") = "" 6650 * StringUtils.lowerCase("aBc") = "abc" 6651 * </pre> 6652 * 6653 * <p><strong>Note:</strong> As described in the documentation for {@link String#toLowerCase()}, 6654 * the result of this method is affected by the current locale. 6655 * For platform-independent case transformations, the method {@link #lowerCase(String, Locale)} 6656 * should be used with a specific locale (e.g. {@link Locale#ENGLISH}).</p> 6657 * 6658 * @param str the String to lower case, may be null 6659 * @return the lower cased String, {@code null} if null String input 6660 */ 6661 public static String lowerCase(final String str) { 6662 if (str == null) { 6663 return null; 6664 } 6665 return str.toLowerCase(); 6666 } 6667 6668 /** 6669 * <p>Converts a String to lower case as per {@link String#toLowerCase(Locale)}.</p> 6670 * 6671 * <p>A {@code null} input String returns {@code null}.</p> 6672 * 6673 * <pre> 6674 * StringUtils.lowerCase(null, Locale.ENGLISH) = null 6675 * StringUtils.lowerCase("", Locale.ENGLISH) = "" 6676 * StringUtils.lowerCase("aBc", Locale.ENGLISH) = "abc" 6677 * </pre> 6678 * 6679 * @param str the String to lower case, may be null 6680 * @param locale the locale that defines the case transformation rules, must not be null 6681 * @return the lower cased String, {@code null} if null String input 6682 * @since 2.5 6683 */ 6684 public static String lowerCase(final String str, final Locale locale) { 6685 if (str == null) { 6686 return null; 6687 } 6688 return str.toLowerCase(locale); 6689 } 6690 6691 /** 6692 * <p>Capitalizes a String changing the first character to title case as 6693 * per {@link Character#toTitleCase(int)}. No other characters are changed.</p> 6694 * 6695 * <p>For a word based algorithm, see {@link org.apache.commons.lang3.text.WordUtils#capitalize(String)}. 6696 * A {@code null} input String returns {@code null}.</p> 6697 * 6698 * <pre> 6699 * StringUtils.capitalize(null) = null 6700 * StringUtils.capitalize("") = "" 6701 * StringUtils.capitalize("cat") = "Cat" 6702 * StringUtils.capitalize("cAt") = "CAt" 6703 * StringUtils.capitalize("'cat'") = "'cat'" 6704 * </pre> 6705 * 6706 * @param str the String to capitalize, may be null 6707 * @return the capitalized String, {@code null} if null String input 6708 * @see org.apache.commons.lang3.text.WordUtils#capitalize(String) 6709 * @see #uncapitalize(String) 6710 * @since 2.0 6711 */ 6712 public static String capitalize(final String str) { 6713 int strLen; 6714 if (str == null || (strLen = str.length()) == 0) { 6715 return str; 6716 } 6717 6718 final int firstCodepoint = str.codePointAt(0); 6719 final int newCodePoint = Character.toTitleCase(firstCodepoint); 6720 if (firstCodepoint == newCodePoint) { 6721 // already capitalized 6722 return str; 6723 } 6724 6725 final int newCodePoints[] = new int[strLen]; // cannot be longer than the char array 6726 int outOffset = 0; 6727 newCodePoints[outOffset++] = newCodePoint; // copy the first codepoint 6728 for (int inOffset = Character.charCount(firstCodepoint); inOffset < strLen; ) { 6729 final int codepoint = str.codePointAt(inOffset); 6730 newCodePoints[outOffset++] = codepoint; // copy the remaining ones 6731 inOffset += Character.charCount(codepoint); 6732 } 6733 return new String(newCodePoints, 0, outOffset); 6734 } 6735 6736 /** 6737 * <p>Uncapitalizes a String, changing the first character to lower case as 6738 * per {@link Character#toLowerCase(int)}. No other characters are changed.</p> 6739 * 6740 * <p>For a word based algorithm, see {@link org.apache.commons.lang3.text.WordUtils#uncapitalize(String)}. 6741 * A {@code null} input String returns {@code null}.</p> 6742 * 6743 * <pre> 6744 * StringUtils.uncapitalize(null) = null 6745 * StringUtils.uncapitalize("") = "" 6746 * StringUtils.uncapitalize("cat") = "cat" 6747 * StringUtils.uncapitalize("Cat") = "cat" 6748 * StringUtils.uncapitalize("CAT") = "cAT" 6749 * </pre> 6750 * 6751 * @param str the String to uncapitalize, may be null 6752 * @return the uncapitalized String, {@code null} if null String input 6753 * @see org.apache.commons.lang3.text.WordUtils#uncapitalize(String) 6754 * @see #capitalize(String) 6755 * @since 2.0 6756 */ 6757 public static String uncapitalize(final String str) { 6758 int strLen; 6759 if (str == null || (strLen = str.length()) == 0) { 6760 return str; 6761 } 6762 6763 final int firstCodepoint = str.codePointAt(0); 6764 final int newCodePoint = Character.toLowerCase(firstCodepoint); 6765 if (firstCodepoint == newCodePoint) { 6766 // already capitalized 6767 return str; 6768 } 6769 6770 final int newCodePoints[] = new int[strLen]; // cannot be longer than the char array 6771 int outOffset = 0; 6772 newCodePoints[outOffset++] = newCodePoint; // copy the first codepoint 6773 for (int inOffset = Character.charCount(firstCodepoint); inOffset < strLen; ) { 6774 final int codepoint = str.codePointAt(inOffset); 6775 newCodePoints[outOffset++] = codepoint; // copy the remaining ones 6776 inOffset += Character.charCount(codepoint); 6777 } 6778 return new String(newCodePoints, 0, outOffset); 6779 } 6780 6781 /** 6782 * <p>Swaps the case of a String changing upper and title case to 6783 * lower case, and lower case to upper case.</p> 6784 * 6785 * <ul> 6786 * <li>Upper case character converts to Lower case</li> 6787 * <li>Title case character converts to Lower case</li> 6788 * <li>Lower case character converts to Upper case</li> 6789 * </ul> 6790 * 6791 * <p>For a word based algorithm, see {@link org.apache.commons.lang3.text.WordUtils#swapCase(String)}. 6792 * A {@code null} input String returns {@code null}.</p> 6793 * 6794 * <pre> 6795 * StringUtils.swapCase(null) = null 6796 * StringUtils.swapCase("") = "" 6797 * StringUtils.swapCase("The dog has a BONE") = "tHE DOG HAS A bone" 6798 * </pre> 6799 * 6800 * <p>NOTE: This method changed in Lang version 2.0. 6801 * It no longer performs a word based algorithm. 6802 * If you only use ASCII, you will notice no change. 6803 * That functionality is available in org.apache.commons.lang3.text.WordUtils.</p> 6804 * 6805 * @param str the String to swap case, may be null 6806 * @return the changed String, {@code null} if null String input 6807 */ 6808 public static String swapCase(final String str) { 6809 if (StringUtils.isEmpty(str)) { 6810 return str; 6811 } 6812 6813 final int strLen = str.length(); 6814 final int newCodePoints[] = new int[strLen]; // cannot be longer than the char array 6815 int outOffset = 0; 6816 for (int i = 0; i < strLen; ) { 6817 final int oldCodepoint = str.codePointAt(i); 6818 final int newCodePoint; 6819 if (Character.isUpperCase(oldCodepoint)) { 6820 newCodePoint = Character.toLowerCase(oldCodepoint); 6821 } else if (Character.isTitleCase(oldCodepoint)) { 6822 newCodePoint = Character.toLowerCase(oldCodepoint); 6823 } else if (Character.isLowerCase(oldCodepoint)) { 6824 newCodePoint = Character.toUpperCase(oldCodepoint); 6825 } else { 6826 newCodePoint = oldCodepoint; 6827 } 6828 newCodePoints[outOffset++] = newCodePoint; 6829 i += Character.charCount(newCodePoint); 6830 } 6831 return new String(newCodePoints, 0, outOffset); 6832 } 6833 6834 // Count matches 6835 //----------------------------------------------------------------------- 6836 /** 6837 * <p>Counts how many times the substring appears in the larger string.</p> 6838 * 6839 * <p>A {@code null} or empty ("") String input returns {@code 0}.</p> 6840 * 6841 * <pre> 6842 * StringUtils.countMatches(null, *) = 0 6843 * StringUtils.countMatches("", *) = 0 6844 * StringUtils.countMatches("abba", null) = 0 6845 * StringUtils.countMatches("abba", "") = 0 6846 * StringUtils.countMatches("abba", "a") = 2 6847 * StringUtils.countMatches("abba", "ab") = 1 6848 * StringUtils.countMatches("abba", "xxx") = 0 6849 * </pre> 6850 * 6851 * @param str the CharSequence to check, may be null 6852 * @param sub the substring to count, may be null 6853 * @return the number of occurrences, 0 if either CharSequence is {@code null} 6854 * @since 3.0 Changed signature from countMatches(String, String) to countMatches(CharSequence, CharSequence) 6855 */ 6856 public static int countMatches(final CharSequence str, final CharSequence sub) { 6857 if (isEmpty(str) || isEmpty(sub)) { 6858 return 0; 6859 } 6860 int count = 0; 6861 int idx = 0; 6862 while ((idx = CharSequenceUtils.indexOf(str, sub, idx)) != INDEX_NOT_FOUND) { 6863 count++; 6864 idx += sub.length(); 6865 } 6866 return count; 6867 } 6868 6869 /** 6870 * <p>Counts how many times the char appears in the given string.</p> 6871 * 6872 * <p>A {@code null} or empty ("") String input returns {@code 0}.</p> 6873 * 6874 * <pre> 6875 * StringUtils.countMatches(null, *) = 0 6876 * StringUtils.countMatches("", *) = 0 6877 * StringUtils.countMatches("abba", 0) = 0 6878 * StringUtils.countMatches("abba", 'a') = 2 6879 * StringUtils.countMatches("abba", 'b') = 2 6880 * StringUtils.countMatches("abba", 'x') = 0 6881 * </pre> 6882 * 6883 * @param str the CharSequence to check, may be null 6884 * @param ch the char to count 6885 * @return the number of occurrences, 0 if the CharSequence is {@code null} 6886 * @since 3.4 6887 */ 6888 public static int countMatches(final CharSequence str, final char ch) { 6889 if (isEmpty(str)) { 6890 return 0; 6891 } 6892 int count = 0; 6893 // We could also call str.toCharArray() for faster look ups but that would generate more garbage. 6894 for (int i = 0; i < str.length(); i++) { 6895 if (ch == str.charAt(i)) { 6896 count++; 6897 } 6898 } 6899 return count; 6900 } 6901 6902 // Character Tests 6903 //----------------------------------------------------------------------- 6904 /** 6905 * <p>Checks if the CharSequence contains only Unicode letters.</p> 6906 * 6907 * <p>{@code null} will return {@code false}. 6908 * An empty CharSequence (length()=0) will return {@code false}.</p> 6909 * 6910 * <pre> 6911 * StringUtils.isAlpha(null) = false 6912 * StringUtils.isAlpha("") = false 6913 * StringUtils.isAlpha(" ") = false 6914 * StringUtils.isAlpha("abc") = true 6915 * StringUtils.isAlpha("ab2c") = false 6916 * StringUtils.isAlpha("ab-c") = false 6917 * </pre> 6918 * 6919 * @param cs the CharSequence to check, may be null 6920 * @return {@code true} if only contains letters, and is non-null 6921 * @since 3.0 Changed signature from isAlpha(String) to isAlpha(CharSequence) 6922 * @since 3.0 Changed "" to return false and not true 6923 */ 6924 public static boolean isAlpha(final CharSequence cs) { 6925 if (isEmpty(cs)) { 6926 return false; 6927 } 6928 final int sz = cs.length(); 6929 for (int i = 0; i < sz; i++) { 6930 if (Character.isLetter(cs.charAt(i)) == false) { 6931 return false; 6932 } 6933 } 6934 return true; 6935 } 6936 6937 /** 6938 * <p>Checks if the CharSequence contains only Unicode letters and 6939 * space (' ').</p> 6940 * 6941 * <p>{@code null} will return {@code false} 6942 * An empty CharSequence (length()=0) will return {@code true}.</p> 6943 * 6944 * <pre> 6945 * StringUtils.isAlphaSpace(null) = false 6946 * StringUtils.isAlphaSpace("") = true 6947 * StringUtils.isAlphaSpace(" ") = true 6948 * StringUtils.isAlphaSpace("abc") = true 6949 * StringUtils.isAlphaSpace("ab c") = true 6950 * StringUtils.isAlphaSpace("ab2c") = false 6951 * StringUtils.isAlphaSpace("ab-c") = false 6952 * </pre> 6953 * 6954 * @param cs the CharSequence to check, may be null 6955 * @return {@code true} if only contains letters and space, 6956 * and is non-null 6957 * @since 3.0 Changed signature from isAlphaSpace(String) to isAlphaSpace(CharSequence) 6958 */ 6959 public static boolean isAlphaSpace(final CharSequence cs) { 6960 if (cs == null) { 6961 return false; 6962 } 6963 final int sz = cs.length(); 6964 for (int i = 0; i < sz; i++) { 6965 if (Character.isLetter(cs.charAt(i)) == false && cs.charAt(i) != ' ') { 6966 return false; 6967 } 6968 } 6969 return true; 6970 } 6971 6972 /** 6973 * <p>Checks if the CharSequence contains only Unicode letters or digits.</p> 6974 * 6975 * <p>{@code null} will return {@code false}. 6976 * An empty CharSequence (length()=0) will return {@code false}.</p> 6977 * 6978 * <pre> 6979 * StringUtils.isAlphanumeric(null) = false 6980 * StringUtils.isAlphanumeric("") = false 6981 * StringUtils.isAlphanumeric(" ") = false 6982 * StringUtils.isAlphanumeric("abc") = true 6983 * StringUtils.isAlphanumeric("ab c") = false 6984 * StringUtils.isAlphanumeric("ab2c") = true 6985 * StringUtils.isAlphanumeric("ab-c") = false 6986 * </pre> 6987 * 6988 * @param cs the CharSequence to check, may be null 6989 * @return {@code true} if only contains letters or digits, 6990 * and is non-null 6991 * @since 3.0 Changed signature from isAlphanumeric(String) to isAlphanumeric(CharSequence) 6992 * @since 3.0 Changed "" to return false and not true 6993 */ 6994 public static boolean isAlphanumeric(final CharSequence cs) { 6995 if (isEmpty(cs)) { 6996 return false; 6997 } 6998 final int sz = cs.length(); 6999 for (int i = 0; i < sz; i++) { 7000 if (Character.isLetterOrDigit(cs.charAt(i)) == false) { 7001 return false; 7002 } 7003 } 7004 return true; 7005 } 7006 7007 /** 7008 * <p>Checks if the CharSequence contains only Unicode letters, digits 7009 * or space ({@code ' '}).</p> 7010 * 7011 * <p>{@code null} will return {@code false}. 7012 * An empty CharSequence (length()=0) will return {@code true}.</p> 7013 * 7014 * <pre> 7015 * StringUtils.isAlphanumericSpace(null) = false 7016 * StringUtils.isAlphanumericSpace("") = true 7017 * StringUtils.isAlphanumericSpace(" ") = true 7018 * StringUtils.isAlphanumericSpace("abc") = true 7019 * StringUtils.isAlphanumericSpace("ab c") = true 7020 * StringUtils.isAlphanumericSpace("ab2c") = true 7021 * StringUtils.isAlphanumericSpace("ab-c") = false 7022 * </pre> 7023 * 7024 * @param cs the CharSequence to check, may be null 7025 * @return {@code true} if only contains letters, digits or space, 7026 * and is non-null 7027 * @since 3.0 Changed signature from isAlphanumericSpace(String) to isAlphanumericSpace(CharSequence) 7028 */ 7029 public static boolean isAlphanumericSpace(final CharSequence cs) { 7030 if (cs == null) { 7031 return false; 7032 } 7033 final int sz = cs.length(); 7034 for (int i = 0; i < sz; i++) { 7035 if (Character.isLetterOrDigit(cs.charAt(i)) == false && cs.charAt(i) != ' ') { 7036 return false; 7037 } 7038 } 7039 return true; 7040 } 7041 7042 /** 7043 * <p>Checks if the CharSequence contains only ASCII printable characters.</p> 7044 * 7045 * <p>{@code null} will return {@code false}. 7046 * An empty CharSequence (length()=0) will return {@code true}.</p> 7047 * 7048 * <pre> 7049 * StringUtils.isAsciiPrintable(null) = false 7050 * StringUtils.isAsciiPrintable("") = true 7051 * StringUtils.isAsciiPrintable(" ") = true 7052 * StringUtils.isAsciiPrintable("Ceki") = true 7053 * StringUtils.isAsciiPrintable("ab2c") = true 7054 * StringUtils.isAsciiPrintable("!ab-c~") = true 7055 * StringUtils.isAsciiPrintable("\u0020") = true 7056 * StringUtils.isAsciiPrintable("\u0021") = true 7057 * StringUtils.isAsciiPrintable("\u007e") = true 7058 * StringUtils.isAsciiPrintable("\u007f") = false 7059 * StringUtils.isAsciiPrintable("Ceki G\u00fclc\u00fc") = false 7060 * </pre> 7061 * 7062 * @param cs the CharSequence to check, may be null 7063 * @return {@code true} if every character is in the range 7064 * 32 thru 126 7065 * @since 2.1 7066 * @since 3.0 Changed signature from isAsciiPrintable(String) to isAsciiPrintable(CharSequence) 7067 */ 7068 public static boolean isAsciiPrintable(final CharSequence cs) { 7069 if (cs == null) { 7070 return false; 7071 } 7072 final int sz = cs.length(); 7073 for (int i = 0; i < sz; i++) { 7074 if (CharUtils.isAsciiPrintable(cs.charAt(i)) == false) { 7075 return false; 7076 } 7077 } 7078 return true; 7079 } 7080 7081 /** 7082 * <p>Checks if the CharSequence contains only Unicode digits. 7083 * A decimal point is not a Unicode digit and returns false.</p> 7084 * 7085 * <p>{@code null} will return {@code false}. 7086 * An empty CharSequence (length()=0) will return {@code false}.</p> 7087 * 7088 * <p>Note that the method does not allow for a leading sign, either positive or negative. 7089 * Also, if a String passes the numeric test, it may still generate a NumberFormatException 7090 * when parsed by Integer.parseInt or Long.parseLong, e.g. if the value is outside the range 7091 * for int or long respectively.</p> 7092 * 7093 * <pre> 7094 * StringUtils.isNumeric(null) = false 7095 * StringUtils.isNumeric("") = false 7096 * StringUtils.isNumeric(" ") = false 7097 * StringUtils.isNumeric("123") = true 7098 * StringUtils.isNumeric("\u0967\u0968\u0969") = true 7099 * StringUtils.isNumeric("12 3") = false 7100 * StringUtils.isNumeric("ab2c") = false 7101 * StringUtils.isNumeric("12-3") = false 7102 * StringUtils.isNumeric("12.3") = false 7103 * StringUtils.isNumeric("-123") = false 7104 * StringUtils.isNumeric("+123") = false 7105 * </pre> 7106 * 7107 * @param cs the CharSequence to check, may be null 7108 * @return {@code true} if only contains digits, and is non-null 7109 * @since 3.0 Changed signature from isNumeric(String) to isNumeric(CharSequence) 7110 * @since 3.0 Changed "" to return false and not true 7111 */ 7112 public static boolean isNumeric(final CharSequence cs) { 7113 if (isEmpty(cs)) { 7114 return false; 7115 } 7116 final int sz = cs.length(); 7117 for (int i = 0; i < sz; i++) { 7118 if (!Character.isDigit(cs.charAt(i))) { 7119 return false; 7120 } 7121 } 7122 return true; 7123 } 7124 7125 /** 7126 * <p>Checks if the CharSequence contains only Unicode digits or space 7127 * ({@code ' '}). 7128 * A decimal point is not a Unicode digit and returns false.</p> 7129 * 7130 * <p>{@code null} will return {@code false}. 7131 * An empty CharSequence (length()=0) will return {@code true}.</p> 7132 * 7133 * <pre> 7134 * StringUtils.isNumericSpace(null) = false 7135 * StringUtils.isNumericSpace("") = true 7136 * StringUtils.isNumericSpace(" ") = true 7137 * StringUtils.isNumericSpace("123") = true 7138 * StringUtils.isNumericSpace("12 3") = true 7139 * StringUtils.isNumeric("\u0967\u0968\u0969") = true 7140 * StringUtils.isNumeric("\u0967\u0968 \u0969") = true 7141 * StringUtils.isNumericSpace("ab2c") = false 7142 * StringUtils.isNumericSpace("12-3") = false 7143 * StringUtils.isNumericSpace("12.3") = false 7144 * </pre> 7145 * 7146 * @param cs the CharSequence to check, may be null 7147 * @return {@code true} if only contains digits or space, 7148 * and is non-null 7149 * @since 3.0 Changed signature from isNumericSpace(String) to isNumericSpace(CharSequence) 7150 */ 7151 public static boolean isNumericSpace(final CharSequence cs) { 7152 if (cs == null) { 7153 return false; 7154 } 7155 final int sz = cs.length(); 7156 for (int i = 0; i < sz; i++) { 7157 if (Character.isDigit(cs.charAt(i)) == false && cs.charAt(i) != ' ') { 7158 return false; 7159 } 7160 } 7161 return true; 7162 } 7163 7164 /** 7165 * <p>Checks if a String {@code str} contains Unicode digits, 7166 * if yes then concatenate all the digits in {@code str} and return it as a String.</p> 7167 * 7168 * <p>An empty ("") String will be returned if no digits found in {@code str}.</p> 7169 * 7170 * <pre> 7171 * StringUtils.getDigits(null) = null 7172 * StringUtils.getDigits("") = "" 7173 * StringUtils.getDigits("abc") = "" 7174 * StringUtils.getDigits("1000$") = "1000" 7175 * StringUtils.getDigits("1123~45") = "12345" 7176 * StringUtils.getDigits("(541) 754-3010") = "5417543010" 7177 * StringUtils.getDigits("\u0967\u0968\u0969") = "\u0967\u0968\u0969" 7178 * </pre> 7179 * 7180 * @param str the String to extract digits from, may be null 7181 * @return String with only digits, 7182 * or an empty ("") String if no digits found, 7183 * or {@code null} String if {@code str} is null 7184 * @since 3.6 7185 */ 7186 public static String getDigits(final String str) { 7187 if (isEmpty(str)) { 7188 return str; 7189 } 7190 final int sz = str.length(); 7191 final StringBuilder strDigits = new StringBuilder(sz); 7192 for (int i = 0; i < sz; i++) { 7193 final char tempChar = str.charAt(i); 7194 if (Character.isDigit(tempChar)) { 7195 strDigits.append(tempChar); 7196 } 7197 } 7198 return strDigits.toString(); 7199 } 7200 7201 /** 7202 * <p>Checks if the CharSequence contains only whitespace.</p> 7203 * 7204 * <p>Whitespace is defined by {@link Character#isWhitespace(char)}.</p> 7205 * 7206 * <p>{@code null} will return {@code false}. 7207 * An empty CharSequence (length()=0) will return {@code true}.</p> 7208 * 7209 * <pre> 7210 * StringUtils.isWhitespace(null) = false 7211 * StringUtils.isWhitespace("") = true 7212 * StringUtils.isWhitespace(" ") = true 7213 * StringUtils.isWhitespace("abc") = false 7214 * StringUtils.isWhitespace("ab2c") = false 7215 * StringUtils.isWhitespace("ab-c") = false 7216 * </pre> 7217 * 7218 * @param cs the CharSequence to check, may be null 7219 * @return {@code true} if only contains whitespace, and is non-null 7220 * @since 2.0 7221 * @since 3.0 Changed signature from isWhitespace(String) to isWhitespace(CharSequence) 7222 */ 7223 public static boolean isWhitespace(final CharSequence cs) { 7224 if (cs == null) { 7225 return false; 7226 } 7227 final int sz = cs.length(); 7228 for (int i = 0; i < sz; i++) { 7229 if (Character.isWhitespace(cs.charAt(i)) == false) { 7230 return false; 7231 } 7232 } 7233 return true; 7234 } 7235 7236 /** 7237 * <p>Checks if the CharSequence contains only lowercase characters.</p> 7238 * 7239 * <p>{@code null} will return {@code false}. 7240 * An empty CharSequence (length()=0) will return {@code false}.</p> 7241 * 7242 * <pre> 7243 * StringUtils.isAllLowerCase(null) = false 7244 * StringUtils.isAllLowerCase("") = false 7245 * StringUtils.isAllLowerCase(" ") = false 7246 * StringUtils.isAllLowerCase("abc") = true 7247 * StringUtils.isAllLowerCase("abC") = false 7248 * StringUtils.isAllLowerCase("ab c") = false 7249 * StringUtils.isAllLowerCase("ab1c") = false 7250 * StringUtils.isAllLowerCase("ab/c") = false 7251 * </pre> 7252 * 7253 * @param cs the CharSequence to check, may be null 7254 * @return {@code true} if only contains lowercase characters, and is non-null 7255 * @since 2.5 7256 * @since 3.0 Changed signature from isAllLowerCase(String) to isAllLowerCase(CharSequence) 7257 */ 7258 public static boolean isAllLowerCase(final CharSequence cs) { 7259 if (cs == null || isEmpty(cs)) { 7260 return false; 7261 } 7262 final int sz = cs.length(); 7263 for (int i = 0; i < sz; i++) { 7264 if (Character.isLowerCase(cs.charAt(i)) == false) { 7265 return false; 7266 } 7267 } 7268 return true; 7269 } 7270 7271 /** 7272 * <p>Checks if the CharSequence contains only uppercase characters.</p> 7273 * 7274 * <p>{@code null} will return {@code false}. 7275 * An empty String (length()=0) will return {@code false}.</p> 7276 * 7277 * <pre> 7278 * StringUtils.isAllUpperCase(null) = false 7279 * StringUtils.isAllUpperCase("") = false 7280 * StringUtils.isAllUpperCase(" ") = false 7281 * StringUtils.isAllUpperCase("ABC") = true 7282 * StringUtils.isAllUpperCase("aBC") = false 7283 * StringUtils.isAllUpperCase("A C") = false 7284 * StringUtils.isAllUpperCase("A1C") = false 7285 * StringUtils.isAllUpperCase("A/C") = false 7286 * </pre> 7287 * 7288 * @param cs the CharSequence to check, may be null 7289 * @return {@code true} if only contains uppercase characters, and is non-null 7290 * @since 2.5 7291 * @since 3.0 Changed signature from isAllUpperCase(String) to isAllUpperCase(CharSequence) 7292 */ 7293 public static boolean isAllUpperCase(final CharSequence cs) { 7294 if (cs == null || isEmpty(cs)) { 7295 return false; 7296 } 7297 final int sz = cs.length(); 7298 for (int i = 0; i < sz; i++) { 7299 if (Character.isUpperCase(cs.charAt(i)) == false) { 7300 return false; 7301 } 7302 } 7303 return true; 7304 } 7305 7306 /** 7307 * <p>Checks if the CharSequence contains mixed casing of both uppercase and lowercase characters.</p> 7308 * 7309 * <p>{@code null} will return {@code false}. An empty CharSequence ({@code length()=0}) will return 7310 * {@code false}.</p> 7311 * 7312 * <pre> 7313 * StringUtils.isMixedCase(null) = false 7314 * StringUtils.isMixedCase("") = false 7315 * StringUtils.isMixedCase("ABC") = false 7316 * StringUtils.isMixedCase("abc") = false 7317 * StringUtils.isMixedCase("aBc") = true 7318 * StringUtils.isMixedCase("A c") = true 7319 * StringUtils.isMixedCase("A1c") = true 7320 * StringUtils.isMixedCase("a/C") = true 7321 * StringUtils.isMixedCase("aC\t") = true 7322 * </pre> 7323 * 7324 * @param cs the CharSequence to check, may be null 7325 * @return {@code true} if the CharSequence contains both uppercase and lowercase characters 7326 * @since 3.5 7327 */ 7328 public static boolean isMixedCase(final CharSequence cs) { 7329 if (isEmpty(cs) || cs.length() == 1) { 7330 return false; 7331 } 7332 boolean containsUppercase = false; 7333 boolean containsLowercase = false; 7334 final int sz = cs.length(); 7335 for (int i = 0; i < sz; i++) { 7336 if (containsUppercase && containsLowercase) { 7337 return true; 7338 } else if (Character.isUpperCase(cs.charAt(i))) { 7339 containsUppercase = true; 7340 } else if (Character.isLowerCase(cs.charAt(i))) { 7341 containsLowercase = true; 7342 } 7343 } 7344 return containsUppercase && containsLowercase; 7345 } 7346 7347 // Defaults 7348 //----------------------------------------------------------------------- 7349 /** 7350 * <p>Returns either the passed in String, 7351 * or if the String is {@code null}, an empty String ("").</p> 7352 * 7353 * <pre> 7354 * StringUtils.defaultString(null) = "" 7355 * StringUtils.defaultString("") = "" 7356 * StringUtils.defaultString("bat") = "bat" 7357 * </pre> 7358 * 7359 * @see ObjectUtils#toString(Object) 7360 * @see String#valueOf(Object) 7361 * @param str the String to check, may be null 7362 * @return the passed in String, or the empty String if it 7363 * was {@code null} 7364 */ 7365 public static String defaultString(final String str) { 7366 return str == null ? EMPTY : str; 7367 } 7368 7369 /** 7370 * <p>Returns either the passed in String, or if the String is 7371 * {@code null}, the value of {@code defaultStr}.</p> 7372 * 7373 * <pre> 7374 * StringUtils.defaultString(null, "NULL") = "NULL" 7375 * StringUtils.defaultString("", "NULL") = "" 7376 * StringUtils.defaultString("bat", "NULL") = "bat" 7377 * </pre> 7378 * 7379 * @see ObjectUtils#toString(Object,String) 7380 * @see String#valueOf(Object) 7381 * @param str the String to check, may be null 7382 * @param defaultStr the default String to return 7383 * if the input is {@code null}, may be null 7384 * @return the passed in String, or the default if it was {@code null} 7385 */ 7386 public static String defaultString(final String str, final String defaultStr) { 7387 return str == null ? defaultStr : str; 7388 } 7389 7390 /** 7391 * <p>Returns either the passed in CharSequence, or if the CharSequence is 7392 * whitespace, empty ("") or {@code null}, the value of {@code defaultStr}.</p> 7393 * 7394 * <p>Whitespace is defined by {@link Character#isWhitespace(char)}.</p> 7395 * 7396 * <pre> 7397 * StringUtils.defaultIfBlank(null, "NULL") = "NULL" 7398 * StringUtils.defaultIfBlank("", "NULL") = "NULL" 7399 * StringUtils.defaultIfBlank(" ", "NULL") = "NULL" 7400 * StringUtils.defaultIfBlank("bat", "NULL") = "bat" 7401 * StringUtils.defaultIfBlank("", null) = null 7402 * </pre> 7403 * @param <T> the specific kind of CharSequence 7404 * @param str the CharSequence to check, may be null 7405 * @param defaultStr the default CharSequence to return 7406 * if the input is whitespace, empty ("") or {@code null}, may be null 7407 * @return the passed in CharSequence, or the default 7408 * @see StringUtils#defaultString(String, String) 7409 */ 7410 public static <T extends CharSequence> T defaultIfBlank(final T str, final T defaultStr) { 7411 return isBlank(str) ? defaultStr : str; 7412 } 7413 7414 /** 7415 * <p>Returns either the passed in CharSequence, or if the CharSequence is 7416 * empty or {@code null}, the value of {@code defaultStr}.</p> 7417 * 7418 * <pre> 7419 * StringUtils.defaultIfEmpty(null, "NULL") = "NULL" 7420 * StringUtils.defaultIfEmpty("", "NULL") = "NULL" 7421 * StringUtils.defaultIfEmpty(" ", "NULL") = " " 7422 * StringUtils.defaultIfEmpty("bat", "NULL") = "bat" 7423 * StringUtils.defaultIfEmpty("", null) = null 7424 * </pre> 7425 * @param <T> the specific kind of CharSequence 7426 * @param str the CharSequence to check, may be null 7427 * @param defaultStr the default CharSequence to return 7428 * if the input is empty ("") or {@code null}, may be null 7429 * @return the passed in CharSequence, or the default 7430 * @see StringUtils#defaultString(String, String) 7431 */ 7432 public static <T extends CharSequence> T defaultIfEmpty(final T str, final T defaultStr) { 7433 return isEmpty(str) ? defaultStr : str; 7434 } 7435 7436 // Rotating (circular shift) 7437 //----------------------------------------------------------------------- 7438 /** 7439 * <p>Rotate (circular shift) a String of {@code shift} characters.</p> 7440 * <ul> 7441 * <li>If {@code shift > 0}, right circular shift (ex : ABCDEF => FABCDE)</li> 7442 * <li>If {@code shift < 0}, left circular shift (ex : ABCDEF => BCDEFA)</li> 7443 * </ul> 7444 * 7445 * <pre> 7446 * StringUtils.rotate(null, *) = null 7447 * StringUtils.rotate("", *) = "" 7448 * StringUtils.rotate("abcdefg", 0) = "abcdefg" 7449 * StringUtils.rotate("abcdefg", 2) = "fgabcde" 7450 * StringUtils.rotate("abcdefg", -2) = "cdefgab" 7451 * StringUtils.rotate("abcdefg", 7) = "abcdefg" 7452 * StringUtils.rotate("abcdefg", -7) = "abcdefg" 7453 * StringUtils.rotate("abcdefg", 9) = "fgabcde" 7454 * StringUtils.rotate("abcdefg", -9) = "cdefgab" 7455 * </pre> 7456 * 7457 * @param str the String to rotate, may be null 7458 * @param shift number of time to shift (positive : right shift, negative : left shift) 7459 * @return the rotated String, 7460 * or the original String if {@code shift == 0}, 7461 * or {@code null} if null String input 7462 * @since 3.5 7463 */ 7464 public static String rotate(final String str, final int shift) { 7465 if (str == null) { 7466 return null; 7467 } 7468 7469 final int strLen = str.length(); 7470 if (shift == 0 || strLen == 0 || shift % strLen == 0) { 7471 return str; 7472 } 7473 7474 final StringBuilder builder = new StringBuilder(strLen); 7475 final int offset = - (shift % strLen); 7476 builder.append(substring(str, offset)); 7477 builder.append(substring(str, 0, offset)); 7478 return builder.toString(); 7479 } 7480 7481 // Reversing 7482 //----------------------------------------------------------------------- 7483 /** 7484 * <p>Reverses a String as per {@link StringBuilder#reverse()}.</p> 7485 * 7486 * <p>A {@code null} String returns {@code null}.</p> 7487 * 7488 * <pre> 7489 * StringUtils.reverse(null) = null 7490 * StringUtils.reverse("") = "" 7491 * StringUtils.reverse("bat") = "tab" 7492 * </pre> 7493 * 7494 * @param str the String to reverse, may be null 7495 * @return the reversed String, {@code null} if null String input 7496 */ 7497 public static String reverse(final String str) { 7498 if (str == null) { 7499 return null; 7500 } 7501 return new StringBuilder(str).reverse().toString(); 7502 } 7503 7504 /** 7505 * <p>Reverses a String that is delimited by a specific character.</p> 7506 * 7507 * <p>The Strings between the delimiters are not reversed. 7508 * Thus java.lang.String becomes String.lang.java (if the delimiter 7509 * is {@code '.'}).</p> 7510 * 7511 * <pre> 7512 * StringUtils.reverseDelimited(null, *) = null 7513 * StringUtils.reverseDelimited("", *) = "" 7514 * StringUtils.reverseDelimited("a.b.c", 'x') = "a.b.c" 7515 * StringUtils.reverseDelimited("a.b.c", ".") = "c.b.a" 7516 * </pre> 7517 * 7518 * @param str the String to reverse, may be null 7519 * @param separatorChar the separator character to use 7520 * @return the reversed String, {@code null} if null String input 7521 * @since 2.0 7522 */ 7523 public static String reverseDelimited(final String str, final char separatorChar) { 7524 if (str == null) { 7525 return null; 7526 } 7527 // could implement manually, but simple way is to reuse other, 7528 // probably slower, methods. 7529 final String[] strs = split(str, separatorChar); 7530 ArrayUtils.reverse(strs); 7531 return join(strs, separatorChar); 7532 } 7533 7534 // Abbreviating 7535 //----------------------------------------------------------------------- 7536 /** 7537 * <p>Abbreviates a String using ellipses. This will turn 7538 * "Now is the time for all good men" into "Now is the time for..."</p> 7539 * 7540 * <p>Specifically:</p> 7541 * <ul> 7542 * <li>If the number of characters in {@code str} is less than or equal to 7543 * {@code maxWidth}, return {@code str}.</li> 7544 * <li>Else abbreviate it to {@code (substring(str, 0, max-3) + "...")}.</li> 7545 * <li>If {@code maxWidth} is less than {@code 4}, throw an 7546 * {@code IllegalArgumentException}.</li> 7547 * <li>In no case will it return a String of length greater than 7548 * {@code maxWidth}.</li> 7549 * </ul> 7550 * 7551 * <pre> 7552 * StringUtils.abbreviate(null, *) = null 7553 * StringUtils.abbreviate("", 4) = "" 7554 * StringUtils.abbreviate("abcdefg", 6) = "abc..." 7555 * StringUtils.abbreviate("abcdefg", 7) = "abcdefg" 7556 * StringUtils.abbreviate("abcdefg", 8) = "abcdefg" 7557 * StringUtils.abbreviate("abcdefg", 4) = "a..." 7558 * StringUtils.abbreviate("abcdefg", 3) = IllegalArgumentException 7559 * </pre> 7560 * 7561 * @param str the String to check, may be null 7562 * @param maxWidth maximum length of result String, must be at least 4 7563 * @return abbreviated String, {@code null} if null String input 7564 * @throws IllegalArgumentException if the width is too small 7565 * @since 2.0 7566 */ 7567 public static String abbreviate(final String str, final int maxWidth) { 7568 final String defaultAbbrevMarker = "..."; 7569 return abbreviate(str, defaultAbbrevMarker, 0, maxWidth); 7570 } 7571 7572 /** 7573 * <p>Abbreviates a String using ellipses. This will turn 7574 * "Now is the time for all good men" into "...is the time for..."</p> 7575 * 7576 * <p>Works like {@code abbreviate(String, int)}, but allows you to specify 7577 * a "left edge" offset. Note that this left edge is not necessarily going to 7578 * be the leftmost character in the result, or the first character following the 7579 * ellipses, but it will appear somewhere in the result. 7580 * 7581 * <p>In no case will it return a String of length greater than 7582 * {@code maxWidth}.</p> 7583 * 7584 * <pre> 7585 * StringUtils.abbreviate(null, *, *) = null 7586 * StringUtils.abbreviate("", 0, 4) = "" 7587 * StringUtils.abbreviate("abcdefghijklmno", -1, 10) = "abcdefg..." 7588 * StringUtils.abbreviate("abcdefghijklmno", 0, 10) = "abcdefg..." 7589 * StringUtils.abbreviate("abcdefghijklmno", 1, 10) = "abcdefg..." 7590 * StringUtils.abbreviate("abcdefghijklmno", 4, 10) = "abcdefg..." 7591 * StringUtils.abbreviate("abcdefghijklmno", 5, 10) = "...fghi..." 7592 * StringUtils.abbreviate("abcdefghijklmno", 6, 10) = "...ghij..." 7593 * StringUtils.abbreviate("abcdefghijklmno", 8, 10) = "...ijklmno" 7594 * StringUtils.abbreviate("abcdefghijklmno", 10, 10) = "...ijklmno" 7595 * StringUtils.abbreviate("abcdefghijklmno", 12, 10) = "...ijklmno" 7596 * StringUtils.abbreviate("abcdefghij", 0, 3) = IllegalArgumentException 7597 * StringUtils.abbreviate("abcdefghij", 5, 6) = IllegalArgumentException 7598 * </pre> 7599 * 7600 * @param str the String to check, may be null 7601 * @param offset left edge of source String 7602 * @param maxWidth maximum length of result String, must be at least 4 7603 * @return abbreviated String, {@code null} if null String input 7604 * @throws IllegalArgumentException if the width is too small 7605 * @since 2.0 7606 */ 7607 public static String abbreviate(final String str, final int offset, final int maxWidth) { 7608 final String defaultAbbrevMarker = "..."; 7609 return abbreviate(str, defaultAbbrevMarker, offset, maxWidth); 7610 } 7611 7612 /** 7613 * <p>Abbreviates a String using another given String as replacement marker. This will turn 7614 * "Now is the time for all good men" into "Now is the time for..." if "..." was defined 7615 * as the replacement marker.</p> 7616 * 7617 * <p>Specifically:</p> 7618 * <ul> 7619 * <li>If the number of characters in {@code str} is less than or equal to 7620 * {@code maxWidth}, return {@code str}.</li> 7621 * <li>Else abbreviate it to {@code (substring(str, 0, max-abbrevMarker.length) + abbrevMarker)}.</li> 7622 * <li>If {@code maxWidth} is less than {@code abbrevMarker.length + 1}, throw an 7623 * {@code IllegalArgumentException}.</li> 7624 * <li>In no case will it return a String of length greater than 7625 * {@code maxWidth}.</li> 7626 * </ul> 7627 * 7628 * <pre> 7629 * StringUtils.abbreviate(null, "...", *) = null 7630 * StringUtils.abbreviate("abcdefg", null, *) = "abcdefg" 7631 * StringUtils.abbreviate("", "...", 4) = "" 7632 * StringUtils.abbreviate("abcdefg", ".", 5) = "abcd." 7633 * StringUtils.abbreviate("abcdefg", ".", 7) = "abcdefg" 7634 * StringUtils.abbreviate("abcdefg", ".", 8) = "abcdefg" 7635 * StringUtils.abbreviate("abcdefg", "..", 4) = "ab.." 7636 * StringUtils.abbreviate("abcdefg", "..", 3) = "a.." 7637 * StringUtils.abbreviate("abcdefg", "..", 2) = IllegalArgumentException 7638 * StringUtils.abbreviate("abcdefg", "...", 3) = IllegalArgumentException 7639 * </pre> 7640 * 7641 * @param str the String to check, may be null 7642 * @param abbrevMarker the String used as replacement marker 7643 * @param maxWidth maximum length of result String, must be at least {@code abbrevMarker.length + 1} 7644 * @return abbreviated String, {@code null} if null String input 7645 * @throws IllegalArgumentException if the width is too small 7646 * @since 3.6 7647 */ 7648 public static String abbreviate(final String str, final String abbrevMarker, final int maxWidth) { 7649 return abbreviate(str, abbrevMarker, 0, maxWidth); 7650 } 7651 7652 /** 7653 * <p>Abbreviates a String using a given replacement marker. This will turn 7654 * "Now is the time for all good men" into "...is the time for..." if "..." was defined 7655 * as the replacement marker.</p> 7656 * 7657 * <p>Works like {@code abbreviate(String, String, int)}, but allows you to specify 7658 * a "left edge" offset. Note that this left edge is not necessarily going to 7659 * be the leftmost character in the result, or the first character following the 7660 * replacement marker, but it will appear somewhere in the result. 7661 * 7662 * <p>In no case will it return a String of length greater than {@code maxWidth}.</p> 7663 * 7664 * <pre> 7665 * StringUtils.abbreviate(null, null, *, *) = null 7666 * StringUtils.abbreviate("abcdefghijklmno", null, *, *) = "abcdefghijklmno" 7667 * StringUtils.abbreviate("", "...", 0, 4) = "" 7668 * StringUtils.abbreviate("abcdefghijklmno", "---", -1, 10) = "abcdefg---" 7669 * StringUtils.abbreviate("abcdefghijklmno", ",", 0, 10) = "abcdefghi," 7670 * StringUtils.abbreviate("abcdefghijklmno", ",", 1, 10) = "abcdefghi," 7671 * StringUtils.abbreviate("abcdefghijklmno", ",", 2, 10) = "abcdefghi," 7672 * StringUtils.abbreviate("abcdefghijklmno", "::", 4, 10) = "::efghij::" 7673 * StringUtils.abbreviate("abcdefghijklmno", "...", 6, 10) = "...ghij..." 7674 * StringUtils.abbreviate("abcdefghijklmno", "*", 9, 10) = "*ghijklmno" 7675 * StringUtils.abbreviate("abcdefghijklmno", "'", 10, 10) = "'ghijklmno" 7676 * StringUtils.abbreviate("abcdefghijklmno", "!", 12, 10) = "!ghijklmno" 7677 * StringUtils.abbreviate("abcdefghij", "abra", 0, 4) = IllegalArgumentException 7678 * StringUtils.abbreviate("abcdefghij", "...", 5, 6) = IllegalArgumentException 7679 * </pre> 7680 * 7681 * @param str the String to check, may be null 7682 * @param abbrevMarker the String used as replacement marker 7683 * @param offset left edge of source String 7684 * @param maxWidth maximum length of result String, must be at least 4 7685 * @return abbreviated String, {@code null} if null String input 7686 * @throws IllegalArgumentException if the width is too small 7687 * @since 3.6 7688 */ 7689 public static String abbreviate(final String str, final String abbrevMarker, int offset, final int maxWidth) { 7690 if (isEmpty(str) || isEmpty(abbrevMarker)) { 7691 return str; 7692 } 7693 7694 final int abbrevMarkerLength = abbrevMarker.length(); 7695 final int minAbbrevWidth = abbrevMarkerLength + 1; 7696 final int minAbbrevWidthOffset = abbrevMarkerLength + abbrevMarkerLength + 1; 7697 7698 if (maxWidth < minAbbrevWidth) { 7699 throw new IllegalArgumentException(String.format("Minimum abbreviation width is %d", minAbbrevWidth)); 7700 } 7701 if (str.length() <= maxWidth) { 7702 return str; 7703 } 7704 if (offset > str.length()) { 7705 offset = str.length(); 7706 } 7707 if (str.length() - offset < maxWidth - abbrevMarkerLength) { 7708 offset = str.length() - (maxWidth - abbrevMarkerLength); 7709 } 7710 if (offset <= abbrevMarkerLength+1) { 7711 return str.substring(0, maxWidth - abbrevMarkerLength) + abbrevMarker; 7712 } 7713 if (maxWidth < minAbbrevWidthOffset) { 7714 throw new IllegalArgumentException(String.format("Minimum abbreviation width with offset is %d", minAbbrevWidthOffset)); 7715 } 7716 if (offset + maxWidth - abbrevMarkerLength < str.length()) { 7717 return abbrevMarker + abbreviate(str.substring(offset), abbrevMarker, maxWidth - abbrevMarkerLength); 7718 } 7719 return abbrevMarker + str.substring(str.length() - (maxWidth - abbrevMarkerLength)); 7720 } 7721 7722 /** 7723 * <p>Abbreviates a String to the length passed, replacing the middle characters with the supplied 7724 * replacement String.</p> 7725 * 7726 * <p>This abbreviation only occurs if the following criteria is met:</p> 7727 * <ul> 7728 * <li>Neither the String for abbreviation nor the replacement String are null or empty </li> 7729 * <li>The length to truncate to is less than the length of the supplied String</li> 7730 * <li>The length to truncate to is greater than 0</li> 7731 * <li>The abbreviated String will have enough room for the length supplied replacement String 7732 * and the first and last characters of the supplied String for abbreviation</li> 7733 * </ul> 7734 * <p>Otherwise, the returned String will be the same as the supplied String for abbreviation. 7735 * </p> 7736 * 7737 * <pre> 7738 * StringUtils.abbreviateMiddle(null, null, 0) = null 7739 * StringUtils.abbreviateMiddle("abc", null, 0) = "abc" 7740 * StringUtils.abbreviateMiddle("abc", ".", 0) = "abc" 7741 * StringUtils.abbreviateMiddle("abc", ".", 3) = "abc" 7742 * StringUtils.abbreviateMiddle("abcdef", ".", 4) = "ab.f" 7743 * </pre> 7744 * 7745 * @param str the String to abbreviate, may be null 7746 * @param middle the String to replace the middle characters with, may be null 7747 * @param length the length to abbreviate {@code str} to. 7748 * @return the abbreviated String if the above criteria is met, or the original String supplied for abbreviation. 7749 * @since 2.5 7750 */ 7751 public static String abbreviateMiddle(final String str, final String middle, final int length) { 7752 if (isEmpty(str) || isEmpty(middle)) { 7753 return str; 7754 } 7755 7756 if (length >= str.length() || length < middle.length()+2) { 7757 return str; 7758 } 7759 7760 final int targetSting = length-middle.length(); 7761 final int startOffset = targetSting/2+targetSting%2; 7762 final int endOffset = str.length()-targetSting/2; 7763 7764 final StringBuilder builder = new StringBuilder(length); 7765 builder.append(str.substring(0,startOffset)); 7766 builder.append(middle); 7767 builder.append(str.substring(endOffset)); 7768 7769 return builder.toString(); 7770 } 7771 7772 // Difference 7773 //----------------------------------------------------------------------- 7774 /** 7775 * <p>Compares two Strings, and returns the portion where they differ. 7776 * More precisely, return the remainder of the second String, 7777 * starting from where it's different from the first. This means that 7778 * the difference between "abc" and "ab" is the empty String and not "c". </p> 7779 * 7780 * <p>For example, 7781 * {@code difference("i am a machine", "i am a robot") -> "robot"}.</p> 7782 * 7783 * <pre> 7784 * StringUtils.difference(null, null) = null 7785 * StringUtils.difference("", "") = "" 7786 * StringUtils.difference("", "abc") = "abc" 7787 * StringUtils.difference("abc", "") = "" 7788 * StringUtils.difference("abc", "abc") = "" 7789 * StringUtils.difference("abc", "ab") = "" 7790 * StringUtils.difference("ab", "abxyz") = "xyz" 7791 * StringUtils.difference("abcde", "abxyz") = "xyz" 7792 * StringUtils.difference("abcde", "xyz") = "xyz" 7793 * </pre> 7794 * 7795 * @param str1 the first String, may be null 7796 * @param str2 the second String, may be null 7797 * @return the portion of str2 where it differs from str1; returns the 7798 * empty String if they are equal 7799 * @see #indexOfDifference(CharSequence,CharSequence) 7800 * @since 2.0 7801 */ 7802 public static String difference(final String str1, final String str2) { 7803 if (str1 == null) { 7804 return str2; 7805 } 7806 if (str2 == null) { 7807 return str1; 7808 } 7809 final int at = indexOfDifference(str1, str2); 7810 if (at == INDEX_NOT_FOUND) { 7811 return EMPTY; 7812 } 7813 return str2.substring(at); 7814 } 7815 7816 /** 7817 * <p>Compares two CharSequences, and returns the index at which the 7818 * CharSequences begin to differ.</p> 7819 * 7820 * <p>For example, 7821 * {@code indexOfDifference("i am a machine", "i am a robot") -> 7}</p> 7822 * 7823 * <pre> 7824 * StringUtils.indexOfDifference(null, null) = -1 7825 * StringUtils.indexOfDifference("", "") = -1 7826 * StringUtils.indexOfDifference("", "abc") = 0 7827 * StringUtils.indexOfDifference("abc", "") = 0 7828 * StringUtils.indexOfDifference("abc", "abc") = -1 7829 * StringUtils.indexOfDifference("ab", "abxyz") = 2 7830 * StringUtils.indexOfDifference("abcde", "abxyz") = 2 7831 * StringUtils.indexOfDifference("abcde", "xyz") = 0 7832 * </pre> 7833 * 7834 * @param cs1 the first CharSequence, may be null 7835 * @param cs2 the second CharSequence, may be null 7836 * @return the index where cs1 and cs2 begin to differ; -1 if they are equal 7837 * @since 2.0 7838 * @since 3.0 Changed signature from indexOfDifference(String, String) to 7839 * indexOfDifference(CharSequence, CharSequence) 7840 */ 7841 public static int indexOfDifference(final CharSequence cs1, final CharSequence cs2) { 7842 if (cs1 == cs2) { 7843 return INDEX_NOT_FOUND; 7844 } 7845 if (cs1 == null || cs2 == null) { 7846 return 0; 7847 } 7848 int i; 7849 for (i = 0; i < cs1.length() && i < cs2.length(); ++i) { 7850 if (cs1.charAt(i) != cs2.charAt(i)) { 7851 break; 7852 } 7853 } 7854 if (i < cs2.length() || i < cs1.length()) { 7855 return i; 7856 } 7857 return INDEX_NOT_FOUND; 7858 } 7859 7860 /** 7861 * <p>Compares all CharSequences in an array and returns the index at which the 7862 * CharSequences begin to differ.</p> 7863 * 7864 * <p>For example, 7865 * <code>indexOfDifference(new String[] {"i am a machine", "i am a robot"}) -> 7</code></p> 7866 * 7867 * <pre> 7868 * StringUtils.indexOfDifference(null) = -1 7869 * StringUtils.indexOfDifference(new String[] {}) = -1 7870 * StringUtils.indexOfDifference(new String[] {"abc"}) = -1 7871 * StringUtils.indexOfDifference(new String[] {null, null}) = -1 7872 * StringUtils.indexOfDifference(new String[] {"", ""}) = -1 7873 * StringUtils.indexOfDifference(new String[] {"", null}) = 0 7874 * StringUtils.indexOfDifference(new String[] {"abc", null, null}) = 0 7875 * StringUtils.indexOfDifference(new String[] {null, null, "abc"}) = 0 7876 * StringUtils.indexOfDifference(new String[] {"", "abc"}) = 0 7877 * StringUtils.indexOfDifference(new String[] {"abc", ""}) = 0 7878 * StringUtils.indexOfDifference(new String[] {"abc", "abc"}) = -1 7879 * StringUtils.indexOfDifference(new String[] {"abc", "a"}) = 1 7880 * StringUtils.indexOfDifference(new String[] {"ab", "abxyz"}) = 2 7881 * StringUtils.indexOfDifference(new String[] {"abcde", "abxyz"}) = 2 7882 * StringUtils.indexOfDifference(new String[] {"abcde", "xyz"}) = 0 7883 * StringUtils.indexOfDifference(new String[] {"xyz", "abcde"}) = 0 7884 * StringUtils.indexOfDifference(new String[] {"i am a machine", "i am a robot"}) = 7 7885 * </pre> 7886 * 7887 * @param css array of CharSequences, entries may be null 7888 * @return the index where the strings begin to differ; -1 if they are all equal 7889 * @since 2.4 7890 * @since 3.0 Changed signature from indexOfDifference(String...) to indexOfDifference(CharSequence...) 7891 */ 7892 public static int indexOfDifference(final CharSequence... css) { 7893 if (css == null || css.length <= 1) { 7894 return INDEX_NOT_FOUND; 7895 } 7896 boolean anyStringNull = false; 7897 boolean allStringsNull = true; 7898 final int arrayLen = css.length; 7899 int shortestStrLen = Integer.MAX_VALUE; 7900 int longestStrLen = 0; 7901 7902 // find the min and max string lengths; this avoids checking to make 7903 // sure we are not exceeding the length of the string each time through 7904 // the bottom loop. 7905 for (CharSequence cs : css) { 7906 if (cs == null) { 7907 anyStringNull = true; 7908 shortestStrLen = 0; 7909 } else { 7910 allStringsNull = false; 7911 shortestStrLen = Math.min(cs.length(), shortestStrLen); 7912 longestStrLen = Math.max(cs.length(), longestStrLen); 7913 } 7914 } 7915 7916 // handle lists containing all nulls or all empty strings 7917 if (allStringsNull || longestStrLen == 0 && !anyStringNull) { 7918 return INDEX_NOT_FOUND; 7919 } 7920 7921 // handle lists containing some nulls or some empty strings 7922 if (shortestStrLen == 0) { 7923 return 0; 7924 } 7925 7926 // find the position with the first difference across all strings 7927 int firstDiff = -1; 7928 for (int stringPos = 0; stringPos < shortestStrLen; stringPos++) { 7929 final char comparisonChar = css[0].charAt(stringPos); 7930 for (int arrayPos = 1; arrayPos < arrayLen; arrayPos++) { 7931 if (css[arrayPos].charAt(stringPos) != comparisonChar) { 7932 firstDiff = stringPos; 7933 break; 7934 } 7935 } 7936 if (firstDiff != -1) { 7937 break; 7938 } 7939 } 7940 7941 if (firstDiff == -1 && shortestStrLen != longestStrLen) { 7942 // we compared all of the characters up to the length of the 7943 // shortest string and didn't find a match, but the string lengths 7944 // vary, so return the length of the shortest string. 7945 return shortestStrLen; 7946 } 7947 return firstDiff; 7948 } 7949 7950 /** 7951 * <p>Compares all Strings in an array and returns the initial sequence of 7952 * characters that is common to all of them.</p> 7953 * 7954 * <p>For example, 7955 * <code>getCommonPrefix(new String[] {"i am a machine", "i am a robot"}) -> "i am a "</code></p> 7956 * 7957 * <pre> 7958 * StringUtils.getCommonPrefix(null) = "" 7959 * StringUtils.getCommonPrefix(new String[] {}) = "" 7960 * StringUtils.getCommonPrefix(new String[] {"abc"}) = "abc" 7961 * StringUtils.getCommonPrefix(new String[] {null, null}) = "" 7962 * StringUtils.getCommonPrefix(new String[] {"", ""}) = "" 7963 * StringUtils.getCommonPrefix(new String[] {"", null}) = "" 7964 * StringUtils.getCommonPrefix(new String[] {"abc", null, null}) = "" 7965 * StringUtils.getCommonPrefix(new String[] {null, null, "abc"}) = "" 7966 * StringUtils.getCommonPrefix(new String[] {"", "abc"}) = "" 7967 * StringUtils.getCommonPrefix(new String[] {"abc", ""}) = "" 7968 * StringUtils.getCommonPrefix(new String[] {"abc", "abc"}) = "abc" 7969 * StringUtils.getCommonPrefix(new String[] {"abc", "a"}) = "a" 7970 * StringUtils.getCommonPrefix(new String[] {"ab", "abxyz"}) = "ab" 7971 * StringUtils.getCommonPrefix(new String[] {"abcde", "abxyz"}) = "ab" 7972 * StringUtils.getCommonPrefix(new String[] {"abcde", "xyz"}) = "" 7973 * StringUtils.getCommonPrefix(new String[] {"xyz", "abcde"}) = "" 7974 * StringUtils.getCommonPrefix(new String[] {"i am a machine", "i am a robot"}) = "i am a " 7975 * </pre> 7976 * 7977 * @param strs array of String objects, entries may be null 7978 * @return the initial sequence of characters that are common to all Strings 7979 * in the array; empty String if the array is null, the elements are all null 7980 * or if there is no common prefix. 7981 * @since 2.4 7982 */ 7983 public static String getCommonPrefix(final String... strs) { 7984 if (strs == null || strs.length == 0) { 7985 return EMPTY; 7986 } 7987 final int smallestIndexOfDiff = indexOfDifference(strs); 7988 if (smallestIndexOfDiff == INDEX_NOT_FOUND) { 7989 // all strings were identical 7990 if (strs[0] == null) { 7991 return EMPTY; 7992 } 7993 return strs[0]; 7994 } else if (smallestIndexOfDiff == 0) { 7995 // there were no common initial characters 7996 return EMPTY; 7997 } else { 7998 // we found a common initial character sequence 7999 return strs[0].substring(0, smallestIndexOfDiff); 8000 } 8001 } 8002 8003 // Misc 8004 //----------------------------------------------------------------------- 8005 /** 8006 * <p>Find the Levenshtein distance between two Strings.</p> 8007 * 8008 * <p>This is the number of changes needed to change one String into 8009 * another, where each change is a single character modification (deletion, 8010 * insertion or substitution).</p> 8011 * 8012 * <p>The implementation uses a single-dimensional array of length s.length() + 1. See 8013 * <a href="http://blog.softwx.net/2014/12/optimizing-levenshtein-algorithm-in-c.html"> 8014 * http://blog.softwx.net/2014/12/optimizing-levenshtein-algorithm-in-c.html</a> for details.</p> 8015 * 8016 * <pre> 8017 * StringUtils.getLevenshteinDistance(null, *) = IllegalArgumentException 8018 * StringUtils.getLevenshteinDistance(*, null) = IllegalArgumentException 8019 * StringUtils.getLevenshteinDistance("","") = 0 8020 * StringUtils.getLevenshteinDistance("","a") = 1 8021 * StringUtils.getLevenshteinDistance("aaapppp", "") = 7 8022 * StringUtils.getLevenshteinDistance("frog", "fog") = 1 8023 * StringUtils.getLevenshteinDistance("fly", "ant") = 3 8024 * StringUtils.getLevenshteinDistance("elephant", "hippo") = 7 8025 * StringUtils.getLevenshteinDistance("hippo", "elephant") = 7 8026 * StringUtils.getLevenshteinDistance("hippo", "zzzzzzzz") = 8 8027 * StringUtils.getLevenshteinDistance("hello", "hallo") = 1 8028 * </pre> 8029 * 8030 * @param s the first String, must not be null 8031 * @param t the second String, must not be null 8032 * @return result distance 8033 * @throws IllegalArgumentException if either String input {@code null} 8034 * @since 3.0 Changed signature from getLevenshteinDistance(String, String) to 8035 * getLevenshteinDistance(CharSequence, CharSequence) 8036 * @deprecated as of 3.6, use commons-text 8037 * <a href="https://commons.apache.org/proper/commons-text/javadocs/api-release/org/apache/commons/text/similarity/LevenshteinDistance.html"> 8038 * LevenshteinDistance</a> instead 8039 */ 8040 @Deprecated 8041 public static int getLevenshteinDistance(CharSequence s, CharSequence t) { 8042 if (s == null || t == null) { 8043 throw new IllegalArgumentException("Strings must not be null"); 8044 } 8045 8046 int n = s.length(); 8047 int m = t.length(); 8048 8049 if (n == 0) { 8050 return m; 8051 } else if (m == 0) { 8052 return n; 8053 } 8054 8055 if (n > m) { 8056 // swap the input strings to consume less memory 8057 final CharSequence tmp = s; 8058 s = t; 8059 t = tmp; 8060 n = m; 8061 m = t.length(); 8062 } 8063 8064 final int p[] = new int[n + 1]; 8065 // indexes into strings s and t 8066 int i; // iterates through s 8067 int j; // iterates through t 8068 int upper_left; 8069 int upper; 8070 8071 char t_j; // jth character of t 8072 int cost; 8073 8074 for (i = 0; i <= n; i++) { 8075 p[i] = i; 8076 } 8077 8078 for (j = 1; j <= m; j++) { 8079 upper_left = p[0]; 8080 t_j = t.charAt(j - 1); 8081 p[0] = j; 8082 8083 for (i = 1; i <= n; i++) { 8084 upper = p[i]; 8085 cost = s.charAt(i - 1) == t_j ? 0 : 1; 8086 // minimum of cell to the left+1, to the top+1, diagonally left and up +cost 8087 p[i] = Math.min(Math.min(p[i - 1] + 1, p[i] + 1), upper_left + cost); 8088 upper_left = upper; 8089 } 8090 } 8091 8092 return p[n]; 8093 } 8094 8095 /** 8096 * <p>Find the Levenshtein distance between two Strings if it's less than or equal to a given 8097 * threshold.</p> 8098 * 8099 * <p>This is the number of changes needed to change one String into 8100 * another, where each change is a single character modification (deletion, 8101 * insertion or substitution).</p> 8102 * 8103 * <p>This implementation follows from Algorithms on Strings, Trees and Sequences by Dan Gusfield 8104 * and Chas Emerick's implementation of the Levenshtein distance algorithm from 8105 * <a href="http://www.merriampark.com/ld.htm">http://www.merriampark.com/ld.htm</a></p> 8106 * 8107 * <pre> 8108 * StringUtils.getLevenshteinDistance(null, *, *) = IllegalArgumentException 8109 * StringUtils.getLevenshteinDistance(*, null, *) = IllegalArgumentException 8110 * StringUtils.getLevenshteinDistance(*, *, -1) = IllegalArgumentException 8111 * StringUtils.getLevenshteinDistance("","", 0) = 0 8112 * StringUtils.getLevenshteinDistance("aaapppp", "", 8) = 7 8113 * StringUtils.getLevenshteinDistance("aaapppp", "", 7) = 7 8114 * StringUtils.getLevenshteinDistance("aaapppp", "", 6)) = -1 8115 * StringUtils.getLevenshteinDistance("elephant", "hippo", 7) = 7 8116 * StringUtils.getLevenshteinDistance("elephant", "hippo", 6) = -1 8117 * StringUtils.getLevenshteinDistance("hippo", "elephant", 7) = 7 8118 * StringUtils.getLevenshteinDistance("hippo", "elephant", 6) = -1 8119 * </pre> 8120 * 8121 * @param s the first String, must not be null 8122 * @param t the second String, must not be null 8123 * @param threshold the target threshold, must not be negative 8124 * @return result distance, or {@code -1} if the distance would be greater than the threshold 8125 * @throws IllegalArgumentException if either String input {@code null} or negative threshold 8126 * @deprecated as of 3.6, use commons-text 8127 * <a href="https://commons.apache.org/proper/commons-text/javadocs/api-release/org/apache/commons/text/similarity/LevenshteinDistance.html"> 8128 * LevenshteinDistance</a> instead 8129 */ 8130 @Deprecated 8131 public static int getLevenshteinDistance(CharSequence s, CharSequence t, final int threshold) { 8132 if (s == null || t == null) { 8133 throw new IllegalArgumentException("Strings must not be null"); 8134 } 8135 if (threshold < 0) { 8136 throw new IllegalArgumentException("Threshold must not be negative"); 8137 } 8138 8139 /* 8140 This implementation only computes the distance if it's less than or equal to the 8141 threshold value, returning -1 if it's greater. The advantage is performance: unbounded 8142 distance is O(nm), but a bound of k allows us to reduce it to O(km) time by only 8143 computing a diagonal stripe of width 2k + 1 of the cost table. 8144 It is also possible to use this to compute the unbounded Levenshtein distance by starting 8145 the threshold at 1 and doubling each time until the distance is found; this is O(dm), where 8146 d is the distance. 8147 8148 One subtlety comes from needing to ignore entries on the border of our stripe 8149 eg. 8150 p[] = |#|#|#|* 8151 d[] = *|#|#|#| 8152 We must ignore the entry to the left of the leftmost member 8153 We must ignore the entry above the rightmost member 8154 8155 Another subtlety comes from our stripe running off the matrix if the strings aren't 8156 of the same size. Since string s is always swapped to be the shorter of the two, 8157 the stripe will always run off to the upper right instead of the lower left of the matrix. 8158 8159 As a concrete example, suppose s is of length 5, t is of length 7, and our threshold is 1. 8160 In this case we're going to walk a stripe of length 3. The matrix would look like so: 8161 8162 1 2 3 4 5 8163 1 |#|#| | | | 8164 2 |#|#|#| | | 8165 3 | |#|#|#| | 8166 4 | | |#|#|#| 8167 5 | | | |#|#| 8168 6 | | | | |#| 8169 7 | | | | | | 8170 8171 Note how the stripe leads off the table as there is no possible way to turn a string of length 5 8172 into one of length 7 in edit distance of 1. 8173 8174 Additionally, this implementation decreases memory usage by using two 8175 single-dimensional arrays and swapping them back and forth instead of allocating 8176 an entire n by m matrix. This requires a few minor changes, such as immediately returning 8177 when it's detected that the stripe has run off the matrix and initially filling the arrays with 8178 large values so that entries we don't compute are ignored. 8179 8180 See Algorithms on Strings, Trees and Sequences by Dan Gusfield for some discussion. 8181 */ 8182 8183 int n = s.length(); // length of s 8184 int m = t.length(); // length of t 8185 8186 // if one string is empty, the edit distance is necessarily the length of the other 8187 if (n == 0) { 8188 return m <= threshold ? m : -1; 8189 } else if (m == 0) { 8190 return n <= threshold ? n : -1; 8191 } else if (Math.abs(n - m) > threshold) { 8192 // no need to calculate the distance if the length difference is greater than the threshold 8193 return -1; 8194 } 8195 8196 if (n > m) { 8197 // swap the two strings to consume less memory 8198 final CharSequence tmp = s; 8199 s = t; 8200 t = tmp; 8201 n = m; 8202 m = t.length(); 8203 } 8204 8205 int p[] = new int[n + 1]; // 'previous' cost array, horizontally 8206 int d[] = new int[n + 1]; // cost array, horizontally 8207 int _d[]; // placeholder to assist in swapping p and d 8208 8209 // fill in starting table values 8210 final int boundary = Math.min(n, threshold) + 1; 8211 for (int i = 0; i < boundary; i++) { 8212 p[i] = i; 8213 } 8214 // these fills ensure that the value above the rightmost entry of our 8215 // stripe will be ignored in following loop iterations 8216 Arrays.fill(p, boundary, p.length, Integer.MAX_VALUE); 8217 Arrays.fill(d, Integer.MAX_VALUE); 8218 8219 // iterates through t 8220 for (int j = 1; j <= m; j++) { 8221 final char t_j = t.charAt(j - 1); // jth character of t 8222 d[0] = j; 8223 8224 // compute stripe indices, constrain to array size 8225 final int min = Math.max(1, j - threshold); 8226 final int max = j > Integer.MAX_VALUE - threshold ? n : Math.min(n, j + threshold); 8227 8228 // the stripe may lead off of the table if s and t are of different sizes 8229 if (min > max) { 8230 return -1; 8231 } 8232 8233 // ignore entry left of leftmost 8234 if (min > 1) { 8235 d[min - 1] = Integer.MAX_VALUE; 8236 } 8237 8238 // iterates through [min, max] in s 8239 for (int i = min; i <= max; i++) { 8240 if (s.charAt(i - 1) == t_j) { 8241 // diagonally left and up 8242 d[i] = p[i - 1]; 8243 } else { 8244 // 1 + minimum of cell to the left, to the top, diagonally left and up 8245 d[i] = 1 + Math.min(Math.min(d[i - 1], p[i]), p[i - 1]); 8246 } 8247 } 8248 8249 // copy current distance counts to 'previous row' distance counts 8250 _d = p; 8251 p = d; 8252 d = _d; 8253 } 8254 8255 // if p[n] is greater than the threshold, there's no guarantee on it being the correct 8256 // distance 8257 if (p[n] <= threshold) { 8258 return p[n]; 8259 } 8260 return -1; 8261 } 8262 8263 /** 8264 * <p>Find the Jaro Winkler Distance which indicates the similarity score between two Strings.</p> 8265 * 8266 * <p>The Jaro measure is the weighted sum of percentage of matched characters from each file and transposed characters. 8267 * Winkler increased this measure for matching initial characters.</p> 8268 * 8269 * <p>This implementation is based on the Jaro Winkler similarity algorithm 8270 * 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> 8271 * 8272 * <pre> 8273 * StringUtils.getJaroWinklerDistance(null, null) = IllegalArgumentException 8274 * StringUtils.getJaroWinklerDistance("","") = 0.0 8275 * StringUtils.getJaroWinklerDistance("","a") = 0.0 8276 * StringUtils.getJaroWinklerDistance("aaapppp", "") = 0.0 8277 * StringUtils.getJaroWinklerDistance("frog", "fog") = 0.93 8278 * StringUtils.getJaroWinklerDistance("fly", "ant") = 0.0 8279 * StringUtils.getJaroWinklerDistance("elephant", "hippo") = 0.44 8280 * StringUtils.getJaroWinklerDistance("hippo", "elephant") = 0.44 8281 * StringUtils.getJaroWinklerDistance("hippo", "zzzzzzzz") = 0.0 8282 * StringUtils.getJaroWinklerDistance("hello", "hallo") = 0.88 8283 * StringUtils.getJaroWinklerDistance("ABC Corporation", "ABC Corp") = 0.93 8284 * StringUtils.getJaroWinklerDistance("D N H Enterprises Inc", "D & H Enterprises, Inc.") = 0.95 8285 * StringUtils.getJaroWinklerDistance("My Gym Children's Fitness Center", "My Gym. Childrens Fitness") = 0.92 8286 * StringUtils.getJaroWinklerDistance("PENNSYLVANIA", "PENNCISYLVNIA") = 0.88 8287 * </pre> 8288 * 8289 * @param first the first String, must not be null 8290 * @param second the second String, must not be null 8291 * @return result distance 8292 * @throws IllegalArgumentException if either String input {@code null} 8293 * @since 3.3 8294 * @deprecated as of 3.6, use commons-text 8295 * <a href="https://commons.apache.org/proper/commons-text/javadocs/api-release/org/apache/commons/text/similarity/JaroWinklerDistance.html"> 8296 * JaroWinklerDistance</a> instead 8297 */ 8298 @Deprecated 8299 public static double getJaroWinklerDistance(final CharSequence first, final CharSequence second) { 8300 final double DEFAULT_SCALING_FACTOR = 0.1; 8301 8302 if (first == null || second == null) { 8303 throw new IllegalArgumentException("Strings must not be null"); 8304 } 8305 8306 final int[] mtp = matches(first, second); 8307 final double m = mtp[0]; 8308 if (m == 0) { 8309 return 0D; 8310 } 8311 final double j = ((m / first.length() + m / second.length() + (m - mtp[1]) / m)) / 3; 8312 final double jw = j < 0.7D ? j : j + Math.min(DEFAULT_SCALING_FACTOR, 1D / mtp[3]) * mtp[2] * (1D - j); 8313 return Math.round(jw * 100.0D) / 100.0D; 8314 } 8315 8316 private static int[] matches(final CharSequence first, final CharSequence second) { 8317 CharSequence max, min; 8318 if (first.length() > second.length()) { 8319 max = first; 8320 min = second; 8321 } else { 8322 max = second; 8323 min = first; 8324 } 8325 final int range = Math.max(max.length() / 2 - 1, 0); 8326 final int[] matchIndexes = new int[min.length()]; 8327 Arrays.fill(matchIndexes, -1); 8328 final boolean[] matchFlags = new boolean[max.length()]; 8329 int matches = 0; 8330 for (int mi = 0; mi < min.length(); mi++) { 8331 final char c1 = min.charAt(mi); 8332 for (int xi = Math.max(mi - range, 0), xn = Math.min(mi + range + 1, max.length()); xi < xn; xi++) { 8333 if (!matchFlags[xi] && c1 == max.charAt(xi)) { 8334 matchIndexes[mi] = xi; 8335 matchFlags[xi] = true; 8336 matches++; 8337 break; 8338 } 8339 } 8340 } 8341 final char[] ms1 = new char[matches]; 8342 final char[] ms2 = new char[matches]; 8343 for (int i = 0, si = 0; i < min.length(); i++) { 8344 if (matchIndexes[i] != -1) { 8345 ms1[si] = min.charAt(i); 8346 si++; 8347 } 8348 } 8349 for (int i = 0, si = 0; i < max.length(); i++) { 8350 if (matchFlags[i]) { 8351 ms2[si] = max.charAt(i); 8352 si++; 8353 } 8354 } 8355 int transpositions = 0; 8356 for (int mi = 0; mi < ms1.length; mi++) { 8357 if (ms1[mi] != ms2[mi]) { 8358 transpositions++; 8359 } 8360 } 8361 int prefix = 0; 8362 for (int mi = 0; mi < min.length(); mi++) { 8363 if (first.charAt(mi) == second.charAt(mi)) { 8364 prefix++; 8365 } else { 8366 break; 8367 } 8368 } 8369 return new int[] { matches, transpositions / 2, prefix, max.length() }; 8370 } 8371 8372 /** 8373 * <p>Find the Fuzzy Distance which indicates the similarity score between two Strings.</p> 8374 * 8375 * <p>This string matching algorithm is similar to the algorithms of editors such as Sublime Text, 8376 * TextMate, Atom and others. One point is given for every matched character. Subsequent 8377 * matches yield two bonus points. A higher score indicates a higher similarity.</p> 8378 * 8379 * <pre> 8380 * StringUtils.getFuzzyDistance(null, null, null) = IllegalArgumentException 8381 * StringUtils.getFuzzyDistance("", "", Locale.ENGLISH) = 0 8382 * StringUtils.getFuzzyDistance("Workshop", "b", Locale.ENGLISH) = 0 8383 * StringUtils.getFuzzyDistance("Room", "o", Locale.ENGLISH) = 1 8384 * StringUtils.getFuzzyDistance("Workshop", "w", Locale.ENGLISH) = 1 8385 * StringUtils.getFuzzyDistance("Workshop", "ws", Locale.ENGLISH) = 2 8386 * StringUtils.getFuzzyDistance("Workshop", "wo", Locale.ENGLISH) = 4 8387 * StringUtils.getFuzzyDistance("Apache Software Foundation", "asf", Locale.ENGLISH) = 3 8388 * </pre> 8389 * 8390 * @param term a full term that should be matched against, must not be null 8391 * @param query the query that will be matched against a term, must not be null 8392 * @param locale This string matching logic is case insensitive. A locale is necessary to normalize 8393 * both Strings to lower case. 8394 * @return result score 8395 * @throws IllegalArgumentException if either String input {@code null} or Locale input {@code null} 8396 * @since 3.4 8397 * @deprecated as of 3.6, use commons-text 8398 * <a href="https://commons.apache.org/proper/commons-text/javadocs/api-release/org/apache/commons/text/similarity/FuzzyScore.html"> 8399 * FuzzyScore</a> instead 8400 */ 8401 @Deprecated 8402 public static int getFuzzyDistance(final CharSequence term, final CharSequence query, final Locale locale) { 8403 if (term == null || query == null) { 8404 throw new IllegalArgumentException("Strings must not be null"); 8405 } else if (locale == null) { 8406 throw new IllegalArgumentException("Locale must not be null"); 8407 } 8408 8409 // fuzzy logic is case insensitive. We normalize the Strings to lower 8410 // case right from the start. Turning characters to lower case 8411 // via Character.toLowerCase(char) is unfortunately insufficient 8412 // as it does not accept a locale. 8413 final String termLowerCase = term.toString().toLowerCase(locale); 8414 final String queryLowerCase = query.toString().toLowerCase(locale); 8415 8416 // the resulting score 8417 int score = 0; 8418 8419 // the position in the term which will be scanned next for potential 8420 // query character matches 8421 int termIndex = 0; 8422 8423 // index of the previously matched character in the term 8424 int previousMatchingCharacterIndex = Integer.MIN_VALUE; 8425 8426 for (int queryIndex = 0; queryIndex < queryLowerCase.length(); queryIndex++) { 8427 final char queryChar = queryLowerCase.charAt(queryIndex); 8428 8429 boolean termCharacterMatchFound = false; 8430 for (; termIndex < termLowerCase.length() && !termCharacterMatchFound; termIndex++) { 8431 final char termChar = termLowerCase.charAt(termIndex); 8432 8433 if (queryChar == termChar) { 8434 // simple character matches result in one point 8435 score++; 8436 8437 // subsequent character matches further improve 8438 // the score. 8439 if (previousMatchingCharacterIndex + 1 == termIndex) { 8440 score += 2; 8441 } 8442 8443 previousMatchingCharacterIndex = termIndex; 8444 8445 // we can leave the nested loop. Every character in the 8446 // query can match at most one character in the term. 8447 termCharacterMatchFound = true; 8448 } 8449 } 8450 } 8451 8452 return score; 8453 } 8454 8455 // startsWith 8456 //----------------------------------------------------------------------- 8457 8458 /** 8459 * <p>Check if a CharSequence starts with a specified prefix.</p> 8460 * 8461 * <p>{@code null}s are handled without exceptions. Two {@code null} 8462 * references are considered to be equal. The comparison is case sensitive.</p> 8463 * 8464 * <pre> 8465 * StringUtils.startsWith(null, null) = true 8466 * StringUtils.startsWith(null, "abc") = false 8467 * StringUtils.startsWith("abcdef", null) = false 8468 * StringUtils.startsWith("abcdef", "abc") = true 8469 * StringUtils.startsWith("ABCDEF", "abc") = false 8470 * </pre> 8471 * 8472 * @see java.lang.String#startsWith(String) 8473 * @param str the CharSequence to check, may be null 8474 * @param prefix the prefix to find, may be null 8475 * @return {@code true} if the CharSequence starts with the prefix, case sensitive, or 8476 * both {@code null} 8477 * @since 2.4 8478 * @since 3.0 Changed signature from startsWith(String, String) to startsWith(CharSequence, CharSequence) 8479 */ 8480 public static boolean startsWith(final CharSequence str, final CharSequence prefix) { 8481 return startsWith(str, prefix, false); 8482 } 8483 8484 /** 8485 * <p>Case insensitive check if a CharSequence starts with a specified prefix.</p> 8486 * 8487 * <p>{@code null}s are handled without exceptions. Two {@code null} 8488 * references are considered to be equal. The comparison is case insensitive.</p> 8489 * 8490 * <pre> 8491 * StringUtils.startsWithIgnoreCase(null, null) = true 8492 * StringUtils.startsWithIgnoreCase(null, "abc") = false 8493 * StringUtils.startsWithIgnoreCase("abcdef", null) = false 8494 * StringUtils.startsWithIgnoreCase("abcdef", "abc") = true 8495 * StringUtils.startsWithIgnoreCase("ABCDEF", "abc") = true 8496 * </pre> 8497 * 8498 * @see java.lang.String#startsWith(String) 8499 * @param str the CharSequence to check, may be null 8500 * @param prefix the prefix to find, may be null 8501 * @return {@code true} if the CharSequence starts with the prefix, case insensitive, or 8502 * both {@code null} 8503 * @since 2.4 8504 * @since 3.0 Changed signature from startsWithIgnoreCase(String, String) to startsWithIgnoreCase(CharSequence, CharSequence) 8505 */ 8506 public static boolean startsWithIgnoreCase(final CharSequence str, final CharSequence prefix) { 8507 return startsWith(str, prefix, true); 8508 } 8509 8510 /** 8511 * <p>Check if a CharSequence starts with a specified prefix (optionally case insensitive).</p> 8512 * 8513 * @see java.lang.String#startsWith(String) 8514 * @param str the CharSequence to check, may be null 8515 * @param prefix the prefix to find, may be null 8516 * @param ignoreCase indicates whether the compare should ignore case 8517 * (case insensitive) or not. 8518 * @return {@code true} if the CharSequence starts with the prefix or 8519 * both {@code null} 8520 */ 8521 private static boolean startsWith(final CharSequence str, final CharSequence prefix, final boolean ignoreCase) { 8522 if (str == null || prefix == null) { 8523 return str == null && prefix == null; 8524 } 8525 if (prefix.length() > str.length()) { 8526 return false; 8527 } 8528 return CharSequenceUtils.regionMatches(str, ignoreCase, 0, prefix, 0, prefix.length()); 8529 } 8530 8531 /** 8532 * <p>Check if a CharSequence starts with any of the provided case-sensitive prefixes.</p> 8533 * 8534 * <pre> 8535 * StringUtils.startsWithAny(null, null) = false 8536 * StringUtils.startsWithAny(null, new String[] {"abc"}) = false 8537 * StringUtils.startsWithAny("abcxyz", null) = false 8538 * StringUtils.startsWithAny("abcxyz", new String[] {""}) = true 8539 * StringUtils.startsWithAny("abcxyz", new String[] {"abc"}) = true 8540 * StringUtils.startsWithAny("abcxyz", new String[] {null, "xyz", "abc"}) = true 8541 * StringUtils.startsWithAny("abcxyz", null, "xyz", "ABCX") = false 8542 * StringUtils.startsWithAny("ABCXYZ", null, "xyz", "abc") = false 8543 * </pre> 8544 * 8545 * @param sequence the CharSequence to check, may be null 8546 * @param searchStrings the case-sensitive CharSequence prefixes, may be empty or contain {@code null} 8547 * @see StringUtils#startsWith(CharSequence, CharSequence) 8548 * @return {@code true} if the input {@code sequence} is {@code null} AND no {@code searchStrings} are provided, or 8549 * the input {@code sequence} begins with any of the provided case-sensitive {@code searchStrings}. 8550 * @since 2.5 8551 * @since 3.0 Changed signature from startsWithAny(String, String[]) to startsWithAny(CharSequence, CharSequence...) 8552 */ 8553 public static boolean startsWithAny(final CharSequence sequence, final CharSequence... searchStrings) { 8554 if (isEmpty(sequence) || ArrayUtils.isEmpty(searchStrings)) { 8555 return false; 8556 } 8557 for (final CharSequence searchString : searchStrings) { 8558 if (startsWith(sequence, searchString)) { 8559 return true; 8560 } 8561 } 8562 return false; 8563 } 8564 8565 // endsWith 8566 //----------------------------------------------------------------------- 8567 8568 /** 8569 * <p>Check if a CharSequence ends with a specified suffix.</p> 8570 * 8571 * <p>{@code null}s are handled without exceptions. Two {@code null} 8572 * references are considered to be equal. The comparison is case sensitive.</p> 8573 * 8574 * <pre> 8575 * StringUtils.endsWith(null, null) = true 8576 * StringUtils.endsWith(null, "def") = false 8577 * StringUtils.endsWith("abcdef", null) = false 8578 * StringUtils.endsWith("abcdef", "def") = true 8579 * StringUtils.endsWith("ABCDEF", "def") = false 8580 * StringUtils.endsWith("ABCDEF", "cde") = false 8581 * StringUtils.endsWith("ABCDEF", "") = true 8582 * </pre> 8583 * 8584 * @see java.lang.String#endsWith(String) 8585 * @param str the CharSequence to check, may be null 8586 * @param suffix the suffix to find, may be null 8587 * @return {@code true} if the CharSequence ends with the suffix, case sensitive, or 8588 * both {@code null} 8589 * @since 2.4 8590 * @since 3.0 Changed signature from endsWith(String, String) to endsWith(CharSequence, CharSequence) 8591 */ 8592 public static boolean endsWith(final CharSequence str, final CharSequence suffix) { 8593 return endsWith(str, suffix, false); 8594 } 8595 8596 /** 8597 * <p>Case insensitive check if a CharSequence ends with a specified suffix.</p> 8598 * 8599 * <p>{@code null}s are handled without exceptions. Two {@code null} 8600 * references are considered to be equal. The comparison is case insensitive.</p> 8601 * 8602 * <pre> 8603 * StringUtils.endsWithIgnoreCase(null, null) = true 8604 * StringUtils.endsWithIgnoreCase(null, "def") = false 8605 * StringUtils.endsWithIgnoreCase("abcdef", null) = false 8606 * StringUtils.endsWithIgnoreCase("abcdef", "def") = true 8607 * StringUtils.endsWithIgnoreCase("ABCDEF", "def") = true 8608 * StringUtils.endsWithIgnoreCase("ABCDEF", "cde") = false 8609 * </pre> 8610 * 8611 * @see java.lang.String#endsWith(String) 8612 * @param str the CharSequence to check, may be null 8613 * @param suffix the suffix to find, may be null 8614 * @return {@code true} if the CharSequence ends with the suffix, case insensitive, or 8615 * both {@code null} 8616 * @since 2.4 8617 * @since 3.0 Changed signature from endsWithIgnoreCase(String, String) to endsWithIgnoreCase(CharSequence, CharSequence) 8618 */ 8619 public static boolean endsWithIgnoreCase(final CharSequence str, final CharSequence suffix) { 8620 return endsWith(str, suffix, true); 8621 } 8622 8623 /** 8624 * <p>Check if a CharSequence ends with a specified suffix (optionally case insensitive).</p> 8625 * 8626 * @see java.lang.String#endsWith(String) 8627 * @param str the CharSequence to check, may be null 8628 * @param suffix the suffix to find, may be null 8629 * @param ignoreCase indicates whether the compare should ignore case 8630 * (case insensitive) or not. 8631 * @return {@code true} if the CharSequence starts with the prefix or 8632 * both {@code null} 8633 */ 8634 private static boolean endsWith(final CharSequence str, final CharSequence suffix, final boolean ignoreCase) { 8635 if (str == null || suffix == null) { 8636 return str == null && suffix == null; 8637 } 8638 if (suffix.length() > str.length()) { 8639 return false; 8640 } 8641 final int strOffset = str.length() - suffix.length(); 8642 return CharSequenceUtils.regionMatches(str, ignoreCase, strOffset, suffix, 0, suffix.length()); 8643 } 8644 8645 /** 8646 * <p> 8647 * Similar to <a 8648 * href="http://www.w3.org/TR/xpath/#function-normalize-space">http://www.w3.org/TR/xpath/#function-normalize 8649 * -space</a> 8650 * </p> 8651 * <p> 8652 * The function returns the argument string with whitespace normalized by using 8653 * <code>{@link #trim(String)}</code> to remove leading and trailing whitespace 8654 * and then replacing sequences of whitespace characters by a single space. 8655 * </p> 8656 * In XML Whitespace characters are the same as those allowed by the <a 8657 * href="http://www.w3.org/TR/REC-xml/#NT-S">S</a> production, which is S ::= (#x20 | #x9 | #xD | #xA)+ 8658 * <p> 8659 * Java's regexp pattern \s defines whitespace as [ \t\n\x0B\f\r] 8660 * 8661 * <p>For reference:</p> 8662 * <ul> 8663 * <li>\x0B = vertical tab</li> 8664 * <li>\f = #xC = form feed</li> 8665 * <li>#x20 = space</li> 8666 * <li>#x9 = \t</li> 8667 * <li>#xA = \n</li> 8668 * <li>#xD = \r</li> 8669 * </ul> 8670 * 8671 * <p> 8672 * The difference is that Java's whitespace includes vertical tab and form feed, which this functional will also 8673 * normalize. Additionally <code>{@link #trim(String)}</code> removes control characters (char <= 32) from both 8674 * ends of this String. 8675 * </p> 8676 * 8677 * @see Pattern 8678 * @see #trim(String) 8679 * @see <a 8680 * href="http://www.w3.org/TR/xpath/#function-normalize-space">http://www.w3.org/TR/xpath/#function-normalize-space</a> 8681 * @param str the source String to normalize whitespaces from, may be null 8682 * @return the modified string with whitespace normalized, {@code null} if null String input 8683 * 8684 * @since 3.0 8685 */ 8686 public static String normalizeSpace(final String str) { 8687 // LANG-1020: Improved performance significantly by normalizing manually instead of using regex 8688 // See https://github.com/librucha/commons-lang-normalizespaces-benchmark for performance test 8689 if (isEmpty(str)) { 8690 return str; 8691 } 8692 final int size = str.length(); 8693 final char[] newChars = new char[size]; 8694 int count = 0; 8695 int whitespacesCount = 0; 8696 boolean startWhitespaces = true; 8697 for (int i = 0; i < size; i++) { 8698 final char actualChar = str.charAt(i); 8699 final boolean isWhitespace = Character.isWhitespace(actualChar); 8700 if (!isWhitespace) { 8701 startWhitespaces = false; 8702 newChars[count++] = (actualChar == 160 ? 32 : actualChar); 8703 whitespacesCount = 0; 8704 } else { 8705 if (whitespacesCount == 0 && !startWhitespaces) { 8706 newChars[count++] = SPACE.charAt(0); 8707 } 8708 whitespacesCount++; 8709 } 8710 } 8711 if (startWhitespaces) { 8712 return EMPTY; 8713 } 8714 return new String(newChars, 0, count - (whitespacesCount > 0 ? 1 : 0)).trim(); 8715 } 8716 8717 /** 8718 * <p>Check if a CharSequence ends with any of the provided case-sensitive suffixes.</p> 8719 * 8720 * <pre> 8721 * StringUtils.endsWithAny(null, null) = false 8722 * StringUtils.endsWithAny(null, new String[] {"abc"}) = false 8723 * StringUtils.endsWithAny("abcxyz", null) = false 8724 * StringUtils.endsWithAny("abcxyz", new String[] {""}) = true 8725 * StringUtils.endsWithAny("abcxyz", new String[] {"xyz"}) = true 8726 * StringUtils.endsWithAny("abcxyz", new String[] {null, "xyz", "abc"}) = true 8727 * StringUtils.endsWithAny("abcXYZ", "def", "XYZ") = true 8728 * StringUtils.endsWithAny("abcXYZ", "def", "xyz") = false 8729 * </pre> 8730 * 8731 * @param sequence the CharSequence to check, may be null 8732 * @param searchStrings the case-sensitive CharSequences to find, may be empty or contain {@code null} 8733 * @see StringUtils#endsWith(CharSequence, CharSequence) 8734 * @return {@code true} if the input {@code sequence} is {@code null} AND no {@code searchStrings} are provided, or 8735 * the input {@code sequence} ends in any of the provided case-sensitive {@code searchStrings}. 8736 * @since 3.0 8737 */ 8738 public static boolean endsWithAny(final CharSequence sequence, final CharSequence... searchStrings) { 8739 if (isEmpty(sequence) || ArrayUtils.isEmpty(searchStrings)) { 8740 return false; 8741 } 8742 for (final CharSequence searchString : searchStrings) { 8743 if (endsWith(sequence, searchString)) { 8744 return true; 8745 } 8746 } 8747 return false; 8748 } 8749 8750 /** 8751 * Appends the suffix to the end of the string if the string does not 8752 * already end with the suffix. 8753 * 8754 * @param str The string. 8755 * @param suffix The suffix to append to the end of the string. 8756 * @param ignoreCase Indicates whether the compare should ignore case. 8757 * @param suffixes Additional suffixes that are valid terminators (optional). 8758 * 8759 * @return A new String if suffix was appended, the same string otherwise. 8760 */ 8761 private static String appendIfMissing(final String str, final CharSequence suffix, final boolean ignoreCase, final CharSequence... suffixes) { 8762 if (str == null || isEmpty(suffix) || endsWith(str, suffix, ignoreCase)) { 8763 return str; 8764 } 8765 if (suffixes != null && suffixes.length > 0) { 8766 for (final CharSequence s : suffixes) { 8767 if (endsWith(str, s, ignoreCase)) { 8768 return str; 8769 } 8770 } 8771 } 8772 return str + suffix.toString(); 8773 } 8774 8775 /** 8776 * Appends the suffix to the end of the string if the string does not 8777 * already end with any of the suffixes. 8778 * 8779 * <pre> 8780 * StringUtils.appendIfMissing(null, null) = null 8781 * StringUtils.appendIfMissing("abc", null) = "abc" 8782 * StringUtils.appendIfMissing("", "xyz") = "xyz" 8783 * StringUtils.appendIfMissing("abc", "xyz") = "abcxyz" 8784 * StringUtils.appendIfMissing("abcxyz", "xyz") = "abcxyz" 8785 * StringUtils.appendIfMissing("abcXYZ", "xyz") = "abcXYZxyz" 8786 * </pre> 8787 * <p>With additional suffixes,</p> 8788 * <pre> 8789 * StringUtils.appendIfMissing(null, null, null) = null 8790 * StringUtils.appendIfMissing("abc", null, null) = "abc" 8791 * StringUtils.appendIfMissing("", "xyz", null) = "xyz" 8792 * StringUtils.appendIfMissing("abc", "xyz", new CharSequence[]{null}) = "abcxyz" 8793 * StringUtils.appendIfMissing("abc", "xyz", "") = "abc" 8794 * StringUtils.appendIfMissing("abc", "xyz", "mno") = "abcxyz" 8795 * StringUtils.appendIfMissing("abcxyz", "xyz", "mno") = "abcxyz" 8796 * StringUtils.appendIfMissing("abcmno", "xyz", "mno") = "abcmno" 8797 * StringUtils.appendIfMissing("abcXYZ", "xyz", "mno") = "abcXYZxyz" 8798 * StringUtils.appendIfMissing("abcMNO", "xyz", "mno") = "abcMNOxyz" 8799 * </pre> 8800 * 8801 * @param str The string. 8802 * @param suffix The suffix to append to the end of the string. 8803 * @param suffixes Additional suffixes that are valid terminators. 8804 * 8805 * @return A new String if suffix was appended, the same string otherwise. 8806 * 8807 * @since 3.2 8808 */ 8809 public static String appendIfMissing(final String str, final CharSequence suffix, final CharSequence... suffixes) { 8810 return appendIfMissing(str, suffix, false, suffixes); 8811 } 8812 8813 /** 8814 * Appends the suffix to the end of the string if the string does not 8815 * already end, case insensitive, with any of the suffixes. 8816 * 8817 * <pre> 8818 * StringUtils.appendIfMissingIgnoreCase(null, null) = null 8819 * StringUtils.appendIfMissingIgnoreCase("abc", null) = "abc" 8820 * StringUtils.appendIfMissingIgnoreCase("", "xyz") = "xyz" 8821 * StringUtils.appendIfMissingIgnoreCase("abc", "xyz") = "abcxyz" 8822 * StringUtils.appendIfMissingIgnoreCase("abcxyz", "xyz") = "abcxyz" 8823 * StringUtils.appendIfMissingIgnoreCase("abcXYZ", "xyz") = "abcXYZ" 8824 * </pre> 8825 * <p>With additional suffixes,</p> 8826 * <pre> 8827 * StringUtils.appendIfMissingIgnoreCase(null, null, null) = null 8828 * StringUtils.appendIfMissingIgnoreCase("abc", null, null) = "abc" 8829 * StringUtils.appendIfMissingIgnoreCase("", "xyz", null) = "xyz" 8830 * StringUtils.appendIfMissingIgnoreCase("abc", "xyz", new CharSequence[]{null}) = "abcxyz" 8831 * StringUtils.appendIfMissingIgnoreCase("abc", "xyz", "") = "abc" 8832 * StringUtils.appendIfMissingIgnoreCase("abc", "xyz", "mno") = "axyz" 8833 * StringUtils.appendIfMissingIgnoreCase("abcxyz", "xyz", "mno") = "abcxyz" 8834 * StringUtils.appendIfMissingIgnoreCase("abcmno", "xyz", "mno") = "abcmno" 8835 * StringUtils.appendIfMissingIgnoreCase("abcXYZ", "xyz", "mno") = "abcXYZ" 8836 * StringUtils.appendIfMissingIgnoreCase("abcMNO", "xyz", "mno") = "abcMNO" 8837 * </pre> 8838 * 8839 * @param str The string. 8840 * @param suffix The suffix to append to the end of the string. 8841 * @param suffixes Additional suffixes that are valid terminators. 8842 * 8843 * @return A new String if suffix was appended, the same string otherwise. 8844 * 8845 * @since 3.2 8846 */ 8847 public static String appendIfMissingIgnoreCase(final String str, final CharSequence suffix, final CharSequence... suffixes) { 8848 return appendIfMissing(str, suffix, true, suffixes); 8849 } 8850 8851 /** 8852 * Prepends the prefix to the start of the string if the string does not 8853 * already start with any of the prefixes. 8854 * 8855 * @param str The string. 8856 * @param prefix The prefix to prepend to the start of the string. 8857 * @param ignoreCase Indicates whether the compare should ignore case. 8858 * @param prefixes Additional prefixes that are valid (optional). 8859 * 8860 * @return A new String if prefix was prepended, the same string otherwise. 8861 */ 8862 private static String prependIfMissing(final String str, final CharSequence prefix, final boolean ignoreCase, final CharSequence... prefixes) { 8863 if (str == null || isEmpty(prefix) || startsWith(str, prefix, ignoreCase)) { 8864 return str; 8865 } 8866 if (prefixes != null && prefixes.length > 0) { 8867 for (final CharSequence p : prefixes) { 8868 if (startsWith(str, p, ignoreCase)) { 8869 return str; 8870 } 8871 } 8872 } 8873 return prefix.toString() + str; 8874 } 8875 8876 /** 8877 * Prepends the prefix to the start of the string if the string does not 8878 * already start with any of the prefixes. 8879 * 8880 * <pre> 8881 * StringUtils.prependIfMissing(null, null) = null 8882 * StringUtils.prependIfMissing("abc", null) = "abc" 8883 * StringUtils.prependIfMissing("", "xyz") = "xyz" 8884 * StringUtils.prependIfMissing("abc", "xyz") = "xyzabc" 8885 * StringUtils.prependIfMissing("xyzabc", "xyz") = "xyzabc" 8886 * StringUtils.prependIfMissing("XYZabc", "xyz") = "xyzXYZabc" 8887 * </pre> 8888 * <p>With additional prefixes,</p> 8889 * <pre> 8890 * StringUtils.prependIfMissing(null, null, null) = null 8891 * StringUtils.prependIfMissing("abc", null, null) = "abc" 8892 * StringUtils.prependIfMissing("", "xyz", null) = "xyz" 8893 * StringUtils.prependIfMissing("abc", "xyz", new CharSequence[]{null}) = "xyzabc" 8894 * StringUtils.prependIfMissing("abc", "xyz", "") = "abc" 8895 * StringUtils.prependIfMissing("abc", "xyz", "mno") = "xyzabc" 8896 * StringUtils.prependIfMissing("xyzabc", "xyz", "mno") = "xyzabc" 8897 * StringUtils.prependIfMissing("mnoabc", "xyz", "mno") = "mnoabc" 8898 * StringUtils.prependIfMissing("XYZabc", "xyz", "mno") = "xyzXYZabc" 8899 * StringUtils.prependIfMissing("MNOabc", "xyz", "mno") = "xyzMNOabc" 8900 * </pre> 8901 * 8902 * @param str The string. 8903 * @param prefix The prefix to prepend to the start of the string. 8904 * @param prefixes Additional prefixes that are valid. 8905 * 8906 * @return A new String if prefix was prepended, the same string otherwise. 8907 * 8908 * @since 3.2 8909 */ 8910 public static String prependIfMissing(final String str, final CharSequence prefix, final CharSequence... prefixes) { 8911 return prependIfMissing(str, prefix, false, prefixes); 8912 } 8913 8914 /** 8915 * Prepends the prefix to the start of the string if the string does not 8916 * already start, case insensitive, with any of the prefixes. 8917 * 8918 * <pre> 8919 * StringUtils.prependIfMissingIgnoreCase(null, null) = null 8920 * StringUtils.prependIfMissingIgnoreCase("abc", null) = "abc" 8921 * StringUtils.prependIfMissingIgnoreCase("", "xyz") = "xyz" 8922 * StringUtils.prependIfMissingIgnoreCase("abc", "xyz") = "xyzabc" 8923 * StringUtils.prependIfMissingIgnoreCase("xyzabc", "xyz") = "xyzabc" 8924 * StringUtils.prependIfMissingIgnoreCase("XYZabc", "xyz") = "XYZabc" 8925 * </pre> 8926 * <p>With additional prefixes,</p> 8927 * <pre> 8928 * StringUtils.prependIfMissingIgnoreCase(null, null, null) = null 8929 * StringUtils.prependIfMissingIgnoreCase("abc", null, null) = "abc" 8930 * StringUtils.prependIfMissingIgnoreCase("", "xyz", null) = "xyz" 8931 * StringUtils.prependIfMissingIgnoreCase("abc", "xyz", new CharSequence[]{null}) = "xyzabc" 8932 * StringUtils.prependIfMissingIgnoreCase("abc", "xyz", "") = "abc" 8933 * StringUtils.prependIfMissingIgnoreCase("abc", "xyz", "mno") = "xyzabc" 8934 * StringUtils.prependIfMissingIgnoreCase("xyzabc", "xyz", "mno") = "xyzabc" 8935 * StringUtils.prependIfMissingIgnoreCase("mnoabc", "xyz", "mno") = "mnoabc" 8936 * StringUtils.prependIfMissingIgnoreCase("XYZabc", "xyz", "mno") = "XYZabc" 8937 * StringUtils.prependIfMissingIgnoreCase("MNOabc", "xyz", "mno") = "MNOabc" 8938 * </pre> 8939 * 8940 * @param str The string. 8941 * @param prefix The prefix to prepend to the start of the string. 8942 * @param prefixes Additional prefixes that are valid (optional). 8943 * 8944 * @return A new String if prefix was prepended, the same string otherwise. 8945 * 8946 * @since 3.2 8947 */ 8948 public static String prependIfMissingIgnoreCase(final String str, final CharSequence prefix, final CharSequence... prefixes) { 8949 return prependIfMissing(str, prefix, true, prefixes); 8950 } 8951 8952 /** 8953 * Converts a <code>byte[]</code> to a String using the specified character encoding. 8954 * 8955 * @param bytes 8956 * the byte array to read from 8957 * @param charsetName 8958 * the encoding to use, if null then use the platform default 8959 * @return a new String 8960 * @throws UnsupportedEncodingException 8961 * If the named charset is not supported 8962 * @throws NullPointerException 8963 * if the input is null 8964 * @deprecated use {@link StringUtils#toEncodedString(byte[], Charset)} instead of String constants in your code 8965 * @since 3.1 8966 */ 8967 @Deprecated 8968 public static String toString(final byte[] bytes, final String charsetName) throws UnsupportedEncodingException { 8969 return charsetName != null ? new String(bytes, charsetName) : new String(bytes, Charset.defaultCharset()); 8970 } 8971 8972 /** 8973 * Converts a <code>byte[]</code> to a String using the specified character encoding. 8974 * 8975 * @param bytes 8976 * the byte array to read from 8977 * @param charset 8978 * the encoding to use, if null then use the platform default 8979 * @return a new String 8980 * @throws NullPointerException 8981 * if {@code bytes} is null 8982 * @since 3.2 8983 * @since 3.3 No longer throws {@link UnsupportedEncodingException}. 8984 */ 8985 public static String toEncodedString(final byte[] bytes, final Charset charset) { 8986 return new String(bytes, charset != null ? charset : Charset.defaultCharset()); 8987 } 8988 8989 /** 8990 * <p> 8991 * Wraps a string with a char. 8992 * </p> 8993 * 8994 * <pre> 8995 * StringUtils.wrap(null, *) = null 8996 * StringUtils.wrap("", *) = "" 8997 * StringUtils.wrap("ab", '\0') = "ab" 8998 * StringUtils.wrap("ab", 'x') = "xabx" 8999 * StringUtils.wrap("ab", '\'') = "'ab'" 9000 * StringUtils.wrap("\"ab\"", '\"') = "\"\"ab\"\"" 9001 * </pre> 9002 * 9003 * @param str 9004 * the string to be wrapped, may be {@code null} 9005 * @param wrapWith 9006 * the char that will wrap {@code str} 9007 * @return the wrapped string, or {@code null} if {@code str==null} 9008 * @since 3.4 9009 */ 9010 public static String wrap(final String str, final char wrapWith) { 9011 9012 if (isEmpty(str) || wrapWith == CharUtils.NUL) { 9013 return str; 9014 } 9015 9016 return wrapWith + str + wrapWith; 9017 } 9018 9019 /** 9020 * <p> 9021 * Wraps a String with another String. 9022 * </p> 9023 * 9024 * <p> 9025 * A {@code null} input String returns {@code null}. 9026 * </p> 9027 * 9028 * <pre> 9029 * StringUtils.wrap(null, *) = null 9030 * StringUtils.wrap("", *) = "" 9031 * StringUtils.wrap("ab", null) = "ab" 9032 * StringUtils.wrap("ab", "x") = "xabx" 9033 * StringUtils.wrap("ab", "\"") = "\"ab\"" 9034 * StringUtils.wrap("\"ab\"", "\"") = "\"\"ab\"\"" 9035 * StringUtils.wrap("ab", "'") = "'ab'" 9036 * StringUtils.wrap("'abcd'", "'") = "''abcd''" 9037 * StringUtils.wrap("\"abcd\"", "'") = "'\"abcd\"'" 9038 * StringUtils.wrap("'abcd'", "\"") = "\"'abcd'\"" 9039 * </pre> 9040 * 9041 * @param str 9042 * the String to be wrapper, may be null 9043 * @param wrapWith 9044 * the String that will wrap str 9045 * @return wrapped String, {@code null} if null String input 9046 * @since 3.4 9047 */ 9048 public static String wrap(final String str, final String wrapWith) { 9049 9050 if (isEmpty(str) || isEmpty(wrapWith)) { 9051 return str; 9052 } 9053 9054 return wrapWith.concat(str).concat(wrapWith); 9055 } 9056 9057 /** 9058 * <p> 9059 * Wraps a string with a char if that char is missing from the start or end of the given string. 9060 * </p> 9061 * 9062 * <pre> 9063 * StringUtils.wrap(null, *) = null 9064 * StringUtils.wrap("", *) = "" 9065 * StringUtils.wrap("ab", '\0') = "ab" 9066 * StringUtils.wrap("ab", 'x') = "xabx" 9067 * StringUtils.wrap("ab", '\'') = "'ab'" 9068 * StringUtils.wrap("\"ab\"", '\"') = "\"ab\"" 9069 * StringUtils.wrap("/", '/') = "/" 9070 * StringUtils.wrap("a/b/c", '/') = "/a/b/c/" 9071 * StringUtils.wrap("/a/b/c", '/') = "/a/b/c/" 9072 * StringUtils.wrap("a/b/c/", '/') = "/a/b/c/" 9073 * </pre> 9074 * 9075 * @param str 9076 * the string to be wrapped, may be {@code null} 9077 * @param wrapWith 9078 * the char that will wrap {@code str} 9079 * @return the wrapped string, or {@code null} if {@code str==null} 9080 * @since 3.5 9081 */ 9082 public static String wrapIfMissing(final String str, final char wrapWith) { 9083 if (isEmpty(str) || wrapWith == CharUtils.NUL) { 9084 return str; 9085 } 9086 final StringBuilder builder = new StringBuilder(str.length() + 2); 9087 if (str.charAt(0) != wrapWith) { 9088 builder.append(wrapWith); 9089 } 9090 builder.append(str); 9091 if (str.charAt(str.length() - 1) != wrapWith) { 9092 builder.append(wrapWith); 9093 } 9094 return builder.toString(); 9095 } 9096 9097 /** 9098 * <p> 9099 * Wraps a string with a string if that string is missing from the start or end of the given string. 9100 * </p> 9101 * 9102 * <pre> 9103 * StringUtils.wrap(null, *) = null 9104 * StringUtils.wrap("", *) = "" 9105 * StringUtils.wrap("ab", null) = "ab" 9106 * StringUtils.wrap("ab", "x") = "xabx" 9107 * StringUtils.wrap("ab", "\"") = "\"ab\"" 9108 * StringUtils.wrap("\"ab\"", "\"") = "\"ab\"" 9109 * StringUtils.wrap("ab", "'") = "'ab'" 9110 * StringUtils.wrap("'abcd'", "'") = "'abcd'" 9111 * StringUtils.wrap("\"abcd\"", "'") = "'\"abcd\"'" 9112 * StringUtils.wrap("'abcd'", "\"") = "\"'abcd'\"" 9113 * StringUtils.wrap("/", "/") = "/" 9114 * StringUtils.wrap("a/b/c", "/") = "/a/b/c/" 9115 * StringUtils.wrap("/a/b/c", "/") = "/a/b/c/" 9116 * StringUtils.wrap("a/b/c/", "/") = "/a/b/c/" 9117 * </pre> 9118 * 9119 * @param str 9120 * the string to be wrapped, may be {@code null} 9121 * @param wrapWith 9122 * the char that will wrap {@code str} 9123 * @return the wrapped string, or {@code null} if {@code str==null} 9124 * @since 3.5 9125 */ 9126 public static String wrapIfMissing(final String str, final String wrapWith) { 9127 if (isEmpty(str) || isEmpty(wrapWith)) { 9128 return str; 9129 } 9130 final StringBuilder builder = new StringBuilder(str.length() + wrapWith.length() + wrapWith.length()); 9131 if (!str.startsWith(wrapWith)) { 9132 builder.append(wrapWith); 9133 } 9134 builder.append(str); 9135 if (!str.endsWith(wrapWith)) { 9136 builder.append(wrapWith); 9137 } 9138 return builder.toString(); 9139 } 9140 9141 /** 9142 * <p> 9143 * Unwraps a given string from anther string. 9144 * </p> 9145 * 9146 * <pre> 9147 * StringUtils.unwrap(null, null) = null 9148 * StringUtils.unwrap(null, "") = null 9149 * StringUtils.unwrap(null, "1") = null 9150 * StringUtils.unwrap("\'abc\'", "\'") = "abc" 9151 * StringUtils.unwrap("\"abc\"", "\"") = "abc" 9152 * StringUtils.unwrap("AABabcBAA", "AA") = "BabcB" 9153 * StringUtils.unwrap("A", "#") = "A" 9154 * StringUtils.unwrap("#A", "#") = "#A" 9155 * StringUtils.unwrap("A#", "#") = "A#" 9156 * </pre> 9157 * 9158 * @param str 9159 * the String to be unwrapped, can be null 9160 * @param wrapToken 9161 * the String used to unwrap 9162 * @return unwrapped String or the original string 9163 * if it is not quoted properly with the wrapToken 9164 * @since 3.6 9165 */ 9166 public static String unwrap(final String str, final String wrapToken) { 9167 if (isEmpty(str) || isEmpty(wrapToken)) { 9168 return str; 9169 } 9170 9171 if (startsWith(str, wrapToken) && endsWith(str, wrapToken)) { 9172 final int startIndex = str.indexOf(wrapToken); 9173 final int endIndex = str.lastIndexOf(wrapToken); 9174 final int wrapLength = wrapToken.length(); 9175 if (startIndex != -1 && endIndex != -1) { 9176 return str.substring(startIndex + wrapLength, endIndex); 9177 } 9178 } 9179 9180 return str; 9181 } 9182 9183 /** 9184 * <p> 9185 * Unwraps a given string from a character. 9186 * </p> 9187 * 9188 * <pre> 9189 * StringUtils.unwrap(null, null) = null 9190 * StringUtils.unwrap(null, '\0') = null 9191 * StringUtils.unwrap(null, '1') = null 9192 * StringUtils.unwrap("\'abc\'", '\'') = "abc" 9193 * StringUtils.unwrap("AABabcBAA", 'A') = "ABabcBA" 9194 * StringUtils.unwrap("A", '#') = "A" 9195 * StringUtils.unwrap("#A", '#') = "#A" 9196 * StringUtils.unwrap("A#", '#') = "A#" 9197 * </pre> 9198 * 9199 * @param str 9200 * the String to be unwrapped, can be null 9201 * @param wrapChar 9202 * the character used to unwrap 9203 * @return unwrapped String or the original string 9204 * if it is not quoted properly with the wrapChar 9205 * @since 3.6 9206 */ 9207 public static String unwrap(final String str, final char wrapChar) { 9208 if (isEmpty(str) || wrapChar == CharUtils.NUL) { 9209 return str; 9210 } 9211 9212 if (str.charAt(0) == wrapChar && str.charAt(str.length() - 1) == wrapChar) { 9213 final int startIndex = 0; 9214 final int endIndex = str.length() - 1; 9215 if (startIndex != -1 && endIndex != -1) { 9216 return str.substring(startIndex + 1, endIndex); 9217 } 9218 } 9219 9220 return str; 9221 } 9222 9223 /** 9224 * <p>Converts a {@code CharSequence} into an array of code points.</p> 9225 * 9226 * <p>Valid pairs of surrogate code units will be converted into a single supplementary 9227 * code point. Isolated surrogate code units (i.e. a high surrogate not followed by a low surrogate or 9228 * a low surrogate not preceeded by a high surrogate) will be returned as-is.</p> 9229 * 9230 * <pre> 9231 * StringUtils.toCodePoints(null) = null 9232 * StringUtils.toCodePoints("") = [] // empty array 9233 * </pre> 9234 * 9235 * @param str the character sequence to convert 9236 * @return an array of code points 9237 * @since 3.6 9238 */ 9239 public static int[] toCodePoints(CharSequence str) { 9240 if (str == null) { 9241 return null; 9242 } 9243 if (str.length() == 0) { 9244 return ArrayUtils.EMPTY_INT_ARRAY; 9245 } 9246 9247 String s = str.toString(); 9248 int[] result = new int[s.codePointCount(0, s.length())]; 9249 int index = 0; 9250 for (int i = 0; i < result.length; i++) { 9251 result[i] = s.codePointAt(index); 9252 index += Character.charCount(result[i]); 9253 } 9254 return result; 9255 } 9256}