1 /* 2 * Licensed to the Apache Software Foundation (ASF) under one or more 3 * contributor license agreements. See the NOTICE file distributed with 4 * this work for additional information regarding copyright ownership. 5 * The ASF licenses this file to You under the Apache License, Version 2.0 6 * (the "License"); you may not use this file except in compliance with 7 * the License. You may obtain a copy of the License at 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 */ 17 package org.apache.commons.lang3; 18 19 import java.io.UnsupportedEncodingException; 20 import java.nio.charset.Charset; 21 import java.text.Normalizer; 22 import java.util.ArrayList; 23 import java.util.Arrays; 24 import java.util.HashSet; 25 import java.util.Iterator; 26 import java.util.List; 27 import java.util.Locale; 28 import java.util.Objects; 29 import java.util.Set; 30 import java.util.function.Supplier; 31 import java.util.regex.Pattern; 32 33 import org.apache.commons.lang3.function.Suppliers; 34 import org.apache.commons.lang3.function.ToBooleanBiFunction; 35 import org.apache.commons.lang3.stream.LangCollectors; 36 import org.apache.commons.lang3.stream.Streams; 37 38 /** 39 * Operations on {@link String} that are 40 * {@code null} safe. 41 * 42 * <ul> 43 * <li><b>IsEmpty/IsBlank</b> 44 * - checks if a String contains text</li> 45 * <li><b>Trim/Strip</b> 46 * - removes leading and trailing whitespace</li> 47 * <li><b>Equals/Compare</b> 48 * - compares two strings in a null-safe manner</li> 49 * <li><b>startsWith</b> 50 * - check if a String starts with a prefix in a null-safe manner</li> 51 * <li><b>endsWith</b> 52 * - check if a String ends with a suffix in a null-safe manner</li> 53 * <li><b>IndexOf/LastIndexOf/Contains</b> 54 * - null-safe index-of checks 55 * <li><b>IndexOfAny/LastIndexOfAny/IndexOfAnyBut/LastIndexOfAnyBut</b> 56 * - index-of any of a set of Strings</li> 57 * <li><b>ContainsOnly/ContainsNone/ContainsAny</b> 58 * - checks if String contains only/none/any of these characters</li> 59 * <li><b>Substring/Left/Right/Mid</b> 60 * - null-safe substring extractions</li> 61 * <li><b>SubstringBefore/SubstringAfter/SubstringBetween</b> 62 * - substring extraction relative to other strings</li> 63 * <li><b>Split/Join</b> 64 * - splits a String into an array of substrings and vice versa</li> 65 * <li><b>Remove/Delete</b> 66 * - removes part of a String</li> 67 * <li><b>Replace/Overlay</b> 68 * - Searches a String and replaces one String with another</li> 69 * <li><b>Chomp/Chop</b> 70 * - removes the last part of a String</li> 71 * <li><b>AppendIfMissing</b> 72 * - appends a suffix to the end of the String if not present</li> 73 * <li><b>PrependIfMissing</b> 74 * - prepends a prefix to the start of the String if not present</li> 75 * <li><b>LeftPad/RightPad/Center/Repeat</b> 76 * - pads a String</li> 77 * <li><b>UpperCase/LowerCase/SwapCase/Capitalize/Uncapitalize</b> 78 * - changes the case of a String</li> 79 * <li><b>CountMatches</b> 80 * - counts the number of occurrences of one String in another</li> 81 * <li><b>IsAlpha/IsNumeric/IsWhitespace/IsAsciiPrintable</b> 82 * - checks the characters in a String</li> 83 * <li><b>DefaultString</b> 84 * - protects against a null input String</li> 85 * <li><b>Rotate</b> 86 * - rotate (circular shift) a String</li> 87 * <li><b>Reverse/ReverseDelimited</b> 88 * - reverses a String</li> 89 * <li><b>Abbreviate</b> 90 * - abbreviates a string using ellipses or another given String</li> 91 * <li><b>Difference</b> 92 * - compares Strings and reports on their differences</li> 93 * <li><b>LevenshteinDistance</b> 94 * - the number of changes needed to change one String into another</li> 95 * </ul> 96 * 97 * <p>The {@link StringUtils} class defines certain words related to 98 * String handling.</p> 99 * 100 * <ul> 101 * <li>null - {@code null}</li> 102 * <li>empty - a zero-length string ({@code ""})</li> 103 * <li>space - the space character ({@code ' '}, char 32)</li> 104 * <li>whitespace - the characters defined by {@link Character#isWhitespace(char)}</li> 105 * <li>trim - the characters <= 32 as in {@link String#trim()}</li> 106 * </ul> 107 * 108 * <p>{@link StringUtils} handles {@code null} input Strings quietly. 109 * That is to say that a {@code null} input will return {@code null}. 110 * Where a {@code boolean} or {@code int} is being returned 111 * details vary by method.</p> 112 * 113 * <p>A side effect of the {@code null} handling is that a 114 * {@link NullPointerException} should be considered a bug in 115 * {@link StringUtils}.</p> 116 * 117 * <p>Methods in this class include sample code in their Javadoc comments to explain their operation. 118 * The symbol {@code *} is used to indicate any input including {@code null}.</p> 119 * 120 * <p>#ThreadSafe#</p> 121 * @see String 122 * @since 1.0 123 */ 124 //@Immutable 125 public class StringUtils { 126 127 // Performance testing notes (JDK 1.4, Jul03, scolebourne) 128 // Whitespace: 129 // Character.isWhitespace() is faster than WHITESPACE.indexOf() 130 // where WHITESPACE is a string of all whitespace characters 131 // 132 // Character access: 133 // String.charAt(n) versus toCharArray(), then array[n] 134 // String.charAt(n) is about 15% worse for a 10K string 135 // They are about equal for a length 50 string 136 // String.charAt(n) is about 4 times better for a length 3 string 137 // String.charAt(n) is best bet overall 138 // 139 // Append: 140 // String.concat about twice as fast as StringBuffer.append 141 // (not sure who tested this) 142 143 /** 144 * A String for a space character. 145 * 146 * @since 3.2 147 */ 148 public static final String SPACE = " "; 149 150 /** 151 * The empty String {@code ""}. 152 * @since 2.0 153 */ 154 public static final String EMPTY = ""; 155 156 /** 157 * A String for linefeed LF ("\n"). 158 * 159 * @see <a href="https://docs.oracle.com/javase/specs/jls/se8/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 LF = "\n"; 164 165 /** 166 * A String for carriage return CR ("\r"). 167 * 168 * @see <a href="https://docs.oracle.com/javase/specs/jls/se8/html/jls-3.html#jls-3.10.6">JLF: Escape Sequences 169 * for Character and String Literals</a> 170 * @since 3.2 171 */ 172 public static final String CR = "\r"; 173 174 /** 175 * Represents a failed index search. 176 * @since 2.1 177 */ 178 public static final int INDEX_NOT_FOUND = -1; 179 180 /** 181 * The maximum size to which the padding constant(s) can expand. 182 */ 183 private static final int PAD_LIMIT = 8192; 184 185 /** 186 * Pattern used in {@link #stripAccents(String)}. 187 */ 188 private static final Pattern STRIP_ACCENTS_PATTERN = Pattern.compile("\\p{InCombiningDiacriticalMarks}+"); //$NON-NLS-1$ 189 190 /** 191 * Abbreviates a String using ellipses. This will turn 192 * "Now is the time for all good men" into "Now is the time for..." 193 * 194 * <p>Specifically:</p> 195 * <ul> 196 * <li>If the number of characters in {@code str} is less than or equal to 197 * {@code maxWidth}, return {@code str}.</li> 198 * <li>Else abbreviate it to {@code (substring(str, 0, max-3) + "...")}.</li> 199 * <li>If {@code maxWidth} is less than {@code 4}, throw an 200 * {@link IllegalArgumentException}.</li> 201 * <li>In no case will it return a String of length greater than 202 * {@code maxWidth}.</li> 203 * </ul> 204 * 205 * <pre> 206 * StringUtils.abbreviate(null, *) = null 207 * StringUtils.abbreviate("", 4) = "" 208 * StringUtils.abbreviate("abcdefg", 6) = "abc..." 209 * StringUtils.abbreviate("abcdefg", 7) = "abcdefg" 210 * StringUtils.abbreviate("abcdefg", 8) = "abcdefg" 211 * StringUtils.abbreviate("abcdefg", 4) = "a..." 212 * StringUtils.abbreviate("abcdefg", 3) = IllegalArgumentException 213 * </pre> 214 * 215 * @param str the String to check, may be null 216 * @param maxWidth maximum length of result String, must be at least 4 217 * @return abbreviated String, {@code null} if null String input 218 * @throws IllegalArgumentException if the width is too small 219 * @since 2.0 220 */ 221 public static String abbreviate(final String str, final int maxWidth) { 222 return abbreviate(str, "...", 0, maxWidth); 223 } 224 225 /** 226 * Abbreviates a String using ellipses. This will turn 227 * "Now is the time for all good men" into "...is the time for..." 228 * 229 * <p>Works like {@code abbreviate(String, int)}, but allows you to specify 230 * a "left edge" offset. Note that this left edge is not necessarily going to 231 * be the leftmost character in the result, or the first character following the 232 * ellipses, but it will appear somewhere in the result. 233 * 234 * <p>In no case will it return a String of length greater than 235 * {@code maxWidth}.</p> 236 * 237 * <pre> 238 * StringUtils.abbreviate(null, *, *) = null 239 * StringUtils.abbreviate("", 0, 4) = "" 240 * StringUtils.abbreviate("abcdefghijklmno", -1, 10) = "abcdefg..." 241 * StringUtils.abbreviate("abcdefghijklmno", 0, 10) = "abcdefg..." 242 * StringUtils.abbreviate("abcdefghijklmno", 1, 10) = "abcdefg..." 243 * StringUtils.abbreviate("abcdefghijklmno", 4, 10) = "abcdefg..." 244 * StringUtils.abbreviate("abcdefghijklmno", 5, 10) = "...fghi..." 245 * StringUtils.abbreviate("abcdefghijklmno", 6, 10) = "...ghij..." 246 * StringUtils.abbreviate("abcdefghijklmno", 8, 10) = "...ijklmno" 247 * StringUtils.abbreviate("abcdefghijklmno", 10, 10) = "...ijklmno" 248 * StringUtils.abbreviate("abcdefghijklmno", 12, 10) = "...ijklmno" 249 * StringUtils.abbreviate("abcdefghij", 0, 3) = IllegalArgumentException 250 * StringUtils.abbreviate("abcdefghij", 5, 6) = IllegalArgumentException 251 * </pre> 252 * 253 * @param str the String to check, may be null 254 * @param offset left edge of source String 255 * @param maxWidth maximum length of result String, must be at least 4 256 * @return abbreviated String, {@code null} if null String input 257 * @throws IllegalArgumentException if the width is too small 258 * @since 2.0 259 */ 260 public static String abbreviate(final String str, final int offset, final int maxWidth) { 261 return abbreviate(str, "...", offset, maxWidth); 262 } 263 264 /** 265 * Abbreviates a String using another given String as replacement marker. This will turn 266 * "Now is the time for all good men" into "Now is the time for..." if "..." was defined 267 * as the replacement marker. 268 * 269 * <p>Specifically:</p> 270 * <ul> 271 * <li>If the number of characters in {@code str} is less than or equal to 272 * {@code maxWidth}, return {@code str}.</li> 273 * <li>Else abbreviate it to {@code (substring(str, 0, max-abbrevMarker.length) + abbrevMarker)}.</li> 274 * <li>If {@code maxWidth} is less than {@code abbrevMarker.length + 1}, throw an 275 * {@link IllegalArgumentException}.</li> 276 * <li>In no case will it return a String of length greater than 277 * {@code maxWidth}.</li> 278 * </ul> 279 * 280 * <pre> 281 * StringUtils.abbreviate(null, "...", *) = null 282 * StringUtils.abbreviate("abcdefg", null, *) = "abcdefg" 283 * StringUtils.abbreviate("", "...", 4) = "" 284 * StringUtils.abbreviate("abcdefg", ".", 5) = "abcd." 285 * StringUtils.abbreviate("abcdefg", ".", 7) = "abcdefg" 286 * StringUtils.abbreviate("abcdefg", ".", 8) = "abcdefg" 287 * StringUtils.abbreviate("abcdefg", "..", 4) = "ab.." 288 * StringUtils.abbreviate("abcdefg", "..", 3) = "a.." 289 * StringUtils.abbreviate("abcdefg", "..", 2) = IllegalArgumentException 290 * StringUtils.abbreviate("abcdefg", "...", 3) = IllegalArgumentException 291 * </pre> 292 * 293 * @param str the String to check, may be null 294 * @param abbrevMarker the String used as replacement marker 295 * @param maxWidth maximum length of result String, must be at least {@code abbrevMarker.length + 1} 296 * @return abbreviated String, {@code null} if null String input 297 * @throws IllegalArgumentException if the width is too small 298 * @since 3.6 299 */ 300 public static String abbreviate(final String str, final String abbrevMarker, final int maxWidth) { 301 return abbreviate(str, abbrevMarker, 0, maxWidth); 302 } 303 /** 304 * Abbreviates a String using a given replacement marker. This will turn 305 * "Now is the time for all good men" into "...is the time for..." if "..." was defined 306 * as the replacement marker. 307 * 308 * <p>Works like {@code abbreviate(String, String, int)}, but allows you to specify 309 * a "left edge" offset. Note that this left edge is not necessarily going to 310 * be the leftmost character in the result, or the first character following the 311 * replacement marker, but it will appear somewhere in the result. 312 * 313 * <p>In no case will it return a String of length greater than {@code maxWidth}.</p> 314 * 315 * <pre> 316 * StringUtils.abbreviate(null, null, *, *) = null 317 * StringUtils.abbreviate("abcdefghijklmno", null, *, *) = "abcdefghijklmno" 318 * StringUtils.abbreviate("", "...", 0, 4) = "" 319 * StringUtils.abbreviate("abcdefghijklmno", "---", -1, 10) = "abcdefg---" 320 * StringUtils.abbreviate("abcdefghijklmno", ",", 0, 10) = "abcdefghi," 321 * StringUtils.abbreviate("abcdefghijklmno", ",", 1, 10) = "abcdefghi," 322 * StringUtils.abbreviate("abcdefghijklmno", ",", 2, 10) = "abcdefghi," 323 * StringUtils.abbreviate("abcdefghijklmno", "::", 4, 10) = "::efghij::" 324 * StringUtils.abbreviate("abcdefghijklmno", "...", 6, 10) = "...ghij..." 325 * StringUtils.abbreviate("abcdefghijklmno", "*", 9, 10) = "*ghijklmno" 326 * StringUtils.abbreviate("abcdefghijklmno", "'", 10, 10) = "'ghijklmno" 327 * StringUtils.abbreviate("abcdefghijklmno", "!", 12, 10) = "!ghijklmno" 328 * StringUtils.abbreviate("abcdefghij", "abra", 0, 4) = IllegalArgumentException 329 * StringUtils.abbreviate("abcdefghij", "...", 5, 6) = IllegalArgumentException 330 * </pre> 331 * 332 * @param str the String to check, may be null 333 * @param abbrevMarker the String used as replacement marker 334 * @param offset left edge of source String 335 * @param maxWidth maximum length of result String, must be at least 4 336 * @return abbreviated String, {@code null} if null String input 337 * @throws IllegalArgumentException if the width is too small 338 * @since 3.6 339 */ 340 public static String abbreviate(final String str, final String abbrevMarker, int offset, final int maxWidth) { 341 if (isNotEmpty(str) && EMPTY.equals(abbrevMarker) && maxWidth > 0) { 342 return substring(str, 0, maxWidth); 343 } 344 if (isAnyEmpty(str, abbrevMarker)) { 345 return str; 346 } 347 final int abbrevMarkerLength = abbrevMarker.length(); 348 final int minAbbrevWidth = abbrevMarkerLength + 1; 349 final int minAbbrevWidthOffset = abbrevMarkerLength + abbrevMarkerLength + 1; 350 351 if (maxWidth < minAbbrevWidth) { 352 throw new IllegalArgumentException(String.format("Minimum abbreviation width is %d", minAbbrevWidth)); 353 } 354 final int strLen = str.length(); 355 if (strLen <= maxWidth) { 356 return str; 357 } 358 if (offset > strLen) { 359 offset = strLen; 360 } 361 if (strLen - offset < maxWidth - abbrevMarkerLength) { 362 offset = strLen - (maxWidth - abbrevMarkerLength); 363 } 364 if (offset <= abbrevMarkerLength + 1) { 365 return str.substring(0, maxWidth - abbrevMarkerLength) + abbrevMarker; 366 } 367 if (maxWidth < minAbbrevWidthOffset) { 368 throw new IllegalArgumentException(String.format("Minimum abbreviation width with offset is %d", minAbbrevWidthOffset)); 369 } 370 if (offset + maxWidth - abbrevMarkerLength < strLen) { 371 return abbrevMarker + abbreviate(str.substring(offset), abbrevMarker, maxWidth - abbrevMarkerLength); 372 } 373 return abbrevMarker + str.substring(strLen - (maxWidth - abbrevMarkerLength)); 374 } 375 376 /** 377 * Abbreviates a String to the length passed, replacing the middle characters with the supplied 378 * replacement String. 379 * 380 * <p>This abbreviation only occurs if the following criteria is met:</p> 381 * <ul> 382 * <li>Neither the String for abbreviation nor the replacement String are null or empty </li> 383 * <li>The length to truncate to is less than the length of the supplied String</li> 384 * <li>The length to truncate to is greater than 0</li> 385 * <li>The abbreviated String will have enough room for the length supplied replacement String 386 * and the first and last characters of the supplied String for abbreviation</li> 387 * </ul> 388 * <p>Otherwise, the returned String will be the same as the supplied String for abbreviation. 389 * </p> 390 * 391 * <pre> 392 * StringUtils.abbreviateMiddle(null, null, 0) = null 393 * StringUtils.abbreviateMiddle("abc", null, 0) = "abc" 394 * StringUtils.abbreviateMiddle("abc", ".", 0) = "abc" 395 * StringUtils.abbreviateMiddle("abc", ".", 3) = "abc" 396 * StringUtils.abbreviateMiddle("abcdef", ".", 4) = "ab.f" 397 * </pre> 398 * 399 * @param str the String to abbreviate, may be null 400 * @param middle the String to replace the middle characters with, may be null 401 * @param length the length to abbreviate {@code str} to. 402 * @return the abbreviated String if the above criteria is met, or the original String supplied for abbreviation. 403 * @since 2.5 404 */ 405 public static String abbreviateMiddle(final String str, final String middle, final int length) { 406 if (isAnyEmpty(str, middle) || length >= str.length() || length < middle.length() + 2) { 407 return str; 408 } 409 final int targetSting = length - middle.length(); 410 final int startOffset = targetSting / 2 + targetSting % 2; 411 final int endOffset = str.length() - targetSting / 2; 412 return str.substring(0, startOffset) + middle + str.substring(endOffset); 413 } 414 415 /** 416 * Appends the suffix to the end of the string if the string does not 417 * already end with the suffix. 418 * 419 * @param str The string. 420 * @param suffix The suffix to append to the end of the string. 421 * @param ignoreCase Indicates whether the compare should ignore case. 422 * @param suffixes Additional suffixes that are valid terminators (optional). 423 * 424 * @return A new String if suffix was appended, the same string otherwise. 425 */ 426 private static String appendIfMissing(final String str, final CharSequence suffix, final boolean ignoreCase, final CharSequence... suffixes) { 427 if (str == null || isEmpty(suffix) || endsWith(str, suffix, ignoreCase)) { 428 return str; 429 } 430 if (ArrayUtils.isNotEmpty(suffixes)) { 431 for (final CharSequence s : suffixes) { 432 if (endsWith(str, s, ignoreCase)) { 433 return str; 434 } 435 } 436 } 437 return str + suffix; 438 } 439 440 /** 441 * Appends the suffix to the end of the string if the string does not 442 * already end with any of the suffixes. 443 * 444 * <pre> 445 * StringUtils.appendIfMissing(null, null) = null 446 * StringUtils.appendIfMissing("abc", null) = "abc" 447 * StringUtils.appendIfMissing("", "xyz" = "xyz" 448 * StringUtils.appendIfMissing("abc", "xyz") = "abcxyz" 449 * StringUtils.appendIfMissing("abcxyz", "xyz") = "abcxyz" 450 * StringUtils.appendIfMissing("abcXYZ", "xyz") = "abcXYZxyz" 451 * </pre> 452 * <p>With additional suffixes,</p> 453 * <pre> 454 * StringUtils.appendIfMissing(null, null, null) = null 455 * StringUtils.appendIfMissing("abc", null, null) = "abc" 456 * StringUtils.appendIfMissing("", "xyz", null) = "xyz" 457 * StringUtils.appendIfMissing("abc", "xyz", new CharSequence[]{null}) = "abcxyz" 458 * StringUtils.appendIfMissing("abc", "xyz", "") = "abc" 459 * StringUtils.appendIfMissing("abc", "xyz", "mno") = "abcxyz" 460 * StringUtils.appendIfMissing("abcxyz", "xyz", "mno") = "abcxyz" 461 * StringUtils.appendIfMissing("abcmno", "xyz", "mno") = "abcmno" 462 * StringUtils.appendIfMissing("abcXYZ", "xyz", "mno") = "abcXYZxyz" 463 * StringUtils.appendIfMissing("abcMNO", "xyz", "mno") = "abcMNOxyz" 464 * </pre> 465 * 466 * @param str The string. 467 * @param suffix The suffix to append to the end of the string. 468 * @param suffixes Additional suffixes that are valid terminators. 469 * 470 * @return A new String if suffix was appended, the same string otherwise. 471 * 472 * @since 3.2 473 */ 474 public static String appendIfMissing(final String str, final CharSequence suffix, final CharSequence... suffixes) { 475 return appendIfMissing(str, suffix, false, suffixes); 476 } 477 478 /** 479 * Appends the suffix to the end of the string if the string does not 480 * already end, case-insensitive, with any of the suffixes. 481 * 482 * <pre> 483 * StringUtils.appendIfMissingIgnoreCase(null, null) = null 484 * StringUtils.appendIfMissingIgnoreCase("abc", null) = "abc" 485 * StringUtils.appendIfMissingIgnoreCase("", "xyz") = "xyz" 486 * StringUtils.appendIfMissingIgnoreCase("abc", "xyz") = "abcxyz" 487 * StringUtils.appendIfMissingIgnoreCase("abcxyz", "xyz") = "abcxyz" 488 * StringUtils.appendIfMissingIgnoreCase("abcXYZ", "xyz") = "abcXYZ" 489 * </pre> 490 * <p>With additional suffixes,</p> 491 * <pre> 492 * StringUtils.appendIfMissingIgnoreCase(null, null, null) = null 493 * StringUtils.appendIfMissingIgnoreCase("abc", null, null) = "abc" 494 * StringUtils.appendIfMissingIgnoreCase("", "xyz", null) = "xyz" 495 * StringUtils.appendIfMissingIgnoreCase("abc", "xyz", new CharSequence[]{null}) = "abcxyz" 496 * StringUtils.appendIfMissingIgnoreCase("abc", "xyz", "") = "abc" 497 * StringUtils.appendIfMissingIgnoreCase("abc", "xyz", "mno") = "abcxyz" 498 * StringUtils.appendIfMissingIgnoreCase("abcxyz", "xyz", "mno") = "abcxyz" 499 * StringUtils.appendIfMissingIgnoreCase("abcmno", "xyz", "mno") = "abcmno" 500 * StringUtils.appendIfMissingIgnoreCase("abcXYZ", "xyz", "mno") = "abcXYZ" 501 * StringUtils.appendIfMissingIgnoreCase("abcMNO", "xyz", "mno") = "abcMNO" 502 * </pre> 503 * 504 * @param str The string. 505 * @param suffix The suffix to append to the end of the string. 506 * @param suffixes Additional suffixes that are valid terminators. 507 * 508 * @return A new String if suffix was appended, the same string otherwise. 509 * 510 * @since 3.2 511 */ 512 public static String appendIfMissingIgnoreCase(final String str, final CharSequence suffix, final CharSequence... suffixes) { 513 return appendIfMissing(str, suffix, true, suffixes); 514 } 515 516 /** 517 * Capitalizes a String changing the first character to title case as 518 * per {@link Character#toTitleCase(int)}. No other characters are changed. 519 * 520 * <p>For a word based algorithm, see {@link org.apache.commons.text.WordUtils#capitalize(String)}. 521 * A {@code null} input String returns {@code null}.</p> 522 * 523 * <pre> 524 * StringUtils.capitalize(null) = null 525 * StringUtils.capitalize("") = "" 526 * StringUtils.capitalize("cat") = "Cat" 527 * StringUtils.capitalize("cAt") = "CAt" 528 * StringUtils.capitalize("'cat'") = "'cat'" 529 * </pre> 530 * 531 * @param str the String to capitalize, may be null 532 * @return the capitalized String, {@code null} if null String input 533 * @see org.apache.commons.text.WordUtils#capitalize(String) 534 * @see #uncapitalize(String) 535 * @since 2.0 536 */ 537 public static String capitalize(final String str) { 538 final int strLen = length(str); 539 if (strLen == 0) { 540 return str; 541 } 542 543 final int firstCodepoint = str.codePointAt(0); 544 final int newCodePoint = Character.toTitleCase(firstCodepoint); 545 if (firstCodepoint == newCodePoint) { 546 // already capitalized 547 return str; 548 } 549 550 final int[] newCodePoints = new int[strLen]; // cannot be longer than the char array 551 int outOffset = 0; 552 newCodePoints[outOffset++] = newCodePoint; // copy the first code point 553 for (int inOffset = Character.charCount(firstCodepoint); inOffset < strLen; ) { 554 final int codePoint = str.codePointAt(inOffset); 555 newCodePoints[outOffset++] = codePoint; // copy the remaining ones 556 inOffset += Character.charCount(codePoint); 557 } 558 return new String(newCodePoints, 0, outOffset); 559 } 560 561 /** 562 * Centers a String in a larger String of size {@code size} 563 * using the space character (' '). 564 * 565 * <p>If the size is less than the String length, the original String is returned. 566 * A {@code null} String returns {@code null}. 567 * A negative size is treated as zero.</p> 568 * 569 * <p>Equivalent to {@code center(str, size, " ")}.</p> 570 * 571 * <pre> 572 * StringUtils.center(null, *) = null 573 * StringUtils.center("", 4) = " " 574 * StringUtils.center("ab", -1) = "ab" 575 * StringUtils.center("ab", 4) = " ab " 576 * StringUtils.center("abcd", 2) = "abcd" 577 * StringUtils.center("a", 4) = " a " 578 * </pre> 579 * 580 * @param str the String to center, may be null 581 * @param size the int size of new String, negative treated as zero 582 * @return centered String, {@code null} if null String input 583 */ 584 public static String center(final String str, final int size) { 585 return center(str, size, ' '); 586 } 587 588 /** 589 * Centers a String in a larger String of size {@code size}. 590 * Uses a supplied character as the value to pad the String with. 591 * 592 * <p>If the size is less than the String length, the String is returned. 593 * A {@code null} String returns {@code null}. 594 * A negative size is treated as zero.</p> 595 * 596 * <pre> 597 * StringUtils.center(null, *, *) = null 598 * StringUtils.center("", 4, ' ') = " " 599 * StringUtils.center("ab", -1, ' ') = "ab" 600 * StringUtils.center("ab", 4, ' ') = " ab " 601 * StringUtils.center("abcd", 2, ' ') = "abcd" 602 * StringUtils.center("a", 4, ' ') = " a " 603 * StringUtils.center("a", 4, 'y') = "yayy" 604 * </pre> 605 * 606 * @param str the String to center, may be null 607 * @param size the int size of new String, negative treated as zero 608 * @param padChar the character to pad the new String with 609 * @return centered String, {@code null} if null String input 610 * @since 2.0 611 */ 612 public static String center(String str, final int size, final char padChar) { 613 if (str == null || size <= 0) { 614 return str; 615 } 616 final int strLen = str.length(); 617 final int pads = size - strLen; 618 if (pads <= 0) { 619 return str; 620 } 621 str = leftPad(str, strLen + pads / 2, padChar); 622 return rightPad(str, size, padChar); 623 } 624 625 /** 626 * Centers a String in a larger String of size {@code size}. 627 * Uses a supplied String as the value to pad the String with. 628 * 629 * <p>If the size is less than the String length, the String is returned. 630 * A {@code null} String returns {@code null}. 631 * A negative size is treated as zero.</p> 632 * 633 * <pre> 634 * StringUtils.center(null, *, *) = null 635 * StringUtils.center("", 4, " ") = " " 636 * StringUtils.center("ab", -1, " ") = "ab" 637 * StringUtils.center("ab", 4, " ") = " ab " 638 * StringUtils.center("abcd", 2, " ") = "abcd" 639 * StringUtils.center("a", 4, " ") = " a " 640 * StringUtils.center("a", 4, "yz") = "yayz" 641 * StringUtils.center("abc", 7, null) = " abc " 642 * StringUtils.center("abc", 7, "") = " abc " 643 * </pre> 644 * 645 * @param str the String to center, may be null 646 * @param size the int size of new String, negative treated as zero 647 * @param padStr the String to pad the new String with, must not be null or empty 648 * @return centered String, {@code null} if null String input 649 * @throws IllegalArgumentException if padStr is {@code null} or empty 650 */ 651 public static String center(String str, final int size, String padStr) { 652 if (str == null || size <= 0) { 653 return str; 654 } 655 if (isEmpty(padStr)) { 656 padStr = SPACE; 657 } 658 final int strLen = str.length(); 659 final int pads = size - strLen; 660 if (pads <= 0) { 661 return str; 662 } 663 str = leftPad(str, strLen + pads / 2, padStr); 664 return rightPad(str, size, padStr); 665 } 666 667 /** 668 * Removes one newline from end of a String if it's there, 669 * otherwise leave it alone. A newline is "{@code \n}", 670 * "{@code \r}", or "{@code \r\n}". 671 * 672 * <p>NOTE: This method changed in 2.0. 673 * It now more closely matches Perl chomp.</p> 674 * 675 * <pre> 676 * StringUtils.chomp(null) = null 677 * StringUtils.chomp("") = "" 678 * StringUtils.chomp("abc \r") = "abc " 679 * StringUtils.chomp("abc\n") = "abc" 680 * StringUtils.chomp("abc\r\n") = "abc" 681 * StringUtils.chomp("abc\r\n\r\n") = "abc\r\n" 682 * StringUtils.chomp("abc\n\r") = "abc\n" 683 * StringUtils.chomp("abc\n\rabc") = "abc\n\rabc" 684 * StringUtils.chomp("\r") = "" 685 * StringUtils.chomp("\n") = "" 686 * StringUtils.chomp("\r\n") = "" 687 * </pre> 688 * 689 * @param str the String to chomp a newline from, may be null 690 * @return String without newline, {@code null} if null String input 691 */ 692 public static String chomp(final String str) { 693 if (isEmpty(str)) { 694 return str; 695 } 696 697 if (str.length() == 1) { 698 final char ch = str.charAt(0); 699 if (ch == CharUtils.CR || ch == CharUtils.LF) { 700 return EMPTY; 701 } 702 return str; 703 } 704 705 int lastIdx = str.length() - 1; 706 final char last = str.charAt(lastIdx); 707 708 if (last == CharUtils.LF) { 709 if (str.charAt(lastIdx - 1) == CharUtils.CR) { 710 lastIdx--; 711 } 712 } else if (last != CharUtils.CR) { 713 lastIdx++; 714 } 715 return str.substring(0, lastIdx); 716 } 717 718 /** 719 * Removes {@code separator} from the end of 720 * {@code str} if it's there, otherwise leave it alone. 721 * 722 * <p>NOTE: This method changed in version 2.0. 723 * It now more closely matches Perl chomp. 724 * For the previous behavior, use {@link #substringBeforeLast(String, String)}. 725 * This method uses {@link String#endsWith(String)}.</p> 726 * 727 * <pre> 728 * StringUtils.chomp(null, *) = null 729 * StringUtils.chomp("", *) = "" 730 * StringUtils.chomp("foobar", "bar") = "foo" 731 * StringUtils.chomp("foobar", "baz") = "foobar" 732 * StringUtils.chomp("foo", "foo") = "" 733 * StringUtils.chomp("foo ", "foo") = "foo " 734 * StringUtils.chomp(" foo", "foo") = " " 735 * StringUtils.chomp("foo", "foooo") = "foo" 736 * StringUtils.chomp("foo", "") = "foo" 737 * StringUtils.chomp("foo", null) = "foo" 738 * </pre> 739 * 740 * @param str the String to chomp from, may be null 741 * @param separator separator String, may be null 742 * @return String without trailing separator, {@code null} if null String input 743 * @deprecated This feature will be removed in Lang 4, use {@link StringUtils#removeEnd(String, String)} instead 744 */ 745 @Deprecated 746 public static String chomp(final String str, final String separator) { 747 return removeEnd(str, separator); 748 } 749 750 /** 751 * Remove the last character from a String. 752 * 753 * <p>If the String ends in {@code \r\n}, then remove both 754 * of them.</p> 755 * 756 * <pre> 757 * StringUtils.chop(null) = null 758 * StringUtils.chop("") = "" 759 * StringUtils.chop("abc \r") = "abc " 760 * StringUtils.chop("abc\n") = "abc" 761 * StringUtils.chop("abc\r\n") = "abc" 762 * StringUtils.chop("abc") = "ab" 763 * StringUtils.chop("abc\nabc") = "abc\nab" 764 * StringUtils.chop("a") = "" 765 * StringUtils.chop("\r") = "" 766 * StringUtils.chop("\n") = "" 767 * StringUtils.chop("\r\n") = "" 768 * </pre> 769 * 770 * @param str the String to chop last character from, may be null 771 * @return String without last character, {@code null} if null String input 772 */ 773 public static String chop(final String str) { 774 if (str == null) { 775 return null; 776 } 777 final int strLen = str.length(); 778 if (strLen < 2) { 779 return EMPTY; 780 } 781 final int lastIdx = strLen - 1; 782 final String ret = str.substring(0, lastIdx); 783 final char last = str.charAt(lastIdx); 784 if (last == CharUtils.LF && ret.charAt(lastIdx - 1) == CharUtils.CR) { 785 return ret.substring(0, lastIdx - 1); 786 } 787 return ret; 788 } 789 790 /** 791 * Compare two Strings lexicographically, as per {@link String#compareTo(String)}, returning : 792 * <ul> 793 * <li>{@code int = 0}, if {@code str1} is equal to {@code str2} (or both {@code null})</li> 794 * <li>{@code int < 0}, if {@code str1} is less than {@code str2}</li> 795 * <li>{@code int > 0}, if {@code str1} is greater than {@code str2}</li> 796 * </ul> 797 * 798 * <p>This is a {@code null} safe version of :</p> 799 * <blockquote><pre>str1.compareTo(str2)</pre></blockquote> 800 * 801 * <p>{@code null} value is considered less than non-{@code null} value. 802 * Two {@code null} references are considered equal.</p> 803 * 804 * <pre>{@code 805 * StringUtils.compare(null, null) = 0 806 * StringUtils.compare(null , "a") < 0 807 * StringUtils.compare("a", null) > 0 808 * StringUtils.compare("abc", "abc") = 0 809 * StringUtils.compare("a", "b") < 0 810 * StringUtils.compare("b", "a") > 0 811 * StringUtils.compare("a", "B") > 0 812 * StringUtils.compare("ab", "abc") < 0 813 * }</pre> 814 * 815 * @see #compare(String, String, boolean) 816 * @see String#compareTo(String) 817 * @param str1 the String to compare from 818 * @param str2 the String to compare to 819 * @return < 0, 0, > 0, if {@code str1} is respectively less, equal or greater than {@code str2} 820 * @since 3.5 821 */ 822 public static int compare(final String str1, final String str2) { 823 return compare(str1, str2, true); 824 } 825 826 /** 827 * Compare two Strings lexicographically, as per {@link String#compareTo(String)}, returning : 828 * <ul> 829 * <li>{@code int = 0}, if {@code str1} is equal to {@code str2} (or both {@code null})</li> 830 * <li>{@code int < 0}, if {@code str1} is less than {@code str2}</li> 831 * <li>{@code int > 0}, if {@code str1} is greater than {@code str2}</li> 832 * </ul> 833 * 834 * <p>This is a {@code null} safe version of :</p> 835 * <blockquote><pre>str1.compareTo(str2)</pre></blockquote> 836 * 837 * <p>{@code null} inputs are handled according to the {@code nullIsLess} parameter. 838 * Two {@code null} references are considered equal.</p> 839 * 840 * <pre>{@code 841 * StringUtils.compare(null, null, *) = 0 842 * StringUtils.compare(null , "a", true) < 0 843 * StringUtils.compare(null , "a", false) > 0 844 * StringUtils.compare("a", null, true) > 0 845 * StringUtils.compare("a", null, false) < 0 846 * StringUtils.compare("abc", "abc", *) = 0 847 * StringUtils.compare("a", "b", *) < 0 848 * StringUtils.compare("b", "a", *) > 0 849 * StringUtils.compare("a", "B", *) > 0 850 * StringUtils.compare("ab", "abc", *) < 0 851 * }</pre> 852 * 853 * @see String#compareTo(String) 854 * @param str1 the String to compare from 855 * @param str2 the String to compare to 856 * @param nullIsLess whether consider {@code null} value less than non-{@code null} value 857 * @return < 0, 0, > 0, if {@code str1} is respectively less, equal ou greater than {@code str2} 858 * @since 3.5 859 */ 860 public static int compare(final String str1, final String str2, final boolean nullIsLess) { 861 if (str1 == str2) { // NOSONARLINT this intentionally uses == to allow for both null 862 return 0; 863 } 864 if (str1 == null) { 865 return nullIsLess ? -1 : 1; 866 } 867 if (str2 == null) { 868 return nullIsLess ? 1 : - 1; 869 } 870 return str1.compareTo(str2); 871 } 872 873 /** 874 * Compare two Strings lexicographically, ignoring case differences, 875 * as per {@link String#compareToIgnoreCase(String)}, returning : 876 * <ul> 877 * <li>{@code int = 0}, if {@code str1} is equal to {@code str2} (or both {@code null})</li> 878 * <li>{@code int < 0}, if {@code str1} is less than {@code str2}</li> 879 * <li>{@code int > 0}, if {@code str1} is greater than {@code str2}</li> 880 * </ul> 881 * 882 * <p>This is a {@code null} safe version of :</p> 883 * <blockquote><pre>str1.compareToIgnoreCase(str2)</pre></blockquote> 884 * 885 * <p>{@code null} value is considered less than non-{@code null} value. 886 * Two {@code null} references are considered equal. 887 * Comparison is case insensitive.</p> 888 * 889 * <pre>{@code 890 * StringUtils.compareIgnoreCase(null, null) = 0 891 * StringUtils.compareIgnoreCase(null , "a") < 0 892 * StringUtils.compareIgnoreCase("a", null) > 0 893 * StringUtils.compareIgnoreCase("abc", "abc") = 0 894 * StringUtils.compareIgnoreCase("abc", "ABC") = 0 895 * StringUtils.compareIgnoreCase("a", "b") < 0 896 * StringUtils.compareIgnoreCase("b", "a") > 0 897 * StringUtils.compareIgnoreCase("a", "B") < 0 898 * StringUtils.compareIgnoreCase("A", "b") < 0 899 * StringUtils.compareIgnoreCase("ab", "ABC") < 0 900 * }</pre> 901 * 902 * @see #compareIgnoreCase(String, String, boolean) 903 * @see String#compareToIgnoreCase(String) 904 * @param str1 the String to compare from 905 * @param str2 the String to compare to 906 * @return < 0, 0, > 0, if {@code str1} is respectively less, equal ou greater than {@code str2}, 907 * ignoring case differences. 908 * @since 3.5 909 */ 910 public static int compareIgnoreCase(final String str1, final String str2) { 911 return compareIgnoreCase(str1, str2, true); 912 } 913 914 /** 915 * Compare two Strings lexicographically, ignoring case differences, 916 * as per {@link String#compareToIgnoreCase(String)}, returning : 917 * <ul> 918 * <li>{@code int = 0}, if {@code str1} is equal to {@code str2} (or both {@code null})</li> 919 * <li>{@code int < 0}, if {@code str1} is less than {@code str2}</li> 920 * <li>{@code int > 0}, if {@code str1} is greater than {@code str2}</li> 921 * </ul> 922 * 923 * <p>This is a {@code null} safe version of :</p> 924 * <blockquote><pre>str1.compareToIgnoreCase(str2)</pre></blockquote> 925 * 926 * <p>{@code null} inputs are handled according to the {@code nullIsLess} parameter. 927 * Two {@code null} references are considered equal. 928 * Comparison is case insensitive.</p> 929 * 930 * <pre>{@code 931 * StringUtils.compareIgnoreCase(null, null, *) = 0 932 * StringUtils.compareIgnoreCase(null , "a", true) < 0 933 * StringUtils.compareIgnoreCase(null , "a", false) > 0 934 * StringUtils.compareIgnoreCase("a", null, true) > 0 935 * StringUtils.compareIgnoreCase("a", null, false) < 0 936 * StringUtils.compareIgnoreCase("abc", "abc", *) = 0 937 * StringUtils.compareIgnoreCase("abc", "ABC", *) = 0 938 * StringUtils.compareIgnoreCase("a", "b", *) < 0 939 * StringUtils.compareIgnoreCase("b", "a", *) > 0 940 * StringUtils.compareIgnoreCase("a", "B", *) < 0 941 * StringUtils.compareIgnoreCase("A", "b", *) < 0 942 * StringUtils.compareIgnoreCase("ab", "abc", *) < 0 943 * }</pre> 944 * 945 * @see String#compareToIgnoreCase(String) 946 * @param str1 the String to compare from 947 * @param str2 the String to compare to 948 * @param nullIsLess whether consider {@code null} value less than non-{@code null} value 949 * @return < 0, 0, > 0, if {@code str1} is respectively less, equal ou greater than {@code str2}, 950 * ignoring case differences. 951 * @since 3.5 952 */ 953 public static int compareIgnoreCase(final String str1, final String str2, final boolean nullIsLess) { 954 if (str1 == str2) { // NOSONARLINT this intentionally uses == to allow for both null 955 return 0; 956 } 957 if (str1 == null) { 958 return nullIsLess ? -1 : 1; 959 } 960 if (str2 == null) { 961 return nullIsLess ? 1 : - 1; 962 } 963 return str1.compareToIgnoreCase(str2); 964 } 965 966 /** 967 * Checks if CharSequence contains a search CharSequence, handling {@code null}. 968 * This method uses {@link String#indexOf(String)} if possible. 969 * 970 * <p>A {@code null} CharSequence will return {@code false}.</p> 971 * 972 * <pre> 973 * StringUtils.contains(null, *) = false 974 * StringUtils.contains(*, null) = false 975 * StringUtils.contains("", "") = true 976 * StringUtils.contains("abc", "") = true 977 * StringUtils.contains("abc", "a") = true 978 * StringUtils.contains("abc", "z") = false 979 * </pre> 980 * 981 * @param seq the CharSequence to check, may be null 982 * @param searchSeq the CharSequence to find, may be null 983 * @return true if the CharSequence contains the search CharSequence, 984 * false if not or {@code null} string input 985 * @since 2.0 986 * @since 3.0 Changed signature from contains(String, String) to contains(CharSequence, CharSequence) 987 */ 988 public static boolean contains(final CharSequence seq, final CharSequence searchSeq) { 989 if (seq == null || searchSeq == null) { 990 return false; 991 } 992 return CharSequenceUtils.indexOf(seq, searchSeq, 0) >= 0; 993 } 994 995 /** 996 * Checks if CharSequence contains a search character, handling {@code null}. 997 * This method uses {@link String#indexOf(int)} if possible. 998 * 999 * <p>A {@code null} or empty ("") CharSequence will return {@code false}.</p> 1000 * 1001 * <pre> 1002 * StringUtils.contains(null, *) = false 1003 * StringUtils.contains("", *) = false 1004 * StringUtils.contains("abc", 'a') = true 1005 * StringUtils.contains("abc", 'z') = false 1006 * </pre> 1007 * 1008 * @param seq the CharSequence to check, may be null 1009 * @param searchChar the character to find 1010 * @return true if the CharSequence contains the search character, 1011 * false if not or {@code null} string input 1012 * @since 2.0 1013 * @since 3.0 Changed signature from contains(String, int) to contains(CharSequence, int) 1014 */ 1015 public static boolean contains(final CharSequence seq, final int searchChar) { 1016 if (isEmpty(seq)) { 1017 return false; 1018 } 1019 return CharSequenceUtils.indexOf(seq, searchChar, 0) >= 0; 1020 } 1021 1022 /** 1023 * Checks if the CharSequence contains any character in the given 1024 * set of characters. 1025 * 1026 * <p>A {@code null} CharSequence will return {@code false}. 1027 * A {@code null} or zero length search array will return {@code false}.</p> 1028 * 1029 * <pre> 1030 * StringUtils.containsAny(null, *) = false 1031 * StringUtils.containsAny("", *) = false 1032 * StringUtils.containsAny(*, null) = false 1033 * StringUtils.containsAny(*, []) = false 1034 * StringUtils.containsAny("zzabyycdxx", ['z', 'a']) = true 1035 * StringUtils.containsAny("zzabyycdxx", ['b', 'y']) = true 1036 * StringUtils.containsAny("zzabyycdxx", ['z', 'y']) = true 1037 * StringUtils.containsAny("aba", ['z']) = false 1038 * </pre> 1039 * 1040 * @param cs the CharSequence to check, may be null 1041 * @param searchChars the chars to search for, may be null 1042 * @return the {@code true} if any of the chars are found, 1043 * {@code false} if no match or null input 1044 * @since 2.4 1045 * @since 3.0 Changed signature from containsAny(String, char[]) to containsAny(CharSequence, char...) 1046 */ 1047 public static boolean containsAny(final CharSequence cs, final char... searchChars) { 1048 if (isEmpty(cs) || ArrayUtils.isEmpty(searchChars)) { 1049 return false; 1050 } 1051 final int csLength = cs.length(); 1052 final int searchLength = searchChars.length; 1053 final int csLast = csLength - 1; 1054 final int searchLast = searchLength - 1; 1055 for (int i = 0; i < csLength; i++) { 1056 final char ch = cs.charAt(i); 1057 for (int j = 0; j < searchLength; j++) { 1058 if (searchChars[j] == ch) { 1059 if (!Character.isHighSurrogate(ch)) { 1060 // ch is in the Basic Multilingual Plane 1061 return true; 1062 } 1063 if (j == searchLast) { 1064 // missing low surrogate, fine, like String.indexOf(String) 1065 return true; 1066 } 1067 if (i < csLast && searchChars[j + 1] == cs.charAt(i + 1)) { 1068 return true; 1069 } 1070 } 1071 } 1072 } 1073 return false; 1074 } 1075 1076 /** 1077 * Checks if the CharSequence contains any character in the given set of characters. 1078 * 1079 * <p> 1080 * A {@code null} CharSequence will return {@code false}. A {@code null} search CharSequence will return 1081 * {@code false}. 1082 * </p> 1083 * 1084 * <pre> 1085 * StringUtils.containsAny(null, *) = false 1086 * StringUtils.containsAny("", *) = false 1087 * StringUtils.containsAny(*, null) = false 1088 * StringUtils.containsAny(*, "") = false 1089 * StringUtils.containsAny("zzabyycdxx", "za") = true 1090 * StringUtils.containsAny("zzabyycdxx", "by") = true 1091 * StringUtils.containsAny("zzabyycdxx", "zy") = true 1092 * StringUtils.containsAny("zzabyycdxx", "\tx") = true 1093 * StringUtils.containsAny("zzabyycdxx", "$.#yF") = true 1094 * StringUtils.containsAny("aba", "z") = false 1095 * </pre> 1096 * 1097 * @param cs 1098 * the CharSequence to check, may be null 1099 * @param searchChars 1100 * the chars to search for, may be null 1101 * @return the {@code true} if any of the chars are found, {@code false} if no match or null input 1102 * @since 2.4 1103 * @since 3.0 Changed signature from containsAny(String, String) to containsAny(CharSequence, CharSequence) 1104 */ 1105 public static boolean containsAny(final CharSequence cs, final CharSequence searchChars) { 1106 if (searchChars == null) { 1107 return false; 1108 } 1109 return containsAny(cs, CharSequenceUtils.toCharArray(searchChars)); 1110 } 1111 1112 /** 1113 * Checks if the CharSequence contains any of the CharSequences in the given array. 1114 * 1115 * <p> 1116 * A {@code null} {@code cs} CharSequence will return {@code false}. A {@code null} or zero length search array will 1117 * return {@code false}. 1118 * </p> 1119 * 1120 * <pre> 1121 * StringUtils.containsAny(null, *) = false 1122 * StringUtils.containsAny("", *) = false 1123 * StringUtils.containsAny(*, null) = false 1124 * StringUtils.containsAny(*, []) = false 1125 * StringUtils.containsAny("abcd", "ab", null) = true 1126 * StringUtils.containsAny("abcd", "ab", "cd") = true 1127 * StringUtils.containsAny("abc", "d", "abc") = true 1128 * </pre> 1129 * 1130 * @param cs The CharSequence to check, may be null 1131 * @param searchCharSequences The array of CharSequences to search for, may be null. Individual CharSequences may be 1132 * null as well. 1133 * @return {@code true} if any of the search CharSequences are found, {@code false} otherwise 1134 * @since 3.4 1135 */ 1136 public static boolean containsAny(final CharSequence cs, final CharSequence... searchCharSequences) { 1137 return containsAny(StringUtils::contains, cs, searchCharSequences); 1138 } 1139 1140 /** 1141 * Checks if the CharSequence contains any of the CharSequences in the given array. 1142 * 1143 * <p> 1144 * A {@code null} {@code cs} CharSequence will return {@code false}. A {@code null} or zero length search array will 1145 * return {@code false}. 1146 * </p> 1147 * 1148 * @param cs The CharSequence to check, may be null 1149 * @param searchCharSequences The array of CharSequences to search for, may be null. Individual CharSequences may be 1150 * null as well. 1151 * @return {@code true} if any of the search CharSequences are found, {@code false} otherwise 1152 * @since 3.12.0 1153 */ 1154 private static boolean containsAny(final ToBooleanBiFunction<CharSequence, CharSequence> test, 1155 final CharSequence cs, final CharSequence... searchCharSequences) { 1156 if (isEmpty(cs) || ArrayUtils.isEmpty(searchCharSequences)) { 1157 return false; 1158 } 1159 for (final CharSequence searchCharSequence : searchCharSequences) { 1160 if (test.applyAsBoolean(cs, searchCharSequence)) { 1161 return true; 1162 } 1163 } 1164 return false; 1165 } 1166 1167 /** 1168 * Checks if the CharSequence contains any of the CharSequences in the given array, ignoring case. 1169 * 1170 * <p> 1171 * A {@code null} {@code cs} CharSequence will return {@code false}. A {@code null} or zero length search array will 1172 * return {@code false}. 1173 * </p> 1174 * 1175 * <pre> 1176 * StringUtils.containsAny(null, *) = false 1177 * StringUtils.containsAny("", *) = false 1178 * StringUtils.containsAny(*, null) = false 1179 * StringUtils.containsAny(*, []) = false 1180 * StringUtils.containsAny("abcd", "ab", null) = true 1181 * StringUtils.containsAny("abcd", "ab", "cd") = true 1182 * StringUtils.containsAny("abc", "d", "abc") = true 1183 * StringUtils.containsAny("abc", "D", "ABC") = true 1184 * StringUtils.containsAny("ABC", "d", "abc") = true 1185 * </pre> 1186 * 1187 * @param cs The CharSequence to check, may be null 1188 * @param searchCharSequences The array of CharSequences to search for, may be null. Individual CharSequences may be 1189 * null as well. 1190 * @return {@code true} if any of the search CharSequences are found, {@code false} otherwise 1191 * @since 3.12.0 1192 */ 1193 public static boolean containsAnyIgnoreCase(final CharSequence cs, final CharSequence... searchCharSequences) { 1194 return containsAny(StringUtils::containsIgnoreCase, cs, searchCharSequences); 1195 } 1196 1197 /** 1198 * Checks if CharSequence contains a search CharSequence irrespective of case, 1199 * handling {@code null}. Case-insensitivity is defined as by 1200 * {@link String#equalsIgnoreCase(String)}. 1201 * 1202 * <p>A {@code null} CharSequence will return {@code false}. 1203 * 1204 * <pre> 1205 * StringUtils.containsIgnoreCase(null, *) = false 1206 * StringUtils.containsIgnoreCase(*, null) = false 1207 * StringUtils.containsIgnoreCase("", "") = true 1208 * StringUtils.containsIgnoreCase("abc", "") = true 1209 * StringUtils.containsIgnoreCase("abc", "a") = true 1210 * StringUtils.containsIgnoreCase("abc", "z") = false 1211 * StringUtils.containsIgnoreCase("abc", "A") = true 1212 * StringUtils.containsIgnoreCase("abc", "Z") = false 1213 * </pre> 1214 * 1215 * @param str the CharSequence to check, may be null 1216 * @param searchStr the CharSequence to find, may be null 1217 * @return true if the CharSequence contains the search CharSequence irrespective of 1218 * case or false if not or {@code null} string input 1219 * @since 3.0 Changed signature from containsIgnoreCase(String, String) to containsIgnoreCase(CharSequence, CharSequence) 1220 */ 1221 public static boolean containsIgnoreCase(final CharSequence str, final CharSequence searchStr) { 1222 if (str == null || searchStr == null) { 1223 return false; 1224 } 1225 final int len = searchStr.length(); 1226 final int max = str.length() - len; 1227 for (int i = 0; i <= max; i++) { 1228 if (CharSequenceUtils.regionMatches(str, true, i, searchStr, 0, len)) { 1229 return true; 1230 } 1231 } 1232 return false; 1233 } 1234 1235 /** 1236 * Checks that the CharSequence does not contain certain characters. 1237 * 1238 * <p>A {@code null} CharSequence will return {@code true}. 1239 * A {@code null} invalid character array will return {@code true}. 1240 * An empty CharSequence (length()=0) always returns true.</p> 1241 * 1242 * <pre> 1243 * StringUtils.containsNone(null, *) = true 1244 * StringUtils.containsNone(*, null) = true 1245 * StringUtils.containsNone("", *) = true 1246 * StringUtils.containsNone("ab", '') = true 1247 * StringUtils.containsNone("abab", 'xyz') = true 1248 * StringUtils.containsNone("ab1", 'xyz') = true 1249 * StringUtils.containsNone("abz", 'xyz') = false 1250 * </pre> 1251 * 1252 * @param cs the CharSequence to check, may be null 1253 * @param searchChars an array of invalid chars, may be null 1254 * @return true if it contains none of the invalid chars, or is null 1255 * @since 2.0 1256 * @since 3.0 Changed signature from containsNone(String, char[]) to containsNone(CharSequence, char...) 1257 */ 1258 public static boolean containsNone(final CharSequence cs, final char... searchChars) { 1259 if (cs == null || searchChars == null) { 1260 return true; 1261 } 1262 final int csLen = cs.length(); 1263 final int csLast = csLen - 1; 1264 final int searchLen = searchChars.length; 1265 final int searchLast = searchLen - 1; 1266 for (int i = 0; i < csLen; i++) { 1267 final char ch = cs.charAt(i); 1268 for (int j = 0; j < searchLen; j++) { 1269 if (searchChars[j] == ch) { 1270 if (!Character.isHighSurrogate(ch)) { 1271 // ch is in the Basic Multilingual Plane 1272 return false; 1273 } 1274 if (j == searchLast) { 1275 // missing low surrogate, fine, like String.indexOf(String) 1276 return false; 1277 } 1278 if (i < csLast && searchChars[j + 1] == cs.charAt(i + 1)) { 1279 return false; 1280 } 1281 } 1282 } 1283 } 1284 return true; 1285 } 1286 1287 /** 1288 * Checks that the CharSequence does not contain certain characters. 1289 * 1290 * <p>A {@code null} CharSequence will return {@code true}. 1291 * A {@code null} invalid character array will return {@code true}. 1292 * An empty String ("") always returns true.</p> 1293 * 1294 * <pre> 1295 * StringUtils.containsNone(null, *) = true 1296 * StringUtils.containsNone(*, null) = true 1297 * StringUtils.containsNone("", *) = true 1298 * StringUtils.containsNone("ab", "") = true 1299 * StringUtils.containsNone("abab", "xyz") = true 1300 * StringUtils.containsNone("ab1", "xyz") = true 1301 * StringUtils.containsNone("abz", "xyz") = false 1302 * </pre> 1303 * 1304 * @param cs the CharSequence to check, may be null 1305 * @param invalidChars a String of invalid chars, may be null 1306 * @return true if it contains none of the invalid chars, or is null 1307 * @since 2.0 1308 * @since 3.0 Changed signature from containsNone(String, String) to containsNone(CharSequence, String) 1309 */ 1310 public static boolean containsNone(final CharSequence cs, final String invalidChars) { 1311 if (invalidChars == null) { 1312 return true; 1313 } 1314 return containsNone(cs, invalidChars.toCharArray()); 1315 } 1316 1317 /** 1318 * Checks if the CharSequence contains only certain characters. 1319 * 1320 * <p>A {@code null} CharSequence will return {@code false}. 1321 * A {@code null} valid character array will return {@code false}. 1322 * An empty CharSequence (length()=0) always returns {@code true}.</p> 1323 * 1324 * <pre> 1325 * StringUtils.containsOnly(null, *) = false 1326 * StringUtils.containsOnly(*, null) = false 1327 * StringUtils.containsOnly("", *) = true 1328 * StringUtils.containsOnly("ab", '') = false 1329 * StringUtils.containsOnly("abab", 'abc') = true 1330 * StringUtils.containsOnly("ab1", 'abc') = false 1331 * StringUtils.containsOnly("abz", 'abc') = false 1332 * </pre> 1333 * 1334 * @param cs the String to check, may be null 1335 * @param valid an array of valid chars, may be null 1336 * @return true if it only contains valid chars and is non-null 1337 * @since 3.0 Changed signature from containsOnly(String, char[]) to containsOnly(CharSequence, char...) 1338 */ 1339 public static boolean containsOnly(final CharSequence cs, final char... valid) { 1340 // All these pre-checks are to maintain API with an older version 1341 if (valid == null || cs == null) { 1342 return false; 1343 } 1344 if (cs.length() == 0) { 1345 return true; 1346 } 1347 if (valid.length == 0) { 1348 return false; 1349 } 1350 return indexOfAnyBut(cs, valid) == INDEX_NOT_FOUND; 1351 } 1352 1353 /** 1354 * Checks if the CharSequence contains only certain characters. 1355 * 1356 * <p>A {@code null} CharSequence will return {@code false}. 1357 * A {@code null} valid character String will return {@code false}. 1358 * An empty String (length()=0) always returns {@code true}.</p> 1359 * 1360 * <pre> 1361 * StringUtils.containsOnly(null, *) = false 1362 * StringUtils.containsOnly(*, null) = false 1363 * StringUtils.containsOnly("", *) = true 1364 * StringUtils.containsOnly("ab", "") = false 1365 * StringUtils.containsOnly("abab", "abc") = true 1366 * StringUtils.containsOnly("ab1", "abc") = false 1367 * StringUtils.containsOnly("abz", "abc") = false 1368 * </pre> 1369 * 1370 * @param cs the CharSequence to check, may be null 1371 * @param validChars a String of valid chars, may be null 1372 * @return true if it only contains valid chars and is non-null 1373 * @since 2.0 1374 * @since 3.0 Changed signature from containsOnly(String, String) to containsOnly(CharSequence, String) 1375 */ 1376 public static boolean containsOnly(final CharSequence cs, final String validChars) { 1377 if (cs == null || validChars == null) { 1378 return false; 1379 } 1380 return containsOnly(cs, validChars.toCharArray()); 1381 } 1382 1383 /** 1384 * Check whether the given CharSequence contains any whitespace characters. 1385 * 1386 * <p>Whitespace is defined by {@link Character#isWhitespace(char)}.</p> 1387 * 1388 * @param seq the CharSequence to check (may be {@code null}) 1389 * @return {@code true} if the CharSequence is not empty and 1390 * contains at least 1 (breaking) whitespace character 1391 * @since 3.0 1392 */ 1393 // From org.springframework.util.StringUtils, under Apache License 2.0 1394 public static boolean containsWhitespace(final CharSequence seq) { 1395 if (isEmpty(seq)) { 1396 return false; 1397 } 1398 final int strLen = seq.length(); 1399 for (int i = 0; i < strLen; i++) { 1400 if (Character.isWhitespace(seq.charAt(i))) { 1401 return true; 1402 } 1403 } 1404 return false; 1405 } 1406 1407 private static void convertRemainingAccentCharacters(final StringBuilder decomposed) { 1408 for (int i = 0; i < decomposed.length(); i++) { 1409 final char charAt = decomposed.charAt(i); 1410 switch (charAt) { 1411 case '\u0141': 1412 decomposed.setCharAt(i, 'L'); 1413 break; 1414 case '\u0142': 1415 decomposed.setCharAt(i, 'l'); 1416 break; 1417 // D with stroke 1418 case '\u0110': 1419 // LATIN CAPITAL LETTER D WITH STROKE 1420 decomposed.setCharAt(i, 'D'); 1421 break; 1422 case '\u0111': 1423 // LATIN SMALL LETTER D WITH STROKE 1424 decomposed.setCharAt(i, 'd'); 1425 break; 1426 // I with bar 1427 case '\u0197': 1428 decomposed.setCharAt(i, 'I'); 1429 break; 1430 case '\u0268': 1431 decomposed.setCharAt(i, 'i'); 1432 break; 1433 case '\u1D7B': 1434 decomposed.setCharAt(i, 'I'); 1435 break; 1436 case '\u1DA4': 1437 decomposed.setCharAt(i, 'i'); 1438 break; 1439 case '\u1DA7': 1440 decomposed.setCharAt(i, 'I'); 1441 break; 1442 // U with bar 1443 case '\u0244': 1444 // LATIN CAPITAL LETTER U BAR 1445 decomposed.setCharAt(i, 'U'); 1446 break; 1447 case '\u0289': 1448 // LATIN SMALL LETTER U BAR 1449 decomposed.setCharAt(i, 'u'); 1450 break; 1451 case '\u1D7E': 1452 // LATIN SMALL CAPITAL LETTER U WITH STROKE 1453 decomposed.setCharAt(i, 'U'); 1454 break; 1455 case '\u1DB6': 1456 // MODIFIER LETTER SMALL U BAR 1457 decomposed.setCharAt(i, 'u'); 1458 break; 1459 // T with stroke 1460 case '\u0166': 1461 // LATIN CAPITAL LETTER T WITH STROKE 1462 decomposed.setCharAt(i, 'T'); 1463 break; 1464 case '\u0167': 1465 // LATIN SMALL LETTER T WITH STROKE 1466 decomposed.setCharAt(i, 't'); 1467 break; 1468 default: 1469 break; 1470 } 1471 } 1472 } 1473 1474 /** 1475 * Counts how many times the char appears in the given string. 1476 * 1477 * <p>A {@code null} or empty ("") String input returns {@code 0}.</p> 1478 * 1479 * <pre> 1480 * StringUtils.countMatches(null, *) = 0 1481 * StringUtils.countMatches("", *) = 0 1482 * StringUtils.countMatches("abba", 0) = 0 1483 * StringUtils.countMatches("abba", 'a') = 2 1484 * StringUtils.countMatches("abba", 'b') = 2 1485 * StringUtils.countMatches("abba", 'x') = 0 1486 * </pre> 1487 * 1488 * @param str the CharSequence to check, may be null 1489 * @param ch the char to count 1490 * @return the number of occurrences, 0 if the CharSequence is {@code null} 1491 * @since 3.4 1492 */ 1493 public static int countMatches(final CharSequence str, final char ch) { 1494 if (isEmpty(str)) { 1495 return 0; 1496 } 1497 int count = 0; 1498 // We could also call str.toCharArray() for faster lookups but that would generate more garbage. 1499 for (int i = 0; i < str.length(); i++) { 1500 if (ch == str.charAt(i)) { 1501 count++; 1502 } 1503 } 1504 return count; 1505 } 1506 1507 /** 1508 * Counts how many times the substring appears in the larger string. 1509 * Note that the code only counts non-overlapping matches. 1510 * 1511 * <p>A {@code null} or empty ("") String input returns {@code 0}.</p> 1512 * 1513 * <pre> 1514 * StringUtils.countMatches(null, *) = 0 1515 * StringUtils.countMatches("", *) = 0 1516 * StringUtils.countMatches("abba", null) = 0 1517 * StringUtils.countMatches("abba", "") = 0 1518 * StringUtils.countMatches("abba", "a") = 2 1519 * StringUtils.countMatches("abba", "ab") = 1 1520 * StringUtils.countMatches("abba", "xxx") = 0 1521 * StringUtils.countMatches("ababa", "aba") = 1 1522 * </pre> 1523 * 1524 * @param str the CharSequence to check, may be null 1525 * @param sub the substring to count, may be null 1526 * @return the number of occurrences, 0 if either CharSequence is {@code null} 1527 * @since 3.0 Changed signature from countMatches(String, String) to countMatches(CharSequence, CharSequence) 1528 */ 1529 public static int countMatches(final CharSequence str, final CharSequence sub) { 1530 if (isEmpty(str) || isEmpty(sub)) { 1531 return 0; 1532 } 1533 int count = 0; 1534 int idx = 0; 1535 while ((idx = CharSequenceUtils.indexOf(str, sub, idx)) != INDEX_NOT_FOUND) { 1536 count++; 1537 idx += sub.length(); 1538 } 1539 return count; 1540 } 1541 1542 /** 1543 * Returns either the passed in CharSequence, or if the CharSequence is 1544 * whitespace, empty ("") or {@code null}, the value of {@code defaultStr}. 1545 * 1546 * <p>Whitespace is defined by {@link Character#isWhitespace(char)}.</p> 1547 * 1548 * <pre> 1549 * StringUtils.defaultIfBlank(null, "NULL") = "NULL" 1550 * StringUtils.defaultIfBlank("", "NULL") = "NULL" 1551 * StringUtils.defaultIfBlank(" ", "NULL") = "NULL" 1552 * StringUtils.defaultIfBlank("bat", "NULL") = "bat" 1553 * StringUtils.defaultIfBlank("", null) = null 1554 * </pre> 1555 * @param <T> the specific kind of CharSequence 1556 * @param str the CharSequence to check, may be null 1557 * @param defaultStr the default CharSequence to return 1558 * if the input is whitespace, empty ("") or {@code null}, may be null 1559 * @return the passed in CharSequence, or the default 1560 * @see StringUtils#defaultString(String, String) 1561 */ 1562 public static <T extends CharSequence> T defaultIfBlank(final T str, final T defaultStr) { 1563 return isBlank(str) ? defaultStr : str; 1564 } 1565 1566 /** 1567 * Returns either the passed in CharSequence, or if the CharSequence is 1568 * empty or {@code null}, the value of {@code defaultStr}. 1569 * 1570 * <pre> 1571 * StringUtils.defaultIfEmpty(null, "NULL") = "NULL" 1572 * StringUtils.defaultIfEmpty("", "NULL") = "NULL" 1573 * StringUtils.defaultIfEmpty(" ", "NULL") = " " 1574 * StringUtils.defaultIfEmpty("bat", "NULL") = "bat" 1575 * StringUtils.defaultIfEmpty("", null) = null 1576 * </pre> 1577 * @param <T> the specific kind of CharSequence 1578 * @param str the CharSequence to check, may be null 1579 * @param defaultStr the default CharSequence to return 1580 * if the input is empty ("") or {@code null}, may be null 1581 * @return the passed in CharSequence, or the default 1582 * @see StringUtils#defaultString(String, String) 1583 */ 1584 public static <T extends CharSequence> T defaultIfEmpty(final T str, final T defaultStr) { 1585 return isEmpty(str) ? defaultStr : str; 1586 } 1587 1588 /** 1589 * Returns either the passed in String, 1590 * or if the String is {@code null}, an empty String (""). 1591 * 1592 * <pre> 1593 * StringUtils.defaultString(null) = "" 1594 * StringUtils.defaultString("") = "" 1595 * StringUtils.defaultString("bat") = "bat" 1596 * </pre> 1597 * 1598 * @see Objects#toString(Object, String) 1599 * @see String#valueOf(Object) 1600 * @param str the String to check, may be null 1601 * @return the passed in String, or the empty String if it 1602 * was {@code null} 1603 */ 1604 public static String defaultString(final String str) { 1605 return Objects.toString(str, EMPTY); 1606 } 1607 1608 /** 1609 * Returns either the given String, or if the String is 1610 * {@code null}, {@code nullDefault}. 1611 * 1612 * <pre> 1613 * StringUtils.defaultString(null, "NULL") = "NULL" 1614 * StringUtils.defaultString("", "NULL") = "" 1615 * StringUtils.defaultString("bat", "NULL") = "bat" 1616 * </pre> 1617 * <p> 1618 * Since this is now provided by Java, instead call {@link Objects#toString(Object, String)}: 1619 * </p> 1620 * <pre> 1621 * Objects.toString(null, "NULL") = "NULL" 1622 * Objects.toString("", "NULL") = "" 1623 * Objects.toString("bat", "NULL") = "bat" 1624 * </pre> 1625 * 1626 * @see Objects#toString(Object, String) 1627 * @see String#valueOf(Object) 1628 * @param str the String to check, may be null 1629 * @param nullDefault the default String to return 1630 * if the input is {@code null}, may be null 1631 * @return the passed in String, or the default if it was {@code null} 1632 * @deprecated Use {@link Objects#toString(Object, String)} 1633 */ 1634 @Deprecated 1635 public static String defaultString(final String str, final String nullDefault) { 1636 return Objects.toString(str, nullDefault); 1637 } 1638 1639 /** 1640 * Deletes all whitespaces from a String as defined by 1641 * {@link Character#isWhitespace(char)}. 1642 * 1643 * <pre> 1644 * StringUtils.deleteWhitespace(null) = null 1645 * StringUtils.deleteWhitespace("") = "" 1646 * StringUtils.deleteWhitespace("abc") = "abc" 1647 * StringUtils.deleteWhitespace(" ab c ") = "abc" 1648 * </pre> 1649 * 1650 * @param str the String to delete whitespace from, may be null 1651 * @return the String without whitespaces, {@code null} if null String input 1652 */ 1653 public static String deleteWhitespace(final String str) { 1654 if (isEmpty(str)) { 1655 return str; 1656 } 1657 final int sz = str.length(); 1658 final char[] chs = new char[sz]; 1659 int count = 0; 1660 for (int i = 0; i < sz; i++) { 1661 if (!Character.isWhitespace(str.charAt(i))) { 1662 chs[count++] = str.charAt(i); 1663 } 1664 } 1665 if (count == sz) { 1666 return str; 1667 } 1668 if (count == 0) { 1669 return EMPTY; 1670 } 1671 return new String(chs, 0, count); 1672 } 1673 1674 /** 1675 * Compares two Strings, and returns the portion where they differ. 1676 * More precisely, return the remainder of the second String, 1677 * starting from where it's different from the first. This means that 1678 * the difference between "abc" and "ab" is the empty String and not "c". 1679 * 1680 * <p>For example, 1681 * {@code difference("i am a machine", "i am a robot") -> "robot"}.</p> 1682 * 1683 * <pre> 1684 * StringUtils.difference(null, null) = null 1685 * StringUtils.difference("", "") = "" 1686 * StringUtils.difference("", "abc") = "abc" 1687 * StringUtils.difference("abc", "") = "" 1688 * StringUtils.difference("abc", "abc") = "" 1689 * StringUtils.difference("abc", "ab") = "" 1690 * StringUtils.difference("ab", "abxyz") = "xyz" 1691 * StringUtils.difference("abcde", "abxyz") = "xyz" 1692 * StringUtils.difference("abcde", "xyz") = "xyz" 1693 * </pre> 1694 * 1695 * @param str1 the first String, may be null 1696 * @param str2 the second String, may be null 1697 * @return the portion of str2 where it differs from str1; returns the 1698 * empty String if they are equal 1699 * @see #indexOfDifference(CharSequence,CharSequence) 1700 * @since 2.0 1701 */ 1702 public static String difference(final String str1, final String str2) { 1703 if (str1 == null) { 1704 return str2; 1705 } 1706 if (str2 == null) { 1707 return str1; 1708 } 1709 final int at = indexOfDifference(str1, str2); 1710 if (at == INDEX_NOT_FOUND) { 1711 return EMPTY; 1712 } 1713 return str2.substring(at); 1714 } 1715 1716 /** 1717 * Check if a CharSequence ends with a specified suffix. 1718 * 1719 * <p>{@code null}s are handled without exceptions. Two {@code null} 1720 * references are considered to be equal. The comparison is case-sensitive.</p> 1721 * 1722 * <pre> 1723 * StringUtils.endsWith(null, null) = true 1724 * StringUtils.endsWith(null, "def") = false 1725 * StringUtils.endsWith("abcdef", null) = false 1726 * StringUtils.endsWith("abcdef", "def") = true 1727 * StringUtils.endsWith("ABCDEF", "def") = false 1728 * StringUtils.endsWith("ABCDEF", "cde") = false 1729 * StringUtils.endsWith("ABCDEF", "") = true 1730 * </pre> 1731 * 1732 * @see String#endsWith(String) 1733 * @param str the CharSequence to check, may be null 1734 * @param suffix the suffix to find, may be null 1735 * @return {@code true} if the CharSequence ends with the suffix, case-sensitive, or 1736 * both {@code null} 1737 * @since 2.4 1738 * @since 3.0 Changed signature from endsWith(String, String) to endsWith(CharSequence, CharSequence) 1739 */ 1740 public static boolean endsWith(final CharSequence str, final CharSequence suffix) { 1741 return endsWith(str, suffix, false); 1742 } 1743 1744 /** 1745 * Check if a CharSequence ends with a specified suffix (optionally case-insensitive). 1746 * 1747 * @see String#endsWith(String) 1748 * @param str the CharSequence to check, may be null 1749 * @param suffix the suffix to find, may be null 1750 * @param ignoreCase indicates whether the compare should ignore case 1751 * (case-insensitive) or not. 1752 * @return {@code true} if the CharSequence starts with the prefix or 1753 * both {@code null} 1754 */ 1755 private static boolean endsWith(final CharSequence str, final CharSequence suffix, final boolean ignoreCase) { 1756 if (str == null || suffix == null) { 1757 return str == suffix; 1758 } 1759 if (suffix.length() > str.length()) { 1760 return false; 1761 } 1762 final int strOffset = str.length() - suffix.length(); 1763 return CharSequenceUtils.regionMatches(str, ignoreCase, strOffset, suffix, 0, suffix.length()); 1764 } 1765 1766 /** 1767 * Check if a CharSequence ends with any of the provided case-sensitive suffixes. 1768 * 1769 * <pre> 1770 * StringUtils.endsWithAny(null, null) = false 1771 * StringUtils.endsWithAny(null, new String[] {"abc"}) = false 1772 * StringUtils.endsWithAny("abcxyz", null) = false 1773 * StringUtils.endsWithAny("abcxyz", new String[] {""}) = true 1774 * StringUtils.endsWithAny("abcxyz", new String[] {"xyz"}) = true 1775 * StringUtils.endsWithAny("abcxyz", new String[] {null, "xyz", "abc"}) = true 1776 * StringUtils.endsWithAny("abcXYZ", "def", "XYZ") = true 1777 * StringUtils.endsWithAny("abcXYZ", "def", "xyz") = false 1778 * </pre> 1779 * 1780 * @param sequence the CharSequence to check, may be null 1781 * @param searchStrings the case-sensitive CharSequences to find, may be empty or contain {@code null} 1782 * @see StringUtils#endsWith(CharSequence, CharSequence) 1783 * @return {@code true} if the input {@code sequence} is {@code null} AND no {@code searchStrings} are provided, or 1784 * the input {@code sequence} ends in any of the provided case-sensitive {@code searchStrings}. 1785 * @since 3.0 1786 */ 1787 public static boolean endsWithAny(final CharSequence sequence, final CharSequence... searchStrings) { 1788 if (isEmpty(sequence) || ArrayUtils.isEmpty(searchStrings)) { 1789 return false; 1790 } 1791 for (final CharSequence searchString : searchStrings) { 1792 if (endsWith(sequence, searchString)) { 1793 return true; 1794 } 1795 } 1796 return false; 1797 } 1798 1799 /** 1800 * Case-insensitive check if a CharSequence ends with a specified suffix. 1801 * 1802 * <p>{@code null}s are handled without exceptions. Two {@code null} 1803 * references are considered to be equal. The comparison is case insensitive.</p> 1804 * 1805 * <pre> 1806 * StringUtils.endsWithIgnoreCase(null, null) = true 1807 * StringUtils.endsWithIgnoreCase(null, "def") = false 1808 * StringUtils.endsWithIgnoreCase("abcdef", null) = false 1809 * StringUtils.endsWithIgnoreCase("abcdef", "def") = true 1810 * StringUtils.endsWithIgnoreCase("ABCDEF", "def") = true 1811 * StringUtils.endsWithIgnoreCase("ABCDEF", "cde") = false 1812 * </pre> 1813 * 1814 * @see String#endsWith(String) 1815 * @param str the CharSequence to check, may be null 1816 * @param suffix the suffix to find, may be null 1817 * @return {@code true} if the CharSequence ends with the suffix, case-insensitive, or 1818 * both {@code null} 1819 * @since 2.4 1820 * @since 3.0 Changed signature from endsWithIgnoreCase(String, String) to endsWithIgnoreCase(CharSequence, CharSequence) 1821 */ 1822 public static boolean endsWithIgnoreCase(final CharSequence str, final CharSequence suffix) { 1823 return endsWith(str, suffix, true); 1824 } 1825 1826 /** 1827 * Compares two CharSequences, returning {@code true} if they represent 1828 * equal sequences of characters. 1829 * 1830 * <p>{@code null}s are handled without exceptions. Two {@code null} 1831 * references are considered to be equal. The comparison is <strong>case-sensitive</strong>.</p> 1832 * 1833 * <pre> 1834 * StringUtils.equals(null, null) = true 1835 * StringUtils.equals(null, "abc") = false 1836 * StringUtils.equals("abc", null) = false 1837 * StringUtils.equals("abc", "abc") = true 1838 * StringUtils.equals("abc", "ABC") = false 1839 * </pre> 1840 * 1841 * @param cs1 the first CharSequence, may be {@code null} 1842 * @param cs2 the second CharSequence, may be {@code null} 1843 * @return {@code true} if the CharSequences are equal (case-sensitive), or both {@code null} 1844 * @since 3.0 Changed signature from equals(String, String) to equals(CharSequence, CharSequence) 1845 * @see Object#equals(Object) 1846 * @see #equalsIgnoreCase(CharSequence, CharSequence) 1847 */ 1848 public static boolean equals(final CharSequence cs1, final CharSequence cs2) { 1849 if (cs1 == cs2) { 1850 return true; 1851 } 1852 if (cs1 == null || cs2 == null) { 1853 return false; 1854 } 1855 if (cs1.length() != cs2.length()) { 1856 return false; 1857 } 1858 if (cs1 instanceof String && cs2 instanceof String) { 1859 return cs1.equals(cs2); 1860 } 1861 // Step-wise comparison 1862 final int length = cs1.length(); 1863 for (int i = 0; i < length; i++) { 1864 if (cs1.charAt(i) != cs2.charAt(i)) { 1865 return false; 1866 } 1867 } 1868 return true; 1869 } 1870 1871 /** 1872 * Compares given {@code string} to a CharSequences vararg of {@code searchStrings}, 1873 * returning {@code true} if the {@code string} is equal to any of the {@code searchStrings}. 1874 * 1875 * <pre> 1876 * StringUtils.equalsAny(null, (CharSequence[]) null) = false 1877 * StringUtils.equalsAny(null, null, null) = true 1878 * StringUtils.equalsAny(null, "abc", "def") = false 1879 * StringUtils.equalsAny("abc", null, "def") = false 1880 * StringUtils.equalsAny("abc", "abc", "def") = true 1881 * StringUtils.equalsAny("abc", "ABC", "DEF") = false 1882 * </pre> 1883 * 1884 * @param string to compare, may be {@code null}. 1885 * @param searchStrings a vararg of strings, may be {@code null}. 1886 * @return {@code true} if the string is equal (case-sensitive) to any other element of {@code searchStrings}; 1887 * {@code false} if {@code searchStrings} is null or contains no matches. 1888 * @since 3.5 1889 */ 1890 public static boolean equalsAny(final CharSequence string, final CharSequence... searchStrings) { 1891 if (ArrayUtils.isNotEmpty(searchStrings)) { 1892 for (final CharSequence next : searchStrings) { 1893 if (equals(string, next)) { 1894 return true; 1895 } 1896 } 1897 } 1898 return false; 1899 } 1900 1901 /** 1902 * Compares given {@code string} to a CharSequences vararg of {@code searchStrings}, 1903 * returning {@code true} if the {@code string} is equal to any of the {@code searchStrings}, ignoring case. 1904 * 1905 * <pre> 1906 * StringUtils.equalsAnyIgnoreCase(null, (CharSequence[]) null) = false 1907 * StringUtils.equalsAnyIgnoreCase(null, null, null) = true 1908 * StringUtils.equalsAnyIgnoreCase(null, "abc", "def") = false 1909 * StringUtils.equalsAnyIgnoreCase("abc", null, "def") = false 1910 * StringUtils.equalsAnyIgnoreCase("abc", "abc", "def") = true 1911 * StringUtils.equalsAnyIgnoreCase("abc", "ABC", "DEF") = true 1912 * </pre> 1913 * 1914 * @param string to compare, may be {@code null}. 1915 * @param searchStrings a vararg of strings, may be {@code null}. 1916 * @return {@code true} if the string is equal (case-insensitive) to any other element of {@code searchStrings}; 1917 * {@code false} if {@code searchStrings} is null or contains no matches. 1918 * @since 3.5 1919 */ 1920 public static boolean equalsAnyIgnoreCase(final CharSequence string, final CharSequence... searchStrings) { 1921 if (ArrayUtils.isNotEmpty(searchStrings)) { 1922 for (final CharSequence next : searchStrings) { 1923 if (equalsIgnoreCase(string, next)) { 1924 return true; 1925 } 1926 } 1927 } 1928 return false; 1929 } 1930 1931 /** 1932 * Compares two CharSequences, returning {@code true} if they represent 1933 * equal sequences of characters, ignoring case. 1934 * 1935 * <p>{@code null}s are handled without exceptions. Two {@code null} 1936 * references are considered equal. The comparison is <strong>case insensitive</strong>.</p> 1937 * 1938 * <pre> 1939 * StringUtils.equalsIgnoreCase(null, null) = true 1940 * StringUtils.equalsIgnoreCase(null, "abc") = false 1941 * StringUtils.equalsIgnoreCase("abc", null) = false 1942 * StringUtils.equalsIgnoreCase("abc", "abc") = true 1943 * StringUtils.equalsIgnoreCase("abc", "ABC") = true 1944 * </pre> 1945 * 1946 * @param cs1 the first CharSequence, may be {@code null} 1947 * @param cs2 the second CharSequence, may be {@code null} 1948 * @return {@code true} if the CharSequences are equal (case-insensitive), or both {@code null} 1949 * @since 3.0 Changed signature from equalsIgnoreCase(String, String) to equalsIgnoreCase(CharSequence, CharSequence) 1950 * @see #equals(CharSequence, CharSequence) 1951 */ 1952 public static boolean equalsIgnoreCase(final CharSequence cs1, final CharSequence cs2) { 1953 if (cs1 == cs2) { 1954 return true; 1955 } 1956 if (cs1 == null || cs2 == null) { 1957 return false; 1958 } 1959 if (cs1.length() != cs2.length()) { 1960 return false; 1961 } 1962 return CharSequenceUtils.regionMatches(cs1, true, 0, cs2, 0, cs1.length()); 1963 } 1964 1965 /** 1966 * Returns the first value in the array which is not empty (""), 1967 * {@code null} or whitespace only. 1968 * 1969 * <p>Whitespace is defined by {@link Character#isWhitespace(char)}.</p> 1970 * 1971 * <p>If all values are blank or the array is {@code null} 1972 * or empty then {@code null} is returned.</p> 1973 * 1974 * <pre> 1975 * StringUtils.firstNonBlank(null, null, null) = null 1976 * StringUtils.firstNonBlank(null, "", " ") = null 1977 * StringUtils.firstNonBlank("abc") = "abc" 1978 * StringUtils.firstNonBlank(null, "xyz") = "xyz" 1979 * StringUtils.firstNonBlank(null, "", " ", "xyz") = "xyz" 1980 * StringUtils.firstNonBlank(null, "xyz", "abc") = "xyz" 1981 * StringUtils.firstNonBlank() = null 1982 * </pre> 1983 * 1984 * @param <T> the specific kind of CharSequence 1985 * @param values the values to test, may be {@code null} or empty 1986 * @return the first value from {@code values} which is not blank, 1987 * or {@code null} if there are no non-blank values 1988 * @since 3.8 1989 */ 1990 @SafeVarargs 1991 public static <T extends CharSequence> T firstNonBlank(final T... values) { 1992 if (values != null) { 1993 for (final T val : values) { 1994 if (isNotBlank(val)) { 1995 return val; 1996 } 1997 } 1998 } 1999 return null; 2000 } 2001 2002 /** 2003 * Returns the first value in the array which is not empty. 2004 * 2005 * <p>If all values are empty or the array is {@code null} 2006 * or empty then {@code null} is returned.</p> 2007 * 2008 * <pre> 2009 * StringUtils.firstNonEmpty(null, null, null) = null 2010 * StringUtils.firstNonEmpty(null, null, "") = null 2011 * StringUtils.firstNonEmpty(null, "", " ") = " " 2012 * StringUtils.firstNonEmpty("abc") = "abc" 2013 * StringUtils.firstNonEmpty(null, "xyz") = "xyz" 2014 * StringUtils.firstNonEmpty("", "xyz") = "xyz" 2015 * StringUtils.firstNonEmpty(null, "xyz", "abc") = "xyz" 2016 * StringUtils.firstNonEmpty() = null 2017 * </pre> 2018 * 2019 * @param <T> the specific kind of CharSequence 2020 * @param values the values to test, may be {@code null} or empty 2021 * @return the first value from {@code values} which is not empty, 2022 * or {@code null} if there are no non-empty values 2023 * @since 3.8 2024 */ 2025 @SafeVarargs 2026 public static <T extends CharSequence> T firstNonEmpty(final T... values) { 2027 if (values != null) { 2028 for (final T val : values) { 2029 if (isNotEmpty(val)) { 2030 return val; 2031 } 2032 } 2033 } 2034 return null; 2035 } 2036 2037 /** 2038 * Calls {@link String#getBytes(Charset)} in a null-safe manner. 2039 * 2040 * @param string input string 2041 * @param charset The {@link Charset} to encode the {@link String}. If null, then use the default Charset. 2042 * @return The empty byte[] if {@code string} is null, the result of {@link String#getBytes(Charset)} otherwise. 2043 * @see String#getBytes(Charset) 2044 * @since 3.10 2045 */ 2046 public static byte[] getBytes(final String string, final Charset charset) { 2047 return string == null ? ArrayUtils.EMPTY_BYTE_ARRAY : string.getBytes(Charsets.toCharset(charset)); 2048 } 2049 2050 /** 2051 * Calls {@link String#getBytes(String)} in a null-safe manner. 2052 * 2053 * @param string input string 2054 * @param charset The {@link Charset} name to encode the {@link String}. If null, then use the default Charset. 2055 * @return The empty byte[] if {@code string} is null, the result of {@link String#getBytes(String)} otherwise. 2056 * @throws UnsupportedEncodingException Thrown when the named charset is not supported. 2057 * @see String#getBytes(String) 2058 * @since 3.10 2059 */ 2060 public static byte[] getBytes(final String string, final String charset) throws UnsupportedEncodingException { 2061 return string == null ? ArrayUtils.EMPTY_BYTE_ARRAY : string.getBytes(Charsets.toCharsetName(charset)); 2062 } 2063 2064 /** 2065 * Compares all Strings in an array and returns the initial sequence of 2066 * characters that is common to all of them. 2067 * 2068 * <p>For example, 2069 * {@code getCommonPrefix(new String[] {"i am a machine", "i am a robot"}) -> "i am a "}</p> 2070 * 2071 * <pre> 2072 * StringUtils.getCommonPrefix(null) = "" 2073 * StringUtils.getCommonPrefix(new String[] {}) = "" 2074 * StringUtils.getCommonPrefix(new String[] {"abc"}) = "abc" 2075 * StringUtils.getCommonPrefix(new String[] {null, null}) = "" 2076 * StringUtils.getCommonPrefix(new String[] {"", ""}) = "" 2077 * StringUtils.getCommonPrefix(new String[] {"", null}) = "" 2078 * StringUtils.getCommonPrefix(new String[] {"abc", null, null}) = "" 2079 * StringUtils.getCommonPrefix(new String[] {null, null, "abc"}) = "" 2080 * StringUtils.getCommonPrefix(new String[] {"", "abc"}) = "" 2081 * StringUtils.getCommonPrefix(new String[] {"abc", ""}) = "" 2082 * StringUtils.getCommonPrefix(new String[] {"abc", "abc"}) = "abc" 2083 * StringUtils.getCommonPrefix(new String[] {"abc", "a"}) = "a" 2084 * StringUtils.getCommonPrefix(new String[] {"ab", "abxyz"}) = "ab" 2085 * StringUtils.getCommonPrefix(new String[] {"abcde", "abxyz"}) = "ab" 2086 * StringUtils.getCommonPrefix(new String[] {"abcde", "xyz"}) = "" 2087 * StringUtils.getCommonPrefix(new String[] {"xyz", "abcde"}) = "" 2088 * StringUtils.getCommonPrefix(new String[] {"i am a machine", "i am a robot"}) = "i am a " 2089 * </pre> 2090 * 2091 * @param strs array of String objects, entries may be null 2092 * @return the initial sequence of characters that are common to all Strings 2093 * in the array; empty String if the array is null, the elements are all null 2094 * or if there is no common prefix. 2095 * @since 2.4 2096 */ 2097 public static String getCommonPrefix(final String... strs) { 2098 if (ArrayUtils.isEmpty(strs)) { 2099 return EMPTY; 2100 } 2101 final int smallestIndexOfDiff = indexOfDifference(strs); 2102 if (smallestIndexOfDiff == INDEX_NOT_FOUND) { 2103 // all strings were identical 2104 if (strs[0] == null) { 2105 return EMPTY; 2106 } 2107 return strs[0]; 2108 } 2109 if (smallestIndexOfDiff == 0) { 2110 // there were no common initial characters 2111 return EMPTY; 2112 } 2113 // we found a common initial character sequence 2114 return strs[0].substring(0, smallestIndexOfDiff); 2115 } 2116 2117 /** 2118 * Checks if a String {@code str} contains Unicode digits, 2119 * if yes then concatenate all the digits in {@code str} and return it as a String. 2120 * 2121 * <p>An empty ("") String will be returned if no digits found in {@code str}.</p> 2122 * 2123 * <pre> 2124 * StringUtils.getDigits(null) = null 2125 * StringUtils.getDigits("") = "" 2126 * StringUtils.getDigits("abc") = "" 2127 * StringUtils.getDigits("1000$") = "1000" 2128 * StringUtils.getDigits("1123~45") = "112345" 2129 * StringUtils.getDigits("(541) 754-3010") = "5417543010" 2130 * StringUtils.getDigits("\u0967\u0968\u0969") = "\u0967\u0968\u0969" 2131 * </pre> 2132 * 2133 * @param str the String to extract digits from, may be null 2134 * @return String with only digits, 2135 * or an empty ("") String if no digits found, 2136 * or {@code null} String if {@code str} is null 2137 * @since 3.6 2138 */ 2139 public static String getDigits(final String str) { 2140 if (isEmpty(str)) { 2141 return str; 2142 } 2143 final int sz = str.length(); 2144 final StringBuilder strDigits = new StringBuilder(sz); 2145 for (int i = 0; i < sz; i++) { 2146 final char tempChar = str.charAt(i); 2147 if (Character.isDigit(tempChar)) { 2148 strDigits.append(tempChar); 2149 } 2150 } 2151 return strDigits.toString(); 2152 } 2153 2154 /** 2155 * Find the Fuzzy Distance which indicates the similarity score between two Strings. 2156 * 2157 * <p>This string matching algorithm is similar to the algorithms of editors such as Sublime Text, 2158 * TextMate, Atom and others. One point is given for every matched character. Subsequent 2159 * matches yield two bonus points. A higher score indicates a higher similarity.</p> 2160 * 2161 * <pre> 2162 * StringUtils.getFuzzyDistance(null, null, null) = IllegalArgumentException 2163 * StringUtils.getFuzzyDistance("", "", Locale.ENGLISH) = 0 2164 * StringUtils.getFuzzyDistance("Workshop", "b", Locale.ENGLISH) = 0 2165 * StringUtils.getFuzzyDistance("Room", "o", Locale.ENGLISH) = 1 2166 * StringUtils.getFuzzyDistance("Workshop", "w", Locale.ENGLISH) = 1 2167 * StringUtils.getFuzzyDistance("Workshop", "ws", Locale.ENGLISH) = 2 2168 * StringUtils.getFuzzyDistance("Workshop", "wo", Locale.ENGLISH) = 4 2169 * StringUtils.getFuzzyDistance("Apache Software Foundation", "asf", Locale.ENGLISH) = 3 2170 * </pre> 2171 * 2172 * @param term a full term that should be matched against, must not be null 2173 * @param query the query that will be matched against a term, must not be null 2174 * @param locale This string matching logic is case-insensitive. A locale is necessary to normalize 2175 * both Strings to lower case. 2176 * @return result score 2177 * @throws IllegalArgumentException if either String input {@code null} or Locale input {@code null} 2178 * @since 3.4 2179 * @deprecated As of 3.6, use Apache Commons Text 2180 * <a href="https://commons.apache.org/proper/commons-text/javadocs/api-release/org/apache/commons/text/similarity/FuzzyScore.html"> 2181 * FuzzyScore</a> instead 2182 */ 2183 @Deprecated 2184 public static int getFuzzyDistance(final CharSequence term, final CharSequence query, final Locale locale) { 2185 if (term == null || query == null) { 2186 throw new IllegalArgumentException("Strings must not be null"); 2187 } 2188 if (locale == null) { 2189 throw new IllegalArgumentException("Locale must not be null"); 2190 } 2191 2192 // fuzzy logic is case-insensitive. We normalize the Strings to lower 2193 // case right from the start. Turning characters to lower case 2194 // via Character.toLowerCase(char) is unfortunately insufficient 2195 // as it does not accept a locale. 2196 final String termLowerCase = term.toString().toLowerCase(locale); 2197 final String queryLowerCase = query.toString().toLowerCase(locale); 2198 2199 // the resulting score 2200 int score = 0; 2201 2202 // the position in the term which will be scanned next for potential 2203 // query character matches 2204 int termIndex = 0; 2205 2206 // index of the previously matched character in the term 2207 int previousMatchingCharacterIndex = Integer.MIN_VALUE; 2208 2209 for (int queryIndex = 0; queryIndex < queryLowerCase.length(); queryIndex++) { 2210 final char queryChar = queryLowerCase.charAt(queryIndex); 2211 2212 boolean termCharacterMatchFound = false; 2213 for (; termIndex < termLowerCase.length() && !termCharacterMatchFound; termIndex++) { 2214 final char termChar = termLowerCase.charAt(termIndex); 2215 2216 if (queryChar == termChar) { 2217 // simple character matches result in one point 2218 score++; 2219 2220 // subsequent character matches further improve 2221 // the score. 2222 if (previousMatchingCharacterIndex + 1 == termIndex) { 2223 score += 2; 2224 } 2225 2226 previousMatchingCharacterIndex = termIndex; 2227 2228 // we can leave the nested loop. Every character in the 2229 // query can match at most one character in the term. 2230 termCharacterMatchFound = true; 2231 } 2232 } 2233 } 2234 2235 return score; 2236 } 2237 2238 /** 2239 * Returns either the passed in CharSequence, or if the CharSequence is 2240 * whitespace, empty ("") or {@code null}, the value supplied by {@code defaultStrSupplier}. 2241 * 2242 * <p>Whitespace is defined by {@link Character#isWhitespace(char)}.</p> 2243 * 2244 * <p>Caller responsible for thread-safety and exception handling of default value supplier</p> 2245 * 2246 * <pre> 2247 * {@code 2248 * StringUtils.getIfBlank(null, () -> "NULL") = "NULL" 2249 * StringUtils.getIfBlank("", () -> "NULL") = "NULL" 2250 * StringUtils.getIfBlank(" ", () -> "NULL") = "NULL" 2251 * StringUtils.getIfBlank("bat", () -> "NULL") = "bat" 2252 * StringUtils.getIfBlank("", () -> null) = null 2253 * StringUtils.getIfBlank("", null) = null 2254 * }</pre> 2255 * @param <T> the specific kind of CharSequence 2256 * @param str the CharSequence to check, may be null 2257 * @param defaultSupplier the supplier of default CharSequence to return 2258 * if the input is whitespace, empty ("") or {@code null}, may be null 2259 * @return the passed in CharSequence, or the default 2260 * @see StringUtils#defaultString(String, String) 2261 * @since 3.10 2262 */ 2263 public static <T extends CharSequence> T getIfBlank(final T str, final Supplier<T> defaultSupplier) { 2264 return isBlank(str) ? Suppliers.get(defaultSupplier) : str; 2265 } 2266 2267 /** 2268 * Returns either the passed in CharSequence, or if the CharSequence is 2269 * empty or {@code null}, the value supplied by {@code defaultStrSupplier}. 2270 * 2271 * <p>Caller responsible for thread-safety and exception handling of default value supplier</p> 2272 * 2273 * <pre> 2274 * {@code 2275 * StringUtils.getIfEmpty(null, () -> "NULL") = "NULL" 2276 * StringUtils.getIfEmpty("", () -> "NULL") = "NULL" 2277 * StringUtils.getIfEmpty(" ", () -> "NULL") = " " 2278 * StringUtils.getIfEmpty("bat", () -> "NULL") = "bat" 2279 * StringUtils.getIfEmpty("", () -> null) = null 2280 * StringUtils.getIfEmpty("", null) = null 2281 * } 2282 * </pre> 2283 * @param <T> the specific kind of CharSequence 2284 * @param str the CharSequence to check, may be null 2285 * @param defaultSupplier the supplier of default CharSequence to return 2286 * if the input is empty ("") or {@code null}, may be null 2287 * @return the passed in CharSequence, or the default 2288 * @see StringUtils#defaultString(String, String) 2289 * @since 3.10 2290 */ 2291 public static <T extends CharSequence> T getIfEmpty(final T str, final Supplier<T> defaultSupplier) { 2292 return isEmpty(str) ? Suppliers.get(defaultSupplier) : str; 2293 } 2294 2295 /** 2296 * Find the Jaro Winkler Distance which indicates the similarity score between two Strings. 2297 * 2298 * <p>The Jaro measure is the weighted sum of percentage of matched characters from each file and transposed characters. 2299 * Winkler increased this measure for matching initial characters.</p> 2300 * 2301 * <p>This implementation is based on the Jaro Winkler similarity algorithm 2302 * from <a href="https://en.wikipedia.org/wiki/Jaro%E2%80%93Winkler_distance">https://en.wikipedia.org/wiki/Jaro%E2%80%93Winkler_distance</a>.</p> 2303 * 2304 * <pre> 2305 * StringUtils.getJaroWinklerDistance(null, null) = IllegalArgumentException 2306 * StringUtils.getJaroWinklerDistance("", "") = 0.0 2307 * StringUtils.getJaroWinklerDistance("", "a") = 0.0 2308 * StringUtils.getJaroWinklerDistance("aaapppp", "") = 0.0 2309 * StringUtils.getJaroWinklerDistance("frog", "fog") = 0.93 2310 * StringUtils.getJaroWinklerDistance("fly", "ant") = 0.0 2311 * StringUtils.getJaroWinklerDistance("elephant", "hippo") = 0.44 2312 * StringUtils.getJaroWinklerDistance("hippo", "elephant") = 0.44 2313 * StringUtils.getJaroWinklerDistance("hippo", "zzzzzzzz") = 0.0 2314 * StringUtils.getJaroWinklerDistance("hello", "hallo") = 0.88 2315 * StringUtils.getJaroWinklerDistance("ABC Corporation", "ABC Corp") = 0.93 2316 * StringUtils.getJaroWinklerDistance("D N H Enterprises Inc", "D & H Enterprises, Inc.") = 0.95 2317 * StringUtils.getJaroWinklerDistance("My Gym Children's Fitness Center", "My Gym. Childrens Fitness") = 0.92 2318 * StringUtils.getJaroWinklerDistance("PENNSYLVANIA", "PENNCISYLVNIA") = 0.88 2319 * </pre> 2320 * 2321 * @param first the first String, must not be null 2322 * @param second the second String, must not be null 2323 * @return result distance 2324 * @throws IllegalArgumentException if either String input {@code null} 2325 * @since 3.3 2326 * @deprecated As of 3.6, use Apache Commons Text 2327 * <a href="https://commons.apache.org/proper/commons-text/javadocs/api-release/org/apache/commons/text/similarity/JaroWinklerDistance.html"> 2328 * JaroWinklerDistance</a> instead 2329 */ 2330 @Deprecated 2331 public static double getJaroWinklerDistance(final CharSequence first, final CharSequence second) { 2332 final double DEFAULT_SCALING_FACTOR = 0.1; 2333 2334 if (first == null || second == null) { 2335 throw new IllegalArgumentException("Strings must not be null"); 2336 } 2337 2338 final int[] mtp = matches(first, second); 2339 final double m = mtp[0]; 2340 if (m == 0) { 2341 return 0D; 2342 } 2343 final double j = (m / first.length() + m / second.length() + (m - mtp[1]) / m) / 3; 2344 final double jw = j < 0.7D ? j : j + Math.min(DEFAULT_SCALING_FACTOR, 1D / mtp[3]) * mtp[2] * (1D - j); 2345 return Math.round(jw * 100.0D) / 100.0D; 2346 } 2347 2348 /** 2349 * Find the Levenshtein distance between two Strings. 2350 * 2351 * <p>This is the number of changes needed to change one String into 2352 * another, where each change is a single character modification (deletion, 2353 * insertion or substitution).</p> 2354 * 2355 * <p>The implementation uses a single-dimensional array of length s.length() + 1. See 2356 * <a href="https://blog.softwx.net/2014/12/optimizing-levenshtein-algorithm-in-c.html"> 2357 * https://blog.softwx.net/2014/12/optimizing-levenshtein-algorithm-in-c.html</a> for details.</p> 2358 * 2359 * <pre> 2360 * StringUtils.getLevenshteinDistance(null, *) = IllegalArgumentException 2361 * StringUtils.getLevenshteinDistance(*, null) = IllegalArgumentException 2362 * StringUtils.getLevenshteinDistance("", "") = 0 2363 * StringUtils.getLevenshteinDistance("", "a") = 1 2364 * StringUtils.getLevenshteinDistance("aaapppp", "") = 7 2365 * StringUtils.getLevenshteinDistance("frog", "fog") = 1 2366 * StringUtils.getLevenshteinDistance("fly", "ant") = 3 2367 * StringUtils.getLevenshteinDistance("elephant", "hippo") = 7 2368 * StringUtils.getLevenshteinDistance("hippo", "elephant") = 7 2369 * StringUtils.getLevenshteinDistance("hippo", "zzzzzzzz") = 8 2370 * StringUtils.getLevenshteinDistance("hello", "hallo") = 1 2371 * </pre> 2372 * 2373 * @param s the first String, must not be null 2374 * @param t the second String, must not be null 2375 * @return result distance 2376 * @throws IllegalArgumentException if either String input {@code null} 2377 * @since 3.0 Changed signature from getLevenshteinDistance(String, String) to 2378 * getLevenshteinDistance(CharSequence, CharSequence) 2379 * @deprecated As of 3.6, use Apache Commons Text 2380 * <a href="https://commons.apache.org/proper/commons-text/javadocs/api-release/org/apache/commons/text/similarity/LevenshteinDistance.html"> 2381 * LevenshteinDistance</a> instead 2382 */ 2383 @Deprecated 2384 public static int getLevenshteinDistance(CharSequence s, CharSequence t) { 2385 if (s == null || t == null) { 2386 throw new IllegalArgumentException("Strings must not be null"); 2387 } 2388 2389 int n = s.length(); 2390 int m = t.length(); 2391 2392 if (n == 0) { 2393 return m; 2394 } 2395 if (m == 0) { 2396 return n; 2397 } 2398 2399 if (n > m) { 2400 // swap the input strings to consume less memory 2401 final CharSequence tmp = s; 2402 s = t; 2403 t = tmp; 2404 n = m; 2405 m = t.length(); 2406 } 2407 2408 final int[] p = new int[n + 1]; 2409 // indexes into strings s and t 2410 int i; // iterates through s 2411 int j; // iterates through t 2412 int upperleft; 2413 int upper; 2414 2415 char jOfT; // jth character of t 2416 int cost; 2417 2418 for (i = 0; i <= n; i++) { 2419 p[i] = i; 2420 } 2421 2422 for (j = 1; j <= m; j++) { 2423 upperleft = p[0]; 2424 jOfT = t.charAt(j - 1); 2425 p[0] = j; 2426 2427 for (i = 1; i <= n; i++) { 2428 upper = p[i]; 2429 cost = s.charAt(i - 1) == jOfT ? 0 : 1; 2430 // minimum of cell to the left+1, to the top+1, diagonally left and up +cost 2431 p[i] = Math.min(Math.min(p[i - 1] + 1, p[i] + 1), upperleft + cost); 2432 upperleft = upper; 2433 } 2434 } 2435 2436 return p[n]; 2437 } 2438 2439 /** 2440 * Find the Levenshtein distance between two Strings if it's less than or equal to a given 2441 * threshold. 2442 * 2443 * <p>This is the number of changes needed to change one String into 2444 * another, where each change is a single character modification (deletion, 2445 * insertion or substitution).</p> 2446 * 2447 * <p>This implementation follows from Algorithms on Strings, Trees and Sequences by Dan Gusfield 2448 * and Chas Emerick's implementation of the Levenshtein distance algorithm from 2449 * <a href="https://web.archive.org/web/20120212021906/http%3A//www.merriampark.com/ld.htm">http://www.merriampark.com/ld.htm</a></p> 2450 * 2451 * <pre> 2452 * StringUtils.getLevenshteinDistance(null, *, *) = IllegalArgumentException 2453 * StringUtils.getLevenshteinDistance(*, null, *) = IllegalArgumentException 2454 * StringUtils.getLevenshteinDistance(*, *, -1) = IllegalArgumentException 2455 * StringUtils.getLevenshteinDistance("", "", 0) = 0 2456 * StringUtils.getLevenshteinDistance("aaapppp", "", 8) = 7 2457 * StringUtils.getLevenshteinDistance("aaapppp", "", 7) = 7 2458 * StringUtils.getLevenshteinDistance("aaapppp", "", 6)) = -1 2459 * StringUtils.getLevenshteinDistance("elephant", "hippo", 7) = 7 2460 * StringUtils.getLevenshteinDistance("elephant", "hippo", 6) = -1 2461 * StringUtils.getLevenshteinDistance("hippo", "elephant", 7) = 7 2462 * StringUtils.getLevenshteinDistance("hippo", "elephant", 6) = -1 2463 * </pre> 2464 * 2465 * @param s the first String, must not be null 2466 * @param t the second String, must not be null 2467 * @param threshold the target threshold, must not be negative 2468 * @return result distance, or {@code -1} if the distance would be greater than the threshold 2469 * @throws IllegalArgumentException if either String input {@code null} or negative threshold 2470 * @deprecated As of 3.6, use Apache Commons Text 2471 * <a href="https://commons.apache.org/proper/commons-text/javadocs/api-release/org/apache/commons/text/similarity/LevenshteinDistance.html"> 2472 * LevenshteinDistance</a> instead 2473 */ 2474 @Deprecated 2475 public static int getLevenshteinDistance(CharSequence s, CharSequence t, final int threshold) { 2476 if (s == null || t == null) { 2477 throw new IllegalArgumentException("Strings must not be null"); 2478 } 2479 if (threshold < 0) { 2480 throw new IllegalArgumentException("Threshold must not be negative"); 2481 } 2482 2483 /* 2484 This implementation only computes the distance if it's less than or equal to the 2485 threshold value, returning -1 if it's greater. The advantage is performance: unbounded 2486 distance is O(nm), but a bound of k allows us to reduce it to O(km) time by only 2487 computing a diagonal stripe of width 2k + 1 of the cost table. 2488 It is also possible to use this to compute the unbounded Levenshtein distance by starting 2489 the threshold at 1 and doubling each time until the distance is found; this is O(dm), where 2490 d is the distance. 2491 2492 One subtlety comes from needing to ignore entries on the border of our stripe 2493 eg. 2494 p[] = |#|#|#|* 2495 d[] = *|#|#|#| 2496 We must ignore the entry to the left of the leftmost member 2497 We must ignore the entry above the rightmost member 2498 2499 Another subtlety comes from our stripe running off the matrix if the strings aren't 2500 of the same size. Since string s is always swapped to be the shorter of the two, 2501 the stripe will always run off to the upper right instead of the lower left of the matrix. 2502 2503 As a concrete example, suppose s is of length 5, t is of length 7, and our threshold is 1. 2504 In this case we're going to walk a stripe of length 3. The matrix would look like so: 2505 2506 1 2 3 4 5 2507 1 |#|#| | | | 2508 2 |#|#|#| | | 2509 3 | |#|#|#| | 2510 4 | | |#|#|#| 2511 5 | | | |#|#| 2512 6 | | | | |#| 2513 7 | | | | | | 2514 2515 Note how the stripe leads off the table as there is no possible way to turn a string of length 5 2516 into one of length 7 in edit distance of 1. 2517 2518 Additionally, this implementation decreases memory usage by using two 2519 single-dimensional arrays and swapping them back and forth instead of allocating 2520 an entire n by m matrix. This requires a few minor changes, such as immediately returning 2521 when it's detected that the stripe has run off the matrix and initially filling the arrays with 2522 large values so that entries we don't compute are ignored. 2523 2524 See Algorithms on Strings, Trees and Sequences by Dan Gusfield for some discussion. 2525 */ 2526 2527 int n = s.length(); // length of s 2528 int m = t.length(); // length of t 2529 2530 // if one string is empty, the edit distance is necessarily the length of the other 2531 if (n == 0) { 2532 return m <= threshold ? m : -1; 2533 } 2534 if (m == 0) { 2535 return n <= threshold ? n : -1; 2536 } 2537 if (Math.abs(n - m) > threshold) { 2538 // no need to calculate the distance if the length difference is greater than the threshold 2539 return -1; 2540 } 2541 2542 if (n > m) { 2543 // swap the two strings to consume less memory 2544 final CharSequence tmp = s; 2545 s = t; 2546 t = tmp; 2547 n = m; 2548 m = t.length(); 2549 } 2550 2551 int[] p = new int[n + 1]; // 'previous' cost array, horizontally 2552 int[] d = new int[n + 1]; // cost array, horizontally 2553 int[] tmp; // placeholder to assist in swapping p and d 2554 2555 // fill in starting table values 2556 final int boundary = Math.min(n, threshold) + 1; 2557 for (int i = 0; i < boundary; i++) { 2558 p[i] = i; 2559 } 2560 // these fills ensure that the value above the rightmost entry of our 2561 // stripe will be ignored in following loop iterations 2562 Arrays.fill(p, boundary, p.length, Integer.MAX_VALUE); 2563 Arrays.fill(d, Integer.MAX_VALUE); 2564 2565 // iterates through t 2566 for (int j = 1; j <= m; j++) { 2567 final char jOfT = t.charAt(j - 1); // jth character of t 2568 d[0] = j; 2569 2570 // compute stripe indices, constrain to array size 2571 final int min = Math.max(1, j - threshold); 2572 final int max = j > Integer.MAX_VALUE - threshold ? n : Math.min(n, j + threshold); 2573 2574 // the stripe may lead off of the table if s and t are of different sizes 2575 if (min > max) { 2576 return -1; 2577 } 2578 2579 // ignore entry left of leftmost 2580 if (min > 1) { 2581 d[min - 1] = Integer.MAX_VALUE; 2582 } 2583 2584 // iterates through [min, max] in s 2585 for (int i = min; i <= max; i++) { 2586 if (s.charAt(i - 1) == jOfT) { 2587 // diagonally left and up 2588 d[i] = p[i - 1]; 2589 } else { 2590 // 1 + minimum of cell to the left, to the top, diagonally left and up 2591 d[i] = 1 + Math.min(Math.min(d[i - 1], p[i]), p[i - 1]); 2592 } 2593 } 2594 2595 // copy current distance counts to 'previous row' distance counts 2596 tmp = p; 2597 p = d; 2598 d = tmp; 2599 } 2600 2601 // if p[n] is greater than the threshold, there's no guarantee on it being the correct 2602 // distance 2603 if (p[n] <= threshold) { 2604 return p[n]; 2605 } 2606 return -1; 2607 } 2608 2609 /** 2610 * Finds the first index within a CharSequence, handling {@code null}. 2611 * This method uses {@link String#indexOf(String, int)} if possible. 2612 * 2613 * <p>A {@code null} CharSequence will return {@code -1}.</p> 2614 * 2615 * <pre> 2616 * StringUtils.indexOf(null, *) = -1 2617 * StringUtils.indexOf(*, null) = -1 2618 * StringUtils.indexOf("", "") = 0 2619 * StringUtils.indexOf("", *) = -1 (except when * = "") 2620 * StringUtils.indexOf("aabaabaa", "a") = 0 2621 * StringUtils.indexOf("aabaabaa", "b") = 2 2622 * StringUtils.indexOf("aabaabaa", "ab") = 1 2623 * StringUtils.indexOf("aabaabaa", "") = 0 2624 * </pre> 2625 * 2626 * @param seq the CharSequence to check, may be null 2627 * @param searchSeq the CharSequence to find, may be null 2628 * @return the first index of the search CharSequence, 2629 * -1 if no match or {@code null} string input 2630 * @since 2.0 2631 * @since 3.0 Changed signature from indexOf(String, String) to indexOf(CharSequence, CharSequence) 2632 */ 2633 public static int indexOf(final CharSequence seq, final CharSequence searchSeq) { 2634 if (seq == null || searchSeq == null) { 2635 return INDEX_NOT_FOUND; 2636 } 2637 return CharSequenceUtils.indexOf(seq, searchSeq, 0); 2638 } 2639 2640 /** 2641 * Finds the first index within a CharSequence, handling {@code null}. 2642 * This method uses {@link String#indexOf(String, int)} if possible. 2643 * 2644 * <p>A {@code null} CharSequence will return {@code -1}. 2645 * A negative start position is treated as zero. 2646 * An empty ("") search CharSequence always matches. 2647 * A start position greater than the string length only matches 2648 * an empty search CharSequence.</p> 2649 * 2650 * <pre> 2651 * StringUtils.indexOf(null, *, *) = -1 2652 * StringUtils.indexOf(*, null, *) = -1 2653 * StringUtils.indexOf("", "", 0) = 0 2654 * StringUtils.indexOf("", *, 0) = -1 (except when * = "") 2655 * StringUtils.indexOf("aabaabaa", "a", 0) = 0 2656 * StringUtils.indexOf("aabaabaa", "b", 0) = 2 2657 * StringUtils.indexOf("aabaabaa", "ab", 0) = 1 2658 * StringUtils.indexOf("aabaabaa", "b", 3) = 5 2659 * StringUtils.indexOf("aabaabaa", "b", 9) = -1 2660 * StringUtils.indexOf("aabaabaa", "b", -1) = 2 2661 * StringUtils.indexOf("aabaabaa", "", 2) = 2 2662 * StringUtils.indexOf("abc", "", 9) = 3 2663 * </pre> 2664 * 2665 * @param seq the CharSequence to check, may be null 2666 * @param searchSeq the CharSequence to find, may be null 2667 * @param startPos the start position, negative treated as zero 2668 * @return the first index of the search CharSequence (always ≥ startPos), 2669 * -1 if no match or {@code null} string input 2670 * @since 2.0 2671 * @since 3.0 Changed signature from indexOf(String, String, int) to indexOf(CharSequence, CharSequence, int) 2672 */ 2673 public static int indexOf(final CharSequence seq, final CharSequence searchSeq, final int startPos) { 2674 if (seq == null || searchSeq == null) { 2675 return INDEX_NOT_FOUND; 2676 } 2677 return CharSequenceUtils.indexOf(seq, searchSeq, startPos); 2678 } 2679 2680 /** 2681 * Returns the index within {@code seq} of the first occurrence of 2682 * the specified character. If a character with value 2683 * {@code searchChar} occurs in the character sequence represented by 2684 * {@code seq} {@link CharSequence} object, then the index (in Unicode 2685 * code units) of the first such occurrence is returned. For 2686 * values of {@code searchChar} in the range from 0 to 0xFFFF 2687 * (inclusive), this is the smallest value <em>k</em> such that: 2688 * <blockquote><pre> 2689 * this.charAt(<em>k</em>) == searchChar 2690 * </pre></blockquote> 2691 * is true. For other values of {@code searchChar}, it is the 2692 * smallest value <em>k</em> such that: 2693 * <blockquote><pre> 2694 * this.codePointAt(<em>k</em>) == searchChar 2695 * </pre></blockquote> 2696 * is true. In either case, if no such character occurs in {@code seq}, 2697 * then {@code INDEX_NOT_FOUND (-1)} is returned. 2698 * 2699 * <p>Furthermore, a {@code null} or empty ("") CharSequence will 2700 * return {@code INDEX_NOT_FOUND (-1)}.</p> 2701 * 2702 * <pre> 2703 * StringUtils.indexOf(null, *) = -1 2704 * StringUtils.indexOf("", *) = -1 2705 * StringUtils.indexOf("aabaabaa", 'a') = 0 2706 * StringUtils.indexOf("aabaabaa", 'b') = 2 2707 * </pre> 2708 * 2709 * @param seq the CharSequence to check, may be null 2710 * @param searchChar the character to find 2711 * @return the first index of the search character, 2712 * -1 if no match or {@code null} string input 2713 * @since 2.0 2714 * @since 3.0 Changed signature from indexOf(String, int) to indexOf(CharSequence, int) 2715 * @since 3.6 Updated {@link CharSequenceUtils} call to behave more like {@link String} 2716 */ 2717 public static int indexOf(final CharSequence seq, final int searchChar) { 2718 if (isEmpty(seq)) { 2719 return INDEX_NOT_FOUND; 2720 } 2721 return CharSequenceUtils.indexOf(seq, searchChar, 0); 2722 } 2723 2724 /** 2725 * Returns the index within {@code seq} of the first occurrence of the 2726 * specified character, starting the search at the specified index. 2727 * <p> 2728 * If a character with value {@code searchChar} occurs in the 2729 * character sequence represented by the {@code seq} {@link CharSequence} 2730 * object at an index no smaller than {@code startPos}, then 2731 * the index of the first such occurrence is returned. For values 2732 * of {@code searchChar} in the range from 0 to 0xFFFF (inclusive), 2733 * this is the smallest value <em>k</em> such that: 2734 * <blockquote><pre> 2735 * (this.charAt(<em>k</em>) == searchChar) && (<em>k</em> >= startPos) 2736 * </pre></blockquote> 2737 * is true. For other values of {@code searchChar}, it is the 2738 * smallest value <em>k</em> such that: 2739 * <blockquote><pre> 2740 * (this.codePointAt(<em>k</em>) == searchChar) && (<em>k</em> >= startPos) 2741 * </pre></blockquote> 2742 * is true. In either case, if no such character occurs in {@code seq} 2743 * at or after position {@code startPos}, then 2744 * {@code -1} is returned. 2745 * 2746 * <p> 2747 * There is no restriction on the value of {@code startPos}. If it 2748 * is negative, it has the same effect as if it were zero: this entire 2749 * string may be searched. If it is greater than the length of this 2750 * string, it has the same effect as if it were equal to the length of 2751 * this string: {@code (INDEX_NOT_FOUND) -1} is returned. Furthermore, a 2752 * {@code null} or empty ("") CharSequence will 2753 * return {@code (INDEX_NOT_FOUND) -1}. 2754 * 2755 * <p>All indices are specified in {@code char} values 2756 * (Unicode code units). 2757 * 2758 * <pre> 2759 * StringUtils.indexOf(null, *, *) = -1 2760 * StringUtils.indexOf("", *, *) = -1 2761 * StringUtils.indexOf("aabaabaa", 'b', 0) = 2 2762 * StringUtils.indexOf("aabaabaa", 'b', 3) = 5 2763 * StringUtils.indexOf("aabaabaa", 'b', 9) = -1 2764 * StringUtils.indexOf("aabaabaa", 'b', -1) = 2 2765 * </pre> 2766 * 2767 * @param seq the CharSequence to check, may be null 2768 * @param searchChar the character to find 2769 * @param startPos the start position, negative treated as zero 2770 * @return the first index of the search character (always ≥ startPos), 2771 * -1 if no match or {@code null} string input 2772 * @since 2.0 2773 * @since 3.0 Changed signature from indexOf(String, int, int) to indexOf(CharSequence, int, int) 2774 * @since 3.6 Updated {@link CharSequenceUtils} call to behave more like {@link String} 2775 */ 2776 public static int indexOf(final CharSequence seq, final int searchChar, final int startPos) { 2777 if (isEmpty(seq)) { 2778 return INDEX_NOT_FOUND; 2779 } 2780 return CharSequenceUtils.indexOf(seq, searchChar, startPos); 2781 } 2782 2783 /** 2784 * Search a CharSequence to find the first index of any 2785 * character in the given set of characters. 2786 * 2787 * <p>A {@code null} String will return {@code -1}. 2788 * A {@code null} or zero length search array will return {@code -1}.</p> 2789 * 2790 * <pre> 2791 * StringUtils.indexOfAny(null, *) = -1 2792 * StringUtils.indexOfAny("", *) = -1 2793 * StringUtils.indexOfAny(*, null) = -1 2794 * StringUtils.indexOfAny(*, []) = -1 2795 * StringUtils.indexOfAny("zzabyycdxx", ['z', 'a']) = 0 2796 * StringUtils.indexOfAny("zzabyycdxx", ['b', 'y']) = 3 2797 * StringUtils.indexOfAny("aba", ['z']) = -1 2798 * </pre> 2799 * 2800 * @param cs the CharSequence to check, may be null 2801 * @param searchChars the chars to search for, may be null 2802 * @return the index of any of the chars, -1 if no match or null input 2803 * @since 2.0 2804 * @since 3.0 Changed signature from indexOfAny(String, char[]) to indexOfAny(CharSequence, char...) 2805 */ 2806 public static int indexOfAny(final CharSequence cs, final char... searchChars) { 2807 if (isEmpty(cs) || ArrayUtils.isEmpty(searchChars)) { 2808 return INDEX_NOT_FOUND; 2809 } 2810 final int csLen = cs.length(); 2811 final int csLast = csLen - 1; 2812 final int searchLen = searchChars.length; 2813 final int searchLast = searchLen - 1; 2814 for (int i = 0; i < csLen; i++) { 2815 final char ch = cs.charAt(i); 2816 for (int j = 0; j < searchLen; j++) { 2817 if (searchChars[j] == ch) { 2818 if (i >= csLast || j >= searchLast || !Character.isHighSurrogate(ch)) { 2819 return i; 2820 } 2821 // ch is a supplementary character 2822 if (searchChars[j + 1] == cs.charAt(i + 1)) { 2823 return i; 2824 } 2825 } 2826 } 2827 } 2828 return INDEX_NOT_FOUND; 2829 } 2830 2831 /** 2832 * Find the first index of any of a set of potential substrings. 2833 * 2834 * <p>A {@code null} CharSequence will return {@code -1}. 2835 * A {@code null} or zero length search array will return {@code -1}. 2836 * A {@code null} search array entry will be ignored, but a search 2837 * array containing "" will return {@code 0} if {@code str} is not 2838 * null. This method uses {@link String#indexOf(String)} if possible.</p> 2839 * 2840 * <pre> 2841 * StringUtils.indexOfAny(null, *) = -1 2842 * StringUtils.indexOfAny(*, null) = -1 2843 * StringUtils.indexOfAny(*, []) = -1 2844 * StringUtils.indexOfAny("zzabyycdxx", ["ab", "cd"]) = 2 2845 * StringUtils.indexOfAny("zzabyycdxx", ["cd", "ab"]) = 2 2846 * StringUtils.indexOfAny("zzabyycdxx", ["mn", "op"]) = -1 2847 * StringUtils.indexOfAny("zzabyycdxx", ["zab", "aby"]) = 1 2848 * StringUtils.indexOfAny("zzabyycdxx", [""]) = 0 2849 * StringUtils.indexOfAny("", [""]) = 0 2850 * StringUtils.indexOfAny("", ["a"]) = -1 2851 * </pre> 2852 * 2853 * @param str the CharSequence to check, may be null 2854 * @param searchStrs the CharSequences to search for, may be null 2855 * @return the first index of any of the searchStrs in str, -1 if no match 2856 * @since 3.0 Changed signature from indexOfAny(String, String[]) to indexOfAny(CharSequence, CharSequence...) 2857 */ 2858 public static int indexOfAny(final CharSequence str, final CharSequence... searchStrs) { 2859 if (str == null || searchStrs == null) { 2860 return INDEX_NOT_FOUND; 2861 } 2862 2863 // String's can't have a MAX_VALUEth index. 2864 int ret = Integer.MAX_VALUE; 2865 2866 int tmp; 2867 for (final CharSequence search : searchStrs) { 2868 if (search == null) { 2869 continue; 2870 } 2871 tmp = CharSequenceUtils.indexOf(str, search, 0); 2872 if (tmp == INDEX_NOT_FOUND) { 2873 continue; 2874 } 2875 2876 if (tmp < ret) { 2877 ret = tmp; 2878 } 2879 } 2880 2881 return ret == Integer.MAX_VALUE ? INDEX_NOT_FOUND : ret; 2882 } 2883 2884 /** 2885 * Search a CharSequence to find the first index of any 2886 * character in the given set of characters. 2887 * 2888 * <p>A {@code null} String will return {@code -1}. 2889 * A {@code null} search string will return {@code -1}.</p> 2890 * 2891 * <pre> 2892 * StringUtils.indexOfAny(null, *) = -1 2893 * StringUtils.indexOfAny("", *) = -1 2894 * StringUtils.indexOfAny(*, null) = -1 2895 * StringUtils.indexOfAny(*, "") = -1 2896 * StringUtils.indexOfAny("zzabyycdxx", "za") = 0 2897 * StringUtils.indexOfAny("zzabyycdxx", "by") = 3 2898 * StringUtils.indexOfAny("aba", "z") = -1 2899 * </pre> 2900 * 2901 * @param cs the CharSequence to check, may be null 2902 * @param searchChars the chars to search for, may be null 2903 * @return the index of any of the chars, -1 if no match or null input 2904 * @since 2.0 2905 * @since 3.0 Changed signature from indexOfAny(String, String) to indexOfAny(CharSequence, String) 2906 */ 2907 public static int indexOfAny(final CharSequence cs, final String searchChars) { 2908 if (isEmpty(cs) || isEmpty(searchChars)) { 2909 return INDEX_NOT_FOUND; 2910 } 2911 return indexOfAny(cs, searchChars.toCharArray()); 2912 } 2913 2914 /** 2915 * Searches a CharSequence to find the first index of any 2916 * character not in the given set of characters. 2917 * 2918 * <p>A {@code null} CharSequence will return {@code -1}. 2919 * A {@code null} or zero length search array will return {@code -1}.</p> 2920 * 2921 * <pre> 2922 * StringUtils.indexOfAnyBut(null, *) = -1 2923 * StringUtils.indexOfAnyBut("", *) = -1 2924 * StringUtils.indexOfAnyBut(*, null) = -1 2925 * StringUtils.indexOfAnyBut(*, []) = -1 2926 * StringUtils.indexOfAnyBut("zzabyycdxx", new char[] {'z', 'a'} ) = 3 2927 * StringUtils.indexOfAnyBut("aba", new char[] {'z'} ) = 0 2928 * StringUtils.indexOfAnyBut("aba", new char[] {'a', 'b'} ) = -1 2929 2930 * </pre> 2931 * 2932 * @param cs the CharSequence to check, may be null 2933 * @param searchChars the chars to search for, may be null 2934 * @return the index of any of the chars, -1 if no match or null input 2935 * @since 2.0 2936 * @since 3.0 Changed signature from indexOfAnyBut(String, char[]) to indexOfAnyBut(CharSequence, char...) 2937 */ 2938 public static int indexOfAnyBut(final CharSequence cs, final char... searchChars) { 2939 if (isEmpty(cs) || ArrayUtils.isEmpty(searchChars)) { 2940 return INDEX_NOT_FOUND; 2941 } 2942 final int csLen = cs.length(); 2943 final int csLast = csLen - 1; 2944 final int searchLen = searchChars.length; 2945 final int searchLast = searchLen - 1; 2946 outer: 2947 for (int i = 0; i < csLen; i++) { 2948 final char ch = cs.charAt(i); 2949 for (int j = 0; j < searchLen; j++) { 2950 if (searchChars[j] == ch) { 2951 if (i >= csLast || j >= searchLast || !Character.isHighSurrogate(ch)) { 2952 continue outer; 2953 } 2954 if (searchChars[j + 1] == cs.charAt(i + 1)) { 2955 continue outer; 2956 } 2957 } 2958 } 2959 return i; 2960 } 2961 return INDEX_NOT_FOUND; 2962 } 2963 2964 /** 2965 * Search a CharSequence to find the first index of any 2966 * character not in the given set of characters. 2967 * 2968 * <p>A {@code null} CharSequence will return {@code -1}. 2969 * A {@code null} or empty search string will return {@code -1}.</p> 2970 * 2971 * <pre> 2972 * StringUtils.indexOfAnyBut(null, *) = -1 2973 * StringUtils.indexOfAnyBut("", *) = -1 2974 * StringUtils.indexOfAnyBut(*, null) = -1 2975 * StringUtils.indexOfAnyBut(*, "") = -1 2976 * StringUtils.indexOfAnyBut("zzabyycdxx", "za") = 3 2977 * StringUtils.indexOfAnyBut("zzabyycdxx", "") = -1 2978 * StringUtils.indexOfAnyBut("aba", "ab") = -1 2979 * </pre> 2980 * 2981 * @param seq the CharSequence to check, may be null 2982 * @param searchChars the chars to search for, may be null 2983 * @return the index of any of the chars, -1 if no match or null input 2984 * @since 2.0 2985 * @since 3.0 Changed signature from indexOfAnyBut(String, String) to indexOfAnyBut(CharSequence, CharSequence) 2986 */ 2987 public static int indexOfAnyBut(final CharSequence seq, final CharSequence searchChars) { 2988 if (isEmpty(seq) || isEmpty(searchChars)) { 2989 return INDEX_NOT_FOUND; 2990 } 2991 final int strLen = seq.length(); 2992 for (int i = 0; i < strLen; i++) { 2993 final char ch = seq.charAt(i); 2994 final boolean chFound = CharSequenceUtils.indexOf(searchChars, ch, 0) >= 0; 2995 if (i + 1 < strLen && Character.isHighSurrogate(ch)) { 2996 final char ch2 = seq.charAt(i + 1); 2997 if (chFound && CharSequenceUtils.indexOf(searchChars, ch2, 0) < 0) { 2998 return i; 2999 } 3000 } else if (!chFound) { 3001 return i; 3002 } 3003 } 3004 return INDEX_NOT_FOUND; 3005 } 3006 3007 /** 3008 * Compares all CharSequences in an array and returns the index at which the 3009 * CharSequences begin to differ. 3010 * 3011 * <p>For example, 3012 * {@code indexOfDifference(new String[] {"i am a machine", "i am a robot"}) -> 7}</p> 3013 * 3014 * <pre> 3015 * StringUtils.indexOfDifference(null) = -1 3016 * StringUtils.indexOfDifference(new String[] {}) = -1 3017 * StringUtils.indexOfDifference(new String[] {"abc"}) = -1 3018 * StringUtils.indexOfDifference(new String[] {null, null}) = -1 3019 * StringUtils.indexOfDifference(new String[] {"", ""}) = -1 3020 * StringUtils.indexOfDifference(new String[] {"", null}) = 0 3021 * StringUtils.indexOfDifference(new String[] {"abc", null, null}) = 0 3022 * StringUtils.indexOfDifference(new String[] {null, null, "abc"}) = 0 3023 * StringUtils.indexOfDifference(new String[] {"", "abc"}) = 0 3024 * StringUtils.indexOfDifference(new String[] {"abc", ""}) = 0 3025 * StringUtils.indexOfDifference(new String[] {"abc", "abc"}) = -1 3026 * StringUtils.indexOfDifference(new String[] {"abc", "a"}) = 1 3027 * StringUtils.indexOfDifference(new String[] {"ab", "abxyz"}) = 2 3028 * StringUtils.indexOfDifference(new String[] {"abcde", "abxyz"}) = 2 3029 * StringUtils.indexOfDifference(new String[] {"abcde", "xyz"}) = 0 3030 * StringUtils.indexOfDifference(new String[] {"xyz", "abcde"}) = 0 3031 * StringUtils.indexOfDifference(new String[] {"i am a machine", "i am a robot"}) = 7 3032 * </pre> 3033 * 3034 * @param css array of CharSequences, entries may be null 3035 * @return the index where the strings begin to differ; -1 if they are all equal 3036 * @since 2.4 3037 * @since 3.0 Changed signature from indexOfDifference(String...) to indexOfDifference(CharSequence...) 3038 */ 3039 public static int indexOfDifference(final CharSequence... css) { 3040 if (ArrayUtils.getLength(css) <= 1) { 3041 return INDEX_NOT_FOUND; 3042 } 3043 boolean anyStringNull = false; 3044 boolean allStringsNull = true; 3045 final int arrayLen = css.length; 3046 int shortestStrLen = Integer.MAX_VALUE; 3047 int longestStrLen = 0; 3048 3049 // find the min and max string lengths; this avoids checking to make 3050 // sure we are not exceeding the length of the string each time through 3051 // the bottom loop. 3052 for (final CharSequence cs : css) { 3053 if (cs == null) { 3054 anyStringNull = true; 3055 shortestStrLen = 0; 3056 } else { 3057 allStringsNull = false; 3058 shortestStrLen = Math.min(cs.length(), shortestStrLen); 3059 longestStrLen = Math.max(cs.length(), longestStrLen); 3060 } 3061 } 3062 3063 // handle lists containing all nulls or all empty strings 3064 if (allStringsNull || longestStrLen == 0 && !anyStringNull) { 3065 return INDEX_NOT_FOUND; 3066 } 3067 3068 // handle lists containing some nulls or some empty strings 3069 if (shortestStrLen == 0) { 3070 return 0; 3071 } 3072 3073 // find the position with the first difference across all strings 3074 int firstDiff = -1; 3075 for (int stringPos = 0; stringPos < shortestStrLen; stringPos++) { 3076 final char comparisonChar = css[0].charAt(stringPos); 3077 for (int arrayPos = 1; arrayPos < arrayLen; arrayPos++) { 3078 if (css[arrayPos].charAt(stringPos) != comparisonChar) { 3079 firstDiff = stringPos; 3080 break; 3081 } 3082 } 3083 if (firstDiff != -1) { 3084 break; 3085 } 3086 } 3087 3088 if (firstDiff == -1 && shortestStrLen != longestStrLen) { 3089 // we compared all of the characters up to the length of the 3090 // shortest string and didn't find a match, but the string lengths 3091 // vary, so return the length of the shortest string. 3092 return shortestStrLen; 3093 } 3094 return firstDiff; 3095 } 3096 3097 /** 3098 * Compares two CharSequences, and returns the index at which the 3099 * CharSequences begin to differ. 3100 * 3101 * <p>For example, 3102 * {@code indexOfDifference("i am a machine", "i am a robot") -> 7}</p> 3103 * 3104 * <pre> 3105 * StringUtils.indexOfDifference(null, null) = -1 3106 * StringUtils.indexOfDifference("", "") = -1 3107 * StringUtils.indexOfDifference("", "abc") = 0 3108 * StringUtils.indexOfDifference("abc", "") = 0 3109 * StringUtils.indexOfDifference("abc", "abc") = -1 3110 * StringUtils.indexOfDifference("ab", "abxyz") = 2 3111 * StringUtils.indexOfDifference("abcde", "abxyz") = 2 3112 * StringUtils.indexOfDifference("abcde", "xyz") = 0 3113 * </pre> 3114 * 3115 * @param cs1 the first CharSequence, may be null 3116 * @param cs2 the second CharSequence, may be null 3117 * @return the index where cs1 and cs2 begin to differ; -1 if they are equal 3118 * @since 2.0 3119 * @since 3.0 Changed signature from indexOfDifference(String, String) to 3120 * indexOfDifference(CharSequence, CharSequence) 3121 */ 3122 public static int indexOfDifference(final CharSequence cs1, final CharSequence cs2) { 3123 if (cs1 == cs2) { 3124 return INDEX_NOT_FOUND; 3125 } 3126 if (cs1 == null || cs2 == null) { 3127 return 0; 3128 } 3129 int i; 3130 for (i = 0; i < cs1.length() && i < cs2.length(); ++i) { 3131 if (cs1.charAt(i) != cs2.charAt(i)) { 3132 break; 3133 } 3134 } 3135 if (i < cs2.length() || i < cs1.length()) { 3136 return i; 3137 } 3138 return INDEX_NOT_FOUND; 3139 } 3140 3141 /** 3142 * Case in-sensitive find of the first index within a CharSequence. 3143 * 3144 * <p>A {@code null} CharSequence will return {@code -1}. 3145 * A negative start position is treated as zero. 3146 * An empty ("") search CharSequence always matches. 3147 * A start position greater than the string length only matches 3148 * an empty search CharSequence.</p> 3149 * 3150 * <pre> 3151 * StringUtils.indexOfIgnoreCase(null, *) = -1 3152 * StringUtils.indexOfIgnoreCase(*, null) = -1 3153 * StringUtils.indexOfIgnoreCase("", "") = 0 3154 * StringUtils.indexOfIgnoreCase(" ", " ") = 0 3155 * StringUtils.indexOfIgnoreCase("aabaabaa", "a") = 0 3156 * StringUtils.indexOfIgnoreCase("aabaabaa", "b") = 2 3157 * StringUtils.indexOfIgnoreCase("aabaabaa", "ab") = 1 3158 * </pre> 3159 * 3160 * @param str the CharSequence to check, may be null 3161 * @param searchStr the CharSequence to find, may be null 3162 * @return the first index of the search CharSequence, 3163 * -1 if no match or {@code null} string input 3164 * @since 2.5 3165 * @since 3.0 Changed signature from indexOfIgnoreCase(String, String) to indexOfIgnoreCase(CharSequence, CharSequence) 3166 */ 3167 public static int indexOfIgnoreCase(final CharSequence str, final CharSequence searchStr) { 3168 return indexOfIgnoreCase(str, searchStr, 0); 3169 } 3170 3171 /** 3172 * Case in-sensitive find of the first index within a CharSequence 3173 * from the specified position. 3174 * 3175 * <p>A {@code null} CharSequence will return {@code -1}. 3176 * A negative start position is treated as zero. 3177 * An empty ("") search CharSequence always matches. 3178 * A start position greater than the string length only matches 3179 * an empty search CharSequence.</p> 3180 * 3181 * <pre> 3182 * StringUtils.indexOfIgnoreCase(null, *, *) = -1 3183 * StringUtils.indexOfIgnoreCase(*, null, *) = -1 3184 * StringUtils.indexOfIgnoreCase("", "", 0) = 0 3185 * StringUtils.indexOfIgnoreCase("aabaabaa", "A", 0) = 0 3186 * StringUtils.indexOfIgnoreCase("aabaabaa", "B", 0) = 2 3187 * StringUtils.indexOfIgnoreCase("aabaabaa", "AB", 0) = 1 3188 * StringUtils.indexOfIgnoreCase("aabaabaa", "B", 3) = 5 3189 * StringUtils.indexOfIgnoreCase("aabaabaa", "B", 9) = -1 3190 * StringUtils.indexOfIgnoreCase("aabaabaa", "B", -1) = 2 3191 * StringUtils.indexOfIgnoreCase("aabaabaa", "", 2) = 2 3192 * StringUtils.indexOfIgnoreCase("abc", "", 9) = -1 3193 * </pre> 3194 * 3195 * @param str the CharSequence to check, may be null 3196 * @param searchStr the CharSequence to find, may be null 3197 * @param startPos the start position, negative treated as zero 3198 * @return the first index of the search CharSequence (always ≥ startPos), 3199 * -1 if no match or {@code null} string input 3200 * @since 2.5 3201 * @since 3.0 Changed signature from indexOfIgnoreCase(String, String, int) to indexOfIgnoreCase(CharSequence, CharSequence, int) 3202 */ 3203 public static int indexOfIgnoreCase(final CharSequence str, final CharSequence searchStr, int startPos) { 3204 if (str == null || searchStr == null) { 3205 return INDEX_NOT_FOUND; 3206 } 3207 if (startPos < 0) { 3208 startPos = 0; 3209 } 3210 final int endLimit = str.length() - searchStr.length() + 1; 3211 if (startPos > endLimit) { 3212 return INDEX_NOT_FOUND; 3213 } 3214 if (searchStr.length() == 0) { 3215 return startPos; 3216 } 3217 for (int i = startPos; i < endLimit; i++) { 3218 if (CharSequenceUtils.regionMatches(str, true, i, searchStr, 0, searchStr.length())) { 3219 return i; 3220 } 3221 } 3222 return INDEX_NOT_FOUND; 3223 } 3224 3225 /** 3226 * Checks if all of the CharSequences are empty (""), null or whitespace only. 3227 * 3228 * <p>Whitespace is defined by {@link Character#isWhitespace(char)}.</p> 3229 * 3230 * <pre> 3231 * StringUtils.isAllBlank(null) = true 3232 * StringUtils.isAllBlank(null, "foo") = false 3233 * StringUtils.isAllBlank(null, null) = true 3234 * StringUtils.isAllBlank("", "bar") = false 3235 * StringUtils.isAllBlank("bob", "") = false 3236 * StringUtils.isAllBlank(" bob ", null) = false 3237 * StringUtils.isAllBlank(" ", "bar") = false 3238 * StringUtils.isAllBlank("foo", "bar") = false 3239 * StringUtils.isAllBlank(new String[] {}) = true 3240 * </pre> 3241 * 3242 * @param css the CharSequences to check, may be null or empty 3243 * @return {@code true} if all of the CharSequences are empty or null or whitespace only 3244 * @since 3.6 3245 */ 3246 public static boolean isAllBlank(final CharSequence... css) { 3247 if (ArrayUtils.isEmpty(css)) { 3248 return true; 3249 } 3250 for (final CharSequence cs : css) { 3251 if (isNotBlank(cs)) { 3252 return false; 3253 } 3254 } 3255 return true; 3256 } 3257 3258 /** 3259 * Checks if all of the CharSequences are empty ("") or null. 3260 * 3261 * <pre> 3262 * StringUtils.isAllEmpty(null) = true 3263 * StringUtils.isAllEmpty(null, "") = true 3264 * StringUtils.isAllEmpty(new String[] {}) = true 3265 * StringUtils.isAllEmpty(null, "foo") = false 3266 * StringUtils.isAllEmpty("", "bar") = false 3267 * StringUtils.isAllEmpty("bob", "") = false 3268 * StringUtils.isAllEmpty(" bob ", null) = false 3269 * StringUtils.isAllEmpty(" ", "bar") = false 3270 * StringUtils.isAllEmpty("foo", "bar") = false 3271 * </pre> 3272 * 3273 * @param css the CharSequences to check, may be null or empty 3274 * @return {@code true} if all of the CharSequences are empty or null 3275 * @since 3.6 3276 */ 3277 public static boolean isAllEmpty(final CharSequence... css) { 3278 if (ArrayUtils.isEmpty(css)) { 3279 return true; 3280 } 3281 for (final CharSequence cs : css) { 3282 if (isNotEmpty(cs)) { 3283 return false; 3284 } 3285 } 3286 return true; 3287 } 3288 3289 /** 3290 * Checks if the CharSequence contains only lowercase characters. 3291 * 3292 * <p>{@code null} will return {@code false}. 3293 * An empty CharSequence (length()=0) will return {@code false}.</p> 3294 * 3295 * <pre> 3296 * StringUtils.isAllLowerCase(null) = false 3297 * StringUtils.isAllLowerCase("") = false 3298 * StringUtils.isAllLowerCase(" ") = false 3299 * StringUtils.isAllLowerCase("abc") = true 3300 * StringUtils.isAllLowerCase("abC") = false 3301 * StringUtils.isAllLowerCase("ab c") = false 3302 * StringUtils.isAllLowerCase("ab1c") = false 3303 * StringUtils.isAllLowerCase("ab/c") = false 3304 * </pre> 3305 * 3306 * @param cs the CharSequence to check, may be null 3307 * @return {@code true} if only contains lowercase characters, and is non-null 3308 * @since 2.5 3309 * @since 3.0 Changed signature from isAllLowerCase(String) to isAllLowerCase(CharSequence) 3310 */ 3311 public static boolean isAllLowerCase(final CharSequence cs) { 3312 if (isEmpty(cs)) { 3313 return false; 3314 } 3315 final int sz = cs.length(); 3316 for (int i = 0; i < sz; i++) { 3317 if (!Character.isLowerCase(cs.charAt(i))) { 3318 return false; 3319 } 3320 } 3321 return true; 3322 } 3323 3324 /** 3325 * Checks if the CharSequence contains only uppercase characters. 3326 * 3327 * <p>{@code null} will return {@code false}. 3328 * An empty String (length()=0) will return {@code false}.</p> 3329 * 3330 * <pre> 3331 * StringUtils.isAllUpperCase(null) = false 3332 * StringUtils.isAllUpperCase("") = false 3333 * StringUtils.isAllUpperCase(" ") = false 3334 * StringUtils.isAllUpperCase("ABC") = true 3335 * StringUtils.isAllUpperCase("aBC") = false 3336 * StringUtils.isAllUpperCase("A C") = false 3337 * StringUtils.isAllUpperCase("A1C") = false 3338 * StringUtils.isAllUpperCase("A/C") = false 3339 * </pre> 3340 * 3341 * @param cs the CharSequence to check, may be null 3342 * @return {@code true} if only contains uppercase characters, and is non-null 3343 * @since 2.5 3344 * @since 3.0 Changed signature from isAllUpperCase(String) to isAllUpperCase(CharSequence) 3345 */ 3346 public static boolean isAllUpperCase(final CharSequence cs) { 3347 if (isEmpty(cs)) { 3348 return false; 3349 } 3350 final int sz = cs.length(); 3351 for (int i = 0; i < sz; i++) { 3352 if (!Character.isUpperCase(cs.charAt(i))) { 3353 return false; 3354 } 3355 } 3356 return true; 3357 } 3358 3359 /** 3360 * Checks if the CharSequence contains only Unicode letters. 3361 * 3362 * <p>{@code null} will return {@code false}. 3363 * An empty CharSequence (length()=0) will return {@code false}.</p> 3364 * 3365 * <pre> 3366 * StringUtils.isAlpha(null) = false 3367 * StringUtils.isAlpha("") = false 3368 * StringUtils.isAlpha(" ") = false 3369 * StringUtils.isAlpha("abc") = true 3370 * StringUtils.isAlpha("ab2c") = false 3371 * StringUtils.isAlpha("ab-c") = false 3372 * </pre> 3373 * 3374 * @param cs the CharSequence to check, may be null 3375 * @return {@code true} if only contains letters, and is non-null 3376 * @since 3.0 Changed signature from isAlpha(String) to isAlpha(CharSequence) 3377 * @since 3.0 Changed "" to return false and not true 3378 */ 3379 public static boolean isAlpha(final CharSequence cs) { 3380 if (isEmpty(cs)) { 3381 return false; 3382 } 3383 final int sz = cs.length(); 3384 for (int i = 0; i < sz; i++) { 3385 if (!Character.isLetter(cs.charAt(i))) { 3386 return false; 3387 } 3388 } 3389 return true; 3390 } 3391 3392 /** 3393 * Checks if the CharSequence contains only Unicode letters or digits. 3394 * 3395 * <p>{@code null} will return {@code false}. 3396 * An empty CharSequence (length()=0) will return {@code false}.</p> 3397 * 3398 * <pre> 3399 * StringUtils.isAlphanumeric(null) = false 3400 * StringUtils.isAlphanumeric("") = false 3401 * StringUtils.isAlphanumeric(" ") = false 3402 * StringUtils.isAlphanumeric("abc") = true 3403 * StringUtils.isAlphanumeric("ab c") = false 3404 * StringUtils.isAlphanumeric("ab2c") = true 3405 * StringUtils.isAlphanumeric("ab-c") = false 3406 * </pre> 3407 * 3408 * @param cs the CharSequence to check, may be null 3409 * @return {@code true} if only contains letters or digits, 3410 * and is non-null 3411 * @since 3.0 Changed signature from isAlphanumeric(String) to isAlphanumeric(CharSequence) 3412 * @since 3.0 Changed "" to return false and not true 3413 */ 3414 public static boolean isAlphanumeric(final CharSequence cs) { 3415 if (isEmpty(cs)) { 3416 return false; 3417 } 3418 final int sz = cs.length(); 3419 for (int i = 0; i < sz; i++) { 3420 if (!Character.isLetterOrDigit(cs.charAt(i))) { 3421 return false; 3422 } 3423 } 3424 return true; 3425 } 3426 3427 /** 3428 * Checks if the CharSequence contains only Unicode letters, digits 3429 * or space ({@code ' '}). 3430 * 3431 * <p>{@code null} will return {@code false}. 3432 * An empty CharSequence (length()=0) will return {@code true}.</p> 3433 * 3434 * <pre> 3435 * StringUtils.isAlphanumericSpace(null) = false 3436 * StringUtils.isAlphanumericSpace("") = true 3437 * StringUtils.isAlphanumericSpace(" ") = true 3438 * StringUtils.isAlphanumericSpace("abc") = true 3439 * StringUtils.isAlphanumericSpace("ab c") = true 3440 * StringUtils.isAlphanumericSpace("ab2c") = true 3441 * StringUtils.isAlphanumericSpace("ab-c") = false 3442 * </pre> 3443 * 3444 * @param cs the CharSequence to check, may be null 3445 * @return {@code true} if only contains letters, digits or space, 3446 * and is non-null 3447 * @since 3.0 Changed signature from isAlphanumericSpace(String) to isAlphanumericSpace(CharSequence) 3448 */ 3449 public static boolean isAlphanumericSpace(final CharSequence cs) { 3450 if (cs == null) { 3451 return false; 3452 } 3453 final int sz = cs.length(); 3454 for (int i = 0; i < sz; i++) { 3455 final char nowChar = cs.charAt(i); 3456 if (nowChar != ' ' && !Character.isLetterOrDigit(nowChar) ) { 3457 return false; 3458 } 3459 } 3460 return true; 3461 } 3462 3463 /** 3464 * Checks if the CharSequence contains only Unicode letters and 3465 * space (' '). 3466 * 3467 * <p>{@code null} will return {@code false} 3468 * An empty CharSequence (length()=0) will return {@code true}.</p> 3469 * 3470 * <pre> 3471 * StringUtils.isAlphaSpace(null) = false 3472 * StringUtils.isAlphaSpace("") = true 3473 * StringUtils.isAlphaSpace(" ") = true 3474 * StringUtils.isAlphaSpace("abc") = true 3475 * StringUtils.isAlphaSpace("ab c") = true 3476 * StringUtils.isAlphaSpace("ab2c") = false 3477 * StringUtils.isAlphaSpace("ab-c") = false 3478 * </pre> 3479 * 3480 * @param cs the CharSequence to check, may be null 3481 * @return {@code true} if only contains letters and space, 3482 * and is non-null 3483 * @since 3.0 Changed signature from isAlphaSpace(String) to isAlphaSpace(CharSequence) 3484 */ 3485 public static boolean isAlphaSpace(final CharSequence cs) { 3486 if (cs == null) { 3487 return false; 3488 } 3489 final int sz = cs.length(); 3490 for (int i = 0; i < sz; i++) { 3491 final char nowChar = cs.charAt(i); 3492 if (nowChar != ' ' && !Character.isLetter(nowChar)) { 3493 return false; 3494 } 3495 } 3496 return true; 3497 } 3498 3499 /** 3500 * Checks if any of the CharSequences are empty ("") or null or whitespace only. 3501 * 3502 * <p>Whitespace is defined by {@link Character#isWhitespace(char)}.</p> 3503 * 3504 * <pre> 3505 * StringUtils.isAnyBlank((String) null) = true 3506 * StringUtils.isAnyBlank((String[]) null) = false 3507 * StringUtils.isAnyBlank(null, "foo") = true 3508 * StringUtils.isAnyBlank(null, null) = true 3509 * StringUtils.isAnyBlank("", "bar") = true 3510 * StringUtils.isAnyBlank("bob", "") = true 3511 * StringUtils.isAnyBlank(" bob ", null) = true 3512 * StringUtils.isAnyBlank(" ", "bar") = true 3513 * StringUtils.isAnyBlank(new String[] {}) = false 3514 * StringUtils.isAnyBlank(new String[]{""}) = true 3515 * StringUtils.isAnyBlank("foo", "bar") = false 3516 * </pre> 3517 * 3518 * @param css the CharSequences to check, may be null or empty 3519 * @return {@code true} if any of the CharSequences are empty or null or whitespace only 3520 * @since 3.2 3521 */ 3522 public static boolean isAnyBlank(final CharSequence... css) { 3523 if (ArrayUtils.isEmpty(css)) { 3524 return false; 3525 } 3526 for (final CharSequence cs : css) { 3527 if (isBlank(cs)) { 3528 return true; 3529 } 3530 } 3531 return false; 3532 } 3533 3534 /** 3535 * Checks if any of the CharSequences are empty ("") or null. 3536 * 3537 * <pre> 3538 * StringUtils.isAnyEmpty((String) null) = true 3539 * StringUtils.isAnyEmpty((String[]) null) = false 3540 * StringUtils.isAnyEmpty(null, "foo") = true 3541 * StringUtils.isAnyEmpty("", "bar") = true 3542 * StringUtils.isAnyEmpty("bob", "") = true 3543 * StringUtils.isAnyEmpty(" bob ", null) = true 3544 * StringUtils.isAnyEmpty(" ", "bar") = false 3545 * StringUtils.isAnyEmpty("foo", "bar") = false 3546 * StringUtils.isAnyEmpty(new String[]{}) = false 3547 * StringUtils.isAnyEmpty(new String[]{""}) = true 3548 * </pre> 3549 * 3550 * @param css the CharSequences to check, may be null or empty 3551 * @return {@code true} if any of the CharSequences are empty or null 3552 * @since 3.2 3553 */ 3554 public static boolean isAnyEmpty(final CharSequence... css) { 3555 if (ArrayUtils.isEmpty(css)) { 3556 return false; 3557 } 3558 for (final CharSequence cs : css) { 3559 if (isEmpty(cs)) { 3560 return true; 3561 } 3562 } 3563 return false; 3564 } 3565 3566 /** 3567 * Checks if the CharSequence contains only ASCII printable characters. 3568 * 3569 * <p>{@code null} will return {@code false}. 3570 * An empty CharSequence (length()=0) will return {@code true}.</p> 3571 * 3572 * <pre> 3573 * StringUtils.isAsciiPrintable(null) = false 3574 * StringUtils.isAsciiPrintable("") = true 3575 * StringUtils.isAsciiPrintable(" ") = true 3576 * StringUtils.isAsciiPrintable("Ceki") = true 3577 * StringUtils.isAsciiPrintable("ab2c") = true 3578 * StringUtils.isAsciiPrintable("!ab-c~") = true 3579 * StringUtils.isAsciiPrintable("\u0020") = true 3580 * StringUtils.isAsciiPrintable("\u0021") = true 3581 * StringUtils.isAsciiPrintable("\u007e") = true 3582 * StringUtils.isAsciiPrintable("\u007f") = false 3583 * StringUtils.isAsciiPrintable("Ceki G\u00fclc\u00fc") = false 3584 * </pre> 3585 * 3586 * @param cs the CharSequence to check, may be null 3587 * @return {@code true} if every character is in the range 3588 * 32 through 126 3589 * @since 2.1 3590 * @since 3.0 Changed signature from isAsciiPrintable(String) to isAsciiPrintable(CharSequence) 3591 */ 3592 public static boolean isAsciiPrintable(final CharSequence cs) { 3593 if (cs == null) { 3594 return false; 3595 } 3596 final int sz = cs.length(); 3597 for (int i = 0; i < sz; i++) { 3598 if (!CharUtils.isAsciiPrintable(cs.charAt(i))) { 3599 return false; 3600 } 3601 } 3602 return true; 3603 } 3604 3605 /** 3606 * Checks if a CharSequence is empty (""), null or whitespace only. 3607 * 3608 * <p>Whitespace is defined by {@link Character#isWhitespace(char)}.</p> 3609 * 3610 * <pre> 3611 * StringUtils.isBlank(null) = true 3612 * StringUtils.isBlank("") = true 3613 * StringUtils.isBlank(" ") = true 3614 * StringUtils.isBlank("bob") = false 3615 * StringUtils.isBlank(" bob ") = false 3616 * </pre> 3617 * 3618 * @param cs the CharSequence to check, may be null 3619 * @return {@code true} if the CharSequence is null, empty or whitespace only 3620 * @since 2.0 3621 * @since 3.0 Changed signature from isBlank(String) to isBlank(CharSequence) 3622 */ 3623 public static boolean isBlank(final CharSequence cs) { 3624 final int strLen = length(cs); 3625 if (strLen == 0) { 3626 return true; 3627 } 3628 for (int i = 0; i < strLen; i++) { 3629 if (!Character.isWhitespace(cs.charAt(i))) { 3630 return false; 3631 } 3632 } 3633 return true; 3634 } 3635 3636 /** 3637 * Checks if a CharSequence is empty ("") or null. 3638 * 3639 * <pre> 3640 * StringUtils.isEmpty(null) = true 3641 * StringUtils.isEmpty("") = true 3642 * StringUtils.isEmpty(" ") = false 3643 * StringUtils.isEmpty("bob") = false 3644 * StringUtils.isEmpty(" bob ") = false 3645 * </pre> 3646 * 3647 * <p>NOTE: This method changed in Lang version 2.0. 3648 * It no longer trims the CharSequence. 3649 * That functionality is available in isBlank().</p> 3650 * 3651 * @param cs the CharSequence to check, may be null 3652 * @return {@code true} if the CharSequence is empty or null 3653 * @since 3.0 Changed signature from isEmpty(String) to isEmpty(CharSequence) 3654 */ 3655 public static boolean isEmpty(final CharSequence cs) { 3656 return cs == null || cs.length() == 0; 3657 } 3658 3659 /** 3660 * Checks if the CharSequence contains mixed casing of both uppercase and lowercase characters. 3661 * 3662 * <p>{@code null} will return {@code false}. An empty CharSequence ({@code length()=0}) will return 3663 * {@code false}.</p> 3664 * 3665 * <pre> 3666 * StringUtils.isMixedCase(null) = false 3667 * StringUtils.isMixedCase("") = false 3668 * StringUtils.isMixedCase(" ") = false 3669 * StringUtils.isMixedCase("ABC") = false 3670 * StringUtils.isMixedCase("abc") = false 3671 * StringUtils.isMixedCase("aBc") = true 3672 * StringUtils.isMixedCase("A c") = true 3673 * StringUtils.isMixedCase("A1c") = true 3674 * StringUtils.isMixedCase("a/C") = true 3675 * StringUtils.isMixedCase("aC\t") = true 3676 * </pre> 3677 * 3678 * @param cs the CharSequence to check, may be null 3679 * @return {@code true} if the CharSequence contains both uppercase and lowercase characters 3680 * @since 3.5 3681 */ 3682 public static boolean isMixedCase(final CharSequence cs) { 3683 if (isEmpty(cs) || cs.length() == 1) { 3684 return false; 3685 } 3686 boolean containsUppercase = false; 3687 boolean containsLowercase = false; 3688 final int sz = cs.length(); 3689 for (int i = 0; i < sz; i++) { 3690 final char nowChar = cs.charAt(i); 3691 if (Character.isUpperCase(nowChar)) { 3692 containsUppercase = true; 3693 } else if (Character.isLowerCase(nowChar)) { 3694 containsLowercase = true; 3695 } 3696 if (containsUppercase && containsLowercase) { 3697 return true; 3698 } 3699 } 3700 return false; 3701 } 3702 3703 /** 3704 * Checks if none of the CharSequences are empty (""), null or whitespace only. 3705 * 3706 * <p>Whitespace is defined by {@link Character#isWhitespace(char)}.</p> 3707 * 3708 * <pre> 3709 * StringUtils.isNoneBlank((String) null) = false 3710 * StringUtils.isNoneBlank((String[]) null) = true 3711 * StringUtils.isNoneBlank(null, "foo") = false 3712 * StringUtils.isNoneBlank(null, null) = false 3713 * StringUtils.isNoneBlank("", "bar") = false 3714 * StringUtils.isNoneBlank("bob", "") = false 3715 * StringUtils.isNoneBlank(" bob ", null) = false 3716 * StringUtils.isNoneBlank(" ", "bar") = false 3717 * StringUtils.isNoneBlank(new String[] {}) = true 3718 * StringUtils.isNoneBlank(new String[]{""}) = false 3719 * StringUtils.isNoneBlank("foo", "bar") = true 3720 * </pre> 3721 * 3722 * @param css the CharSequences to check, may be null or empty 3723 * @return {@code true} if none of the CharSequences are empty or null or whitespace only 3724 * @since 3.2 3725 */ 3726 public static boolean isNoneBlank(final CharSequence... css) { 3727 return !isAnyBlank(css); 3728 } 3729 3730 /** 3731 * Checks if none of the CharSequences are empty ("") or null. 3732 * 3733 * <pre> 3734 * StringUtils.isNoneEmpty((String) null) = false 3735 * StringUtils.isNoneEmpty((String[]) null) = true 3736 * StringUtils.isNoneEmpty(null, "foo") = false 3737 * StringUtils.isNoneEmpty("", "bar") = false 3738 * StringUtils.isNoneEmpty("bob", "") = false 3739 * StringUtils.isNoneEmpty(" bob ", null) = false 3740 * StringUtils.isNoneEmpty(new String[] {}) = true 3741 * StringUtils.isNoneEmpty(new String[]{""}) = false 3742 * StringUtils.isNoneEmpty(" ", "bar") = true 3743 * StringUtils.isNoneEmpty("foo", "bar") = true 3744 * </pre> 3745 * 3746 * @param css the CharSequences to check, may be null or empty 3747 * @return {@code true} if none of the CharSequences are empty or null 3748 * @since 3.2 3749 */ 3750 public static boolean isNoneEmpty(final CharSequence... css) { 3751 return !isAnyEmpty(css); 3752 } 3753 3754 /** 3755 * Checks if a CharSequence is not empty (""), not null and not whitespace only. 3756 * 3757 * <p>Whitespace is defined by {@link Character#isWhitespace(char)}.</p> 3758 * 3759 * <pre> 3760 * StringUtils.isNotBlank(null) = false 3761 * StringUtils.isNotBlank("") = false 3762 * StringUtils.isNotBlank(" ") = false 3763 * StringUtils.isNotBlank("bob") = true 3764 * StringUtils.isNotBlank(" bob ") = true 3765 * </pre> 3766 * 3767 * @param cs the CharSequence to check, may be null 3768 * @return {@code true} if the CharSequence is 3769 * not empty and not null and not whitespace only 3770 * @since 2.0 3771 * @since 3.0 Changed signature from isNotBlank(String) to isNotBlank(CharSequence) 3772 */ 3773 public static boolean isNotBlank(final CharSequence cs) { 3774 return !isBlank(cs); 3775 } 3776 3777 /** 3778 * Checks if a CharSequence is not empty ("") and not null. 3779 * 3780 * <pre> 3781 * StringUtils.isNotEmpty(null) = false 3782 * StringUtils.isNotEmpty("") = false 3783 * StringUtils.isNotEmpty(" ") = true 3784 * StringUtils.isNotEmpty("bob") = true 3785 * StringUtils.isNotEmpty(" bob ") = true 3786 * </pre> 3787 * 3788 * @param cs the CharSequence to check, may be null 3789 * @return {@code true} if the CharSequence is not empty and not null 3790 * @since 3.0 Changed signature from isNotEmpty(String) to isNotEmpty(CharSequence) 3791 */ 3792 public static boolean isNotEmpty(final CharSequence cs) { 3793 return !isEmpty(cs); 3794 } 3795 3796 /** 3797 * Checks if the CharSequence contains only Unicode digits. 3798 * A decimal point is not a Unicode digit and returns false. 3799 * 3800 * <p>{@code null} will return {@code false}. 3801 * An empty CharSequence (length()=0) will return {@code false}.</p> 3802 * 3803 * <p>Note that the method does not allow for a leading sign, either positive or negative. 3804 * Also, if a String passes the numeric test, it may still generate a NumberFormatException 3805 * when parsed by Integer.parseInt or Long.parseLong, e.g. if the value is outside the range 3806 * for int or long respectively.</p> 3807 * 3808 * <pre> 3809 * StringUtils.isNumeric(null) = false 3810 * StringUtils.isNumeric("") = false 3811 * StringUtils.isNumeric(" ") = false 3812 * StringUtils.isNumeric("123") = true 3813 * StringUtils.isNumeric("\u0967\u0968\u0969") = true 3814 * StringUtils.isNumeric("12 3") = false 3815 * StringUtils.isNumeric("ab2c") = false 3816 * StringUtils.isNumeric("12-3") = false 3817 * StringUtils.isNumeric("12.3") = false 3818 * StringUtils.isNumeric("-123") = false 3819 * StringUtils.isNumeric("+123") = false 3820 * </pre> 3821 * 3822 * @param cs the CharSequence to check, may be null 3823 * @return {@code true} if only contains digits, and is non-null 3824 * @since 3.0 Changed signature from isNumeric(String) to isNumeric(CharSequence) 3825 * @since 3.0 Changed "" to return false and not true 3826 */ 3827 public static boolean isNumeric(final CharSequence cs) { 3828 if (isEmpty(cs)) { 3829 return false; 3830 } 3831 final int sz = cs.length(); 3832 for (int i = 0; i < sz; i++) { 3833 if (!Character.isDigit(cs.charAt(i))) { 3834 return false; 3835 } 3836 } 3837 return true; 3838 } 3839 3840 /** 3841 * Checks if the CharSequence contains only Unicode digits or space 3842 * ({@code ' '}). 3843 * A decimal point is not a Unicode digit and returns false. 3844 * 3845 * <p>{@code null} will return {@code false}. 3846 * An empty CharSequence (length()=0) will return {@code true}.</p> 3847 * 3848 * <pre> 3849 * StringUtils.isNumericSpace(null) = false 3850 * StringUtils.isNumericSpace("") = true 3851 * StringUtils.isNumericSpace(" ") = true 3852 * StringUtils.isNumericSpace("123") = true 3853 * StringUtils.isNumericSpace("12 3") = true 3854 * StringUtils.isNumericSpace("\u0967\u0968\u0969") = true 3855 * StringUtils.isNumericSpace("\u0967\u0968 \u0969") = true 3856 * StringUtils.isNumericSpace("ab2c") = false 3857 * StringUtils.isNumericSpace("12-3") = false 3858 * StringUtils.isNumericSpace("12.3") = false 3859 * </pre> 3860 * 3861 * @param cs the CharSequence to check, may be null 3862 * @return {@code true} if only contains digits or space, 3863 * and is non-null 3864 * @since 3.0 Changed signature from isNumericSpace(String) to isNumericSpace(CharSequence) 3865 */ 3866 public static boolean isNumericSpace(final CharSequence cs) { 3867 if (cs == null) { 3868 return false; 3869 } 3870 final int sz = cs.length(); 3871 for (int i = 0; i < sz; i++) { 3872 final char nowChar = cs.charAt(i); 3873 if (nowChar != ' ' && !Character.isDigit(nowChar)) { 3874 return false; 3875 } 3876 } 3877 return true; 3878 } 3879 3880 /** 3881 * Checks if the CharSequence contains only whitespace. 3882 * 3883 * <p>Whitespace is defined by {@link Character#isWhitespace(char)}.</p> 3884 * 3885 * <p>{@code null} will return {@code false}. 3886 * An empty CharSequence (length()=0) will return {@code true}.</p> 3887 * 3888 * <pre> 3889 * StringUtils.isWhitespace(null) = false 3890 * StringUtils.isWhitespace("") = true 3891 * StringUtils.isWhitespace(" ") = true 3892 * StringUtils.isWhitespace("abc") = false 3893 * StringUtils.isWhitespace("ab2c") = false 3894 * StringUtils.isWhitespace("ab-c") = false 3895 * </pre> 3896 * 3897 * @param cs the CharSequence to check, may be null 3898 * @return {@code true} if only contains whitespace, and is non-null 3899 * @since 2.0 3900 * @since 3.0 Changed signature from isWhitespace(String) to isWhitespace(CharSequence) 3901 */ 3902 public static boolean isWhitespace(final CharSequence cs) { 3903 if (cs == null) { 3904 return false; 3905 } 3906 final int sz = cs.length(); 3907 for (int i = 0; i < sz; i++) { 3908 if (!Character.isWhitespace(cs.charAt(i))) { 3909 return false; 3910 } 3911 } 3912 return true; 3913 } 3914 3915 /** 3916 * Joins the elements of the provided array into a single String containing the provided list of elements. 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([false, false], ';') = "false;false" 3928 * </pre> 3929 * 3930 * @param array 3931 * the array of values to join together, may be null 3932 * @param delimiter 3933 * the separator character to use 3934 * @return the joined String, {@code null} if null array input 3935 * @since 3.12.0 3936 */ 3937 public static String join(final boolean[] array, final char delimiter) { 3938 if (array == null) { 3939 return null; 3940 } 3941 return join(array, delimiter, 0, array.length); 3942 } 3943 3944 /** 3945 * Joins the elements of the provided array into a single String containing the provided list of elements. 3946 * 3947 * <p> 3948 * No delimiter is added before or after the list. Null objects or empty strings within the array are represented 3949 * by empty strings. 3950 * </p> 3951 * 3952 * <pre> 3953 * StringUtils.join(null, *) = null 3954 * StringUtils.join([], *) = "" 3955 * StringUtils.join([null], *) = "" 3956 * StringUtils.join([true, false, true], ';') = "true;false;true" 3957 * </pre> 3958 * 3959 * @param array 3960 * the array of values to join together, may be null 3961 * @param delimiter 3962 * the separator character to use 3963 * @param startIndex 3964 * the first index to start joining from. It is an error to pass in a start index past the end of the 3965 * array 3966 * @param endIndex 3967 * the index to stop joining from (exclusive). It is an error to pass in an end index past the end of 3968 * the array 3969 * @return the joined String, {@code null} if null array input 3970 * @since 3.12.0 3971 */ 3972 public static String join(final boolean[] array, final char delimiter, final int startIndex, final int endIndex) { 3973 if (array == null) { 3974 return null; 3975 } 3976 if (endIndex - startIndex <= 0) { 3977 return EMPTY; 3978 } 3979 final StringBuilder stringBuilder = new StringBuilder(array.length * 5 + array.length - 1); 3980 for (int i = startIndex; i < endIndex; i++) { 3981 stringBuilder 3982 .append(array[i]) 3983 .append(delimiter); 3984 } 3985 return stringBuilder.substring(0, stringBuilder.length() - 1); 3986 } 3987 3988 /** 3989 * Joins the elements of the provided array into a single String containing the provided list of elements. 3990 * 3991 * <p> 3992 * No delimiter is added before or after the list. Null objects or empty strings within the array are represented 3993 * by empty strings. 3994 * </p> 3995 * 3996 * <pre> 3997 * StringUtils.join(null, *) = null 3998 * StringUtils.join([], *) = "" 3999 * StringUtils.join([null], *) = "" 4000 * StringUtils.join([1, 2, 3], ';') = "1;2;3" 4001 * StringUtils.join([1, 2, 3], null) = "123" 4002 * </pre> 4003 * 4004 * @param array 4005 * the array of values to join together, may be null 4006 * @param delimiter 4007 * the separator character to use 4008 * @return the joined String, {@code null} if null array input 4009 * @since 3.2 4010 */ 4011 public static String join(final byte[] array, final char delimiter) { 4012 if (array == null) { 4013 return null; 4014 } 4015 return join(array, delimiter, 0, array.length); 4016 } 4017 4018 /** 4019 * Joins the elements of the provided array into a single String containing the provided list of elements. 4020 * 4021 * <p> 4022 * No delimiter is added before or after the list. Null objects or empty strings within the array are represented 4023 * by empty strings. 4024 * </p> 4025 * 4026 * <pre> 4027 * StringUtils.join(null, *) = null 4028 * StringUtils.join([], *) = "" 4029 * StringUtils.join([null], *) = "" 4030 * StringUtils.join([1, 2, 3], ';') = "1;2;3" 4031 * StringUtils.join([1, 2, 3], null) = "123" 4032 * </pre> 4033 * 4034 * @param array 4035 * the array of values to join together, may be null 4036 * @param delimiter 4037 * the separator character to use 4038 * @param startIndex 4039 * the first index to start joining from. It is an error to pass in a start index past the end of the 4040 * array 4041 * @param endIndex 4042 * the index to stop joining from (exclusive). It is an error to pass in an end index past the end of 4043 * the array 4044 * @return the joined String, {@code null} if null array input 4045 * @since 3.2 4046 */ 4047 public static String join(final byte[] array, final char delimiter, final int startIndex, final int endIndex) { 4048 if (array == null) { 4049 return null; 4050 } 4051 if (endIndex - startIndex <= 0) { 4052 return EMPTY; 4053 } 4054 final StringBuilder stringBuilder = new StringBuilder(); 4055 for (int i = startIndex; i < endIndex; i++) { 4056 stringBuilder 4057 .append(array[i]) 4058 .append(delimiter); 4059 } 4060 return stringBuilder.substring(0, stringBuilder.length() - 1); 4061 } 4062 4063 /** 4064 * Joins the elements of the provided array into a single String containing the provided list of elements. 4065 * 4066 * <p> 4067 * No delimiter is added before or after the list. Null objects or empty strings within the array are represented 4068 * by empty strings. 4069 * </p> 4070 * 4071 * <pre> 4072 * StringUtils.join(null, *) = null 4073 * StringUtils.join([], *) = "" 4074 * StringUtils.join([null], *) = "" 4075 * StringUtils.join([1, 2, 3], ';') = "1;2;3" 4076 * StringUtils.join([1, 2, 3], null) = "123" 4077 * </pre> 4078 * 4079 * @param array 4080 * the array of values to join together, may be null 4081 * @param delimiter 4082 * the separator character to use 4083 * @return the joined String, {@code null} if null array input 4084 * @since 3.2 4085 */ 4086 public static String join(final char[] array, final char delimiter) { 4087 if (array == null) { 4088 return null; 4089 } 4090 return join(array, delimiter, 0, array.length); 4091 } 4092 4093 /** 4094 * Joins the elements of the provided array into a single String containing the provided list of elements. 4095 * 4096 * <p> 4097 * No delimiter is added before or after the list. Null objects or empty strings within the array are represented 4098 * by empty strings. 4099 * </p> 4100 * 4101 * <pre> 4102 * StringUtils.join(null, *) = null 4103 * StringUtils.join([], *) = "" 4104 * StringUtils.join([null], *) = "" 4105 * StringUtils.join([1, 2, 3], ';') = "1;2;3" 4106 * StringUtils.join([1, 2, 3], null) = "123" 4107 * </pre> 4108 * 4109 * @param array 4110 * the array of values to join together, may be null 4111 * @param delimiter 4112 * the separator character to use 4113 * @param startIndex 4114 * the first index to start joining from. It is an error to pass in a start index past the end of the 4115 * array 4116 * @param endIndex 4117 * the index to stop joining from (exclusive). It is an error to pass in an end index past the end of 4118 * the array 4119 * @return the joined String, {@code null} if null array input 4120 * @since 3.2 4121 */ 4122 public static String join(final char[] array, final char delimiter, final int startIndex, final int endIndex) { 4123 if (array == null) { 4124 return null; 4125 } 4126 if (endIndex - startIndex <= 0) { 4127 return EMPTY; 4128 } 4129 final StringBuilder stringBuilder = new StringBuilder(array.length * 2 - 1); 4130 for (int i = startIndex; i < endIndex; i++) { 4131 stringBuilder 4132 .append(array[i]) 4133 .append(delimiter); 4134 } 4135 return stringBuilder.substring(0, stringBuilder.length() - 1); 4136 } 4137 4138 /** 4139 * Joins the elements of the provided array into a single String containing the provided list of elements. 4140 * 4141 * <p> 4142 * No delimiter is added before or after the list. Null objects or empty strings within the array are represented 4143 * by empty strings. 4144 * </p> 4145 * 4146 * <pre> 4147 * StringUtils.join(null, *) = null 4148 * StringUtils.join([], *) = "" 4149 * StringUtils.join([null], *) = "" 4150 * StringUtils.join([1, 2, 3], ';') = "1;2;3" 4151 * StringUtils.join([1, 2, 3], null) = "123" 4152 * </pre> 4153 * 4154 * @param array 4155 * the array of values to join together, may be null 4156 * @param delimiter 4157 * the separator character to use 4158 * @return the joined String, {@code null} if null array input 4159 * @since 3.2 4160 */ 4161 public static String join(final double[] array, final char delimiter) { 4162 if (array == null) { 4163 return null; 4164 } 4165 return join(array, delimiter, 0, array.length); 4166 } 4167 4168 /** 4169 * Joins the elements of the provided array into a single String containing the provided list of elements. 4170 * 4171 * <p> 4172 * No delimiter is added before or after the list. Null objects or empty strings within the array are represented 4173 * by empty strings. 4174 * </p> 4175 * 4176 * <pre> 4177 * StringUtils.join(null, *) = null 4178 * StringUtils.join([], *) = "" 4179 * StringUtils.join([null], *) = "" 4180 * StringUtils.join([1, 2, 3], ';') = "1;2;3" 4181 * StringUtils.join([1, 2, 3], null) = "123" 4182 * </pre> 4183 * 4184 * @param array 4185 * the array of values to join together, may be null 4186 * @param delimiter 4187 * the separator character to use 4188 * @param startIndex 4189 * the first index to start joining from. It is an error to pass in a start index past the end of the 4190 * array 4191 * @param endIndex 4192 * the index to stop joining from (exclusive). It is an error to pass in an end index past the end of 4193 * the array 4194 * @return the joined String, {@code null} if null array input 4195 * @since 3.2 4196 */ 4197 public static String join(final double[] array, final char delimiter, final int startIndex, final int endIndex) { 4198 if (array == null) { 4199 return null; 4200 } 4201 if (endIndex - startIndex <= 0) { 4202 return EMPTY; 4203 } 4204 final StringBuilder stringBuilder = new StringBuilder(); 4205 for (int i = startIndex; i < endIndex; i++) { 4206 stringBuilder 4207 .append(array[i]) 4208 .append(delimiter); 4209 } 4210 return stringBuilder.substring(0, stringBuilder.length() - 1); 4211 } 4212 4213 /** 4214 * Joins the elements of the provided array into a single String containing the provided list of elements. 4215 * 4216 * <p> 4217 * No delimiter is added before or after the list. Null objects or empty strings within the array are represented 4218 * by empty strings. 4219 * </p> 4220 * 4221 * <pre> 4222 * StringUtils.join(null, *) = null 4223 * StringUtils.join([], *) = "" 4224 * StringUtils.join([null], *) = "" 4225 * StringUtils.join([1, 2, 3], ';') = "1;2;3" 4226 * StringUtils.join([1, 2, 3], null) = "123" 4227 * </pre> 4228 * 4229 * @param array 4230 * the array of values to join together, may be null 4231 * @param delimiter 4232 * the separator character to use 4233 * @return the joined String, {@code null} if null array input 4234 * @since 3.2 4235 */ 4236 public static String join(final float[] array, final char delimiter) { 4237 if (array == null) { 4238 return null; 4239 } 4240 return join(array, delimiter, 0, array.length); 4241 } 4242 4243 /** 4244 * Joins the elements of the provided array into a single String containing the provided list of elements. 4245 * 4246 * <p> 4247 * No delimiter is added before or after the list. Null objects or empty strings within the array are represented 4248 * by empty strings. 4249 * </p> 4250 * 4251 * <pre> 4252 * StringUtils.join(null, *) = null 4253 * StringUtils.join([], *) = "" 4254 * StringUtils.join([null], *) = "" 4255 * StringUtils.join([1, 2, 3], ';') = "1;2;3" 4256 * StringUtils.join([1, 2, 3], null) = "123" 4257 * </pre> 4258 * 4259 * @param array 4260 * the array of values to join together, may be null 4261 * @param delimiter 4262 * the separator character to use 4263 * @param startIndex 4264 * the first index to start joining from. It is an error to pass in a start index past the end of the 4265 * array 4266 * @param endIndex 4267 * the index to stop joining from (exclusive). It is an error to pass in an end index past the end of 4268 * the array 4269 * @return the joined String, {@code null} if null array input 4270 * @since 3.2 4271 */ 4272 public static String join(final float[] array, final char delimiter, final int startIndex, final int endIndex) { 4273 if (array == null) { 4274 return null; 4275 } 4276 if (endIndex - startIndex <= 0) { 4277 return EMPTY; 4278 } 4279 final StringBuilder stringBuilder = new StringBuilder(); 4280 for (int i = startIndex; i < endIndex; i++) { 4281 stringBuilder 4282 .append(array[i]) 4283 .append(delimiter); 4284 } 4285 return stringBuilder.substring(0, stringBuilder.length() - 1); 4286 } 4287 4288 /** 4289 * Joins the elements of the provided array into a single String containing the provided list of elements. 4290 * 4291 * <p> 4292 * No delimiter is added before or after the list. Null objects or empty strings within the array are represented 4293 * by empty strings. 4294 * </p> 4295 * 4296 * <pre> 4297 * StringUtils.join(null, *) = null 4298 * StringUtils.join([], *) = "" 4299 * StringUtils.join([null], *) = "" 4300 * StringUtils.join([1, 2, 3], ';') = "1;2;3" 4301 * StringUtils.join([1, 2, 3], null) = "123" 4302 * </pre> 4303 * 4304 * @param array 4305 * the array of values to join together, may be null 4306 * @param separator 4307 * the separator character to use 4308 * @return the joined String, {@code null} if null array input 4309 * @since 3.2 4310 */ 4311 public static String join(final int[] array, final char separator) { 4312 if (array == null) { 4313 return null; 4314 } 4315 return join(array, separator, 0, array.length); 4316 } 4317 4318 /** 4319 * Joins the elements of the provided array into a single String containing the provided list of elements. 4320 * 4321 * <p> 4322 * No delimiter is added before or after the list. Null objects or empty strings within the array are represented 4323 * by empty strings. 4324 * </p> 4325 * 4326 * <pre> 4327 * StringUtils.join(null, *) = null 4328 * StringUtils.join([], *) = "" 4329 * StringUtils.join([null], *) = "" 4330 * StringUtils.join([1, 2, 3], ';') = "1;2;3" 4331 * StringUtils.join([1, 2, 3], null) = "123" 4332 * </pre> 4333 * 4334 * @param array 4335 * the array of values to join together, may be null 4336 * @param delimiter 4337 * the separator character to use 4338 * @param startIndex 4339 * the first index to start joining from. It is an error to pass in a start index past the end of the 4340 * array 4341 * @param endIndex 4342 * the index to stop joining from (exclusive). It is an error to pass in an end index past the end of 4343 * the array 4344 * @return the joined String, {@code null} if null array input 4345 * @since 3.2 4346 */ 4347 public static String join(final int[] array, final char delimiter, final int startIndex, final int endIndex) { 4348 if (array == null) { 4349 return null; 4350 } 4351 if (endIndex - startIndex <= 0) { 4352 return EMPTY; 4353 } 4354 final StringBuilder stringBuilder = new StringBuilder(); 4355 for (int i = startIndex; i < endIndex; i++) { 4356 stringBuilder 4357 .append(array[i]) 4358 .append(delimiter); 4359 } 4360 return stringBuilder.substring(0, stringBuilder.length() - 1); 4361 } 4362 4363 /** 4364 * Joins the elements of the provided {@link Iterable} into 4365 * a single String containing the provided elements. 4366 * 4367 * <p>No delimiter is added before or after the list. Null objects or empty 4368 * strings within the iteration are represented by empty strings.</p> 4369 * 4370 * <p>See the examples here: {@link #join(Object[],char)}.</p> 4371 * 4372 * @param iterable the {@link Iterable} providing the values to join together, may be null 4373 * @param separator the separator character to use 4374 * @return the joined String, {@code null} if null iterator input 4375 * @since 2.3 4376 */ 4377 public static String join(final Iterable<?> iterable, final char separator) { 4378 return iterable != null ? join(iterable.iterator(), separator) : null; 4379 } 4380 4381 /** 4382 * Joins the elements of the provided {@link Iterable} into 4383 * a single String containing the provided elements. 4384 * 4385 * <p>No delimiter is added before or after the list. 4386 * A {@code null} separator is the same as an empty String ("").</p> 4387 * 4388 * <p>See the examples here: {@link #join(Object[],String)}.</p> 4389 * 4390 * @param iterable the {@link Iterable} providing the values to join together, may be null 4391 * @param separator the separator character to use, null treated as "" 4392 * @return the joined String, {@code null} if null iterator input 4393 * @since 2.3 4394 */ 4395 public static String join(final Iterable<?> iterable, final String separator) { 4396 return iterable != null ? join(iterable.iterator(), separator) : null; 4397 } 4398 4399 /** 4400 * Joins the elements of the provided {@link Iterator} into 4401 * a single String containing the provided elements. 4402 * 4403 * <p>No delimiter is added before or after the list. Null objects or empty 4404 * strings within the iteration are represented by empty strings.</p> 4405 * 4406 * <p>See the examples here: {@link #join(Object[],char)}.</p> 4407 * 4408 * @param iterator the {@link Iterator} of values to join together, may be null 4409 * @param separator the separator character to use 4410 * @return the joined String, {@code null} if null iterator input 4411 * @since 2.0 4412 */ 4413 public static String join(final Iterator<?> iterator, final char separator) { 4414 // handle null, zero and one elements before building a buffer 4415 if (iterator == null) { 4416 return null; 4417 } 4418 if (!iterator.hasNext()) { 4419 return EMPTY; 4420 } 4421 return Streams.of(iterator).collect(LangCollectors.joining(toStringOrEmpty(String.valueOf(separator)), EMPTY, EMPTY, StringUtils::toStringOrEmpty)); 4422 } 4423 4424 /** 4425 * Joins the elements of the provided {@link Iterator} into 4426 * a single String containing the provided elements. 4427 * 4428 * <p>No delimiter is added before or after the list. 4429 * A {@code null} separator is the same as an empty String ("").</p> 4430 * 4431 * <p>See the examples here: {@link #join(Object[],String)}.</p> 4432 * 4433 * @param iterator the {@link Iterator} of values to join together, may be null 4434 * @param separator the separator character to use, null treated as "" 4435 * @return the joined String, {@code null} if null iterator input 4436 */ 4437 public static String join(final Iterator<?> iterator, final String separator) { 4438 // handle null, zero and one elements before building a buffer 4439 if (iterator == null) { 4440 return null; 4441 } 4442 if (!iterator.hasNext()) { 4443 return EMPTY; 4444 } 4445 return Streams.of(iterator).collect(LangCollectors.joining(toStringOrEmpty(separator), EMPTY, EMPTY, StringUtils::toStringOrEmpty)); 4446 } 4447 4448 /** 4449 * Joins the elements of the provided {@link List} into a single String 4450 * containing the provided list of elements. 4451 * 4452 * <p>No delimiter is added before or after the list. 4453 * Null objects or empty strings within the array are represented by 4454 * empty strings.</p> 4455 * 4456 * <pre> 4457 * StringUtils.join(null, *) = null 4458 * StringUtils.join([], *) = "" 4459 * StringUtils.join([null], *) = "" 4460 * StringUtils.join(["a", "b", "c"], ';') = "a;b;c" 4461 * StringUtils.join(["a", "b", "c"], null) = "abc" 4462 * StringUtils.join([null, "", "a"], ';') = ";;a" 4463 * </pre> 4464 * 4465 * @param list the {@link List} of values to join together, may be null 4466 * @param separator the separator character to use 4467 * @param startIndex the first index to start joining from. It is 4468 * an error to pass in a start index past the end of the list 4469 * @param endIndex the index to stop joining from (exclusive). It is 4470 * an error to pass in an end index past the end of the list 4471 * @return the joined String, {@code null} if null list input 4472 * @since 3.8 4473 */ 4474 public static String join(final List<?> list, final char separator, final int startIndex, final int endIndex) { 4475 if (list == null) { 4476 return null; 4477 } 4478 final int noOfItems = endIndex - startIndex; 4479 if (noOfItems <= 0) { 4480 return EMPTY; 4481 } 4482 final List<?> subList = list.subList(startIndex, endIndex); 4483 return join(subList.iterator(), separator); 4484 } 4485 4486 /** 4487 * Joins the elements of the provided {@link List} into a single String 4488 * containing the provided list of elements. 4489 * 4490 * <p>No delimiter is added before or after the list. 4491 * Null objects or empty strings within the array are represented by 4492 * empty strings.</p> 4493 * 4494 * <pre> 4495 * StringUtils.join(null, *) = null 4496 * StringUtils.join([], *) = "" 4497 * StringUtils.join([null], *) = "" 4498 * StringUtils.join(["a", "b", "c"], ';') = "a;b;c" 4499 * StringUtils.join(["a", "b", "c"], null) = "abc" 4500 * StringUtils.join([null, "", "a"], ';') = ";;a" 4501 * </pre> 4502 * 4503 * @param list the {@link List} of values to join together, may be null 4504 * @param separator the separator character to use 4505 * @param startIndex the first index to start joining from. It is 4506 * an error to pass in a start index past the end of the list 4507 * @param endIndex the index to stop joining from (exclusive). It is 4508 * an error to pass in an end index past the end of the list 4509 * @return the joined String, {@code null} if null list input 4510 * @since 3.8 4511 */ 4512 public static String join(final List<?> list, final String separator, final int startIndex, final int endIndex) { 4513 if (list == null) { 4514 return null; 4515 } 4516 final int noOfItems = endIndex - startIndex; 4517 if (noOfItems <= 0) { 4518 return EMPTY; 4519 } 4520 final List<?> subList = list.subList(startIndex, endIndex); 4521 return join(subList.iterator(), separator); 4522 } 4523 4524 /** 4525 * Joins the elements of the provided array into a single String containing the provided list of elements. 4526 * 4527 * <p> 4528 * No delimiter is added before or after the list. Null objects or empty strings within the array are represented 4529 * by empty strings. 4530 * </p> 4531 * 4532 * <pre> 4533 * StringUtils.join(null, *) = null 4534 * StringUtils.join([], *) = "" 4535 * StringUtils.join([null], *) = "" 4536 * StringUtils.join([1, 2, 3], ';') = "1;2;3" 4537 * StringUtils.join([1, 2, 3], null) = "123" 4538 * </pre> 4539 * 4540 * @param array 4541 * the array of values to join together, may be null 4542 * @param separator 4543 * the separator character to use 4544 * @return the joined String, {@code null} if null array input 4545 * @since 3.2 4546 */ 4547 public static String join(final long[] array, final char separator) { 4548 if (array == null) { 4549 return null; 4550 } 4551 return join(array, separator, 0, array.length); 4552 } 4553 4554 /** 4555 * Joins the elements of the provided array into a single String containing the provided list of elements. 4556 * 4557 * <p> 4558 * No delimiter is added before or after the list. Null objects or empty strings within the array are represented 4559 * by empty strings. 4560 * </p> 4561 * 4562 * <pre> 4563 * StringUtils.join(null, *) = null 4564 * StringUtils.join([], *) = "" 4565 * StringUtils.join([null], *) = "" 4566 * StringUtils.join([1, 2, 3], ';') = "1;2;3" 4567 * StringUtils.join([1, 2, 3], null) = "123" 4568 * </pre> 4569 * 4570 * @param array 4571 * the array of values to join together, may be null 4572 * @param delimiter 4573 * the separator character to use 4574 * @param startIndex 4575 * the first index to start joining from. It is an error to pass in a start index past the end of the 4576 * array 4577 * @param endIndex 4578 * the index to stop joining from (exclusive). It is an error to pass in an end index past the end of 4579 * the array 4580 * @return the joined String, {@code null} if null array input 4581 * @since 3.2 4582 */ 4583 public static String join(final long[] array, final char delimiter, final int startIndex, final int endIndex) { 4584 if (array == null) { 4585 return null; 4586 } 4587 if (endIndex - startIndex <= 0) { 4588 return EMPTY; 4589 } 4590 final StringBuilder stringBuilder = new StringBuilder(); 4591 for (int i = startIndex; i < endIndex; i++) { 4592 stringBuilder 4593 .append(array[i]) 4594 .append(delimiter); 4595 } 4596 return stringBuilder.substring(0, stringBuilder.length() - 1); 4597 } 4598 4599 /** 4600 * Joins the elements of the provided array into a single String 4601 * containing the provided list of elements. 4602 * 4603 * <p>No delimiter is added before or after the list. 4604 * Null objects or empty strings within the array are represented by 4605 * empty strings.</p> 4606 * 4607 * <pre> 4608 * StringUtils.join(null, *) = null 4609 * StringUtils.join([], *) = "" 4610 * StringUtils.join([null], *) = "" 4611 * StringUtils.join(["a", "b", "c"], ';') = "a;b;c" 4612 * StringUtils.join(["a", "b", "c"], null) = "abc" 4613 * StringUtils.join([null, "", "a"], ';') = ";;a" 4614 * </pre> 4615 * 4616 * @param array the array of values to join together, may be null 4617 * @param delimiter the separator character to use 4618 * @return the joined String, {@code null} if null array input 4619 * @since 2.0 4620 */ 4621 public static String join(final Object[] array, final char delimiter) { 4622 if (array == null) { 4623 return null; 4624 } 4625 return join(array, delimiter, 0, array.length); 4626 } 4627 4628 /** 4629 * Joins the elements of the provided array into a single String 4630 * containing the provided list of elements. 4631 * 4632 * <p>No delimiter is added before or after the list. 4633 * Null objects or empty strings within the array are represented by 4634 * empty strings.</p> 4635 * 4636 * <pre> 4637 * StringUtils.join(null, *) = null 4638 * StringUtils.join([], *) = "" 4639 * StringUtils.join([null], *) = "" 4640 * StringUtils.join(["a", "b", "c"], ';') = "a;b;c" 4641 * StringUtils.join(["a", "b", "c"], null) = "abc" 4642 * StringUtils.join([null, "", "a"], ';') = ";;a" 4643 * </pre> 4644 * 4645 * @param array the array of values to join together, may be null 4646 * @param delimiter the separator character to use 4647 * @param startIndex the first index to start joining from. It is 4648 * an error to pass in a start index past the end of the array 4649 * @param endIndex the index to stop joining from (exclusive). It is 4650 * an error to pass in an end index past the end of the array 4651 * @return the joined String, {@code null} if null array input 4652 * @since 2.0 4653 */ 4654 public static String join(final Object[] array, final char delimiter, final int startIndex, final int endIndex) { 4655 return join(array, String.valueOf(delimiter), startIndex, endIndex); 4656 } 4657 4658 /** 4659 * Joins the elements of the provided array into a single String 4660 * containing the provided list of elements. 4661 * 4662 * <p>No delimiter is added before or after the list. 4663 * A {@code null} separator is the same as an empty String (""). 4664 * Null objects or empty strings within the array are represented by 4665 * empty strings.</p> 4666 * 4667 * <pre> 4668 * StringUtils.join(null, *) = null 4669 * StringUtils.join([], *) = "" 4670 * StringUtils.join([null], *) = "" 4671 * StringUtils.join(["a", "b", "c"], "--") = "a--b--c" 4672 * StringUtils.join(["a", "b", "c"], null) = "abc" 4673 * StringUtils.join(["a", "b", "c"], "") = "abc" 4674 * StringUtils.join([null, "", "a"], ',') = ",,a" 4675 * </pre> 4676 * 4677 * @param array the array of values to join together, may be null 4678 * @param delimiter the separator character to use, null treated as "" 4679 * @return the joined String, {@code null} if null array input 4680 */ 4681 public static String join(final Object[] array, final String delimiter) { 4682 return array != null ? join(array, toStringOrEmpty(delimiter), 0, array.length) : null; 4683 } 4684 4685 /** 4686 * Joins the elements of the provided array into a single String 4687 * containing the provided list of elements. 4688 * 4689 * <p>No delimiter is added before or after the list. 4690 * A {@code null} separator is the same as an empty String (""). 4691 * Null objects or empty strings within the array are represented by 4692 * empty strings.</p> 4693 * 4694 * <pre> 4695 * StringUtils.join(null, *, *, *) = null 4696 * StringUtils.join([], *, *, *) = "" 4697 * StringUtils.join([null], *, *, *) = "" 4698 * StringUtils.join(["a", "b", "c"], "--", 0, 3) = "a--b--c" 4699 * StringUtils.join(["a", "b", "c"], "--", 1, 3) = "b--c" 4700 * StringUtils.join(["a", "b", "c"], "--", 2, 3) = "c" 4701 * StringUtils.join(["a", "b", "c"], "--", 2, 2) = "" 4702 * StringUtils.join(["a", "b", "c"], null, 0, 3) = "abc" 4703 * StringUtils.join(["a", "b", "c"], "", 0, 3) = "abc" 4704 * StringUtils.join([null, "", "a"], ',', 0, 3) = ",,a" 4705 * </pre> 4706 * 4707 * @param array the array of values to join together, may be null 4708 * @param delimiter the separator character to use, null treated as "" 4709 * @param startIndex the first index to start joining from. 4710 * @param endIndex the index to stop joining from (exclusive). 4711 * @return the joined String, {@code null} if null array input; or the empty string 4712 * if {@code endIndex - startIndex <= 0}. The number of joined entries is given by 4713 * {@code endIndex - startIndex} 4714 * @throws ArrayIndexOutOfBoundsException ife<br> 4715 * {@code startIndex < 0} or <br> 4716 * {@code startIndex >= array.length()} or <br> 4717 * {@code endIndex < 0} or <br> 4718 * {@code endIndex > array.length()} 4719 */ 4720 public static String join(final Object[] array, final String delimiter, final int startIndex, final int endIndex) { 4721 return array != null ? Streams.of(array).skip(startIndex).limit(Math.max(0, endIndex - startIndex)) 4722 .collect(LangCollectors.joining(delimiter, EMPTY, EMPTY, StringUtils::toStringOrEmpty)) : null; 4723 } 4724 4725 /** 4726 * Joins the elements of the provided array into a single String containing the provided list of elements. 4727 * 4728 * <p> 4729 * No delimiter is added before or after the list. Null objects or empty strings within the array are represented 4730 * by empty strings. 4731 * </p> 4732 * 4733 * <pre> 4734 * StringUtils.join(null, *) = null 4735 * StringUtils.join([], *) = "" 4736 * StringUtils.join([null], *) = "" 4737 * StringUtils.join([1, 2, 3], ';') = "1;2;3" 4738 * StringUtils.join([1, 2, 3], null) = "123" 4739 * </pre> 4740 * 4741 * @param array 4742 * the array of values to join together, may be null 4743 * @param delimiter 4744 * the separator character to use 4745 * @return the joined String, {@code null} if null array input 4746 * @since 3.2 4747 */ 4748 public static String join(final short[] array, final char delimiter) { 4749 if (array == null) { 4750 return null; 4751 } 4752 return join(array, delimiter, 0, array.length); 4753 } 4754 4755 /** 4756 * Joins the elements of the provided array into a single String containing the provided list of elements. 4757 * 4758 * <p> 4759 * No delimiter is added before or after the list. Null objects or empty strings within the array are represented 4760 * by empty strings. 4761 * </p> 4762 * 4763 * <pre> 4764 * StringUtils.join(null, *) = null 4765 * StringUtils.join([], *) = "" 4766 * StringUtils.join([null], *) = "" 4767 * StringUtils.join([1, 2, 3], ';') = "1;2;3" 4768 * StringUtils.join([1, 2, 3], null) = "123" 4769 * </pre> 4770 * 4771 * @param array 4772 * the array of values to join together, may be null 4773 * @param delimiter 4774 * the separator character to use 4775 * @param startIndex 4776 * the first index to start joining from. It is an error to pass in a start index past the end of the 4777 * array 4778 * @param endIndex 4779 * the index to stop joining from (exclusive). It is an error to pass in an end index past the end of 4780 * the array 4781 * @return the joined String, {@code null} if null array input 4782 * @since 3.2 4783 */ 4784 public static String join(final short[] array, final char delimiter, final int startIndex, final int endIndex) { 4785 if (array == null) { 4786 return null; 4787 } 4788 if (endIndex - startIndex <= 0) { 4789 return EMPTY; 4790 } 4791 final StringBuilder stringBuilder = new StringBuilder(); 4792 for (int i = startIndex; i < endIndex; i++) { 4793 stringBuilder 4794 .append(array[i]) 4795 .append(delimiter); 4796 } 4797 return stringBuilder.substring(0, stringBuilder.length() - 1); 4798 } 4799 4800 /** 4801 * Joins the elements of the provided array into a single String 4802 * containing the provided list of elements. 4803 * 4804 * <p>No separator is added to the joined String. 4805 * Null objects or empty strings within the array are represented by 4806 * empty strings.</p> 4807 * 4808 * <pre> 4809 * StringUtils.join(null) = null 4810 * StringUtils.join([]) = "" 4811 * StringUtils.join([null]) = "" 4812 * StringUtils.join(["a", "b", "c"]) = "abc" 4813 * StringUtils.join([null, "", "a"]) = "a" 4814 * </pre> 4815 * 4816 * @param <T> the specific type of values to join together 4817 * @param elements the values to join together, may be null 4818 * @return the joined String, {@code null} if null array input 4819 * @since 2.0 4820 * @since 3.0 Changed signature to use varargs 4821 */ 4822 @SafeVarargs 4823 public static <T> String join(final T... elements) { 4824 return join(elements, null); 4825 } 4826 4827 /** 4828 * Joins the elements of the provided varargs into a 4829 * single String containing the provided elements. 4830 * 4831 * <p>No delimiter is added before or after the list. 4832 * {@code null} elements and separator are treated as empty Strings ("").</p> 4833 * 4834 * <pre> 4835 * StringUtils.joinWith(",", {"a", "b"}) = "a,b" 4836 * StringUtils.joinWith(",", {"a", "b",""}) = "a,b," 4837 * StringUtils.joinWith(",", {"a", null, "b"}) = "a,,b" 4838 * StringUtils.joinWith(null, {"a", "b"}) = "ab" 4839 * </pre> 4840 * 4841 * @param delimiter the separator character to use, null treated as "" 4842 * @param array the varargs providing the values to join together. {@code null} elements are treated as "" 4843 * @return the joined String. 4844 * @throws IllegalArgumentException if a null varargs is provided 4845 * @since 3.5 4846 */ 4847 public static String joinWith(final String delimiter, final Object... array) { 4848 if (array == null) { 4849 throw new IllegalArgumentException("Object varargs must not be null"); 4850 } 4851 return join(array, delimiter); 4852 } 4853 4854 /** 4855 * Finds the last index within a CharSequence, handling {@code null}. 4856 * This method uses {@link String#lastIndexOf(String)} if possible. 4857 * 4858 * <p>A {@code null} CharSequence will return {@code -1}.</p> 4859 * 4860 * <pre> 4861 * StringUtils.lastIndexOf(null, *) = -1 4862 * StringUtils.lastIndexOf(*, null) = -1 4863 * StringUtils.lastIndexOf("", "") = 0 4864 * StringUtils.lastIndexOf("aabaabaa", "a") = 7 4865 * StringUtils.lastIndexOf("aabaabaa", "b") = 5 4866 * StringUtils.lastIndexOf("aabaabaa", "ab") = 4 4867 * StringUtils.lastIndexOf("aabaabaa", "") = 8 4868 * </pre> 4869 * 4870 * @param seq the CharSequence to check, may be null 4871 * @param searchSeq the CharSequence to find, may be null 4872 * @return the last index of the search String, 4873 * -1 if no match or {@code null} string input 4874 * @since 2.0 4875 * @since 3.0 Changed signature from lastIndexOf(String, String) to lastIndexOf(CharSequence, CharSequence) 4876 */ 4877 public static int lastIndexOf(final CharSequence seq, final CharSequence searchSeq) { 4878 if (seq == null) { 4879 return INDEX_NOT_FOUND; 4880 } 4881 return CharSequenceUtils.lastIndexOf(seq, searchSeq, seq.length()); 4882 } 4883 4884 /** 4885 * Finds the last index within a CharSequence, handling {@code null}. 4886 * This method uses {@link String#lastIndexOf(String, int)} if possible. 4887 * 4888 * <p>A {@code null} CharSequence will return {@code -1}. 4889 * A negative start position returns {@code -1}. 4890 * An empty ("") search CharSequence always matches unless the start position is negative. 4891 * A start position greater than the string length searches the whole string. 4892 * The search starts at the startPos and works backwards; matches starting after the start 4893 * position are ignored. 4894 * </p> 4895 * 4896 * <pre> 4897 * StringUtils.lastIndexOf(null, *, *) = -1 4898 * StringUtils.lastIndexOf(*, null, *) = -1 4899 * StringUtils.lastIndexOf("aabaabaa", "a", 8) = 7 4900 * StringUtils.lastIndexOf("aabaabaa", "b", 8) = 5 4901 * StringUtils.lastIndexOf("aabaabaa", "ab", 8) = 4 4902 * StringUtils.lastIndexOf("aabaabaa", "b", 9) = 5 4903 * StringUtils.lastIndexOf("aabaabaa", "b", -1) = -1 4904 * StringUtils.lastIndexOf("aabaabaa", "a", 0) = 0 4905 * StringUtils.lastIndexOf("aabaabaa", "b", 0) = -1 4906 * StringUtils.lastIndexOf("aabaabaa", "b", 1) = -1 4907 * StringUtils.lastIndexOf("aabaabaa", "b", 2) = 2 4908 * StringUtils.lastIndexOf("aabaabaa", "ba", 2) = 2 4909 * </pre> 4910 * 4911 * @param seq the CharSequence to check, may be null 4912 * @param searchSeq the CharSequence to find, may be null 4913 * @param startPos the start position, negative treated as zero 4914 * @return the last index of the search CharSequence (always ≤ startPos), 4915 * -1 if no match or {@code null} string input 4916 * @since 2.0 4917 * @since 3.0 Changed signature from lastIndexOf(String, String, int) to lastIndexOf(CharSequence, CharSequence, int) 4918 */ 4919 public static int lastIndexOf(final CharSequence seq, final CharSequence searchSeq, final int startPos) { 4920 return CharSequenceUtils.lastIndexOf(seq, searchSeq, startPos); 4921 } 4922 4923 /** 4924 * Returns the index within {@code seq} of the last occurrence of 4925 * the specified character. For values of {@code searchChar} in the 4926 * range from 0 to 0xFFFF (inclusive), the index (in Unicode code 4927 * units) returned is the largest value <em>k</em> such that: 4928 * <blockquote><pre> 4929 * this.charAt(<em>k</em>) == searchChar 4930 * </pre></blockquote> 4931 * is true. For other values of {@code searchChar}, it is the 4932 * largest value <em>k</em> such that: 4933 * <blockquote><pre> 4934 * this.codePointAt(<em>k</em>) == searchChar 4935 * </pre></blockquote> 4936 * is true. In either case, if no such character occurs in this 4937 * string, then {@code -1} is returned. Furthermore, a {@code null} or empty ("") 4938 * {@link CharSequence} will return {@code -1}. The 4939 * {@code seq} {@link CharSequence} object is searched backwards 4940 * starting at the last character. 4941 * 4942 * <pre> 4943 * StringUtils.lastIndexOf(null, *) = -1 4944 * StringUtils.lastIndexOf("", *) = -1 4945 * StringUtils.lastIndexOf("aabaabaa", 'a') = 7 4946 * StringUtils.lastIndexOf("aabaabaa", 'b') = 5 4947 * </pre> 4948 * 4949 * @param seq the {@link CharSequence} to check, may be null 4950 * @param searchChar the character to find 4951 * @return the last index of the search character, 4952 * -1 if no match or {@code null} string input 4953 * @since 2.0 4954 * @since 3.0 Changed signature from lastIndexOf(String, int) to lastIndexOf(CharSequence, int) 4955 * @since 3.6 Updated {@link CharSequenceUtils} call to behave more like {@link String} 4956 */ 4957 public static int lastIndexOf(final CharSequence seq, final int searchChar) { 4958 if (isEmpty(seq)) { 4959 return INDEX_NOT_FOUND; 4960 } 4961 return CharSequenceUtils.lastIndexOf(seq, searchChar, seq.length()); 4962 } 4963 4964 /** 4965 * Returns the index within {@code seq} of the last occurrence of 4966 * the specified character, searching backward starting at the 4967 * specified index. For values of {@code searchChar} in the range 4968 * from 0 to 0xFFFF (inclusive), the index returned is the largest 4969 * value <em>k</em> such that: 4970 * <blockquote><pre> 4971 * (this.charAt(<em>k</em>) == searchChar) && (<em>k</em> <= startPos) 4972 * </pre></blockquote> 4973 * is true. For other values of {@code searchChar}, it is the 4974 * largest value <em>k</em> such that: 4975 * <blockquote><pre> 4976 * (this.codePointAt(<em>k</em>) == searchChar) && (<em>k</em> <= startPos) 4977 * </pre></blockquote> 4978 * is true. In either case, if no such character occurs in {@code seq} 4979 * at or before position {@code startPos}, then 4980 * {@code -1} is returned. Furthermore, a {@code null} or empty ("") 4981 * {@link CharSequence} will return {@code -1}. A start position greater 4982 * than the string length searches the whole string. 4983 * The search starts at the {@code startPos} and works backwards; 4984 * matches starting after the start position are ignored. 4985 * 4986 * <p>All indices are specified in {@code char} values 4987 * (Unicode code units). 4988 * 4989 * <pre> 4990 * StringUtils.lastIndexOf(null, *, *) = -1 4991 * StringUtils.lastIndexOf("", *, *) = -1 4992 * StringUtils.lastIndexOf("aabaabaa", 'b', 8) = 5 4993 * StringUtils.lastIndexOf("aabaabaa", 'b', 4) = 2 4994 * StringUtils.lastIndexOf("aabaabaa", 'b', 0) = -1 4995 * StringUtils.lastIndexOf("aabaabaa", 'b', 9) = 5 4996 * StringUtils.lastIndexOf("aabaabaa", 'b', -1) = -1 4997 * StringUtils.lastIndexOf("aabaabaa", 'a', 0) = 0 4998 * </pre> 4999 * 5000 * @param seq the CharSequence to check, may be null 5001 * @param searchChar the character to find 5002 * @param startPos the start position 5003 * @return the last index of the search character (always ≤ startPos), 5004 * -1 if no match or {@code null} string input 5005 * @since 2.0 5006 * @since 3.0 Changed signature from lastIndexOf(String, int, int) to lastIndexOf(CharSequence, int, int) 5007 */ 5008 public static int lastIndexOf(final CharSequence seq, final int searchChar, final int startPos) { 5009 if (isEmpty(seq)) { 5010 return INDEX_NOT_FOUND; 5011 } 5012 return CharSequenceUtils.lastIndexOf(seq, searchChar, startPos); 5013 } 5014 5015 /** 5016 * Find the latest index of any substring in a set of potential substrings. 5017 * 5018 * <p>A {@code null} CharSequence will return {@code -1}. 5019 * A {@code null} search array will return {@code -1}. 5020 * A {@code null} or zero length search array entry will be ignored, 5021 * but a search array containing "" will return the length of {@code str} 5022 * if {@code str} is not null. This method uses {@link String#indexOf(String)} if possible</p> 5023 * 5024 * <pre> 5025 * StringUtils.lastIndexOfAny(null, *) = -1 5026 * StringUtils.lastIndexOfAny(*, null) = -1 5027 * StringUtils.lastIndexOfAny(*, []) = -1 5028 * StringUtils.lastIndexOfAny(*, [null]) = -1 5029 * StringUtils.lastIndexOfAny("zzabyycdxx", ["ab", "cd"]) = 6 5030 * StringUtils.lastIndexOfAny("zzabyycdxx", ["cd", "ab"]) = 6 5031 * StringUtils.lastIndexOfAny("zzabyycdxx", ["mn", "op"]) = -1 5032 * StringUtils.lastIndexOfAny("zzabyycdxx", ["mn", "op"]) = -1 5033 * StringUtils.lastIndexOfAny("zzabyycdxx", ["mn", ""]) = 10 5034 * </pre> 5035 * 5036 * @param str the CharSequence to check, may be null 5037 * @param searchStrs the CharSequences to search for, may be null 5038 * @return the last index of any of the CharSequences, -1 if no match 5039 * @since 3.0 Changed signature from lastIndexOfAny(String, String[]) to lastIndexOfAny(CharSequence, CharSequence) 5040 */ 5041 public static int lastIndexOfAny(final CharSequence str, final CharSequence... searchStrs) { 5042 if (str == null || searchStrs == null) { 5043 return INDEX_NOT_FOUND; 5044 } 5045 int ret = INDEX_NOT_FOUND; 5046 int tmp; 5047 for (final CharSequence search : searchStrs) { 5048 if (search == null) { 5049 continue; 5050 } 5051 tmp = CharSequenceUtils.lastIndexOf(str, search, str.length()); 5052 if (tmp > ret) { 5053 ret = tmp; 5054 } 5055 } 5056 return ret; 5057 } 5058 5059 /** 5060 * Case in-sensitive find of the last index within a CharSequence. 5061 * 5062 * <p>A {@code null} CharSequence will return {@code -1}. 5063 * A negative start position returns {@code -1}. 5064 * An empty ("") search CharSequence always matches unless the start position is negative. 5065 * A start position greater than the string length searches the whole string.</p> 5066 * 5067 * <pre> 5068 * StringUtils.lastIndexOfIgnoreCase(null, *) = -1 5069 * StringUtils.lastIndexOfIgnoreCase(*, null) = -1 5070 * StringUtils.lastIndexOfIgnoreCase("aabaabaa", "A") = 7 5071 * StringUtils.lastIndexOfIgnoreCase("aabaabaa", "B") = 5 5072 * StringUtils.lastIndexOfIgnoreCase("aabaabaa", "AB") = 4 5073 * </pre> 5074 * 5075 * @param str the CharSequence to check, may be null 5076 * @param searchStr the CharSequence to find, may be null 5077 * @return the first index of the search CharSequence, 5078 * -1 if no match or {@code null} string input 5079 * @since 2.5 5080 * @since 3.0 Changed signature from lastIndexOfIgnoreCase(String, String) to lastIndexOfIgnoreCase(CharSequence, CharSequence) 5081 */ 5082 public static int lastIndexOfIgnoreCase(final CharSequence str, final CharSequence searchStr) { 5083 if (str == null || searchStr == null) { 5084 return INDEX_NOT_FOUND; 5085 } 5086 return lastIndexOfIgnoreCase(str, searchStr, str.length()); 5087 } 5088 5089 /** 5090 * Case in-sensitive find of the last index within a CharSequence 5091 * from the specified position. 5092 * 5093 * <p>A {@code null} CharSequence will return {@code -1}. 5094 * A negative start position returns {@code -1}. 5095 * An empty ("") search CharSequence always matches unless the start position is negative. 5096 * A start position greater than the string length searches the whole string. 5097 * The search starts at the startPos and works backwards; matches starting after the start 5098 * position are ignored. 5099 * </p> 5100 * 5101 * <pre> 5102 * StringUtils.lastIndexOfIgnoreCase(null, *, *) = -1 5103 * StringUtils.lastIndexOfIgnoreCase(*, null, *) = -1 5104 * StringUtils.lastIndexOfIgnoreCase("aabaabaa", "A", 8) = 7 5105 * StringUtils.lastIndexOfIgnoreCase("aabaabaa", "B", 8) = 5 5106 * StringUtils.lastIndexOfIgnoreCase("aabaabaa", "AB", 8) = 4 5107 * StringUtils.lastIndexOfIgnoreCase("aabaabaa", "B", 9) = 5 5108 * StringUtils.lastIndexOfIgnoreCase("aabaabaa", "B", -1) = -1 5109 * StringUtils.lastIndexOfIgnoreCase("aabaabaa", "A", 0) = 0 5110 * StringUtils.lastIndexOfIgnoreCase("aabaabaa", "B", 0) = -1 5111 * </pre> 5112 * 5113 * @param str the CharSequence to check, may be null 5114 * @param searchStr the CharSequence to find, may be null 5115 * @param startPos the start position 5116 * @return the last index of the search CharSequence (always ≤ startPos), 5117 * -1 if no match or {@code null} input 5118 * @since 2.5 5119 * @since 3.0 Changed signature from lastIndexOfIgnoreCase(String, String, int) to lastIndexOfIgnoreCase(CharSequence, CharSequence, int) 5120 */ 5121 public static int lastIndexOfIgnoreCase(final CharSequence str, final CharSequence searchStr, int startPos) { 5122 if (str == null || searchStr == null) { 5123 return INDEX_NOT_FOUND; 5124 } 5125 final int searchStrLength = searchStr.length(); 5126 final int strLength = str.length(); 5127 if (startPos > strLength - searchStrLength) { 5128 startPos = strLength - searchStrLength; 5129 } 5130 if (startPos < 0) { 5131 return INDEX_NOT_FOUND; 5132 } 5133 if (searchStrLength == 0) { 5134 return startPos; 5135 } 5136 5137 for (int i = startPos; i >= 0; i--) { 5138 if (CharSequenceUtils.regionMatches(str, true, i, searchStr, 0, searchStrLength)) { 5139 return i; 5140 } 5141 } 5142 return INDEX_NOT_FOUND; 5143 } 5144 5145 /** 5146 * Finds the n-th last index within a String, handling {@code null}. 5147 * This method uses {@link String#lastIndexOf(String)}. 5148 * 5149 * <p>A {@code null} String will return {@code -1}.</p> 5150 * 5151 * <pre> 5152 * StringUtils.lastOrdinalIndexOf(null, *, *) = -1 5153 * StringUtils.lastOrdinalIndexOf(*, null, *) = -1 5154 * StringUtils.lastOrdinalIndexOf("", "", *) = 0 5155 * StringUtils.lastOrdinalIndexOf("aabaabaa", "a", 1) = 7 5156 * StringUtils.lastOrdinalIndexOf("aabaabaa", "a", 2) = 6 5157 * StringUtils.lastOrdinalIndexOf("aabaabaa", "b", 1) = 5 5158 * StringUtils.lastOrdinalIndexOf("aabaabaa", "b", 2) = 2 5159 * StringUtils.lastOrdinalIndexOf("aabaabaa", "ab", 1) = 4 5160 * StringUtils.lastOrdinalIndexOf("aabaabaa", "ab", 2) = 1 5161 * StringUtils.lastOrdinalIndexOf("aabaabaa", "", 1) = 8 5162 * StringUtils.lastOrdinalIndexOf("aabaabaa", "", 2) = 8 5163 * </pre> 5164 * 5165 * <p>Note that 'tail(CharSequence str, int n)' may be implemented as: </p> 5166 * 5167 * <pre> 5168 * str.substring(lastOrdinalIndexOf(str, "\n", n) + 1) 5169 * </pre> 5170 * 5171 * @param str the CharSequence to check, may be null 5172 * @param searchStr the CharSequence to find, may be null 5173 * @param ordinal the n-th last {@code searchStr} to find 5174 * @return the n-th last index of the search CharSequence, 5175 * {@code -1} ({@code INDEX_NOT_FOUND}) if no match or {@code null} string input 5176 * @since 2.5 5177 * @since 3.0 Changed signature from lastOrdinalIndexOf(String, String, int) to lastOrdinalIndexOf(CharSequence, CharSequence, int) 5178 */ 5179 public static int lastOrdinalIndexOf(final CharSequence str, final CharSequence searchStr, final int ordinal) { 5180 return ordinalIndexOf(str, searchStr, ordinal, true); 5181 } 5182 5183 /** 5184 * Gets the leftmost {@code len} characters of a String. 5185 * 5186 * <p>If {@code len} characters are not available, or the 5187 * String is {@code null}, the String will be returned without 5188 * an exception. An empty String is returned if len is negative.</p> 5189 * 5190 * <pre> 5191 * StringUtils.left(null, *) = null 5192 * StringUtils.left(*, -ve) = "" 5193 * StringUtils.left("", *) = "" 5194 * StringUtils.left("abc", 0) = "" 5195 * StringUtils.left("abc", 2) = "ab" 5196 * StringUtils.left("abc", 4) = "abc" 5197 * </pre> 5198 * 5199 * @param str the String to get the leftmost characters from, may be null 5200 * @param len the length of the required String 5201 * @return the leftmost characters, {@code null} if null String input 5202 */ 5203 public static String left(final String str, final int len) { 5204 if (str == null) { 5205 return null; 5206 } 5207 if (len < 0) { 5208 return EMPTY; 5209 } 5210 if (str.length() <= len) { 5211 return str; 5212 } 5213 return str.substring(0, len); 5214 } 5215 5216 /** 5217 * Left pad a String with spaces (' '). 5218 * 5219 * <p>The String is padded to the size of {@code size}.</p> 5220 * 5221 * <pre> 5222 * StringUtils.leftPad(null, *) = null 5223 * StringUtils.leftPad("", 3) = " " 5224 * StringUtils.leftPad("bat", 3) = "bat" 5225 * StringUtils.leftPad("bat", 5) = " bat" 5226 * StringUtils.leftPad("bat", 1) = "bat" 5227 * StringUtils.leftPad("bat", -1) = "bat" 5228 * </pre> 5229 * 5230 * @param str the String to pad out, may be null 5231 * @param size the size to pad to 5232 * @return left padded String or original String if no padding is necessary, 5233 * {@code null} if null String input 5234 */ 5235 public static String leftPad(final String str, final int size) { 5236 return leftPad(str, size, ' '); 5237 } 5238 5239 /** 5240 * Left pad a String with a specified character. 5241 * 5242 * <p>Pad to a size of {@code size}.</p> 5243 * 5244 * <pre> 5245 * StringUtils.leftPad(null, *, *) = null 5246 * StringUtils.leftPad("", 3, 'z') = "zzz" 5247 * StringUtils.leftPad("bat", 3, 'z') = "bat" 5248 * StringUtils.leftPad("bat", 5, 'z') = "zzbat" 5249 * StringUtils.leftPad("bat", 1, 'z') = "bat" 5250 * StringUtils.leftPad("bat", -1, 'z') = "bat" 5251 * </pre> 5252 * 5253 * @param str the String to pad out, may be null 5254 * @param size the size to pad to 5255 * @param padChar the character to pad with 5256 * @return left padded String or original String if no padding is necessary, 5257 * {@code null} if null String input 5258 * @since 2.0 5259 */ 5260 public static String leftPad(final String str, final int size, final char padChar) { 5261 if (str == null) { 5262 return null; 5263 } 5264 final int pads = size - str.length(); 5265 if (pads <= 0) { 5266 return str; // returns original String when possible 5267 } 5268 if (pads > PAD_LIMIT) { 5269 return leftPad(str, size, String.valueOf(padChar)); 5270 } 5271 return repeat(padChar, pads).concat(str); 5272 } 5273 5274 /** 5275 * Left pad a String with a specified String. 5276 * 5277 * <p>Pad to a size of {@code size}.</p> 5278 * 5279 * <pre> 5280 * StringUtils.leftPad(null, *, *) = null 5281 * StringUtils.leftPad("", 3, "z") = "zzz" 5282 * StringUtils.leftPad("bat", 3, "yz") = "bat" 5283 * StringUtils.leftPad("bat", 5, "yz") = "yzbat" 5284 * StringUtils.leftPad("bat", 8, "yz") = "yzyzybat" 5285 * StringUtils.leftPad("bat", 1, "yz") = "bat" 5286 * StringUtils.leftPad("bat", -1, "yz") = "bat" 5287 * StringUtils.leftPad("bat", 5, null) = " bat" 5288 * StringUtils.leftPad("bat", 5, "") = " bat" 5289 * </pre> 5290 * 5291 * @param str the String to pad out, may be null 5292 * @param size the size to pad to 5293 * @param padStr the String to pad with, null or empty treated as single space 5294 * @return left padded String or original String if no padding is necessary, 5295 * {@code null} if null String input 5296 */ 5297 public static String leftPad(final String str, final int size, String padStr) { 5298 if (str == null) { 5299 return null; 5300 } 5301 if (isEmpty(padStr)) { 5302 padStr = SPACE; 5303 } 5304 final int padLen = padStr.length(); 5305 final int strLen = str.length(); 5306 final int pads = size - strLen; 5307 if (pads <= 0) { 5308 return str; // returns original String when possible 5309 } 5310 if (padLen == 1 && pads <= PAD_LIMIT) { 5311 return leftPad(str, size, padStr.charAt(0)); 5312 } 5313 5314 if (pads == padLen) { 5315 return padStr.concat(str); 5316 } 5317 if (pads < padLen) { 5318 return padStr.substring(0, pads).concat(str); 5319 } 5320 final char[] padding = new char[pads]; 5321 final char[] padChars = padStr.toCharArray(); 5322 for (int i = 0; i < pads; i++) { 5323 padding[i] = padChars[i % padLen]; 5324 } 5325 return new String(padding).concat(str); 5326 } 5327 5328 /** 5329 * Gets a CharSequence length or {@code 0} if the CharSequence is 5330 * {@code null}. 5331 * 5332 * @param cs 5333 * a CharSequence or {@code null} 5334 * @return CharSequence length or {@code 0} if the CharSequence is 5335 * {@code null}. 5336 * @since 2.4 5337 * @since 3.0 Changed signature from length(String) to length(CharSequence) 5338 */ 5339 public static int length(final CharSequence cs) { 5340 return cs == null ? 0 : cs.length(); 5341 } 5342 5343 /** 5344 * Converts a String to lower case as per {@link String#toLowerCase()}. 5345 * 5346 * <p>A {@code null} input String returns {@code null}.</p> 5347 * 5348 * <pre> 5349 * StringUtils.lowerCase(null) = null 5350 * StringUtils.lowerCase("") = "" 5351 * StringUtils.lowerCase("aBc") = "abc" 5352 * </pre> 5353 * 5354 * <p><strong>Note:</strong> As described in the documentation for {@link String#toLowerCase()}, 5355 * the result of this method is affected by the current locale. 5356 * For platform-independent case transformations, the method {@link #lowerCase(String, Locale)} 5357 * should be used with a specific locale (e.g. {@link Locale#ENGLISH}).</p> 5358 * 5359 * @param str the String to lower case, may be null 5360 * @return the lower cased String, {@code null} if null String input 5361 */ 5362 public static String lowerCase(final String str) { 5363 if (str == null) { 5364 return null; 5365 } 5366 return str.toLowerCase(); 5367 } 5368 5369 /** 5370 * Converts a String to lower case as per {@link String#toLowerCase(Locale)}. 5371 * 5372 * <p>A {@code null} input String returns {@code null}.</p> 5373 * 5374 * <pre> 5375 * StringUtils.lowerCase(null, Locale.ENGLISH) = null 5376 * StringUtils.lowerCase("", Locale.ENGLISH) = "" 5377 * StringUtils.lowerCase("aBc", Locale.ENGLISH) = "abc" 5378 * </pre> 5379 * 5380 * @param str the String to lower case, may be null 5381 * @param locale the locale that defines the case transformation rules, must not be null 5382 * @return the lower cased String, {@code null} if null String input 5383 * @since 2.5 5384 */ 5385 public static String lowerCase(final String str, final Locale locale) { 5386 if (str == null) { 5387 return null; 5388 } 5389 return str.toLowerCase(LocaleUtils.toLocale(locale)); 5390 } 5391 5392 private static int[] matches(final CharSequence first, final CharSequence second) { 5393 final CharSequence max; 5394 final CharSequence min; 5395 if (first.length() > second.length()) { 5396 max = first; 5397 min = second; 5398 } else { 5399 max = second; 5400 min = first; 5401 } 5402 final int range = Math.max(max.length() / 2 - 1, 0); 5403 final int[] matchIndexes = ArrayFill.fill(new int[min.length()], -1); 5404 final boolean[] matchFlags = new boolean[max.length()]; 5405 int matches = 0; 5406 for (int mi = 0; mi < min.length(); mi++) { 5407 final char c1 = min.charAt(mi); 5408 for (int xi = Math.max(mi - range, 0), xn = Math.min(mi + range + 1, max.length()); xi < xn; xi++) { 5409 if (!matchFlags[xi] && c1 == max.charAt(xi)) { 5410 matchIndexes[mi] = xi; 5411 matchFlags[xi] = true; 5412 matches++; 5413 break; 5414 } 5415 } 5416 } 5417 final char[] ms1 = new char[matches]; 5418 final char[] ms2 = new char[matches]; 5419 for (int i = 0, si = 0; i < min.length(); i++) { 5420 if (matchIndexes[i] != -1) { 5421 ms1[si] = min.charAt(i); 5422 si++; 5423 } 5424 } 5425 for (int i = 0, si = 0; i < max.length(); i++) { 5426 if (matchFlags[i]) { 5427 ms2[si] = max.charAt(i); 5428 si++; 5429 } 5430 } 5431 int transpositions = 0; 5432 for (int mi = 0; mi < ms1.length; mi++) { 5433 if (ms1[mi] != ms2[mi]) { 5434 transpositions++; 5435 } 5436 } 5437 int prefix = 0; 5438 for (int mi = 0; mi < min.length(); mi++) { 5439 if (first.charAt(mi) != second.charAt(mi)) { 5440 break; 5441 } 5442 prefix++; 5443 } 5444 return new int[] { matches, transpositions / 2, prefix, max.length() }; 5445 } 5446 5447 /** 5448 * Gets {@code len} characters from the middle of a String. 5449 * 5450 * <p>If {@code len} characters are not available, the remainder 5451 * of the String will be returned without an exception. If the 5452 * String is {@code null}, {@code null} will be returned. 5453 * An empty String is returned if len is negative or exceeds the 5454 * length of {@code str}.</p> 5455 * 5456 * <pre> 5457 * StringUtils.mid(null, *, *) = null 5458 * StringUtils.mid(*, *, -ve) = "" 5459 * StringUtils.mid("", 0, *) = "" 5460 * StringUtils.mid("abc", 0, 2) = "ab" 5461 * StringUtils.mid("abc", 0, 4) = "abc" 5462 * StringUtils.mid("abc", 2, 4) = "c" 5463 * StringUtils.mid("abc", 4, 2) = "" 5464 * StringUtils.mid("abc", -2, 2) = "ab" 5465 * </pre> 5466 * 5467 * @param str the String to get the characters from, may be null 5468 * @param pos the position to start from, negative treated as zero 5469 * @param len the length of the required String 5470 * @return the middle characters, {@code null} if null String input 5471 */ 5472 public static String mid(final String str, int pos, final int len) { 5473 if (str == null) { 5474 return null; 5475 } 5476 if (len < 0 || pos > str.length()) { 5477 return EMPTY; 5478 } 5479 if (pos < 0) { 5480 pos = 0; 5481 } 5482 if (str.length() <= pos + len) { 5483 return str.substring(pos); 5484 } 5485 return str.substring(pos, pos + len); 5486 } 5487 5488 /** 5489 * Similar to <a 5490 * href="https://www.w3.org/TR/xpath/#function-normalize-space">https://www.w3.org/TR/xpath/#function-normalize 5491 * -space</a> 5492 * 5493 * <p> 5494 * The function returns the argument string with whitespace normalized by using 5495 * {@code {@link #trim(String)}} to remove leading and trailing whitespace 5496 * and then replacing sequences of whitespace characters by a single space. 5497 * </p> 5498 * In XML Whitespace characters are the same as those allowed by the <a 5499 * href="https://www.w3.org/TR/REC-xml/#NT-S">S</a> production, which is S ::= (#x20 | #x9 | #xD | #xA)+ 5500 * <p> 5501 * Java's regexp pattern \s defines whitespace as [ \t\n\x0B\f\r] 5502 * 5503 * <p>For reference:</p> 5504 * <ul> 5505 * <li>\x0B = vertical tab</li> 5506 * <li>\f = #xC = form feed</li> 5507 * <li>#x20 = space</li> 5508 * <li>#x9 = \t</li> 5509 * <li>#xA = \n</li> 5510 * <li>#xD = \r</li> 5511 * </ul> 5512 * 5513 * <p> 5514 * The difference is that Java's whitespace includes vertical tab and form feed, which this functional will also 5515 * normalize. Additionally {@code {@link #trim(String)}} removes control characters (char <= 32) from both 5516 * ends of this String. 5517 * </p> 5518 * 5519 * @see Pattern 5520 * @see #trim(String) 5521 * @see <a 5522 * href="https://www.w3.org/TR/xpath/#function-normalize-space">https://www.w3.org/TR/xpath/#function-normalize-space</a> 5523 * @param str the source String to normalize whitespaces from, may be null 5524 * @return the modified string with whitespace normalized, {@code null} if null String input 5525 * 5526 * @since 3.0 5527 */ 5528 public static String normalizeSpace(final String str) { 5529 // LANG-1020: Improved performance significantly by normalizing manually instead of using regex 5530 // See https://github.com/librucha/commons-lang-normalizespaces-benchmark for performance test 5531 if (isEmpty(str)) { 5532 return str; 5533 } 5534 final int size = str.length(); 5535 final char[] newChars = new char[size]; 5536 int count = 0; 5537 int whitespacesCount = 0; 5538 boolean startWhitespaces = true; 5539 for (int i = 0; i < size; i++) { 5540 final char actualChar = str.charAt(i); 5541 final boolean isWhitespace = Character.isWhitespace(actualChar); 5542 if (isWhitespace) { 5543 if (whitespacesCount == 0 && !startWhitespaces) { 5544 newChars[count++] = SPACE.charAt(0); 5545 } 5546 whitespacesCount++; 5547 } else { 5548 startWhitespaces = false; 5549 newChars[count++] = actualChar == 160 ? 32 : actualChar; 5550 whitespacesCount = 0; 5551 } 5552 } 5553 if (startWhitespaces) { 5554 return EMPTY; 5555 } 5556 return new String(newChars, 0, count - (whitespacesCount > 0 ? 1 : 0)).trim(); 5557 } 5558 5559 /** 5560 * Finds the n-th index within a CharSequence, handling {@code null}. 5561 * This method uses {@link String#indexOf(String)} if possible. 5562 * <p><b>Note:</b> The code starts looking for a match at the start of the target, 5563 * incrementing the starting index by one after each successful match 5564 * (unless {@code searchStr} is an empty string in which case the position 5565 * is never incremented and {@code 0} is returned immediately). 5566 * This means that matches may overlap.</p> 5567 * <p>A {@code null} CharSequence will return {@code -1}.</p> 5568 * 5569 * <pre> 5570 * StringUtils.ordinalIndexOf(null, *, *) = -1 5571 * StringUtils.ordinalIndexOf(*, null, *) = -1 5572 * StringUtils.ordinalIndexOf("", "", *) = 0 5573 * StringUtils.ordinalIndexOf("aabaabaa", "a", 1) = 0 5574 * StringUtils.ordinalIndexOf("aabaabaa", "a", 2) = 1 5575 * StringUtils.ordinalIndexOf("aabaabaa", "b", 1) = 2 5576 * StringUtils.ordinalIndexOf("aabaabaa", "b", 2) = 5 5577 * StringUtils.ordinalIndexOf("aabaabaa", "ab", 1) = 1 5578 * StringUtils.ordinalIndexOf("aabaabaa", "ab", 2) = 4 5579 * StringUtils.ordinalIndexOf("aabaabaa", "", 1) = 0 5580 * StringUtils.ordinalIndexOf("aabaabaa", "", 2) = 0 5581 * </pre> 5582 * 5583 * <p>Matches may overlap:</p> 5584 * <pre> 5585 * StringUtils.ordinalIndexOf("ababab", "aba", 1) = 0 5586 * StringUtils.ordinalIndexOf("ababab", "aba", 2) = 2 5587 * StringUtils.ordinalIndexOf("ababab", "aba", 3) = -1 5588 * 5589 * StringUtils.ordinalIndexOf("abababab", "abab", 1) = 0 5590 * StringUtils.ordinalIndexOf("abababab", "abab", 2) = 2 5591 * StringUtils.ordinalIndexOf("abababab", "abab", 3) = 4 5592 * StringUtils.ordinalIndexOf("abababab", "abab", 4) = -1 5593 * </pre> 5594 * 5595 * <p>Note that 'head(CharSequence str, int n)' may be implemented as: </p> 5596 * 5597 * <pre> 5598 * str.substring(0, lastOrdinalIndexOf(str, "\n", n)) 5599 * </pre> 5600 * 5601 * @param str the CharSequence to check, may be null 5602 * @param searchStr the CharSequence to find, may be null 5603 * @param ordinal the n-th {@code searchStr} to find 5604 * @return the n-th index of the search CharSequence, 5605 * {@code -1} ({@code INDEX_NOT_FOUND}) if no match or {@code null} string input 5606 * @since 2.1 5607 * @since 3.0 Changed signature from ordinalIndexOf(String, String, int) to ordinalIndexOf(CharSequence, CharSequence, int) 5608 */ 5609 public static int ordinalIndexOf(final CharSequence str, final CharSequence searchStr, final int ordinal) { 5610 return ordinalIndexOf(str, searchStr, ordinal, false); 5611 } 5612 5613 /** 5614 * Finds the n-th index within a String, handling {@code null}. 5615 * This method uses {@link String#indexOf(String)} if possible. 5616 * <p>Note that matches may overlap<p> 5617 * 5618 * <p>A {@code null} CharSequence will return {@code -1}.</p> 5619 * 5620 * @param str the CharSequence to check, may be null 5621 * @param searchStr the CharSequence to find, may be null 5622 * @param ordinal the n-th {@code searchStr} to find, overlapping matches are allowed. 5623 * @param lastIndex true if lastOrdinalIndexOf() otherwise false if ordinalIndexOf() 5624 * @return the n-th index of the search CharSequence, 5625 * {@code -1} ({@code INDEX_NOT_FOUND}) if no match or {@code null} string input 5626 */ 5627 // Shared code between ordinalIndexOf(String, String, int) and lastOrdinalIndexOf(String, String, int) 5628 private static int ordinalIndexOf(final CharSequence str, final CharSequence searchStr, final int ordinal, final boolean lastIndex) { 5629 if (str == null || searchStr == null || ordinal <= 0) { 5630 return INDEX_NOT_FOUND; 5631 } 5632 if (searchStr.length() == 0) { 5633 return lastIndex ? str.length() : 0; 5634 } 5635 int found = 0; 5636 // set the initial index beyond the end of the string 5637 // this is to allow for the initial index decrement/increment 5638 int index = lastIndex ? str.length() : INDEX_NOT_FOUND; 5639 do { 5640 if (lastIndex) { 5641 index = CharSequenceUtils.lastIndexOf(str, searchStr, index - 1); // step backwards through string 5642 } else { 5643 index = CharSequenceUtils.indexOf(str, searchStr, index + 1); // step forwards through string 5644 } 5645 if (index < 0) { 5646 return index; 5647 } 5648 found++; 5649 } while (found < ordinal); 5650 return index; 5651 } 5652 5653 /** 5654 * Overlays part of a String with another String. 5655 * 5656 * <p>A {@code null} string input returns {@code null}. 5657 * A negative index is treated as zero. 5658 * An index greater than the string length is treated as the string length. 5659 * The start index is always the smaller of the two indices.</p> 5660 * 5661 * <pre> 5662 * StringUtils.overlay(null, *, *, *) = null 5663 * StringUtils.overlay("", "abc", 0, 0) = "abc" 5664 * StringUtils.overlay("abcdef", null, 2, 4) = "abef" 5665 * StringUtils.overlay("abcdef", "", 2, 4) = "abef" 5666 * StringUtils.overlay("abcdef", "", 4, 2) = "abef" 5667 * StringUtils.overlay("abcdef", "zzzz", 2, 4) = "abzzzzef" 5668 * StringUtils.overlay("abcdef", "zzzz", 4, 2) = "abzzzzef" 5669 * StringUtils.overlay("abcdef", "zzzz", -1, 4) = "zzzzef" 5670 * StringUtils.overlay("abcdef", "zzzz", 2, 8) = "abzzzz" 5671 * StringUtils.overlay("abcdef", "zzzz", -2, -3) = "zzzzabcdef" 5672 * StringUtils.overlay("abcdef", "zzzz", 8, 10) = "abcdefzzzz" 5673 * </pre> 5674 * 5675 * @param str the String to do overlaying in, may be null 5676 * @param overlay the String to overlay, may be null 5677 * @param start the position to start overlaying at 5678 * @param end the position to stop overlaying before 5679 * @return overlayed String, {@code null} if null String input 5680 * @since 2.0 5681 */ 5682 public static String overlay(final String str, String overlay, int start, int end) { 5683 if (str == null) { 5684 return null; 5685 } 5686 if (overlay == null) { 5687 overlay = EMPTY; 5688 } 5689 final int len = str.length(); 5690 if (start < 0) { 5691 start = 0; 5692 } 5693 if (start > len) { 5694 start = len; 5695 } 5696 if (end < 0) { 5697 end = 0; 5698 } 5699 if (end > len) { 5700 end = len; 5701 } 5702 if (start > end) { 5703 final int temp = start; 5704 start = end; 5705 end = temp; 5706 } 5707 return str.substring(0, start) + 5708 overlay + 5709 str.substring(end); 5710 } 5711 5712 /** 5713 * Prepends the prefix to the start of the string if the string does not 5714 * already start with any of the prefixes. 5715 * 5716 * @param str The string. 5717 * @param prefix The prefix to prepend to the start of the string. 5718 * @param ignoreCase Indicates whether the compare should ignore case. 5719 * @param prefixes Additional prefixes that are valid (optional). 5720 * 5721 * @return A new String if prefix was prepended, the same string otherwise. 5722 */ 5723 private static String prependIfMissing(final String str, final CharSequence prefix, final boolean ignoreCase, final CharSequence... prefixes) { 5724 if (str == null || isEmpty(prefix) || startsWith(str, prefix, ignoreCase)) { 5725 return str; 5726 } 5727 if (ArrayUtils.isNotEmpty(prefixes)) { 5728 for (final CharSequence p : prefixes) { 5729 if (startsWith(str, p, ignoreCase)) { 5730 return str; 5731 } 5732 } 5733 } 5734 return prefix + str; 5735 } 5736 5737 /** 5738 * Prepends the prefix to the start of the string if the string does not 5739 * already start with any of the prefixes. 5740 * 5741 * <pre> 5742 * StringUtils.prependIfMissing(null, null) = null 5743 * StringUtils.prependIfMissing("abc", null) = "abc" 5744 * StringUtils.prependIfMissing("", "xyz") = "xyz" 5745 * StringUtils.prependIfMissing("abc", "xyz") = "xyzabc" 5746 * StringUtils.prependIfMissing("xyzabc", "xyz") = "xyzabc" 5747 * StringUtils.prependIfMissing("XYZabc", "xyz") = "xyzXYZabc" 5748 * </pre> 5749 * <p>With additional prefixes,</p> 5750 * <pre> 5751 * StringUtils.prependIfMissing(null, null, null) = null 5752 * StringUtils.prependIfMissing("abc", null, null) = "abc" 5753 * StringUtils.prependIfMissing("", "xyz", null) = "xyz" 5754 * StringUtils.prependIfMissing("abc", "xyz", new CharSequence[]{null}) = "xyzabc" 5755 * StringUtils.prependIfMissing("abc", "xyz", "") = "abc" 5756 * StringUtils.prependIfMissing("abc", "xyz", "mno") = "xyzabc" 5757 * StringUtils.prependIfMissing("xyzabc", "xyz", "mno") = "xyzabc" 5758 * StringUtils.prependIfMissing("mnoabc", "xyz", "mno") = "mnoabc" 5759 * StringUtils.prependIfMissing("XYZabc", "xyz", "mno") = "xyzXYZabc" 5760 * StringUtils.prependIfMissing("MNOabc", "xyz", "mno") = "xyzMNOabc" 5761 * </pre> 5762 * 5763 * @param str The string. 5764 * @param prefix The prefix to prepend to the start of the string. 5765 * @param prefixes Additional prefixes that are valid. 5766 * 5767 * @return A new String if prefix was prepended, the same string otherwise. 5768 * 5769 * @since 3.2 5770 */ 5771 public static String prependIfMissing(final String str, final CharSequence prefix, final CharSequence... prefixes) { 5772 return prependIfMissing(str, prefix, false, prefixes); 5773 } 5774 5775 /** 5776 * Prepends the prefix to the start of the string if the string does not 5777 * already start, case-insensitive, with any of the prefixes. 5778 * 5779 * <pre> 5780 * StringUtils.prependIfMissingIgnoreCase(null, null) = null 5781 * StringUtils.prependIfMissingIgnoreCase("abc", null) = "abc" 5782 * StringUtils.prependIfMissingIgnoreCase("", "xyz") = "xyz" 5783 * StringUtils.prependIfMissingIgnoreCase("abc", "xyz") = "xyzabc" 5784 * StringUtils.prependIfMissingIgnoreCase("xyzabc", "xyz") = "xyzabc" 5785 * StringUtils.prependIfMissingIgnoreCase("XYZabc", "xyz") = "XYZabc" 5786 * </pre> 5787 * <p>With additional prefixes,</p> 5788 * <pre> 5789 * StringUtils.prependIfMissingIgnoreCase(null, null, null) = null 5790 * StringUtils.prependIfMissingIgnoreCase("abc", null, null) = "abc" 5791 * StringUtils.prependIfMissingIgnoreCase("", "xyz", null) = "xyz" 5792 * StringUtils.prependIfMissingIgnoreCase("abc", "xyz", new CharSequence[]{null}) = "xyzabc" 5793 * StringUtils.prependIfMissingIgnoreCase("abc", "xyz", "") = "abc" 5794 * StringUtils.prependIfMissingIgnoreCase("abc", "xyz", "mno") = "xyzabc" 5795 * StringUtils.prependIfMissingIgnoreCase("xyzabc", "xyz", "mno") = "xyzabc" 5796 * StringUtils.prependIfMissingIgnoreCase("mnoabc", "xyz", "mno") = "mnoabc" 5797 * StringUtils.prependIfMissingIgnoreCase("XYZabc", "xyz", "mno") = "XYZabc" 5798 * StringUtils.prependIfMissingIgnoreCase("MNOabc", "xyz", "mno") = "MNOabc" 5799 * </pre> 5800 * 5801 * @param str The string. 5802 * @param prefix The prefix to prepend to the start of the string. 5803 * @param prefixes Additional prefixes that are valid (optional). 5804 * 5805 * @return A new String if prefix was prepended, the same string otherwise. 5806 * 5807 * @since 3.2 5808 */ 5809 public static String prependIfMissingIgnoreCase(final String str, final CharSequence prefix, final CharSequence... prefixes) { 5810 return prependIfMissing(str, prefix, true, prefixes); 5811 } 5812 5813 /** 5814 * Removes all occurrences of a character from within the source string. 5815 * 5816 * <p>A {@code null} source string will return {@code null}. 5817 * An empty ("") source string will return the empty string.</p> 5818 * 5819 * <pre> 5820 * StringUtils.remove(null, *) = null 5821 * StringUtils.remove("", *) = "" 5822 * StringUtils.remove("queued", 'u') = "qeed" 5823 * StringUtils.remove("queued", 'z') = "queued" 5824 * </pre> 5825 * 5826 * @param str the source String to search, may be null 5827 * @param remove the char to search for and remove, may be null 5828 * @return the substring with the char removed if found, 5829 * {@code null} if null String input 5830 * @since 2.1 5831 */ 5832 public static String remove(final String str, final char remove) { 5833 if (isEmpty(str) || str.indexOf(remove) == INDEX_NOT_FOUND) { 5834 return str; 5835 } 5836 final char[] chars = str.toCharArray(); 5837 int pos = 0; 5838 for (int i = 0; i < chars.length; i++) { 5839 if (chars[i] != remove) { 5840 chars[pos++] = chars[i]; 5841 } 5842 } 5843 return new String(chars, 0, pos); 5844 } 5845 5846 /** 5847 * Removes all occurrences of a substring from within the source string. 5848 * 5849 * <p>A {@code null} source string will return {@code null}. 5850 * An empty ("") source string will return the empty string. 5851 * A {@code null} remove string will return the source string. 5852 * An empty ("") remove string will return the source string.</p> 5853 * 5854 * <pre> 5855 * StringUtils.remove(null, *) = null 5856 * StringUtils.remove("", *) = "" 5857 * StringUtils.remove(*, null) = * 5858 * StringUtils.remove(*, "") = * 5859 * StringUtils.remove("queued", "ue") = "qd" 5860 * StringUtils.remove("queued", "zz") = "queued" 5861 * </pre> 5862 * 5863 * @param str the source String to search, may be null 5864 * @param remove the String to search for and remove, may be null 5865 * @return the substring with the string removed if found, 5866 * {@code null} if null String input 5867 * @since 2.1 5868 */ 5869 public static String remove(final String str, final String remove) { 5870 if (isEmpty(str) || isEmpty(remove)) { 5871 return str; 5872 } 5873 return replace(str, remove, EMPTY, -1); 5874 } 5875 5876 /** 5877 * Removes each substring of the text String that matches the given regular expression. 5878 * 5879 * This method is a {@code null} safe equivalent to: 5880 * <ul> 5881 * <li>{@code text.replaceAll(regex, StringUtils.EMPTY)}</li> 5882 * <li>{@code Pattern.compile(regex).matcher(text).replaceAll(StringUtils.EMPTY)}</li> 5883 * </ul> 5884 * 5885 * <p>A {@code null} reference passed to this method is a no-op.</p> 5886 * 5887 * <p>Unlike in the {@link #removePattern(String, String)} method, the {@link Pattern#DOTALL} option 5888 * is NOT automatically added. 5889 * To use the DOTALL option prepend {@code "(?s)"} to the regex. 5890 * DOTALL is also known as single-line mode in Perl.</p> 5891 * 5892 * <pre>{@code 5893 * StringUtils.removeAll(null, *) = null 5894 * StringUtils.removeAll("any", (String) null) = "any" 5895 * StringUtils.removeAll("any", "") = "any" 5896 * StringUtils.removeAll("any", ".*") = "" 5897 * StringUtils.removeAll("any", ".+") = "" 5898 * StringUtils.removeAll("abc", ".?") = "" 5899 * StringUtils.removeAll("A<__>\n<__>B", "<.*>") = "A\nB" 5900 * StringUtils.removeAll("A<__>\n<__>B", "(?s)<.*>") = "AB" 5901 * StringUtils.removeAll("ABCabc123abc", "[a-z]") = "ABC123" 5902 * }</pre> 5903 * 5904 * @param text text to remove from, may be null 5905 * @param regex the regular expression to which this string is to be matched 5906 * @return the text with any removes processed, 5907 * {@code null} if null String input 5908 * 5909 * @throws java.util.regex.PatternSyntaxException 5910 * if the regular expression's syntax is invalid 5911 * 5912 * @see #replaceAll(String, String, String) 5913 * @see #removePattern(String, String) 5914 * @see String#replaceAll(String, String) 5915 * @see java.util.regex.Pattern 5916 * @see java.util.regex.Pattern#DOTALL 5917 * @since 3.5 5918 * 5919 * @deprecated Moved to RegExUtils. 5920 */ 5921 @Deprecated 5922 public static String removeAll(final String text, final String regex) { 5923 return RegExUtils.removeAll(text, regex); 5924 } 5925 5926 /** 5927 * Removes a substring only if it is at the end of a source string, 5928 * otherwise returns the source string. 5929 * 5930 * <p>A {@code null} source string will return {@code null}. 5931 * An empty ("") source string will return the empty string. 5932 * A {@code null} search string will return the source string.</p> 5933 * 5934 * <pre> 5935 * StringUtils.removeEnd(null, *) = null 5936 * StringUtils.removeEnd("", *) = "" 5937 * StringUtils.removeEnd(*, null) = * 5938 * StringUtils.removeEnd("www.domain.com", ".com.") = "www.domain.com" 5939 * StringUtils.removeEnd("www.domain.com", ".com") = "www.domain" 5940 * StringUtils.removeEnd("www.domain.com", "domain") = "www.domain.com" 5941 * StringUtils.removeEnd("abc", "") = "abc" 5942 * </pre> 5943 * 5944 * @param str the source String to search, may be null 5945 * @param remove the String to search for and remove, may be null 5946 * @return the substring with the string removed if found, 5947 * {@code null} if null String input 5948 * @since 2.1 5949 */ 5950 public static String removeEnd(final String str, final String remove) { 5951 if (isEmpty(str) || isEmpty(remove)) { 5952 return str; 5953 } 5954 if (str.endsWith(remove)) { 5955 return str.substring(0, str.length() - remove.length()); 5956 } 5957 return str; 5958 } 5959 5960 /** 5961 * Case-insensitive removal of a substring if it is at the end of a source string, 5962 * otherwise returns the source string. 5963 * 5964 * <p>A {@code null} source string will return {@code null}. 5965 * An empty ("") source string will return the empty string. 5966 * A {@code null} search string will return the source string.</p> 5967 * 5968 * <pre> 5969 * StringUtils.removeEndIgnoreCase(null, *) = null 5970 * StringUtils.removeEndIgnoreCase("", *) = "" 5971 * StringUtils.removeEndIgnoreCase(*, null) = * 5972 * StringUtils.removeEndIgnoreCase("www.domain.com", ".com.") = "www.domain.com" 5973 * StringUtils.removeEndIgnoreCase("www.domain.com", ".com") = "www.domain" 5974 * StringUtils.removeEndIgnoreCase("www.domain.com", "domain") = "www.domain.com" 5975 * StringUtils.removeEndIgnoreCase("abc", "") = "abc" 5976 * StringUtils.removeEndIgnoreCase("www.domain.com", ".COM") = "www.domain") 5977 * StringUtils.removeEndIgnoreCase("www.domain.COM", ".com") = "www.domain") 5978 * </pre> 5979 * 5980 * @param str the source String to search, may be null 5981 * @param remove the String to search for (case-insensitive) and remove, may be null 5982 * @return the substring with the string removed if found, 5983 * {@code null} if null String input 5984 * @since 2.4 5985 */ 5986 public static String removeEndIgnoreCase(final String str, final String remove) { 5987 if (isEmpty(str) || isEmpty(remove)) { 5988 return str; 5989 } 5990 if (endsWithIgnoreCase(str, remove)) { 5991 return str.substring(0, str.length() - remove.length()); 5992 } 5993 return str; 5994 } 5995 5996 /** 5997 * Removes the first substring of the text string that matches the given regular expression. 5998 * 5999 * This method is a {@code null} safe equivalent to: 6000 * <ul> 6001 * <li>{@code text.replaceFirst(regex, StringUtils.EMPTY)}</li> 6002 * <li>{@code Pattern.compile(regex).matcher(text).replaceFirst(StringUtils.EMPTY)}</li> 6003 * </ul> 6004 * 6005 * <p>A {@code null} reference passed to this method is a no-op.</p> 6006 * 6007 * <p>The {@link Pattern#DOTALL} option is NOT automatically added. 6008 * To use the DOTALL option prepend {@code "(?s)"} to the regex. 6009 * DOTALL is also known as single-line mode in Perl.</p> 6010 * 6011 * <pre>{@code 6012 * StringUtils.removeFirst(null, *) = null 6013 * StringUtils.removeFirst("any", (String) null) = "any" 6014 * StringUtils.removeFirst("any", "") = "any" 6015 * StringUtils.removeFirst("any", ".*") = "" 6016 * StringUtils.removeFirst("any", ".+") = "" 6017 * StringUtils.removeFirst("abc", ".?") = "bc" 6018 * StringUtils.removeFirst("A<__>\n<__>B", "<.*>") = "A\n<__>B" 6019 * StringUtils.removeFirst("A<__>\n<__>B", "(?s)<.*>") = "AB" 6020 * StringUtils.removeFirst("ABCabc123", "[a-z]") = "ABCbc123" 6021 * StringUtils.removeFirst("ABCabc123abc", "[a-z]+") = "ABC123abc" 6022 * }</pre> 6023 * 6024 * @param text text to remove from, may be null 6025 * @param regex the regular expression to which this string is to be matched 6026 * @return the text with the first replacement processed, 6027 * {@code null} if null String input 6028 * 6029 * @throws java.util.regex.PatternSyntaxException 6030 * if the regular expression's syntax is invalid 6031 * 6032 * @see #replaceFirst(String, String, String) 6033 * @see String#replaceFirst(String, String) 6034 * @see java.util.regex.Pattern 6035 * @see java.util.regex.Pattern#DOTALL 6036 * @since 3.5 6037 * 6038 * @deprecated Moved to RegExUtils. 6039 */ 6040 @Deprecated 6041 public static String removeFirst(final String text, final String regex) { 6042 return replaceFirst(text, regex, EMPTY); 6043 } 6044 6045 /** 6046 * Case-insensitive removal of all occurrences of a substring from within 6047 * the source string. 6048 * 6049 * <p> 6050 * A {@code null} source string will return {@code null}. An empty ("") 6051 * source string will return the empty string. A {@code null} remove string 6052 * will return the source string. An empty ("") remove string will return 6053 * the source string. 6054 * </p> 6055 * 6056 * <pre> 6057 * StringUtils.removeIgnoreCase(null, *) = null 6058 * StringUtils.removeIgnoreCase("", *) = "" 6059 * StringUtils.removeIgnoreCase(*, null) = * 6060 * StringUtils.removeIgnoreCase(*, "") = * 6061 * StringUtils.removeIgnoreCase("queued", "ue") = "qd" 6062 * StringUtils.removeIgnoreCase("queued", "zz") = "queued" 6063 * StringUtils.removeIgnoreCase("quEUed", "UE") = "qd" 6064 * StringUtils.removeIgnoreCase("queued", "zZ") = "queued" 6065 * </pre> 6066 * 6067 * @param str 6068 * the source String to search, may be null 6069 * @param remove 6070 * the String to search for (case-insensitive) and remove, may be 6071 * null 6072 * @return the substring with the string removed if found, {@code null} if 6073 * null String input 6074 * @since 3.5 6075 */ 6076 public static String removeIgnoreCase(final String str, final String remove) { 6077 return replaceIgnoreCase(str, remove, EMPTY, -1); 6078 } 6079 6080 /** 6081 * Removes each substring of the source String that matches the given regular expression using the DOTALL option. 6082 * 6083 * This call is a {@code null} safe equivalent to: 6084 * <ul> 6085 * <li>{@code source.replaceAll("(?s)" + regex, StringUtils.EMPTY)}</li> 6086 * <li>{@code Pattern.compile(regex, Pattern.DOTALL).matcher(source).replaceAll(StringUtils.EMPTY)}</li> 6087 * </ul> 6088 * 6089 * <p>A {@code null} reference passed to this method is a no-op.</p> 6090 * 6091 * <pre>{@code 6092 * StringUtils.removePattern(null, *) = null 6093 * StringUtils.removePattern("any", (String) null) = "any" 6094 * StringUtils.removePattern("A<__>\n<__>B", "<.*>") = "AB" 6095 * StringUtils.removePattern("ABCabc123", "[a-z]") = "ABC123" 6096 * }</pre> 6097 * 6098 * @param source 6099 * the source string 6100 * @param regex 6101 * the regular expression to which this string is to be matched 6102 * @return The resulting {@link String} 6103 * @see #replacePattern(String, String, String) 6104 * @see String#replaceAll(String, String) 6105 * @see Pattern#DOTALL 6106 * @since 3.2 6107 * @since 3.5 Changed {@code null} reference passed to this method is a no-op. 6108 * 6109 * @deprecated Moved to RegExUtils. 6110 */ 6111 @Deprecated 6112 public static String removePattern(final String source, final String regex) { 6113 return RegExUtils.removePattern(source, regex); 6114 } 6115 6116 /** 6117 * Removes a char only if it is at the beginning of a source string, 6118 * otherwise returns the source string. 6119 * 6120 * <p>A {@code null} source string will return {@code null}. 6121 * An empty ("") source string will return the empty string. 6122 * A {@code null} search char will return the source string.</p> 6123 * 6124 * <pre> 6125 * StringUtils.removeStart(null, *) = null 6126 * StringUtils.removeStart("", *) = "" 6127 * StringUtils.removeStart(*, null) = * 6128 * StringUtils.removeStart("/path", '/') = "path" 6129 * StringUtils.removeStart("path", '/') = "path" 6130 * StringUtils.removeStart("path", 0) = "path" 6131 * </pre> 6132 * 6133 * @param str the source String to search, may be null. 6134 * @param remove the char to search for and remove. 6135 * @return the substring with the char removed if found, 6136 * {@code null} if null String input. 6137 * @since 3.13.0 6138 */ 6139 public static String removeStart(final String str, final char remove) { 6140 if (isEmpty(str)) { 6141 return str; 6142 } 6143 return str.charAt(0) == remove ? str.substring(1) : str; 6144 } 6145 6146 /** 6147 * Removes a substring only if it is at the beginning of a source string, 6148 * otherwise returns the source string. 6149 * 6150 * <p>A {@code null} source string will return {@code null}. 6151 * An empty ("") source string will return the empty string. 6152 * A {@code null} search string will return the source string.</p> 6153 * 6154 * <pre> 6155 * StringUtils.removeStart(null, *) = null 6156 * StringUtils.removeStart("", *) = "" 6157 * StringUtils.removeStart(*, null) = * 6158 * StringUtils.removeStart("www.domain.com", "www.") = "domain.com" 6159 * StringUtils.removeStart("domain.com", "www.") = "domain.com" 6160 * StringUtils.removeStart("www.domain.com", "domain") = "www.domain.com" 6161 * StringUtils.removeStart("abc", "") = "abc" 6162 * </pre> 6163 * 6164 * @param str the source String to search, may be null 6165 * @param remove the String to search for and remove, may be null 6166 * @return the substring with the string removed if found, 6167 * {@code null} if null String input 6168 * @since 2.1 6169 */ 6170 public static String removeStart(final String str, final String remove) { 6171 if (isEmpty(str) || isEmpty(remove)) { 6172 return str; 6173 } 6174 if (str.startsWith(remove)) { 6175 return str.substring(remove.length()); 6176 } 6177 return str; 6178 } 6179 6180 /** 6181 * Case-insensitive removal of a substring if it is at the beginning of a source string, 6182 * otherwise returns the source string. 6183 * 6184 * <p>A {@code null} source string will return {@code null}. 6185 * An empty ("") source string will return the empty string. 6186 * A {@code null} search string will return the source string.</p> 6187 * 6188 * <pre> 6189 * StringUtils.removeStartIgnoreCase(null, *) = null 6190 * StringUtils.removeStartIgnoreCase("", *) = "" 6191 * StringUtils.removeStartIgnoreCase(*, null) = * 6192 * StringUtils.removeStartIgnoreCase("www.domain.com", "www.") = "domain.com" 6193 * StringUtils.removeStartIgnoreCase("www.domain.com", "WWW.") = "domain.com" 6194 * StringUtils.removeStartIgnoreCase("domain.com", "www.") = "domain.com" 6195 * StringUtils.removeStartIgnoreCase("www.domain.com", "domain") = "www.domain.com" 6196 * StringUtils.removeStartIgnoreCase("abc", "") = "abc" 6197 * </pre> 6198 * 6199 * @param str the source String to search, may be null 6200 * @param remove the String to search for (case-insensitive) and remove, may be null 6201 * @return the substring with the string removed if found, 6202 * {@code null} if null String input 6203 * @since 2.4 6204 */ 6205 public static String removeStartIgnoreCase(final String str, final String remove) { 6206 if (str != null && startsWithIgnoreCase(str, remove)) { 6207 return str.substring(length(remove)); 6208 } 6209 return str; 6210 } 6211 6212 /** 6213 * Returns padding using the specified delimiter repeated 6214 * to a given length. 6215 * 6216 * <pre> 6217 * StringUtils.repeat('e', 0) = "" 6218 * StringUtils.repeat('e', 3) = "eee" 6219 * StringUtils.repeat('e', -2) = "" 6220 * </pre> 6221 * 6222 * <p>Note: this method does not support padding with 6223 * <a href="https://www.unicode.org/glossary/#supplementary_character">Unicode Supplementary Characters</a> 6224 * as they require a pair of {@code char}s to be represented. 6225 * If you are needing to support full I18N of your applications 6226 * consider using {@link #repeat(String, int)} instead. 6227 * </p> 6228 * 6229 * @param ch character to repeat 6230 * @param repeat number of times to repeat char, negative treated as zero 6231 * @return String with repeated character 6232 * @see #repeat(String, int) 6233 */ 6234 public static String repeat(final char ch, final int repeat) { 6235 if (repeat <= 0) { 6236 return EMPTY; 6237 } 6238 return new String(ArrayFill.fill(new char[repeat], ch)); 6239 } 6240 6241 /** 6242 * Repeat a String {@code repeat} times to form a 6243 * new String. 6244 * 6245 * <pre> 6246 * StringUtils.repeat(null, 2) = null 6247 * StringUtils.repeat("", 0) = "" 6248 * StringUtils.repeat("", 2) = "" 6249 * StringUtils.repeat("a", 3) = "aaa" 6250 * StringUtils.repeat("ab", 2) = "abab" 6251 * StringUtils.repeat("a", -2) = "" 6252 * </pre> 6253 * 6254 * @param str the String to repeat, may be null 6255 * @param repeat number of times to repeat str, negative treated as zero 6256 * @return a new String consisting of the original String repeated, 6257 * {@code null} if null String input 6258 */ 6259 public static String repeat(final String str, final int repeat) { 6260 // Performance tuned for 2.0 (JDK1.4) 6261 if (str == null) { 6262 return null; 6263 } 6264 if (repeat <= 0) { 6265 return EMPTY; 6266 } 6267 final int inputLength = str.length(); 6268 if (repeat == 1 || inputLength == 0) { 6269 return str; 6270 } 6271 if (inputLength == 1 && repeat <= PAD_LIMIT) { 6272 return repeat(str.charAt(0), repeat); 6273 } 6274 6275 final int outputLength = inputLength * repeat; 6276 switch (inputLength) { 6277 case 1 : 6278 return repeat(str.charAt(0), repeat); 6279 case 2 : 6280 final char ch0 = str.charAt(0); 6281 final char ch1 = str.charAt(1); 6282 final char[] output2 = new char[outputLength]; 6283 for (int i = repeat * 2 - 2; i >= 0; i--, i--) { 6284 output2[i] = ch0; 6285 output2[i + 1] = ch1; 6286 } 6287 return new String(output2); 6288 default : 6289 final StringBuilder buf = new StringBuilder(outputLength); 6290 for (int i = 0; i < repeat; i++) { 6291 buf.append(str); 6292 } 6293 return buf.toString(); 6294 } 6295 } 6296 6297 /** 6298 * Repeat a String {@code repeat} times to form a 6299 * new String, with a String separator injected each time. 6300 * 6301 * <pre> 6302 * StringUtils.repeat(null, null, 2) = null 6303 * StringUtils.repeat(null, "x", 2) = null 6304 * StringUtils.repeat("", null, 0) = "" 6305 * StringUtils.repeat("", "", 2) = "" 6306 * StringUtils.repeat("", "x", 3) = "xx" 6307 * StringUtils.repeat("?", ", ", 3) = "?, ?, ?" 6308 * </pre> 6309 * 6310 * @param str the String to repeat, may be null 6311 * @param separator the String to inject, may be null 6312 * @param repeat number of times to repeat str, negative treated as zero 6313 * @return a new String consisting of the original String repeated, 6314 * {@code null} if null String input 6315 * @since 2.5 6316 */ 6317 public static String repeat(final String str, final String separator, final int repeat) { 6318 if (str == null || separator == null) { 6319 return repeat(str, repeat); 6320 } 6321 // given that repeat(String, int) is quite optimized, better to rely on it than try and splice this into it 6322 final String result = repeat(str + separator, repeat); 6323 return removeEnd(result, separator); 6324 } 6325 6326 /** 6327 * Replaces all occurrences of a String within another String. 6328 * 6329 * <p>A {@code null} reference passed to this method is a no-op.</p> 6330 * 6331 * <pre> 6332 * StringUtils.replace(null, *, *) = null 6333 * StringUtils.replace("", *, *) = "" 6334 * StringUtils.replace("any", null, *) = "any" 6335 * StringUtils.replace("any", *, null) = "any" 6336 * StringUtils.replace("any", "", *) = "any" 6337 * StringUtils.replace("aba", "a", null) = "aba" 6338 * StringUtils.replace("aba", "a", "") = "b" 6339 * StringUtils.replace("aba", "a", "z") = "zbz" 6340 * </pre> 6341 * 6342 * @see #replace(String text, String searchString, String replacement, int max) 6343 * @param text text to search and replace in, may be null 6344 * @param searchString the String to search for, may be null 6345 * @param replacement the String to replace it with, may be null 6346 * @return the text with any replacements processed, 6347 * {@code null} if null String input 6348 */ 6349 public static String replace(final String text, final String searchString, final String replacement) { 6350 return replace(text, searchString, replacement, -1); 6351 } 6352 6353 /** 6354 * Replaces a String with another String inside a larger String, 6355 * for the first {@code max} values of the search String. 6356 * 6357 * <p>A {@code null} reference passed to this method is a no-op.</p> 6358 * 6359 * <pre> 6360 * StringUtils.replace(null, *, *, *) = null 6361 * StringUtils.replace("", *, *, *) = "" 6362 * StringUtils.replace("any", null, *, *) = "any" 6363 * StringUtils.replace("any", *, null, *) = "any" 6364 * StringUtils.replace("any", "", *, *) = "any" 6365 * StringUtils.replace("any", *, *, 0) = "any" 6366 * StringUtils.replace("abaa", "a", null, -1) = "abaa" 6367 * StringUtils.replace("abaa", "a", "", -1) = "b" 6368 * StringUtils.replace("abaa", "a", "z", 0) = "abaa" 6369 * StringUtils.replace("abaa", "a", "z", 1) = "zbaa" 6370 * StringUtils.replace("abaa", "a", "z", 2) = "zbza" 6371 * StringUtils.replace("abaa", "a", "z", -1) = "zbzz" 6372 * </pre> 6373 * 6374 * @param text text to search and replace in, may be null 6375 * @param searchString the String to search for, may be null 6376 * @param replacement the String to replace it with, may be null 6377 * @param max maximum number of values to replace, or {@code -1} if no maximum 6378 * @return the text with any replacements processed, 6379 * {@code null} if null String input 6380 */ 6381 public static String replace(final String text, final String searchString, final String replacement, final int max) { 6382 return replace(text, searchString, replacement, max, false); 6383 } 6384 6385 /** 6386 * Replaces a String with another String inside a larger String, 6387 * for the first {@code max} values of the search String, 6388 * case-sensitively/insensitively based on {@code ignoreCase} value. 6389 * 6390 * <p>A {@code null} reference passed to this method is a no-op.</p> 6391 * 6392 * <pre> 6393 * StringUtils.replace(null, *, *, *, false) = null 6394 * StringUtils.replace("", *, *, *, false) = "" 6395 * StringUtils.replace("any", null, *, *, false) = "any" 6396 * StringUtils.replace("any", *, null, *, false) = "any" 6397 * StringUtils.replace("any", "", *, *, false) = "any" 6398 * StringUtils.replace("any", *, *, 0, false) = "any" 6399 * StringUtils.replace("abaa", "a", null, -1, false) = "abaa" 6400 * StringUtils.replace("abaa", "a", "", -1, false) = "b" 6401 * StringUtils.replace("abaa", "a", "z", 0, false) = "abaa" 6402 * StringUtils.replace("abaa", "A", "z", 1, false) = "abaa" 6403 * StringUtils.replace("abaa", "A", "z", 1, true) = "zbaa" 6404 * StringUtils.replace("abAa", "a", "z", 2, true) = "zbza" 6405 * StringUtils.replace("abAa", "a", "z", -1, true) = "zbzz" 6406 * </pre> 6407 * 6408 * @param text text to search and replace in, may be null 6409 * @param searchString the String to search for (case-insensitive), may be null 6410 * @param replacement the String to replace it with, may be null 6411 * @param max maximum number of values to replace, or {@code -1} if no maximum 6412 * @param ignoreCase if true replace is case-insensitive, otherwise case-sensitive 6413 * @return the text with any replacements processed, 6414 * {@code null} if null String input 6415 */ 6416 private static String replace(final String text, String searchString, final String replacement, int max, final boolean ignoreCase) { 6417 if (isEmpty(text) || isEmpty(searchString) || replacement == null || max == 0) { 6418 return text; 6419 } 6420 if (ignoreCase) { 6421 searchString = searchString.toLowerCase(); 6422 } 6423 int start = 0; 6424 int end = ignoreCase ? indexOfIgnoreCase(text, searchString, start) : indexOf(text, searchString, start); 6425 if (end == INDEX_NOT_FOUND) { 6426 return text; 6427 } 6428 final int replLength = searchString.length(); 6429 int increase = Math.max(replacement.length() - replLength, 0); 6430 increase *= max < 0 ? 16 : Math.min(max, 64); 6431 final StringBuilder buf = new StringBuilder(text.length() + increase); 6432 while (end != INDEX_NOT_FOUND) { 6433 buf.append(text, start, end).append(replacement); 6434 start = end + replLength; 6435 if (--max == 0) { 6436 break; 6437 } 6438 end = ignoreCase ? indexOfIgnoreCase(text, searchString, start) : indexOf(text, searchString, start); 6439 } 6440 buf.append(text, start, text.length()); 6441 return buf.toString(); 6442 } 6443 6444 /** 6445 * Replaces each substring of the text String that matches the given regular expression 6446 * with the given replacement. 6447 * 6448 * This method is a {@code null} safe equivalent to: 6449 * <ul> 6450 * <li>{@code text.replaceAll(regex, replacement)}</li> 6451 * <li>{@code Pattern.compile(regex).matcher(text).replaceAll(replacement)}</li> 6452 * </ul> 6453 * 6454 * <p>A {@code null} reference passed to this method is a no-op.</p> 6455 * 6456 * <p>Unlike in the {@link #replacePattern(String, String, String)} method, the {@link Pattern#DOTALL} option 6457 * is NOT automatically added. 6458 * To use the DOTALL option prepend {@code "(?s)"} to the regex. 6459 * DOTALL is also known as single-line mode in Perl.</p> 6460 * 6461 * <pre>{@code 6462 * StringUtils.replaceAll(null, *, *) = null 6463 * StringUtils.replaceAll("any", (String) null, *) = "any" 6464 * StringUtils.replaceAll("any", *, null) = "any" 6465 * StringUtils.replaceAll("", "", "zzz") = "zzz" 6466 * StringUtils.replaceAll("", ".*", "zzz") = "zzz" 6467 * StringUtils.replaceAll("", ".+", "zzz") = "" 6468 * StringUtils.replaceAll("abc", "", "ZZ") = "ZZaZZbZZcZZ" 6469 * StringUtils.replaceAll("<__>\n<__>", "<.*>", "z") = "z\nz" 6470 * StringUtils.replaceAll("<__>\n<__>", "(?s)<.*>", "z") = "z" 6471 * StringUtils.replaceAll("ABCabc123", "[a-z]", "_") = "ABC___123" 6472 * StringUtils.replaceAll("ABCabc123", "[^A-Z0-9]+", "_") = "ABC_123" 6473 * StringUtils.replaceAll("ABCabc123", "[^A-Z0-9]+", "") = "ABC123" 6474 * StringUtils.replaceAll("Lorem ipsum dolor sit", "( +)([a-z]+)", "_$2") = "Lorem_ipsum_dolor_sit" 6475 * }</pre> 6476 * 6477 * @param text text to search and replace in, may be null 6478 * @param regex the regular expression to which this string is to be matched 6479 * @param replacement the string to be substituted for each match 6480 * @return the text with any replacements processed, 6481 * {@code null} if null String input 6482 * 6483 * @throws java.util.regex.PatternSyntaxException 6484 * if the regular expression's syntax is invalid 6485 * 6486 * @see #replacePattern(String, String, String) 6487 * @see String#replaceAll(String, String) 6488 * @see java.util.regex.Pattern 6489 * @see java.util.regex.Pattern#DOTALL 6490 * @since 3.5 6491 * 6492 * @deprecated Moved to RegExUtils. 6493 */ 6494 @Deprecated 6495 public static String replaceAll(final String text, final String regex, final String replacement) { 6496 return RegExUtils.replaceAll(text, regex, replacement); 6497 } 6498 6499 /** 6500 * Replaces all occurrences of a character in a String with another. 6501 * This is a null-safe version of {@link String#replace(char, char)}. 6502 * 6503 * <p>A {@code null} string input returns {@code null}. 6504 * An empty ("") string input returns an empty string.</p> 6505 * 6506 * <pre> 6507 * StringUtils.replaceChars(null, *, *) = null 6508 * StringUtils.replaceChars("", *, *) = "" 6509 * StringUtils.replaceChars("abcba", 'b', 'y') = "aycya" 6510 * StringUtils.replaceChars("abcba", 'z', 'y') = "abcba" 6511 * </pre> 6512 * 6513 * @param str String to replace characters in, may be null 6514 * @param searchChar the character to search for, may be null 6515 * @param replaceChar the character to replace, may be null 6516 * @return modified String, {@code null} if null string input 6517 * @since 2.0 6518 */ 6519 public static String replaceChars(final String str, final char searchChar, final char replaceChar) { 6520 if (str == null) { 6521 return null; 6522 } 6523 return str.replace(searchChar, replaceChar); 6524 } 6525 6526 /** 6527 * Replaces multiple characters in a String in one go. 6528 * This method can also be used to delete characters. 6529 * 6530 * <p>For example:<br> 6531 * {@code replaceChars("hello", "ho", "jy") = jelly}.</p> 6532 * 6533 * <p>A {@code null} string input returns {@code null}. 6534 * An empty ("") string input returns an empty string. 6535 * A null or empty set of search characters returns the input string.</p> 6536 * 6537 * <p>The length of the search characters should normally equal the length 6538 * of the replace characters. 6539 * If the search characters is longer, then the extra search characters 6540 * are deleted. 6541 * If the search characters is shorter, then the extra replace characters 6542 * are ignored.</p> 6543 * 6544 * <pre> 6545 * StringUtils.replaceChars(null, *, *) = null 6546 * StringUtils.replaceChars("", *, *) = "" 6547 * StringUtils.replaceChars("abc", null, *) = "abc" 6548 * StringUtils.replaceChars("abc", "", *) = "abc" 6549 * StringUtils.replaceChars("abc", "b", null) = "ac" 6550 * StringUtils.replaceChars("abc", "b", "") = "ac" 6551 * StringUtils.replaceChars("abcba", "bc", "yz") = "ayzya" 6552 * StringUtils.replaceChars("abcba", "bc", "y") = "ayya" 6553 * StringUtils.replaceChars("abcba", "bc", "yzx") = "ayzya" 6554 * </pre> 6555 * 6556 * @param str String to replace characters in, may be null 6557 * @param searchChars a set of characters to search for, may be null 6558 * @param replaceChars a set of characters to replace, may be null 6559 * @return modified String, {@code null} if null string input 6560 * @since 2.0 6561 */ 6562 public static String replaceChars(final String str, final String searchChars, String replaceChars) { 6563 if (isEmpty(str) || isEmpty(searchChars)) { 6564 return str; 6565 } 6566 if (replaceChars == null) { 6567 replaceChars = EMPTY; 6568 } 6569 boolean modified = false; 6570 final int replaceCharsLength = replaceChars.length(); 6571 final int strLength = str.length(); 6572 final StringBuilder buf = new StringBuilder(strLength); 6573 for (int i = 0; i < strLength; i++) { 6574 final char ch = str.charAt(i); 6575 final int index = searchChars.indexOf(ch); 6576 if (index >= 0) { 6577 modified = true; 6578 if (index < replaceCharsLength) { 6579 buf.append(replaceChars.charAt(index)); 6580 } 6581 } else { 6582 buf.append(ch); 6583 } 6584 } 6585 if (modified) { 6586 return buf.toString(); 6587 } 6588 return str; 6589 } 6590 6591 /** 6592 * Replaces all occurrences of Strings within another String. 6593 * 6594 * <p> 6595 * A {@code null} reference passed to this method is a no-op, or if 6596 * any "search string" or "string to replace" is null, that replace will be 6597 * ignored. This will not repeat. For repeating replaces, call the 6598 * overloaded method. 6599 * </p> 6600 * 6601 * <pre> 6602 * StringUtils.replaceEach(null, *, *) = null 6603 * StringUtils.replaceEach("", *, *) = "" 6604 * StringUtils.replaceEach("aba", null, null) = "aba" 6605 * StringUtils.replaceEach("aba", new String[0], null) = "aba" 6606 * StringUtils.replaceEach("aba", null, new String[0]) = "aba" 6607 * StringUtils.replaceEach("aba", new String[]{"a"}, null) = "aba" 6608 * StringUtils.replaceEach("aba", new String[]{"a"}, new String[]{""}) = "b" 6609 * StringUtils.replaceEach("aba", new String[]{null}, new String[]{"a"}) = "aba" 6610 * StringUtils.replaceEach("abcde", new String[]{"ab", "d"}, new String[]{"w", "t"}) = "wcte" 6611 * (example of how it does not repeat) 6612 * StringUtils.replaceEach("abcde", new String[]{"ab", "d"}, new String[]{"d", "t"}) = "dcte" 6613 * </pre> 6614 * 6615 * @param text 6616 * text to search and replace in, no-op if null 6617 * @param searchList 6618 * the Strings to search for, no-op if null 6619 * @param replacementList 6620 * the Strings to replace them with, no-op if null 6621 * @return the text with any replacements processed, {@code null} if 6622 * null String input 6623 * @throws IllegalArgumentException 6624 * if the lengths of the arrays are not the same (null is ok, 6625 * and/or size 0) 6626 * @since 2.4 6627 */ 6628 public static String replaceEach(final String text, final String[] searchList, final String[] replacementList) { 6629 return replaceEach(text, searchList, replacementList, false, 0); 6630 } 6631 6632 /** 6633 * Replace all occurrences of Strings within another String. 6634 * This is a private recursive helper method for {@link #replaceEachRepeatedly(String, String[], String[])} and 6635 * {@link #replaceEach(String, String[], String[])} 6636 * 6637 * <p> 6638 * A {@code null} reference passed to this method is a no-op, or if 6639 * any "search string" or "string to replace" is null, that replace will be 6640 * ignored. 6641 * </p> 6642 * 6643 * <pre> 6644 * StringUtils.replaceEach(null, *, *, *, *) = null 6645 * StringUtils.replaceEach("", *, *, *, *) = "" 6646 * StringUtils.replaceEach("aba", null, null, *, *) = "aba" 6647 * StringUtils.replaceEach("aba", new String[0], null, *, *) = "aba" 6648 * StringUtils.replaceEach("aba", null, new String[0], *, *) = "aba" 6649 * StringUtils.replaceEach("aba", new String[]{"a"}, null, *, *) = "aba" 6650 * StringUtils.replaceEach("aba", new String[]{"a"}, new String[]{""}, *, >=0) = "b" 6651 * StringUtils.replaceEach("aba", new String[]{null}, new String[]{"a"}, *, >=0) = "aba" 6652 * StringUtils.replaceEach("abcde", new String[]{"ab", "d"}, new String[]{"w", "t"}, *, >=0) = "wcte" 6653 * (example of how it repeats) 6654 * StringUtils.replaceEach("abcde", new String[]{"ab", "d"}, new String[]{"d", "t"}, false, >=0) = "dcte" 6655 * StringUtils.replaceEach("abcde", new String[]{"ab", "d"}, new String[]{"d", "t"}, true, >=2) = "tcte" 6656 * StringUtils.replaceEach("abcde", new String[]{"ab", "d"}, new String[]{"d", "ab"}, *, *) = IllegalStateException 6657 * </pre> 6658 * 6659 * @param text 6660 * text to search and replace in, no-op if null 6661 * @param searchList 6662 * the Strings to search for, no-op if null 6663 * @param replacementList 6664 * the Strings to replace them with, no-op if null 6665 * @param repeat if true, then replace repeatedly 6666 * until there are no more possible replacements or timeToLive < 0 6667 * @param timeToLive 6668 * if less than 0 then there is a circular reference and endless 6669 * loop 6670 * @return the text with any replacements processed, {@code null} if 6671 * null String input 6672 * @throws IllegalStateException 6673 * if the search is repeating and there is an endless loop due 6674 * to outputs of one being inputs to another 6675 * @throws IllegalArgumentException 6676 * if the lengths of the arrays are not the same (null is ok, 6677 * and/or size 0) 6678 * @since 2.4 6679 */ 6680 private static String replaceEach( 6681 final String text, final String[] searchList, final String[] replacementList, final boolean repeat, final int timeToLive) { 6682 6683 // mchyzer Performance note: This creates very few new objects (one major goal) 6684 // let me know if there are performance requests, we can create a harness to measure 6685 6686 // if recursing, this shouldn't be less than 0 6687 if (timeToLive < 0) { 6688 final Set<String> searchSet = new HashSet<>(Arrays.asList(searchList)); 6689 final Set<String> replacementSet = new HashSet<>(Arrays.asList(replacementList)); 6690 searchSet.retainAll(replacementSet); 6691 if (!searchSet.isEmpty()) { 6692 throw new IllegalStateException("Aborting to protect against StackOverflowError - " + 6693 "output of one loop is the input of another"); 6694 } 6695 } 6696 6697 if (isEmpty(text) || ArrayUtils.isEmpty(searchList) || ArrayUtils.isEmpty(replacementList) || ArrayUtils.isNotEmpty(searchList) && timeToLive == -1) { 6698 return text; 6699 } 6700 6701 final int searchLength = searchList.length; 6702 final int replacementLength = replacementList.length; 6703 6704 // make sure lengths are ok, these need to be equal 6705 if (searchLength != replacementLength) { 6706 throw new IllegalArgumentException("Search and Replace array lengths don't match: " 6707 + searchLength 6708 + " vs " 6709 + replacementLength); 6710 } 6711 6712 // keep track of which still have matches 6713 final boolean[] noMoreMatchesForReplIndex = new boolean[searchLength]; 6714 6715 // index on index that the match was found 6716 int textIndex = -1; 6717 int replaceIndex = -1; 6718 int tempIndex; 6719 6720 // index of replace array that will replace the search string found 6721 // NOTE: logic duplicated below START 6722 for (int i = 0; i < searchLength; i++) { 6723 if (noMoreMatchesForReplIndex[i] || isEmpty(searchList[i]) || replacementList[i] == null) { 6724 continue; 6725 } 6726 tempIndex = text.indexOf(searchList[i]); 6727 6728 // see if we need to keep searching for this 6729 if (tempIndex == -1) { 6730 noMoreMatchesForReplIndex[i] = true; 6731 } else if (textIndex == -1 || tempIndex < textIndex) { 6732 textIndex = tempIndex; 6733 replaceIndex = i; 6734 } 6735 } 6736 // NOTE: logic mostly below END 6737 6738 // no search strings found, we are done 6739 if (textIndex == -1) { 6740 return text; 6741 } 6742 6743 int start = 0; 6744 6745 // get a good guess on the size of the result buffer so it doesn't have to double if it goes over a bit 6746 int increase = 0; 6747 6748 // count the replacement text elements that are larger than their corresponding text being replaced 6749 for (int i = 0; i < searchList.length; i++) { 6750 if (searchList[i] == null || replacementList[i] == null) { 6751 continue; 6752 } 6753 final int greater = replacementList[i].length() - searchList[i].length(); 6754 if (greater > 0) { 6755 increase += 3 * greater; // assume 3 matches 6756 } 6757 } 6758 // have upper-bound at 20% increase, then let Java take over 6759 increase = Math.min(increase, text.length() / 5); 6760 6761 final StringBuilder buf = new StringBuilder(text.length() + increase); 6762 6763 while (textIndex != -1) { 6764 6765 for (int i = start; i < textIndex; i++) { 6766 buf.append(text.charAt(i)); 6767 } 6768 buf.append(replacementList[replaceIndex]); 6769 6770 start = textIndex + searchList[replaceIndex].length(); 6771 6772 textIndex = -1; 6773 replaceIndex = -1; 6774 // find the next earliest match 6775 // NOTE: logic mostly duplicated above START 6776 for (int i = 0; i < searchLength; i++) { 6777 if (noMoreMatchesForReplIndex[i] || isEmpty(searchList[i]) || replacementList[i] == null) { 6778 continue; 6779 } 6780 tempIndex = text.indexOf(searchList[i], start); 6781 6782 // see if we need to keep searching for this 6783 if (tempIndex == -1) { 6784 noMoreMatchesForReplIndex[i] = true; 6785 } else if (textIndex == -1 || tempIndex < textIndex) { 6786 textIndex = tempIndex; 6787 replaceIndex = i; 6788 } 6789 } 6790 // NOTE: logic duplicated above END 6791 6792 } 6793 final int textLength = text.length(); 6794 for (int i = start; i < textLength; i++) { 6795 buf.append(text.charAt(i)); 6796 } 6797 final String result = buf.toString(); 6798 if (!repeat) { 6799 return result; 6800 } 6801 6802 return replaceEach(result, searchList, replacementList, repeat, timeToLive - 1); 6803 } 6804 6805 /** 6806 * Replaces all occurrences of Strings within another String. 6807 * 6808 * <p> 6809 * A {@code null} reference passed to this method is a no-op, or if 6810 * any "search string" or "string to replace" is null, that replace will be 6811 * ignored. 6812 * </p> 6813 * 6814 * <pre> 6815 * StringUtils.replaceEachRepeatedly(null, *, *) = null 6816 * StringUtils.replaceEachRepeatedly("", *, *) = "" 6817 * StringUtils.replaceEachRepeatedly("aba", null, null) = "aba" 6818 * StringUtils.replaceEachRepeatedly("aba", new String[0], null) = "aba" 6819 * StringUtils.replaceEachRepeatedly("aba", null, new String[0]) = "aba" 6820 * StringUtils.replaceEachRepeatedly("aba", new String[]{"a"}, null) = "aba" 6821 * StringUtils.replaceEachRepeatedly("aba", new String[]{"a"}, new String[]{""}) = "b" 6822 * StringUtils.replaceEachRepeatedly("aba", new String[]{null}, new String[]{"a"}) = "aba" 6823 * StringUtils.replaceEachRepeatedly("abcde", new String[]{"ab", "d"}, new String[]{"w", "t"}) = "wcte" 6824 * (example of how it repeats) 6825 * StringUtils.replaceEachRepeatedly("abcde", new String[]{"ab", "d"}, new String[]{"d", "t"}) = "tcte" 6826 * StringUtils.replaceEachRepeatedly("abcde", new String[]{"ab", "d"}, new String[]{"d", "ab"}) = IllegalStateException 6827 * </pre> 6828 * 6829 * @param text 6830 * text to search and replace in, no-op if null 6831 * @param searchList 6832 * the Strings to search for, no-op if null 6833 * @param replacementList 6834 * the Strings to replace them with, no-op if null 6835 * @return the text with any replacements processed, {@code null} if 6836 * null String input 6837 * @throws IllegalStateException 6838 * if the search is repeating and there is an endless loop due 6839 * to outputs of one being inputs to another 6840 * @throws IllegalArgumentException 6841 * if the lengths of the arrays are not the same (null is ok, 6842 * and/or size 0) 6843 * @since 2.4 6844 */ 6845 public static String replaceEachRepeatedly(final String text, final String[] searchList, final String[] replacementList) { 6846 return replaceEach(text, searchList, replacementList, true, ArrayUtils.getLength(searchList)); 6847 } 6848 6849 /** 6850 * Replaces the first substring of the text string that matches the given regular expression 6851 * with the given replacement. 6852 * 6853 * This method is a {@code null} safe equivalent to: 6854 * <ul> 6855 * <li>{@code text.replaceFirst(regex, replacement)}</li> 6856 * <li>{@code Pattern.compile(regex).matcher(text).replaceFirst(replacement)}</li> 6857 * </ul> 6858 * 6859 * <p>A {@code null} reference passed to this method is a no-op.</p> 6860 * 6861 * <p>The {@link Pattern#DOTALL} option is NOT automatically added. 6862 * To use the DOTALL option prepend {@code "(?s)"} to the regex. 6863 * DOTALL is also known as single-line mode in Perl.</p> 6864 * 6865 * <pre>{@code 6866 * StringUtils.replaceFirst(null, *, *) = null 6867 * StringUtils.replaceFirst("any", (String) null, *) = "any" 6868 * StringUtils.replaceFirst("any", *, null) = "any" 6869 * StringUtils.replaceFirst("", "", "zzz") = "zzz" 6870 * StringUtils.replaceFirst("", ".*", "zzz") = "zzz" 6871 * StringUtils.replaceFirst("", ".+", "zzz") = "" 6872 * StringUtils.replaceFirst("abc", "", "ZZ") = "ZZabc" 6873 * StringUtils.replaceFirst("<__>\n<__>", "<.*>", "z") = "z\n<__>" 6874 * StringUtils.replaceFirst("<__>\n<__>", "(?s)<.*>", "z") = "z" 6875 * StringUtils.replaceFirst("ABCabc123", "[a-z]", "_") = "ABC_bc123" 6876 * StringUtils.replaceFirst("ABCabc123abc", "[^A-Z0-9]+", "_") = "ABC_123abc" 6877 * StringUtils.replaceFirst("ABCabc123abc", "[^A-Z0-9]+", "") = "ABC123abc" 6878 * StringUtils.replaceFirst("Lorem ipsum dolor sit", "( +)([a-z]+)", "_$2") = "Lorem_ipsum dolor sit" 6879 * }</pre> 6880 * 6881 * @param text text to search and replace in, may be null 6882 * @param regex the regular expression to which this string is to be matched 6883 * @param replacement the string to be substituted for the first match 6884 * @return the text with the first replacement processed, 6885 * {@code null} if null String input 6886 * 6887 * @throws java.util.regex.PatternSyntaxException 6888 * if the regular expression's syntax is invalid 6889 * 6890 * @see String#replaceFirst(String, String) 6891 * @see java.util.regex.Pattern 6892 * @see java.util.regex.Pattern#DOTALL 6893 * @since 3.5 6894 * 6895 * @deprecated Moved to RegExUtils. 6896 */ 6897 @Deprecated 6898 public static String replaceFirst(final String text, final String regex, final String replacement) { 6899 return RegExUtils.replaceFirst(text, regex, replacement); 6900 } 6901 6902 /** 6903 * Case insensitively replaces all occurrences of a String within another String. 6904 * 6905 * <p>A {@code null} reference passed to this method is a no-op.</p> 6906 * 6907 * <pre> 6908 * StringUtils.replaceIgnoreCase(null, *, *) = null 6909 * StringUtils.replaceIgnoreCase("", *, *) = "" 6910 * StringUtils.replaceIgnoreCase("any", null, *) = "any" 6911 * StringUtils.replaceIgnoreCase("any", *, null) = "any" 6912 * StringUtils.replaceIgnoreCase("any", "", *) = "any" 6913 * StringUtils.replaceIgnoreCase("aba", "a", null) = "aba" 6914 * StringUtils.replaceIgnoreCase("abA", "A", "") = "b" 6915 * StringUtils.replaceIgnoreCase("aba", "A", "z") = "zbz" 6916 * </pre> 6917 * 6918 * @see #replaceIgnoreCase(String text, String searchString, String replacement, int max) 6919 * @param text text to search and replace in, may be null 6920 * @param searchString the String to search for (case-insensitive), may be null 6921 * @param replacement the String to replace it with, may be null 6922 * @return the text with any replacements processed, 6923 * {@code null} if null String input 6924 * @since 3.5 6925 */ 6926 public static String replaceIgnoreCase(final String text, final String searchString, final String replacement) { 6927 return replaceIgnoreCase(text, searchString, replacement, -1); 6928 } 6929 6930 /** 6931 * Case insensitively replaces a String with another String inside a larger String, 6932 * for the first {@code max} values of the search String. 6933 * 6934 * <p>A {@code null} reference passed to this method is a no-op.</p> 6935 * 6936 * <pre> 6937 * StringUtils.replaceIgnoreCase(null, *, *, *) = null 6938 * StringUtils.replaceIgnoreCase("", *, *, *) = "" 6939 * StringUtils.replaceIgnoreCase("any", null, *, *) = "any" 6940 * StringUtils.replaceIgnoreCase("any", *, null, *) = "any" 6941 * StringUtils.replaceIgnoreCase("any", "", *, *) = "any" 6942 * StringUtils.replaceIgnoreCase("any", *, *, 0) = "any" 6943 * StringUtils.replaceIgnoreCase("abaa", "a", null, -1) = "abaa" 6944 * StringUtils.replaceIgnoreCase("abaa", "a", "", -1) = "b" 6945 * StringUtils.replaceIgnoreCase("abaa", "a", "z", 0) = "abaa" 6946 * StringUtils.replaceIgnoreCase("abaa", "A", "z", 1) = "zbaa" 6947 * StringUtils.replaceIgnoreCase("abAa", "a", "z", 2) = "zbza" 6948 * StringUtils.replaceIgnoreCase("abAa", "a", "z", -1) = "zbzz" 6949 * </pre> 6950 * 6951 * @param text text to search and replace in, may be null 6952 * @param searchString the String to search for (case-insensitive), may be null 6953 * @param replacement the String to replace it with, may be null 6954 * @param max maximum number of values to replace, or {@code -1} if no maximum 6955 * @return the text with any replacements processed, 6956 * {@code null} if null String input 6957 * @since 3.5 6958 */ 6959 public static String replaceIgnoreCase(final String text, final String searchString, final String replacement, final int max) { 6960 return replace(text, searchString, replacement, max, true); 6961 } 6962 6963 /** 6964 * Replaces a String with another String inside a larger String, once. 6965 * 6966 * <p>A {@code null} reference passed to this method is a no-op.</p> 6967 * 6968 * <pre> 6969 * StringUtils.replaceOnce(null, *, *) = null 6970 * StringUtils.replaceOnce("", *, *) = "" 6971 * StringUtils.replaceOnce("any", null, *) = "any" 6972 * StringUtils.replaceOnce("any", *, null) = "any" 6973 * StringUtils.replaceOnce("any", "", *) = "any" 6974 * StringUtils.replaceOnce("aba", "a", null) = "aba" 6975 * StringUtils.replaceOnce("aba", "a", "") = "ba" 6976 * StringUtils.replaceOnce("aba", "a", "z") = "zba" 6977 * </pre> 6978 * 6979 * @see #replace(String text, String searchString, String replacement, int max) 6980 * @param text text to search and replace in, may be null 6981 * @param searchString the String to search for, may be null 6982 * @param replacement the String to replace with, may be null 6983 * @return the text with any replacements processed, 6984 * {@code null} if null String input 6985 */ 6986 public static String replaceOnce(final String text, final String searchString, final String replacement) { 6987 return replace(text, searchString, replacement, 1); 6988 } 6989 6990 /** 6991 * Case insensitively replaces a String with another String inside a larger String, once. 6992 * 6993 * <p>A {@code null} reference passed to this method is a no-op.</p> 6994 * 6995 * <pre> 6996 * StringUtils.replaceOnceIgnoreCase(null, *, *) = null 6997 * StringUtils.replaceOnceIgnoreCase("", *, *) = "" 6998 * StringUtils.replaceOnceIgnoreCase("any", null, *) = "any" 6999 * StringUtils.replaceOnceIgnoreCase("any", *, null) = "any" 7000 * StringUtils.replaceOnceIgnoreCase("any", "", *) = "any" 7001 * StringUtils.replaceOnceIgnoreCase("aba", "a", null) = "aba" 7002 * StringUtils.replaceOnceIgnoreCase("aba", "a", "") = "ba" 7003 * StringUtils.replaceOnceIgnoreCase("aba", "a", "z") = "zba" 7004 * StringUtils.replaceOnceIgnoreCase("FoOFoofoo", "foo", "") = "Foofoo" 7005 * </pre> 7006 * 7007 * @see #replaceIgnoreCase(String text, String searchString, String replacement, int max) 7008 * @param text text to search and replace in, may be null 7009 * @param searchString the String to search for (case-insensitive), may be null 7010 * @param replacement the String to replace with, may be null 7011 * @return the text with any replacements processed, 7012 * {@code null} if null String input 7013 * @since 3.5 7014 */ 7015 public static String replaceOnceIgnoreCase(final String text, final String searchString, final String replacement) { 7016 return replaceIgnoreCase(text, searchString, replacement, 1); 7017 } 7018 7019 /** 7020 * Replaces each substring of the source String that matches the given regular expression with the given 7021 * replacement using the {@link Pattern#DOTALL} option. DOTALL is also known as single-line mode in Perl. 7022 * 7023 * This call is a {@code null} safe equivalent to: 7024 * <ul> 7025 * <li>{@code source.replaceAll("(?s)" + regex, replacement)}</li> 7026 * <li>{@code Pattern.compile(regex, Pattern.DOTALL).matcher(source).replaceAll(replacement)}</li> 7027 * </ul> 7028 * 7029 * <p>A {@code null} reference passed to this method is a no-op.</p> 7030 * 7031 * <pre>{@code 7032 * StringUtils.replacePattern(null, *, *) = null 7033 * StringUtils.replacePattern("any", (String) null, *) = "any" 7034 * StringUtils.replacePattern("any", *, null) = "any" 7035 * StringUtils.replacePattern("", "", "zzz") = "zzz" 7036 * StringUtils.replacePattern("", ".*", "zzz") = "zzz" 7037 * StringUtils.replacePattern("", ".+", "zzz") = "" 7038 * StringUtils.replacePattern("<__>\n<__>", "<.*>", "z") = "z" 7039 * StringUtils.replacePattern("ABCabc123", "[a-z]", "_") = "ABC___123" 7040 * StringUtils.replacePattern("ABCabc123", "[^A-Z0-9]+", "_") = "ABC_123" 7041 * StringUtils.replacePattern("ABCabc123", "[^A-Z0-9]+", "") = "ABC123" 7042 * StringUtils.replacePattern("Lorem ipsum dolor sit", "( +)([a-z]+)", "_$2") = "Lorem_ipsum_dolor_sit" 7043 * }</pre> 7044 * 7045 * @param source 7046 * the source string 7047 * @param regex 7048 * the regular expression to which this string is to be matched 7049 * @param replacement 7050 * the string to be substituted for each match 7051 * @return The resulting {@link String} 7052 * @see #replaceAll(String, String, String) 7053 * @see String#replaceAll(String, String) 7054 * @see Pattern#DOTALL 7055 * @since 3.2 7056 * @since 3.5 Changed {@code null} reference passed to this method is a no-op. 7057 * 7058 * @deprecated Moved to RegExUtils. 7059 */ 7060 @Deprecated 7061 public static String replacePattern(final String source, final String regex, final String replacement) { 7062 return RegExUtils.replacePattern(source, regex, replacement); 7063 } 7064 7065 /** 7066 * Reverses a String as per {@link StringBuilder#reverse()}. 7067 * 7068 * <p>A {@code null} String returns {@code null}.</p> 7069 * 7070 * <pre> 7071 * StringUtils.reverse(null) = null 7072 * StringUtils.reverse("") = "" 7073 * StringUtils.reverse("bat") = "tab" 7074 * </pre> 7075 * 7076 * @param str the String to reverse, may be null 7077 * @return the reversed String, {@code null} if null String input 7078 */ 7079 public static String reverse(final String str) { 7080 if (str == null) { 7081 return null; 7082 } 7083 return new StringBuilder(str).reverse().toString(); 7084 } 7085 7086 /** 7087 * Reverses a String that is delimited by a specific character. 7088 * 7089 * <p>The Strings between the delimiters are not reversed. 7090 * Thus java.lang.String becomes String.lang.java (if the delimiter 7091 * is {@code '.'}).</p> 7092 * 7093 * <pre> 7094 * StringUtils.reverseDelimited(null, *) = null 7095 * StringUtils.reverseDelimited("", *) = "" 7096 * StringUtils.reverseDelimited("a.b.c", 'x') = "a.b.c" 7097 * StringUtils.reverseDelimited("a.b.c", ".") = "c.b.a" 7098 * </pre> 7099 * 7100 * @param str the String to reverse, may be null 7101 * @param separatorChar the separator character to use 7102 * @return the reversed String, {@code null} if null String input 7103 * @since 2.0 7104 */ 7105 public static String reverseDelimited(final String str, final char separatorChar) { 7106 final String[] strs = split(str, separatorChar); 7107 ArrayUtils.reverse(strs); 7108 return join(strs, separatorChar); 7109 } 7110 7111 /** 7112 * Gets the rightmost {@code len} characters of a String. 7113 * 7114 * <p>If {@code len} characters are not available, or the String 7115 * is {@code null}, the String will be returned without an 7116 * an exception. An empty String is returned if len is negative.</p> 7117 * 7118 * <pre> 7119 * StringUtils.right(null, *) = null 7120 * StringUtils.right(*, -ve) = "" 7121 * StringUtils.right("", *) = "" 7122 * StringUtils.right("abc", 0) = "" 7123 * StringUtils.right("abc", 2) = "bc" 7124 * StringUtils.right("abc", 4) = "abc" 7125 * </pre> 7126 * 7127 * @param str the String to get the rightmost characters from, may be null 7128 * @param len the length of the required String 7129 * @return the rightmost characters, {@code null} if null String input 7130 */ 7131 public static String right(final String str, final int len) { 7132 if (str == null) { 7133 return null; 7134 } 7135 if (len < 0) { 7136 return EMPTY; 7137 } 7138 if (str.length() <= len) { 7139 return str; 7140 } 7141 return str.substring(str.length() - len); 7142 } 7143 7144 /** 7145 * Right pad a String with spaces (' '). 7146 * 7147 * <p>The String is padded to the size of {@code size}.</p> 7148 * 7149 * <pre> 7150 * StringUtils.rightPad(null, *) = null 7151 * StringUtils.rightPad("", 3) = " " 7152 * StringUtils.rightPad("bat", 3) = "bat" 7153 * StringUtils.rightPad("bat", 5) = "bat " 7154 * StringUtils.rightPad("bat", 1) = "bat" 7155 * StringUtils.rightPad("bat", -1) = "bat" 7156 * </pre> 7157 * 7158 * @param str the String to pad out, may be null 7159 * @param size the size to pad to 7160 * @return right padded String or original String if no padding is necessary, 7161 * {@code null} if null String input 7162 */ 7163 public static String rightPad(final String str, final int size) { 7164 return rightPad(str, size, ' '); 7165 } 7166 7167 /** 7168 * Right pad a String with a specified character. 7169 * 7170 * <p>The String is padded to the size of {@code size}.</p> 7171 * 7172 * <pre> 7173 * StringUtils.rightPad(null, *, *) = null 7174 * StringUtils.rightPad("", 3, 'z') = "zzz" 7175 * StringUtils.rightPad("bat", 3, 'z') = "bat" 7176 * StringUtils.rightPad("bat", 5, 'z') = "batzz" 7177 * StringUtils.rightPad("bat", 1, 'z') = "bat" 7178 * StringUtils.rightPad("bat", -1, 'z') = "bat" 7179 * </pre> 7180 * 7181 * @param str the String to pad out, may be null 7182 * @param size the size to pad to 7183 * @param padChar the character to pad with 7184 * @return right padded String or original String if no padding is necessary, 7185 * {@code null} if null String input 7186 * @since 2.0 7187 */ 7188 public static String rightPad(final String str, final int size, final char padChar) { 7189 if (str == null) { 7190 return null; 7191 } 7192 final int pads = size - str.length(); 7193 if (pads <= 0) { 7194 return str; // returns original String when possible 7195 } 7196 if (pads > PAD_LIMIT) { 7197 return rightPad(str, size, String.valueOf(padChar)); 7198 } 7199 return str.concat(repeat(padChar, pads)); 7200 } 7201 7202 /** 7203 * Right pad a String with a specified String. 7204 * 7205 * <p>The String is padded to the size of {@code size}.</p> 7206 * 7207 * <pre> 7208 * StringUtils.rightPad(null, *, *) = null 7209 * StringUtils.rightPad("", 3, "z") = "zzz" 7210 * StringUtils.rightPad("bat", 3, "yz") = "bat" 7211 * StringUtils.rightPad("bat", 5, "yz") = "batyz" 7212 * StringUtils.rightPad("bat", 8, "yz") = "batyzyzy" 7213 * StringUtils.rightPad("bat", 1, "yz") = "bat" 7214 * StringUtils.rightPad("bat", -1, "yz") = "bat" 7215 * StringUtils.rightPad("bat", 5, null) = "bat " 7216 * StringUtils.rightPad("bat", 5, "") = "bat " 7217 * </pre> 7218 * 7219 * @param str the String to pad out, may be null 7220 * @param size the size to pad to 7221 * @param padStr the String to pad with, null or empty treated as single space 7222 * @return right padded String or original String if no padding is necessary, 7223 * {@code null} if null String input 7224 */ 7225 public static String rightPad(final String str, final int size, String padStr) { 7226 if (str == null) { 7227 return null; 7228 } 7229 if (isEmpty(padStr)) { 7230 padStr = SPACE; 7231 } 7232 final int padLen = padStr.length(); 7233 final int strLen = str.length(); 7234 final int pads = size - strLen; 7235 if (pads <= 0) { 7236 return str; // returns original String when possible 7237 } 7238 if (padLen == 1 && pads <= PAD_LIMIT) { 7239 return rightPad(str, size, padStr.charAt(0)); 7240 } 7241 7242 if (pads == padLen) { 7243 return str.concat(padStr); 7244 } 7245 if (pads < padLen) { 7246 return str.concat(padStr.substring(0, pads)); 7247 } 7248 final char[] padding = new char[pads]; 7249 final char[] padChars = padStr.toCharArray(); 7250 for (int i = 0; i < pads; i++) { 7251 padding[i] = padChars[i % padLen]; 7252 } 7253 return str.concat(new String(padding)); 7254 } 7255 7256 /** 7257 * Rotate (circular shift) a String of {@code shift} characters. 7258 * <ul> 7259 * <li>If {@code shift > 0}, right circular shift (ex : ABCDEF => FABCDE)</li> 7260 * <li>If {@code shift < 0}, left circular shift (ex : ABCDEF => BCDEFA)</li> 7261 * </ul> 7262 * 7263 * <pre> 7264 * StringUtils.rotate(null, *) = null 7265 * StringUtils.rotate("", *) = "" 7266 * StringUtils.rotate("abcdefg", 0) = "abcdefg" 7267 * StringUtils.rotate("abcdefg", 2) = "fgabcde" 7268 * StringUtils.rotate("abcdefg", -2) = "cdefgab" 7269 * StringUtils.rotate("abcdefg", 7) = "abcdefg" 7270 * StringUtils.rotate("abcdefg", -7) = "abcdefg" 7271 * StringUtils.rotate("abcdefg", 9) = "fgabcde" 7272 * StringUtils.rotate("abcdefg", -9) = "cdefgab" 7273 * </pre> 7274 * 7275 * @param str the String to rotate, may be null 7276 * @param shift number of time to shift (positive : right shift, negative : left shift) 7277 * @return the rotated String, 7278 * or the original String if {@code shift == 0}, 7279 * or {@code null} if null String input 7280 * @since 3.5 7281 */ 7282 public static String rotate(final String str, final int shift) { 7283 if (str == null) { 7284 return null; 7285 } 7286 7287 final int strLen = str.length(); 7288 if (shift == 0 || strLen == 0 || shift % strLen == 0) { 7289 return str; 7290 } 7291 7292 final StringBuilder builder = new StringBuilder(strLen); 7293 final int offset = - (shift % strLen); 7294 builder.append(substring(str, offset)); 7295 builder.append(substring(str, 0, offset)); 7296 return builder.toString(); 7297 } 7298 7299 /** 7300 * Splits the provided text into an array, using whitespace as the 7301 * separator. 7302 * Whitespace is defined by {@link Character#isWhitespace(char)}. 7303 * 7304 * <p>The separator is not included in the returned String array. 7305 * Adjacent separators are treated as one separator. 7306 * For more control over the split use the StrTokenizer class.</p> 7307 * 7308 * <p>A {@code null} input String returns {@code null}.</p> 7309 * 7310 * <pre> 7311 * StringUtils.split(null) = null 7312 * StringUtils.split("") = [] 7313 * StringUtils.split("abc def") = ["abc", "def"] 7314 * StringUtils.split("abc def") = ["abc", "def"] 7315 * StringUtils.split(" abc ") = ["abc"] 7316 * </pre> 7317 * 7318 * @param str the String to parse, may be null 7319 * @return an array of parsed Strings, {@code null} if null String input 7320 */ 7321 public static String[] split(final String str) { 7322 return split(str, null, -1); 7323 } 7324 7325 /** 7326 * Splits the provided text into an array, separator specified. 7327 * This is an alternative to using StringTokenizer. 7328 * 7329 * <p>The separator is not included in the returned String array. 7330 * Adjacent separators are treated as one separator. 7331 * For more control over the split use the StrTokenizer class.</p> 7332 * 7333 * <p>A {@code null} input String returns {@code null}.</p> 7334 * 7335 * <pre> 7336 * StringUtils.split(null, *) = null 7337 * StringUtils.split("", *) = [] 7338 * StringUtils.split("a.b.c", '.') = ["a", "b", "c"] 7339 * StringUtils.split("a..b.c", '.') = ["a", "b", "c"] 7340 * StringUtils.split("a:b:c", '.') = ["a:b:c"] 7341 * StringUtils.split("a b c", ' ') = ["a", "b", "c"] 7342 * </pre> 7343 * 7344 * @param str the String to parse, may be null 7345 * @param separatorChar the character used as the delimiter 7346 * @return an array of parsed Strings, {@code null} if null String input 7347 * @since 2.0 7348 */ 7349 public static String[] split(final String str, final char separatorChar) { 7350 return splitWorker(str, separatorChar, false); 7351 } 7352 7353 /** 7354 * Splits the provided text into an array, separators specified. 7355 * This is an alternative to using StringTokenizer. 7356 * 7357 * <p>The separator is not included in the returned String array. 7358 * Adjacent separators are treated as one separator. 7359 * For more control over the split use the StrTokenizer class.</p> 7360 * 7361 * <p>A {@code null} input String returns {@code null}. 7362 * A {@code null} separatorChars splits on whitespace.</p> 7363 * 7364 * <pre> 7365 * StringUtils.split(null, *) = null 7366 * StringUtils.split("", *) = [] 7367 * StringUtils.split("abc def", null) = ["abc", "def"] 7368 * StringUtils.split("abc def", " ") = ["abc", "def"] 7369 * StringUtils.split("abc def", " ") = ["abc", "def"] 7370 * StringUtils.split("ab:cd:ef", ":") = ["ab", "cd", "ef"] 7371 * </pre> 7372 * 7373 * @param str the String to parse, may be null 7374 * @param separatorChars the characters used as the delimiters, 7375 * {@code null} splits on whitespace 7376 * @return an array of parsed Strings, {@code null} if null String input 7377 */ 7378 public static String[] split(final String str, final String separatorChars) { 7379 return splitWorker(str, separatorChars, -1, false); 7380 } 7381 7382 /** 7383 * Splits the provided text into an array with a maximum length, 7384 * separators specified. 7385 * 7386 * <p>The separator is not included in the returned String array. 7387 * Adjacent separators are treated as one separator.</p> 7388 * 7389 * <p>A {@code null} input String returns {@code null}. 7390 * A {@code null} separatorChars splits on whitespace.</p> 7391 * 7392 * <p>If more than {@code max} delimited substrings are found, the last 7393 * returned string includes all characters after the first {@code max - 1} 7394 * returned strings (including separator characters).</p> 7395 * 7396 * <pre> 7397 * StringUtils.split(null, *, *) = null 7398 * StringUtils.split("", *, *) = [] 7399 * StringUtils.split("ab cd ef", null, 0) = ["ab", "cd", "ef"] 7400 * StringUtils.split("ab cd ef", null, 0) = ["ab", "cd", "ef"] 7401 * StringUtils.split("ab:cd:ef", ":", 0) = ["ab", "cd", "ef"] 7402 * StringUtils.split("ab:cd:ef", ":", 2) = ["ab", "cd:ef"] 7403 * </pre> 7404 * 7405 * @param str the String to parse, may be null 7406 * @param separatorChars the characters used as the delimiters, 7407 * {@code null} splits on whitespace 7408 * @param max the maximum number of elements to include in the 7409 * array. A zero or negative value implies no limit 7410 * @return an array of parsed Strings, {@code null} if null String input 7411 */ 7412 public static String[] split(final String str, final String separatorChars, final int max) { 7413 return splitWorker(str, separatorChars, max, false); 7414 } 7415 7416 /** 7417 * Splits a String by Character type as returned by 7418 * {@code java.lang.Character.getType(char)}. Groups of contiguous 7419 * characters of the same type are returned as complete tokens. 7420 * <pre> 7421 * StringUtils.splitByCharacterType(null) = null 7422 * StringUtils.splitByCharacterType("") = [] 7423 * StringUtils.splitByCharacterType("ab de fg") = ["ab", " ", "de", " ", "fg"] 7424 * StringUtils.splitByCharacterType("ab de fg") = ["ab", " ", "de", " ", "fg"] 7425 * StringUtils.splitByCharacterType("ab:cd:ef") = ["ab", ":", "cd", ":", "ef"] 7426 * StringUtils.splitByCharacterType("number5") = ["number", "5"] 7427 * StringUtils.splitByCharacterType("fooBar") = ["foo", "B", "ar"] 7428 * StringUtils.splitByCharacterType("foo200Bar") = ["foo", "200", "B", "ar"] 7429 * StringUtils.splitByCharacterType("ASFRules") = ["ASFR", "ules"] 7430 * </pre> 7431 * @param str the String to split, may be {@code null} 7432 * @return an array of parsed Strings, {@code null} if null String input 7433 * @since 2.4 7434 */ 7435 public static String[] splitByCharacterType(final String str) { 7436 return splitByCharacterType(str, false); 7437 } 7438 7439 /** 7440 * <p>Splits a String by Character type as returned by 7441 * {@code java.lang.Character.getType(char)}. Groups of contiguous 7442 * characters of the same type are returned as complete tokens, with the 7443 * following exception: if {@code camelCase} is {@code true}, 7444 * the character of type {@code Character.UPPERCASE_LETTER}, if any, 7445 * immediately preceding a token of type {@code Character.LOWERCASE_LETTER} 7446 * will belong to the following token rather than to the preceding, if any, 7447 * {@code Character.UPPERCASE_LETTER} token. 7448 * @param str the String to split, may be {@code null} 7449 * @param camelCase whether to use so-called "camel-case" for letter types 7450 * @return an array of parsed Strings, {@code null} if null String input 7451 * @since 2.4 7452 */ 7453 private static String[] splitByCharacterType(final String str, final boolean camelCase) { 7454 if (str == null) { 7455 return null; 7456 } 7457 if (str.isEmpty()) { 7458 return ArrayUtils.EMPTY_STRING_ARRAY; 7459 } 7460 final char[] c = str.toCharArray(); 7461 final List<String> list = new ArrayList<>(); 7462 int tokenStart = 0; 7463 int currentType = Character.getType(c[tokenStart]); 7464 for (int pos = tokenStart + 1; pos < c.length; pos++) { 7465 final int type = Character.getType(c[pos]); 7466 if (type == currentType) { 7467 continue; 7468 } 7469 if (camelCase && type == Character.LOWERCASE_LETTER && currentType == Character.UPPERCASE_LETTER) { 7470 final int newTokenStart = pos - 1; 7471 if (newTokenStart != tokenStart) { 7472 list.add(new String(c, tokenStart, newTokenStart - tokenStart)); 7473 tokenStart = newTokenStart; 7474 } 7475 } else { 7476 list.add(new String(c, tokenStart, pos - tokenStart)); 7477 tokenStart = pos; 7478 } 7479 currentType = type; 7480 } 7481 list.add(new String(c, tokenStart, c.length - tokenStart)); 7482 return list.toArray(ArrayUtils.EMPTY_STRING_ARRAY); 7483 } 7484 7485 /** 7486 * <p>Splits a String by Character type as returned by 7487 * {@code java.lang.Character.getType(char)}. Groups of contiguous 7488 * characters of the same type are returned as complete tokens, with the 7489 * following exception: the character of type 7490 * {@code Character.UPPERCASE_LETTER}, if any, immediately 7491 * preceding a token of type {@code Character.LOWERCASE_LETTER} 7492 * will belong to the following token rather than to the preceding, if any, 7493 * {@code Character.UPPERCASE_LETTER} token. 7494 * <pre> 7495 * StringUtils.splitByCharacterTypeCamelCase(null) = null 7496 * StringUtils.splitByCharacterTypeCamelCase("") = [] 7497 * StringUtils.splitByCharacterTypeCamelCase("ab de fg") = ["ab", " ", "de", " ", "fg"] 7498 * StringUtils.splitByCharacterTypeCamelCase("ab de fg") = ["ab", " ", "de", " ", "fg"] 7499 * StringUtils.splitByCharacterTypeCamelCase("ab:cd:ef") = ["ab", ":", "cd", ":", "ef"] 7500 * StringUtils.splitByCharacterTypeCamelCase("number5") = ["number", "5"] 7501 * StringUtils.splitByCharacterTypeCamelCase("fooBar") = ["foo", "Bar"] 7502 * StringUtils.splitByCharacterTypeCamelCase("foo200Bar") = ["foo", "200", "Bar"] 7503 * StringUtils.splitByCharacterTypeCamelCase("ASFRules") = ["ASF", "Rules"] 7504 * </pre> 7505 * @param str the String to split, may be {@code null} 7506 * @return an array of parsed Strings, {@code null} if null String input 7507 * @since 2.4 7508 */ 7509 public static String[] splitByCharacterTypeCamelCase(final String str) { 7510 return splitByCharacterType(str, true); 7511 } 7512 7513 /** 7514 * <p>Splits the provided text into an array, separator string specified. 7515 * 7516 * <p>The separator(s) will not be included in the returned String array. 7517 * Adjacent separators are treated as one separator.</p> 7518 * 7519 * <p>A {@code null} input String returns {@code null}. 7520 * A {@code null} separator splits on whitespace.</p> 7521 * 7522 * <pre> 7523 * StringUtils.splitByWholeSeparator(null, *) = null 7524 * StringUtils.splitByWholeSeparator("", *) = [] 7525 * StringUtils.splitByWholeSeparator("ab de fg", null) = ["ab", "de", "fg"] 7526 * StringUtils.splitByWholeSeparator("ab de fg", null) = ["ab", "de", "fg"] 7527 * StringUtils.splitByWholeSeparator("ab:cd:ef", ":") = ["ab", "cd", "ef"] 7528 * StringUtils.splitByWholeSeparator("ab-!-cd-!-ef", "-!-") = ["ab", "cd", "ef"] 7529 * </pre> 7530 * 7531 * @param str the String to parse, may be null 7532 * @param separator String containing the String to be used as a delimiter, 7533 * {@code null} splits on whitespace 7534 * @return an array of parsed Strings, {@code null} if null String was input 7535 */ 7536 public static String[] splitByWholeSeparator(final String str, final String separator) { 7537 return splitByWholeSeparatorWorker(str, separator, -1, false); 7538 } 7539 7540 /** 7541 * Splits the provided text into an array, separator string specified. 7542 * Returns a maximum of {@code max} substrings. 7543 * 7544 * <p>The separator(s) will not be included in the returned String array. 7545 * Adjacent separators are treated as one separator.</p> 7546 * 7547 * <p>A {@code null} input String returns {@code null}. 7548 * A {@code null} separator splits on whitespace.</p> 7549 * 7550 * <pre> 7551 * StringUtils.splitByWholeSeparator(null, *, *) = null 7552 * StringUtils.splitByWholeSeparator("", *, *) = [] 7553 * StringUtils.splitByWholeSeparator("ab de fg", null, 0) = ["ab", "de", "fg"] 7554 * StringUtils.splitByWholeSeparator("ab de fg", null, 0) = ["ab", "de", "fg"] 7555 * StringUtils.splitByWholeSeparator("ab:cd:ef", ":", 2) = ["ab", "cd:ef"] 7556 * StringUtils.splitByWholeSeparator("ab-!-cd-!-ef", "-!-", 5) = ["ab", "cd", "ef"] 7557 * StringUtils.splitByWholeSeparator("ab-!-cd-!-ef", "-!-", 2) = ["ab", "cd-!-ef"] 7558 * </pre> 7559 * 7560 * @param str the String to parse, may be null 7561 * @param separator String containing the String to be used as a delimiter, 7562 * {@code null} splits on whitespace 7563 * @param max the maximum number of elements to include in the returned 7564 * array. A zero or negative value implies no limit. 7565 * @return an array of parsed Strings, {@code null} if null String was input 7566 */ 7567 public static String[] splitByWholeSeparator( final String str, final String separator, final int max) { 7568 return splitByWholeSeparatorWorker(str, separator, max, false); 7569 } 7570 7571 /** 7572 * Splits the provided text into an array, separator string specified. 7573 * 7574 * <p>The separator is not included in the returned String array. 7575 * Adjacent separators are treated as separators for empty tokens. 7576 * For more control over the split use the StrTokenizer class.</p> 7577 * 7578 * <p>A {@code null} input String returns {@code null}. 7579 * A {@code null} separator splits on whitespace.</p> 7580 * 7581 * <pre> 7582 * StringUtils.splitByWholeSeparatorPreserveAllTokens(null, *) = null 7583 * StringUtils.splitByWholeSeparatorPreserveAllTokens("", *) = [] 7584 * StringUtils.splitByWholeSeparatorPreserveAllTokens("ab de fg", null) = ["ab", "de", "fg"] 7585 * StringUtils.splitByWholeSeparatorPreserveAllTokens("ab de fg", null) = ["ab", "", "", "de", "fg"] 7586 * StringUtils.splitByWholeSeparatorPreserveAllTokens("ab:cd:ef", ":") = ["ab", "cd", "ef"] 7587 * StringUtils.splitByWholeSeparatorPreserveAllTokens("ab-!-cd-!-ef", "-!-") = ["ab", "cd", "ef"] 7588 * </pre> 7589 * 7590 * @param str the String to parse, may be null 7591 * @param separator String containing the String to be used as a delimiter, 7592 * {@code null} splits on whitespace 7593 * @return an array of parsed Strings, {@code null} if null String was input 7594 * @since 2.4 7595 */ 7596 public static String[] splitByWholeSeparatorPreserveAllTokens(final String str, final String separator) { 7597 return splitByWholeSeparatorWorker(str, separator, -1, true); 7598 } 7599 7600 /** 7601 * Splits the provided text into an array, separator string specified. 7602 * Returns a maximum of {@code max} substrings. 7603 * 7604 * <p>The separator is not included in the returned String array. 7605 * Adjacent separators are treated as separators for empty tokens. 7606 * For more control over the split use the StrTokenizer class.</p> 7607 * 7608 * <p>A {@code null} input String returns {@code null}. 7609 * A {@code null} separator splits on whitespace.</p> 7610 * 7611 * <pre> 7612 * StringUtils.splitByWholeSeparatorPreserveAllTokens(null, *, *) = null 7613 * StringUtils.splitByWholeSeparatorPreserveAllTokens("", *, *) = [] 7614 * StringUtils.splitByWholeSeparatorPreserveAllTokens("ab de fg", null, 0) = ["ab", "de", "fg"] 7615 * StringUtils.splitByWholeSeparatorPreserveAllTokens("ab de fg", null, 0) = ["ab", "", "", "de", "fg"] 7616 * StringUtils.splitByWholeSeparatorPreserveAllTokens("ab:cd:ef", ":", 2) = ["ab", "cd:ef"] 7617 * StringUtils.splitByWholeSeparatorPreserveAllTokens("ab-!-cd-!-ef", "-!-", 5) = ["ab", "cd", "ef"] 7618 * StringUtils.splitByWholeSeparatorPreserveAllTokens("ab-!-cd-!-ef", "-!-", 2) = ["ab", "cd-!-ef"] 7619 * </pre> 7620 * 7621 * @param str the String to parse, may be null 7622 * @param separator String containing the String to be used as a delimiter, 7623 * {@code null} splits on whitespace 7624 * @param max the maximum number of elements to include in the returned 7625 * array. A zero or negative value implies no limit. 7626 * @return an array of parsed Strings, {@code null} if null String was input 7627 * @since 2.4 7628 */ 7629 public static String[] splitByWholeSeparatorPreserveAllTokens(final String str, final String separator, final int max) { 7630 return splitByWholeSeparatorWorker(str, separator, max, true); 7631 } 7632 7633 /** 7634 * Performs the logic for the {@code splitByWholeSeparatorPreserveAllTokens} methods. 7635 * 7636 * @param str the String to parse, may be {@code null} 7637 * @param separator String containing the String to be used as a delimiter, 7638 * {@code null} splits on whitespace 7639 * @param max the maximum number of elements to include in the returned 7640 * array. A zero or negative value implies no limit. 7641 * @param preserveAllTokens if {@code true}, adjacent separators are 7642 * treated as empty token separators; if {@code false}, adjacent 7643 * separators are treated as one separator. 7644 * @return an array of parsed Strings, {@code null} if null String input 7645 * @since 2.4 7646 */ 7647 private static String[] splitByWholeSeparatorWorker( 7648 final String str, final String separator, final int max, final boolean preserveAllTokens) { 7649 if (str == null) { 7650 return null; 7651 } 7652 7653 final int len = str.length(); 7654 7655 if (len == 0) { 7656 return ArrayUtils.EMPTY_STRING_ARRAY; 7657 } 7658 7659 if (separator == null || EMPTY.equals(separator)) { 7660 // Split on whitespace. 7661 return splitWorker(str, null, max, preserveAllTokens); 7662 } 7663 7664 final int separatorLength = separator.length(); 7665 7666 final ArrayList<String> substrings = new ArrayList<>(); 7667 int numberOfSubstrings = 0; 7668 int beg = 0; 7669 int end = 0; 7670 while (end < len) { 7671 end = str.indexOf(separator, beg); 7672 7673 if (end > -1) { 7674 if (end > beg) { 7675 numberOfSubstrings += 1; 7676 7677 if (numberOfSubstrings == max) { 7678 end = len; 7679 substrings.add(str.substring(beg)); 7680 } else { 7681 // The following is OK, because String.substring( beg, end ) excludes 7682 // the character at the position 'end'. 7683 substrings.add(str.substring(beg, end)); 7684 7685 // Set the starting point for the next search. 7686 // The following is equivalent to beg = end + (separatorLength - 1) + 1, 7687 // which is the right calculation: 7688 beg = end + separatorLength; 7689 } 7690 } else { 7691 // We found a consecutive occurrence of the separator, so skip it. 7692 if (preserveAllTokens) { 7693 numberOfSubstrings += 1; 7694 if (numberOfSubstrings == max) { 7695 end = len; 7696 substrings.add(str.substring(beg)); 7697 } else { 7698 substrings.add(EMPTY); 7699 } 7700 } 7701 beg = end + separatorLength; 7702 } 7703 } else { 7704 // String.substring( beg ) goes from 'beg' to the end of the String. 7705 substrings.add(str.substring(beg)); 7706 end = len; 7707 } 7708 } 7709 7710 return substrings.toArray(ArrayUtils.EMPTY_STRING_ARRAY); 7711 } 7712 7713 /** 7714 * Splits the provided text into an array, using whitespace as the 7715 * separator, preserving all tokens, including empty tokens created by 7716 * adjacent separators. This is an alternative to using StringTokenizer. 7717 * Whitespace is defined by {@link Character#isWhitespace(char)}. 7718 * 7719 * <p>The separator is not included in the returned String array. 7720 * Adjacent separators are treated as separators for empty tokens. 7721 * For more control over the split use the StrTokenizer class.</p> 7722 * 7723 * <p>A {@code null} input String returns {@code null}.</p> 7724 * 7725 * <pre> 7726 * StringUtils.splitPreserveAllTokens(null) = null 7727 * StringUtils.splitPreserveAllTokens("") = [] 7728 * StringUtils.splitPreserveAllTokens("abc def") = ["abc", "def"] 7729 * StringUtils.splitPreserveAllTokens("abc def") = ["abc", "", "def"] 7730 * StringUtils.splitPreserveAllTokens(" abc ") = ["", "abc", ""] 7731 * </pre> 7732 * 7733 * @param str the String to parse, may be {@code null} 7734 * @return an array of parsed Strings, {@code null} if null String input 7735 * @since 2.1 7736 */ 7737 public static String[] splitPreserveAllTokens(final String str) { 7738 return splitWorker(str, null, -1, true); 7739 } 7740 7741 /** 7742 * Splits the provided text into an array, separator specified, 7743 * preserving all tokens, including empty tokens created by adjacent 7744 * separators. This is an alternative to using StringTokenizer. 7745 * 7746 * <p>The separator is not included in the returned String array. 7747 * Adjacent separators are treated as separators for empty tokens. 7748 * For more control over the split use the StrTokenizer class.</p> 7749 * 7750 * <p>A {@code null} input String returns {@code null}.</p> 7751 * 7752 * <pre> 7753 * StringUtils.splitPreserveAllTokens(null, *) = null 7754 * StringUtils.splitPreserveAllTokens("", *) = [] 7755 * StringUtils.splitPreserveAllTokens("a.b.c", '.') = ["a", "b", "c"] 7756 * StringUtils.splitPreserveAllTokens("a..b.c", '.') = ["a", "", "b", "c"] 7757 * StringUtils.splitPreserveAllTokens("a:b:c", '.') = ["a:b:c"] 7758 * StringUtils.splitPreserveAllTokens("a\tb\nc", null) = ["a", "b", "c"] 7759 * StringUtils.splitPreserveAllTokens("a b c", ' ') = ["a", "b", "c"] 7760 * StringUtils.splitPreserveAllTokens("a b c ", ' ') = ["a", "b", "c", ""] 7761 * StringUtils.splitPreserveAllTokens("a b c ", ' ') = ["a", "b", "c", "", ""] 7762 * StringUtils.splitPreserveAllTokens(" a b c", ' ') = ["", "a", "b", "c"] 7763 * StringUtils.splitPreserveAllTokens(" a b c", ' ') = ["", "", "a", "b", "c"] 7764 * StringUtils.splitPreserveAllTokens(" a b c ", ' ') = ["", "a", "b", "c", ""] 7765 * </pre> 7766 * 7767 * @param str the String to parse, may be {@code null} 7768 * @param separatorChar the character used as the delimiter, 7769 * {@code null} splits on whitespace 7770 * @return an array of parsed Strings, {@code null} if null String input 7771 * @since 2.1 7772 */ 7773 public static String[] splitPreserveAllTokens(final String str, final char separatorChar) { 7774 return splitWorker(str, separatorChar, true); 7775 } 7776 7777 /** 7778 * Splits the provided text into an array, separators specified, 7779 * preserving all tokens, including empty tokens created by adjacent 7780 * separators. This is an alternative to using StringTokenizer. 7781 * 7782 * <p>The separator is not included in the returned String array. 7783 * Adjacent separators are treated as separators for empty tokens. 7784 * For more control over the split use the StrTokenizer class.</p> 7785 * 7786 * <p>A {@code null} input String returns {@code null}. 7787 * A {@code null} separatorChars splits on whitespace.</p> 7788 * 7789 * <pre> 7790 * StringUtils.splitPreserveAllTokens(null, *) = null 7791 * StringUtils.splitPreserveAllTokens("", *) = [] 7792 * StringUtils.splitPreserveAllTokens("abc def", null) = ["abc", "def"] 7793 * StringUtils.splitPreserveAllTokens("abc def", " ") = ["abc", "def"] 7794 * StringUtils.splitPreserveAllTokens("abc def", " ") = ["abc", "", "def"] 7795 * StringUtils.splitPreserveAllTokens("ab:cd:ef", ":") = ["ab", "cd", "ef"] 7796 * StringUtils.splitPreserveAllTokens("ab:cd:ef:", ":") = ["ab", "cd", "ef", ""] 7797 * StringUtils.splitPreserveAllTokens("ab:cd:ef::", ":") = ["ab", "cd", "ef", "", ""] 7798 * StringUtils.splitPreserveAllTokens("ab::cd:ef", ":") = ["ab", "", "cd", "ef"] 7799 * StringUtils.splitPreserveAllTokens(":cd:ef", ":") = ["", "cd", "ef"] 7800 * StringUtils.splitPreserveAllTokens("::cd:ef", ":") = ["", "", "cd", "ef"] 7801 * StringUtils.splitPreserveAllTokens(":cd:ef:", ":") = ["", "cd", "ef", ""] 7802 * </pre> 7803 * 7804 * @param str the String to parse, may be {@code null} 7805 * @param separatorChars the characters used as the delimiters, 7806 * {@code null} splits on whitespace 7807 * @return an array of parsed Strings, {@code null} if null String input 7808 * @since 2.1 7809 */ 7810 public static String[] splitPreserveAllTokens(final String str, final String separatorChars) { 7811 return splitWorker(str, separatorChars, -1, true); 7812 } 7813 7814 /** 7815 * Splits the provided text into an array with a maximum length, 7816 * separators specified, preserving all tokens, including empty tokens 7817 * created by adjacent separators. 7818 * 7819 * <p>The separator is not included in the returned String array. 7820 * Adjacent separators are treated as separators for empty tokens. 7821 * Adjacent separators are treated as one separator.</p> 7822 * 7823 * <p>A {@code null} input String returns {@code null}. 7824 * A {@code null} separatorChars splits on whitespace.</p> 7825 * 7826 * <p>If more than {@code max} delimited substrings are found, the last 7827 * returned string includes all characters after the first {@code max - 1} 7828 * returned strings (including separator characters).</p> 7829 * 7830 * <pre> 7831 * StringUtils.splitPreserveAllTokens(null, *, *) = null 7832 * StringUtils.splitPreserveAllTokens("", *, *) = [] 7833 * StringUtils.splitPreserveAllTokens("ab de fg", null, 0) = ["ab", "de", "fg"] 7834 * StringUtils.splitPreserveAllTokens("ab de fg", null, 0) = ["ab", "", "", "de", "fg"] 7835 * StringUtils.splitPreserveAllTokens("ab:cd:ef", ":", 0) = ["ab", "cd", "ef"] 7836 * StringUtils.splitPreserveAllTokens("ab:cd:ef", ":", 2) = ["ab", "cd:ef"] 7837 * StringUtils.splitPreserveAllTokens("ab de fg", null, 2) = ["ab", " de fg"] 7838 * StringUtils.splitPreserveAllTokens("ab de fg", null, 3) = ["ab", "", " de fg"] 7839 * StringUtils.splitPreserveAllTokens("ab de fg", null, 4) = ["ab", "", "", "de fg"] 7840 * </pre> 7841 * 7842 * @param str the String to parse, may be {@code null} 7843 * @param separatorChars the characters used as the delimiters, 7844 * {@code null} splits on whitespace 7845 * @param max the maximum number of elements to include in the 7846 * array. A zero or negative value implies no limit 7847 * @return an array of parsed Strings, {@code null} if null String input 7848 * @since 2.1 7849 */ 7850 public static String[] splitPreserveAllTokens(final String str, final String separatorChars, final int max) { 7851 return splitWorker(str, separatorChars, max, true); 7852 } 7853 7854 /** 7855 * Performs the logic for the {@code split} and 7856 * {@code splitPreserveAllTokens} methods that do not return a 7857 * maximum array length. 7858 * 7859 * @param str the String to parse, may be {@code null} 7860 * @param separatorChar the separate character 7861 * @param preserveAllTokens if {@code true}, adjacent separators are 7862 * treated as empty token separators; if {@code false}, adjacent 7863 * separators are treated as one separator. 7864 * @return an array of parsed Strings, {@code null} if null String input 7865 */ 7866 private static String[] splitWorker(final String str, final char separatorChar, final boolean preserveAllTokens) { 7867 // Performance tuned for 2.0 (JDK1.4) 7868 if (str == null) { 7869 return null; 7870 } 7871 final int len = str.length(); 7872 if (len == 0) { 7873 return ArrayUtils.EMPTY_STRING_ARRAY; 7874 } 7875 final List<String> list = new ArrayList<>(); 7876 int i = 0; 7877 int start = 0; 7878 boolean match = false; 7879 boolean lastMatch = false; 7880 while (i < len) { 7881 if (str.charAt(i) == separatorChar) { 7882 if (match || preserveAllTokens) { 7883 list.add(str.substring(start, i)); 7884 match = false; 7885 lastMatch = true; 7886 } 7887 start = ++i; 7888 continue; 7889 } 7890 lastMatch = false; 7891 match = true; 7892 i++; 7893 } 7894 if (match || preserveAllTokens && lastMatch) { 7895 list.add(str.substring(start, i)); 7896 } 7897 return list.toArray(ArrayUtils.EMPTY_STRING_ARRAY); 7898 } 7899 7900 /** 7901 * Performs the logic for the {@code split} and 7902 * {@code splitPreserveAllTokens} methods that return a maximum array 7903 * length. 7904 * 7905 * @param str the String to parse, may be {@code null} 7906 * @param separatorChars the separate character 7907 * @param max the maximum number of elements to include in the 7908 * array. A zero or negative value implies no limit. 7909 * @param preserveAllTokens if {@code true}, adjacent separators are 7910 * treated as empty token separators; if {@code false}, adjacent 7911 * separators are treated as one separator. 7912 * @return an array of parsed Strings, {@code null} if null String input 7913 */ 7914 private static String[] splitWorker(final String str, final String separatorChars, final int max, final boolean preserveAllTokens) { 7915 // Performance tuned for 2.0 (JDK1.4) 7916 // Direct code is quicker than StringTokenizer. 7917 // Also, StringTokenizer uses isSpace() not isWhitespace() 7918 7919 if (str == null) { 7920 return null; 7921 } 7922 final int len = str.length(); 7923 if (len == 0) { 7924 return ArrayUtils.EMPTY_STRING_ARRAY; 7925 } 7926 final List<String> list = new ArrayList<>(); 7927 int sizePlus1 = 1; 7928 int i = 0; 7929 int start = 0; 7930 boolean match = false; 7931 boolean lastMatch = false; 7932 if (separatorChars == null) { 7933 // Null separator means use whitespace 7934 while (i < len) { 7935 if (Character.isWhitespace(str.charAt(i))) { 7936 if (match || preserveAllTokens) { 7937 lastMatch = true; 7938 if (sizePlus1++ == max) { 7939 i = len; 7940 lastMatch = false; 7941 } 7942 list.add(str.substring(start, i)); 7943 match = false; 7944 } 7945 start = ++i; 7946 continue; 7947 } 7948 lastMatch = false; 7949 match = true; 7950 i++; 7951 } 7952 } else if (separatorChars.length() == 1) { 7953 // Optimise 1 character case 7954 final char sep = separatorChars.charAt(0); 7955 while (i < len) { 7956 if (str.charAt(i) == sep) { 7957 if (match || preserveAllTokens) { 7958 lastMatch = true; 7959 if (sizePlus1++ == max) { 7960 i = len; 7961 lastMatch = false; 7962 } 7963 list.add(str.substring(start, i)); 7964 match = false; 7965 } 7966 start = ++i; 7967 continue; 7968 } 7969 lastMatch = false; 7970 match = true; 7971 i++; 7972 } 7973 } else { 7974 // standard case 7975 while (i < len) { 7976 if (separatorChars.indexOf(str.charAt(i)) >= 0) { 7977 if (match || preserveAllTokens) { 7978 lastMatch = true; 7979 if (sizePlus1++ == max) { 7980 i = len; 7981 lastMatch = false; 7982 } 7983 list.add(str.substring(start, i)); 7984 match = false; 7985 } 7986 start = ++i; 7987 continue; 7988 } 7989 lastMatch = false; 7990 match = true; 7991 i++; 7992 } 7993 } 7994 if (match || preserveAllTokens && lastMatch) { 7995 list.add(str.substring(start, i)); 7996 } 7997 return list.toArray(ArrayUtils.EMPTY_STRING_ARRAY); 7998 } 7999 8000 /** 8001 * Check if a CharSequence starts with a specified prefix. 8002 * 8003 * <p>{@code null}s are handled without exceptions. Two {@code null} 8004 * references are considered to be equal. The comparison is case-sensitive.</p> 8005 * 8006 * <pre> 8007 * StringUtils.startsWith(null, null) = true 8008 * StringUtils.startsWith(null, "abc") = false 8009 * StringUtils.startsWith("abcdef", null) = false 8010 * StringUtils.startsWith("abcdef", "abc") = true 8011 * StringUtils.startsWith("ABCDEF", "abc") = false 8012 * </pre> 8013 * 8014 * @see String#startsWith(String) 8015 * @param str the CharSequence to check, may be null 8016 * @param prefix the prefix to find, may be null 8017 * @return {@code true} if the CharSequence starts with the prefix, case-sensitive, or 8018 * both {@code null} 8019 * @since 2.4 8020 * @since 3.0 Changed signature from startsWith(String, String) to startsWith(CharSequence, CharSequence) 8021 */ 8022 public static boolean startsWith(final CharSequence str, final CharSequence prefix) { 8023 return startsWith(str, prefix, false); 8024 } 8025 8026 /** 8027 * Check if a CharSequence starts with a specified prefix (optionally case-insensitive). 8028 * 8029 * @see String#startsWith(String) 8030 * @param str the CharSequence to check, may be null 8031 * @param prefix the prefix to find, may be null 8032 * @param ignoreCase indicates whether the compare should ignore case 8033 * (case-insensitive) or not. 8034 * @return {@code true} if the CharSequence starts with the prefix or 8035 * both {@code null} 8036 */ 8037 private static boolean startsWith(final CharSequence str, final CharSequence prefix, final boolean ignoreCase) { 8038 if (str == null || prefix == null) { 8039 return str == prefix; 8040 } 8041 // Get length once instead of twice in the unlikely case that it changes. 8042 final int preLen = prefix.length(); 8043 if (preLen > str.length()) { 8044 return false; 8045 } 8046 return CharSequenceUtils.regionMatches(str, ignoreCase, 0, prefix, 0, preLen); 8047 } 8048 8049 /** 8050 * Check if a CharSequence starts with any of the provided case-sensitive prefixes. 8051 * 8052 * <pre> 8053 * StringUtils.startsWithAny(null, null) = false 8054 * StringUtils.startsWithAny(null, new String[] {"abc"}) = false 8055 * StringUtils.startsWithAny("abcxyz", null) = false 8056 * StringUtils.startsWithAny("abcxyz", new String[] {""}) = true 8057 * StringUtils.startsWithAny("abcxyz", new String[] {"abc"}) = true 8058 * StringUtils.startsWithAny("abcxyz", new String[] {null, "xyz", "abc"}) = true 8059 * StringUtils.startsWithAny("abcxyz", null, "xyz", "ABCX") = false 8060 * StringUtils.startsWithAny("ABCXYZ", null, "xyz", "abc") = false 8061 * </pre> 8062 * 8063 * @param sequence the CharSequence to check, may be null 8064 * @param searchStrings the case-sensitive CharSequence prefixes, may be empty or contain {@code null} 8065 * @see StringUtils#startsWith(CharSequence, CharSequence) 8066 * @return {@code true} if the input {@code sequence} is {@code null} AND no {@code searchStrings} are provided, or 8067 * the input {@code sequence} begins with any of the provided case-sensitive {@code searchStrings}. 8068 * @since 2.5 8069 * @since 3.0 Changed signature from startsWithAny(String, String[]) to startsWithAny(CharSequence, CharSequence...) 8070 */ 8071 public static boolean startsWithAny(final CharSequence sequence, final CharSequence... searchStrings) { 8072 if (isEmpty(sequence) || ArrayUtils.isEmpty(searchStrings)) { 8073 return false; 8074 } 8075 for (final CharSequence searchString : searchStrings) { 8076 if (startsWith(sequence, searchString)) { 8077 return true; 8078 } 8079 } 8080 return false; 8081 } 8082 8083 /** 8084 * Case-insensitive check if a CharSequence starts with a specified prefix. 8085 * 8086 * <p>{@code null}s are handled without exceptions. Two {@code null} 8087 * references are considered to be equal. The comparison is case insensitive.</p> 8088 * 8089 * <pre> 8090 * StringUtils.startsWithIgnoreCase(null, null) = true 8091 * StringUtils.startsWithIgnoreCase(null, "abc") = false 8092 * StringUtils.startsWithIgnoreCase("abcdef", null) = false 8093 * StringUtils.startsWithIgnoreCase("abcdef", "abc") = true 8094 * StringUtils.startsWithIgnoreCase("ABCDEF", "abc") = true 8095 * </pre> 8096 * 8097 * @see String#startsWith(String) 8098 * @param str the CharSequence to check, may be null 8099 * @param prefix the prefix to find, may be null 8100 * @return {@code true} if the CharSequence starts with the prefix, case-insensitive, or 8101 * both {@code null} 8102 * @since 2.4 8103 * @since 3.0 Changed signature from startsWithIgnoreCase(String, String) to startsWithIgnoreCase(CharSequence, CharSequence) 8104 */ 8105 public static boolean startsWithIgnoreCase(final CharSequence str, final CharSequence prefix) { 8106 return startsWith(str, prefix, true); 8107 } 8108 8109 /** 8110 * Strips whitespace from the start and end of a String. 8111 * 8112 * <p>This is similar to {@link #trim(String)} but removes whitespace. 8113 * Whitespace is defined by {@link Character#isWhitespace(char)}.</p> 8114 * 8115 * <p>A {@code null} input String returns {@code null}.</p> 8116 * 8117 * <pre> 8118 * StringUtils.strip(null) = null 8119 * StringUtils.strip("") = "" 8120 * StringUtils.strip(" ") = "" 8121 * StringUtils.strip("abc") = "abc" 8122 * StringUtils.strip(" abc") = "abc" 8123 * StringUtils.strip("abc ") = "abc" 8124 * StringUtils.strip(" abc ") = "abc" 8125 * StringUtils.strip(" ab c ") = "ab c" 8126 * </pre> 8127 * 8128 * @param str the String to remove whitespace from, may be null 8129 * @return the stripped String, {@code null} if null String input 8130 */ 8131 public static String strip(final String str) { 8132 return strip(str, null); 8133 } 8134 8135 /** 8136 * Strips any of a set of characters from the start and end of a String. 8137 * This is similar to {@link String#trim()} but allows the characters 8138 * to be stripped to be controlled. 8139 * 8140 * <p>A {@code null} input String returns {@code null}. 8141 * An empty string ("") input returns the empty string.</p> 8142 * 8143 * <p>If the stripChars String is {@code null}, whitespace is 8144 * stripped as defined by {@link Character#isWhitespace(char)}. 8145 * Alternatively use {@link #strip(String)}.</p> 8146 * 8147 * <pre> 8148 * StringUtils.strip(null, *) = null 8149 * StringUtils.strip("", *) = "" 8150 * StringUtils.strip("abc", null) = "abc" 8151 * StringUtils.strip(" abc", null) = "abc" 8152 * StringUtils.strip("abc ", null) = "abc" 8153 * StringUtils.strip(" abc ", null) = "abc" 8154 * StringUtils.strip(" abcyx", "xyz") = " abc" 8155 * </pre> 8156 * 8157 * @param str the String to remove characters from, may be null 8158 * @param stripChars the characters to remove, null treated as whitespace 8159 * @return the stripped String, {@code null} if null String input 8160 */ 8161 public static String strip(String str, final String stripChars) { 8162 str = stripStart(str, stripChars); 8163 return stripEnd(str, stripChars); 8164 } 8165 8166 /** 8167 * Removes diacritics (~= accents) from a string. The case will not be altered. 8168 * <p>For instance, 'à' will be replaced by 'a'.</p> 8169 * <p>Decomposes ligatures and digraphs per the KD column in the 8170 * <a href = "https://www.unicode.org/charts/normalization/">Unicode Normalization Chart.</a></p> 8171 * 8172 * <pre> 8173 * StringUtils.stripAccents(null) = null 8174 * StringUtils.stripAccents("") = "" 8175 * StringUtils.stripAccents("control") = "control" 8176 * StringUtils.stripAccents("éclair") = "eclair" 8177 * </pre> 8178 * 8179 * @param input String to be stripped 8180 * @return input text with diacritics removed 8181 * 8182 * @since 3.0 8183 */ 8184 // 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). 8185 public static String stripAccents(final String input) { 8186 if (isEmpty(input)) { 8187 return input; 8188 } 8189 final StringBuilder decomposed = new StringBuilder(Normalizer.normalize(input, Normalizer.Form.NFKD)); 8190 convertRemainingAccentCharacters(decomposed); 8191 return STRIP_ACCENTS_PATTERN.matcher(decomposed).replaceAll(EMPTY); 8192 } 8193 8194 /** 8195 * Strips whitespace from the start and end of every String in an array. 8196 * Whitespace is defined by {@link Character#isWhitespace(char)}. 8197 * 8198 * <p>A new array is returned each time, except for length zero. 8199 * A {@code null} array will return {@code null}. 8200 * An empty array will return itself. 8201 * A {@code null} array entry will be ignored.</p> 8202 * 8203 * <pre> 8204 * StringUtils.stripAll(null) = null 8205 * StringUtils.stripAll([]) = [] 8206 * StringUtils.stripAll(["abc", " abc"]) = ["abc", "abc"] 8207 * StringUtils.stripAll(["abc ", null]) = ["abc", null] 8208 * </pre> 8209 * 8210 * @param strs the array to remove whitespace from, may be null 8211 * @return the stripped Strings, {@code null} if null array input 8212 */ 8213 public static String[] stripAll(final String... strs) { 8214 return stripAll(strs, null); 8215 } 8216 8217 /** 8218 * Strips any of a set of characters from the start and end of every 8219 * String in an array. 8220 * <p>Whitespace is defined by {@link Character#isWhitespace(char)}.</p> 8221 * 8222 * <p>A new array is returned each time, except for length zero. 8223 * A {@code null} array will return {@code null}. 8224 * An empty array will return itself. 8225 * A {@code null} array entry will be ignored. 8226 * A {@code null} stripChars will strip whitespace as defined by 8227 * {@link Character#isWhitespace(char)}.</p> 8228 * 8229 * <pre> 8230 * StringUtils.stripAll(null, *) = null 8231 * StringUtils.stripAll([], *) = [] 8232 * StringUtils.stripAll(["abc", " abc"], null) = ["abc", "abc"] 8233 * StringUtils.stripAll(["abc ", null], null) = ["abc", null] 8234 * StringUtils.stripAll(["abc ", null], "yz") = ["abc ", null] 8235 * StringUtils.stripAll(["yabcz", null], "yz") = ["abc", null] 8236 * </pre> 8237 * 8238 * @param strs the array to remove characters from, may be null 8239 * @param stripChars the characters to remove, null treated as whitespace 8240 * @return the stripped Strings, {@code null} if null array input 8241 */ 8242 public static String[] stripAll(final String[] strs, final String stripChars) { 8243 final int strsLen = ArrayUtils.getLength(strs); 8244 if (strsLen == 0) { 8245 return strs; 8246 } 8247 final String[] newArr = new String[strsLen]; 8248 Arrays.setAll(newArr, i -> strip(strs[i], stripChars)); 8249 return newArr; 8250 } 8251 8252 /** 8253 * Strips any of a set of characters from the end of a String. 8254 * 8255 * <p>A {@code null} input String returns {@code null}. 8256 * An empty string ("") input returns the empty string.</p> 8257 * 8258 * <p>If the stripChars String is {@code null}, whitespace is 8259 * stripped as defined by {@link Character#isWhitespace(char)}.</p> 8260 * 8261 * <pre> 8262 * StringUtils.stripEnd(null, *) = null 8263 * StringUtils.stripEnd("", *) = "" 8264 * StringUtils.stripEnd("abc", "") = "abc" 8265 * StringUtils.stripEnd("abc", null) = "abc" 8266 * StringUtils.stripEnd(" abc", null) = " abc" 8267 * StringUtils.stripEnd("abc ", null) = "abc" 8268 * StringUtils.stripEnd(" abc ", null) = " abc" 8269 * StringUtils.stripEnd(" abcyx", "xyz") = " abc" 8270 * StringUtils.stripEnd("120.00", ".0") = "12" 8271 * </pre> 8272 * 8273 * @param str the String to remove characters from, may be null 8274 * @param stripChars the set of characters to remove, null treated as whitespace 8275 * @return the stripped String, {@code null} if null String input 8276 */ 8277 public static String stripEnd(final String str, final String stripChars) { 8278 int end = length(str); 8279 if (end == 0) { 8280 return str; 8281 } 8282 8283 if (stripChars == null) { 8284 while (end != 0 && Character.isWhitespace(str.charAt(end - 1))) { 8285 end--; 8286 } 8287 } else if (stripChars.isEmpty()) { 8288 return str; 8289 } else { 8290 while (end != 0 && stripChars.indexOf(str.charAt(end - 1)) != INDEX_NOT_FOUND) { 8291 end--; 8292 } 8293 } 8294 return str.substring(0, end); 8295 } 8296 8297 /** 8298 * Strips any of a set of characters from the start of a String. 8299 * 8300 * <p>A {@code null} input String returns {@code null}. 8301 * An empty string ("") input returns the empty string.</p> 8302 * 8303 * <p>If the stripChars String is {@code null}, whitespace is 8304 * stripped as defined by {@link Character#isWhitespace(char)}.</p> 8305 * 8306 * <pre> 8307 * StringUtils.stripStart(null, *) = null 8308 * StringUtils.stripStart("", *) = "" 8309 * StringUtils.stripStart("abc", "") = "abc" 8310 * StringUtils.stripStart("abc", null) = "abc" 8311 * StringUtils.stripStart(" abc", null) = "abc" 8312 * StringUtils.stripStart("abc ", null) = "abc " 8313 * StringUtils.stripStart(" abc ", null) = "abc " 8314 * StringUtils.stripStart("yxabc ", "xyz") = "abc " 8315 * </pre> 8316 * 8317 * @param str the String to remove characters from, may be null 8318 * @param stripChars the characters to remove, null treated as whitespace 8319 * @return the stripped String, {@code null} if null String input 8320 */ 8321 public static String stripStart(final String str, final String stripChars) { 8322 final int strLen = length(str); 8323 if (strLen == 0) { 8324 return str; 8325 } 8326 int start = 0; 8327 if (stripChars == null) { 8328 while (start != strLen && Character.isWhitespace(str.charAt(start))) { 8329 start++; 8330 } 8331 } else if (stripChars.isEmpty()) { 8332 return str; 8333 } else { 8334 while (start != strLen && stripChars.indexOf(str.charAt(start)) != INDEX_NOT_FOUND) { 8335 start++; 8336 } 8337 } 8338 return str.substring(start); 8339 } 8340 8341 /** 8342 * Strips whitespace from the start and end of a String returning 8343 * an empty String if {@code null} input. 8344 * 8345 * <p>This is similar to {@link #trimToEmpty(String)} but removes whitespace. 8346 * Whitespace is defined by {@link Character#isWhitespace(char)}.</p> 8347 * 8348 * <pre> 8349 * StringUtils.stripToEmpty(null) = "" 8350 * StringUtils.stripToEmpty("") = "" 8351 * StringUtils.stripToEmpty(" ") = "" 8352 * StringUtils.stripToEmpty("abc") = "abc" 8353 * StringUtils.stripToEmpty(" abc") = "abc" 8354 * StringUtils.stripToEmpty("abc ") = "abc" 8355 * StringUtils.stripToEmpty(" abc ") = "abc" 8356 * StringUtils.stripToEmpty(" ab c ") = "ab c" 8357 * </pre> 8358 * 8359 * @param str the String to be stripped, may be null 8360 * @return the trimmed String, or an empty String if {@code null} input 8361 * @since 2.0 8362 */ 8363 public static String stripToEmpty(final String str) { 8364 return str == null ? EMPTY : strip(str, null); 8365 } 8366 8367 /** 8368 * Strips whitespace from the start and end of a String returning 8369 * {@code null} if the String is empty ("") after the strip. 8370 * 8371 * <p>This is similar to {@link #trimToNull(String)} but removes whitespace. 8372 * Whitespace is defined by {@link Character#isWhitespace(char)}.</p> 8373 * 8374 * <pre> 8375 * StringUtils.stripToNull(null) = null 8376 * StringUtils.stripToNull("") = null 8377 * StringUtils.stripToNull(" ") = null 8378 * StringUtils.stripToNull("abc") = "abc" 8379 * StringUtils.stripToNull(" abc") = "abc" 8380 * StringUtils.stripToNull("abc ") = "abc" 8381 * StringUtils.stripToNull(" abc ") = "abc" 8382 * StringUtils.stripToNull(" ab c ") = "ab c" 8383 * </pre> 8384 * 8385 * @param str the String to be stripped, may be null 8386 * @return the stripped String, 8387 * {@code null} if whitespace, empty or null String input 8388 * @since 2.0 8389 */ 8390 public static String stripToNull(String str) { 8391 if (str == null) { 8392 return null; 8393 } 8394 str = strip(str, null); 8395 return str.isEmpty() ? null : str; // NOSONARLINT str cannot be null here 8396 } 8397 8398 /** 8399 * Gets a substring from the specified String avoiding exceptions. 8400 * 8401 * <p>A negative start position can be used to start {@code n} 8402 * characters from the end of the String.</p> 8403 * 8404 * <p>A {@code null} String will return {@code null}. 8405 * An empty ("") String will return "".</p> 8406 * 8407 * <pre> 8408 * StringUtils.substring(null, *) = null 8409 * StringUtils.substring("", *) = "" 8410 * StringUtils.substring("abc", 0) = "abc" 8411 * StringUtils.substring("abc", 2) = "c" 8412 * StringUtils.substring("abc", 4) = "" 8413 * StringUtils.substring("abc", -2) = "bc" 8414 * StringUtils.substring("abc", -4) = "abc" 8415 * </pre> 8416 * 8417 * @param str the String to get the substring from, may be null 8418 * @param start the position to start from, negative means 8419 * count back from the end of the String by this many characters 8420 * @return substring from start position, {@code null} if null String input 8421 */ 8422 public static String substring(final String str, int start) { 8423 if (str == null) { 8424 return null; 8425 } 8426 8427 // handle negatives, which means last n characters 8428 if (start < 0) { 8429 start = str.length() + start; // remember start is negative 8430 } 8431 8432 if (start < 0) { 8433 start = 0; 8434 } 8435 if (start > str.length()) { 8436 return EMPTY; 8437 } 8438 8439 return str.substring(start); 8440 } 8441 8442 /** 8443 * Gets a substring from the specified String avoiding exceptions. 8444 * 8445 * <p>A negative start position can be used to start/end {@code n} 8446 * characters from the end of the String.</p> 8447 * 8448 * <p>The returned substring starts with the character in the {@code start} 8449 * position and ends before the {@code end} position. All position counting is 8450 * zero-based -- i.e., to start at the beginning of the string use 8451 * {@code start = 0}. Negative start and end positions can be used to 8452 * specify offsets relative to the end of the String.</p> 8453 * 8454 * <p>If {@code start} is not strictly to the left of {@code end}, "" 8455 * is returned.</p> 8456 * 8457 * <pre> 8458 * StringUtils.substring(null, *, *) = null 8459 * StringUtils.substring("", * , *) = ""; 8460 * StringUtils.substring("abc", 0, 2) = "ab" 8461 * StringUtils.substring("abc", 2, 0) = "" 8462 * StringUtils.substring("abc", 2, 4) = "c" 8463 * StringUtils.substring("abc", 4, 6) = "" 8464 * StringUtils.substring("abc", 2, 2) = "" 8465 * StringUtils.substring("abc", -2, -1) = "b" 8466 * StringUtils.substring("abc", -4, 2) = "ab" 8467 * </pre> 8468 * 8469 * @param str the String to get the substring from, may be null 8470 * @param start the position to start from, negative means 8471 * count back from the end of the String by this many characters 8472 * @param end the position to end at (exclusive), negative means 8473 * count back from the end of the String by this many characters 8474 * @return substring from start position to end position, 8475 * {@code null} if null String input 8476 */ 8477 public static String substring(final String str, int start, int end) { 8478 if (str == null) { 8479 return null; 8480 } 8481 8482 // handle negatives 8483 if (end < 0) { 8484 end = str.length() + end; // remember end is negative 8485 } 8486 if (start < 0) { 8487 start = str.length() + start; // remember start is negative 8488 } 8489 8490 // check length next 8491 if (end > str.length()) { 8492 end = str.length(); 8493 } 8494 8495 // if start is greater than end, return "" 8496 if (start > end) { 8497 return EMPTY; 8498 } 8499 8500 if (start < 0) { 8501 start = 0; 8502 } 8503 if (end < 0) { 8504 end = 0; 8505 } 8506 8507 return str.substring(start, end); 8508 } 8509 8510 /** 8511 * Gets the substring after the first occurrence of a separator. 8512 * The separator is not returned. 8513 * 8514 * <p>A {@code null} string input will return {@code null}. 8515 * An empty ("") string input will return the empty string. 8516 * 8517 * <p>If nothing is found, the empty string is returned.</p> 8518 * 8519 * <pre> 8520 * StringUtils.substringAfter(null, *) = null 8521 * StringUtils.substringAfter("", *) = "" 8522 * StringUtils.substringAfter("abc", 'a') = "bc" 8523 * StringUtils.substringAfter("abcba", 'b') = "cba" 8524 * StringUtils.substringAfter("abc", 'c') = "" 8525 * StringUtils.substringAfter("abc", 'd') = "" 8526 * StringUtils.substringAfter(" abc", 32) = "abc" 8527 * </pre> 8528 * 8529 * @param str the String to get a substring from, may be null 8530 * @param separator the character (Unicode code point) to search. 8531 * @return the substring after the first occurrence of the separator, 8532 * {@code null} if null String input 8533 * @since 3.11 8534 */ 8535 public static String substringAfter(final String str, final int separator) { 8536 if (isEmpty(str)) { 8537 return str; 8538 } 8539 final int pos = str.indexOf(separator); 8540 if (pos == INDEX_NOT_FOUND) { 8541 return EMPTY; 8542 } 8543 return str.substring(pos + 1); 8544 } 8545 8546 /** 8547 * Gets the substring after the first occurrence of a separator. 8548 * The separator is not returned. 8549 * 8550 * <p>A {@code null} string input will return {@code null}. 8551 * An empty ("") string input will return the empty string. 8552 * A {@code null} separator will return the empty string if the 8553 * input string is not {@code null}.</p> 8554 * 8555 * <p>If nothing is found, the empty string is returned.</p> 8556 * 8557 * <pre> 8558 * StringUtils.substringAfter(null, *) = null 8559 * StringUtils.substringAfter("", *) = "" 8560 * StringUtils.substringAfter(*, null) = "" 8561 * StringUtils.substringAfter("abc", "a") = "bc" 8562 * StringUtils.substringAfter("abcba", "b") = "cba" 8563 * StringUtils.substringAfter("abc", "c") = "" 8564 * StringUtils.substringAfter("abc", "d") = "" 8565 * StringUtils.substringAfter("abc", "") = "abc" 8566 * </pre> 8567 * 8568 * @param str the String to get a substring from, may be null 8569 * @param separator the String to search for, may be null 8570 * @return the substring after the first occurrence of the separator, 8571 * {@code null} if null String input 8572 * @since 2.0 8573 */ 8574 public static String substringAfter(final String str, final String separator) { 8575 if (isEmpty(str)) { 8576 return str; 8577 } 8578 if (separator == null) { 8579 return EMPTY; 8580 } 8581 final int pos = str.indexOf(separator); 8582 if (pos == INDEX_NOT_FOUND) { 8583 return EMPTY; 8584 } 8585 return str.substring(pos + separator.length()); 8586 } 8587 8588 /** 8589 * Gets the substring after the last occurrence of a separator. 8590 * The separator is not returned. 8591 * 8592 * <p>A {@code null} string input will return {@code null}. 8593 * An empty ("") string input will return the empty string. 8594 * 8595 * <p>If nothing is found, the empty string is returned.</p> 8596 * 8597 * <pre> 8598 * StringUtils.substringAfterLast(null, *) = null 8599 * StringUtils.substringAfterLast("", *) = "" 8600 * StringUtils.substringAfterLast("abc", 'a') = "bc" 8601 * StringUtils.substringAfterLast(" bc", 32) = "bc" 8602 * StringUtils.substringAfterLast("abcba", 'b') = "a" 8603 * StringUtils.substringAfterLast("abc", 'c') = "" 8604 * StringUtils.substringAfterLast("a", 'a') = "" 8605 * StringUtils.substringAfterLast("a", 'z') = "" 8606 * </pre> 8607 * 8608 * @param str the String to get a substring from, may be null 8609 * @param separator the character (Unicode code point) to search. 8610 * @return the substring after the last occurrence of the separator, 8611 * {@code null} if null String input 8612 * @since 3.11 8613 */ 8614 public static String substringAfterLast(final String str, final int separator) { 8615 if (isEmpty(str)) { 8616 return str; 8617 } 8618 final int pos = str.lastIndexOf(separator); 8619 if (pos == INDEX_NOT_FOUND || pos == str.length() - 1) { 8620 return EMPTY; 8621 } 8622 return str.substring(pos + 1); 8623 } 8624 8625 /** 8626 * Gets the substring after the last occurrence of a separator. 8627 * The separator is not returned. 8628 * 8629 * <p>A {@code null} string input will return {@code null}. 8630 * An empty ("") string input will return the empty string. 8631 * An empty or {@code null} separator will return the empty string if 8632 * the input string is not {@code null}.</p> 8633 * 8634 * <p>If nothing is found, the empty string is returned.</p> 8635 * 8636 * <pre> 8637 * StringUtils.substringAfterLast(null, *) = null 8638 * StringUtils.substringAfterLast("", *) = "" 8639 * StringUtils.substringAfterLast(*, "") = "" 8640 * StringUtils.substringAfterLast(*, null) = "" 8641 * StringUtils.substringAfterLast("abc", "a") = "bc" 8642 * StringUtils.substringAfterLast("abcba", "b") = "a" 8643 * StringUtils.substringAfterLast("abc", "c") = "" 8644 * StringUtils.substringAfterLast("a", "a") = "" 8645 * StringUtils.substringAfterLast("a", "z") = "" 8646 * </pre> 8647 * 8648 * @param str the String to get a substring from, may be null 8649 * @param separator the String to search for, may be null 8650 * @return the substring after the last occurrence of the separator, 8651 * {@code null} if null String input 8652 * @since 2.0 8653 */ 8654 public static String substringAfterLast(final String str, final String separator) { 8655 if (isEmpty(str)) { 8656 return str; 8657 } 8658 if (isEmpty(separator)) { 8659 return EMPTY; 8660 } 8661 final int pos = str.lastIndexOf(separator); 8662 if (pos == INDEX_NOT_FOUND || pos == str.length() - separator.length()) { 8663 return EMPTY; 8664 } 8665 return str.substring(pos + separator.length()); 8666 } 8667 8668 /** 8669 * Gets the substring before the first occurrence of a separator. The separator is not returned. 8670 * 8671 * <p> 8672 * A {@code null} string input will return {@code null}. An empty ("") string input will return the empty string. 8673 * </p> 8674 * 8675 * <p> 8676 * If nothing is found, the string input is returned. 8677 * </p> 8678 * 8679 * <pre> 8680 * StringUtils.substringBefore(null, *) = null 8681 * StringUtils.substringBefore("", *) = "" 8682 * StringUtils.substringBefore("abc", 'a') = "" 8683 * StringUtils.substringBefore("abcba", 'b') = "a" 8684 * StringUtils.substringBefore("abc", 'c') = "ab" 8685 * StringUtils.substringBefore("abc", 'd') = "abc" 8686 * </pre> 8687 * 8688 * @param str the String to get a substring from, may be null 8689 * @param separator the character (Unicode code point) to search. 8690 * @return the substring before the first occurrence of the separator, {@code null} if null String input 8691 * @since 3.12.0 8692 */ 8693 public static String substringBefore(final String str, final int separator) { 8694 if (isEmpty(str)) { 8695 return str; 8696 } 8697 final int pos = str.indexOf(separator); 8698 if (pos == INDEX_NOT_FOUND) { 8699 return str; 8700 } 8701 return str.substring(0, pos); 8702 } 8703 8704 /** 8705 * Gets the substring before the first occurrence of a separator. 8706 * The separator is not returned. 8707 * 8708 * <p>A {@code null} string input will return {@code null}. 8709 * An empty ("") string input will return the empty string. 8710 * A {@code null} separator will return the input string.</p> 8711 * 8712 * <p>If nothing is found, the string input is returned.</p> 8713 * 8714 * <pre> 8715 * StringUtils.substringBefore(null, *) = null 8716 * StringUtils.substringBefore("", *) = "" 8717 * StringUtils.substringBefore("abc", "a") = "" 8718 * StringUtils.substringBefore("abcba", "b") = "a" 8719 * StringUtils.substringBefore("abc", "c") = "ab" 8720 * StringUtils.substringBefore("abc", "d") = "abc" 8721 * StringUtils.substringBefore("abc", "") = "" 8722 * StringUtils.substringBefore("abc", null) = "abc" 8723 * </pre> 8724 * 8725 * @param str the String to get a substring from, may be null 8726 * @param separator the String to search for, may be null 8727 * @return the substring before the first occurrence of the separator, 8728 * {@code null} if null String input 8729 * @since 2.0 8730 */ 8731 public static String substringBefore(final String str, final String separator) { 8732 if (isEmpty(str) || separator == null) { 8733 return str; 8734 } 8735 if (separator.isEmpty()) { 8736 return EMPTY; 8737 } 8738 final int pos = str.indexOf(separator); 8739 if (pos == INDEX_NOT_FOUND) { 8740 return str; 8741 } 8742 return str.substring(0, pos); 8743 } 8744 8745 /** 8746 * Gets the substring before the last occurrence of a separator. 8747 * The separator is not returned. 8748 * 8749 * <p>A {@code null} string input will return {@code null}. 8750 * An empty ("") string input will return the empty string. 8751 * An empty or {@code null} separator will return the input string.</p> 8752 * 8753 * <p>If nothing is found, the string input is returned.</p> 8754 * 8755 * <pre> 8756 * StringUtils.substringBeforeLast(null, *) = null 8757 * StringUtils.substringBeforeLast("", *) = "" 8758 * StringUtils.substringBeforeLast("abcba", "b") = "abc" 8759 * StringUtils.substringBeforeLast("abc", "c") = "ab" 8760 * StringUtils.substringBeforeLast("a", "a") = "" 8761 * StringUtils.substringBeforeLast("a", "z") = "a" 8762 * StringUtils.substringBeforeLast("a", null) = "a" 8763 * StringUtils.substringBeforeLast("a", "") = "a" 8764 * </pre> 8765 * 8766 * @param str the String to get a substring from, may be null 8767 * @param separator the String to search for, may be null 8768 * @return the substring before the last occurrence of the separator, 8769 * {@code null} if null String input 8770 * @since 2.0 8771 */ 8772 public static String substringBeforeLast(final String str, final String separator) { 8773 if (isEmpty(str) || isEmpty(separator)) { 8774 return str; 8775 } 8776 final int pos = str.lastIndexOf(separator); 8777 if (pos == INDEX_NOT_FOUND) { 8778 return str; 8779 } 8780 return str.substring(0, pos); 8781 } 8782 8783 /** 8784 * Gets the String that is nested in between two instances of the 8785 * same String. 8786 * 8787 * <p>A {@code null} input String returns {@code null}. 8788 * A {@code null} tag returns {@code null}.</p> 8789 * 8790 * <pre> 8791 * StringUtils.substringBetween(null, *) = null 8792 * StringUtils.substringBetween("", "") = "" 8793 * StringUtils.substringBetween("", "tag") = null 8794 * StringUtils.substringBetween("tagabctag", null) = null 8795 * StringUtils.substringBetween("tagabctag", "") = "" 8796 * StringUtils.substringBetween("tagabctag", "tag") = "abc" 8797 * </pre> 8798 * 8799 * @param str the String containing the substring, may be null 8800 * @param tag the String before and after the substring, may be null 8801 * @return the substring, {@code null} if no match 8802 * @since 2.0 8803 */ 8804 public static String substringBetween(final String str, final String tag) { 8805 return substringBetween(str, tag, tag); 8806 } 8807 8808 /** 8809 * Gets the String that is nested in between two Strings. 8810 * Only the first match is returned. 8811 * 8812 * <p>A {@code null} input String returns {@code null}. 8813 * A {@code null} open/close returns {@code null} (no match). 8814 * An empty ("") open and close returns an empty string.</p> 8815 * 8816 * <pre> 8817 * StringUtils.substringBetween("wx[b]yz", "[", "]") = "b" 8818 * StringUtils.substringBetween(null, *, *) = null 8819 * StringUtils.substringBetween(*, null, *) = null 8820 * StringUtils.substringBetween(*, *, null) = null 8821 * StringUtils.substringBetween("", "", "") = "" 8822 * StringUtils.substringBetween("", "", "]") = null 8823 * StringUtils.substringBetween("", "[", "]") = null 8824 * StringUtils.substringBetween("yabcz", "", "") = "" 8825 * StringUtils.substringBetween("yabcz", "y", "z") = "abc" 8826 * StringUtils.substringBetween("yabczyabcz", "y", "z") = "abc" 8827 * </pre> 8828 * 8829 * @param str the String containing the substring, may be null 8830 * @param open the String before the substring, may be null 8831 * @param close the String after the substring, may be null 8832 * @return the substring, {@code null} if no match 8833 * @since 2.0 8834 */ 8835 public static String substringBetween(final String str, final String open, final String close) { 8836 if (!ObjectUtils.allNotNull(str, open, close)) { 8837 return null; 8838 } 8839 final int start = str.indexOf(open); 8840 if (start != INDEX_NOT_FOUND) { 8841 final int end = str.indexOf(close, start + open.length()); 8842 if (end != INDEX_NOT_FOUND) { 8843 return str.substring(start + open.length(), end); 8844 } 8845 } 8846 return null; 8847 } 8848 8849 /** 8850 * Searches a String for substrings delimited by a start and end tag, 8851 * returning all matching substrings in an array. 8852 * 8853 * <p>A {@code null} input String returns {@code null}. 8854 * A {@code null} open/close returns {@code null} (no match). 8855 * An empty ("") open/close returns {@code null} (no match).</p> 8856 * 8857 * <pre> 8858 * StringUtils.substringsBetween("[a][b][c]", "[", "]") = ["a","b","c"] 8859 * StringUtils.substringsBetween(null, *, *) = null 8860 * StringUtils.substringsBetween(*, null, *) = null 8861 * StringUtils.substringsBetween(*, *, null) = null 8862 * StringUtils.substringsBetween("", "[", "]") = [] 8863 * </pre> 8864 * 8865 * @param str the String containing the substrings, null returns null, empty returns empty 8866 * @param open the String identifying the start of the substring, empty returns null 8867 * @param close the String identifying the end of the substring, empty returns null 8868 * @return a String Array of substrings, or {@code null} if no match 8869 * @since 2.3 8870 */ 8871 public static String[] substringsBetween(final String str, final String open, final String close) { 8872 if (str == null || isEmpty(open) || isEmpty(close)) { 8873 return null; 8874 } 8875 final int strLen = str.length(); 8876 if (strLen == 0) { 8877 return ArrayUtils.EMPTY_STRING_ARRAY; 8878 } 8879 final int closeLen = close.length(); 8880 final int openLen = open.length(); 8881 final List<String> list = new ArrayList<>(); 8882 int pos = 0; 8883 while (pos < strLen - closeLen) { 8884 int start = str.indexOf(open, pos); 8885 if (start < 0) { 8886 break; 8887 } 8888 start += openLen; 8889 final int end = str.indexOf(close, start); 8890 if (end < 0) { 8891 break; 8892 } 8893 list.add(str.substring(start, end)); 8894 pos = end + closeLen; 8895 } 8896 if (list.isEmpty()) { 8897 return null; 8898 } 8899 return list.toArray(ArrayUtils.EMPTY_STRING_ARRAY); 8900 } 8901 8902 /** 8903 * Swaps the case of a String changing upper and title case to 8904 * lower case, and lower case to upper case. 8905 * 8906 * <ul> 8907 * <li>Upper case character converts to Lower case</li> 8908 * <li>Title case character converts to Lower case</li> 8909 * <li>Lower case character converts to Upper case</li> 8910 * </ul> 8911 * 8912 * <p>For a word based algorithm, see {@link org.apache.commons.text.WordUtils#swapCase(String)}. 8913 * A {@code null} input String returns {@code null}.</p> 8914 * 8915 * <pre> 8916 * StringUtils.swapCase(null) = null 8917 * StringUtils.swapCase("") = "" 8918 * StringUtils.swapCase("The dog has a BONE") = "tHE DOG HAS A bone" 8919 * </pre> 8920 * 8921 * <p>NOTE: This method changed in Lang version 2.0. 8922 * It no longer performs a word based algorithm. 8923 * If you only use ASCII, you will notice no change. 8924 * That functionality is available in org.apache.commons.lang3.text.WordUtils.</p> 8925 * 8926 * @param str the String to swap case, may be null 8927 * @return the changed String, {@code null} if null String input 8928 */ 8929 public static String swapCase(final String str) { 8930 if (isEmpty(str)) { 8931 return str; 8932 } 8933 8934 final int strLen = str.length(); 8935 final int[] newCodePoints = new int[strLen]; // cannot be longer than the char array 8936 int outOffset = 0; 8937 for (int i = 0; i < strLen; ) { 8938 final int oldCodepoint = str.codePointAt(i); 8939 final int newCodePoint; 8940 if (Character.isUpperCase(oldCodepoint) || Character.isTitleCase(oldCodepoint)) { 8941 newCodePoint = Character.toLowerCase(oldCodepoint); 8942 } else if (Character.isLowerCase(oldCodepoint)) { 8943 newCodePoint = Character.toUpperCase(oldCodepoint); 8944 } else { 8945 newCodePoint = oldCodepoint; 8946 } 8947 newCodePoints[outOffset++] = newCodePoint; 8948 i += Character.charCount(newCodePoint); 8949 } 8950 return new String(newCodePoints, 0, outOffset); 8951 } 8952 8953 /** 8954 * Converts a {@link CharSequence} into an array of code points. 8955 * 8956 * <p>Valid pairs of surrogate code units will be converted into a single supplementary 8957 * code point. Isolated surrogate code units (i.e. a high surrogate not followed by a low surrogate or 8958 * a low surrogate not preceded by a high surrogate) will be returned as-is.</p> 8959 * 8960 * <pre> 8961 * StringUtils.toCodePoints(null) = null 8962 * StringUtils.toCodePoints("") = [] // empty array 8963 * </pre> 8964 * 8965 * @param cs the character sequence to convert 8966 * @return an array of code points 8967 * @since 3.6 8968 */ 8969 public static int[] toCodePoints(final CharSequence cs) { 8970 if (cs == null) { 8971 return null; 8972 } 8973 if (cs.length() == 0) { 8974 return ArrayUtils.EMPTY_INT_ARRAY; 8975 } 8976 8977 final String s = cs.toString(); 8978 final int[] result = new int[s.codePointCount(0, s.length())]; 8979 int index = 0; 8980 for (int i = 0; i < result.length; i++) { 8981 result[i] = s.codePointAt(index); 8982 index += Character.charCount(result[i]); 8983 } 8984 return result; 8985 } 8986 8987 /** 8988 * Converts a {@code byte[]} to a String using the specified character encoding. 8989 * 8990 * @param bytes 8991 * the byte array to read from 8992 * @param charset 8993 * the encoding to use, if null then use the platform default 8994 * @return a new String 8995 * @throws NullPointerException 8996 * if {@code bytes} is null 8997 * @since 3.2 8998 * @since 3.3 No longer throws {@link UnsupportedEncodingException}. 8999 */ 9000 public static String toEncodedString(final byte[] bytes, final Charset charset) { 9001 return new String(bytes, Charsets.toCharset(charset)); 9002 } 9003 9004 /** 9005 * Converts the given source String as a lower-case using the {@link Locale#ROOT} locale in a null-safe manner. 9006 * 9007 * @param source A source String or null. 9008 * @return the given source String as a lower-case using the {@link Locale#ROOT} locale or null. 9009 * @since 3.10 9010 */ 9011 public static String toRootLowerCase(final String source) { 9012 return source == null ? null : source.toLowerCase(Locale.ROOT); 9013 } 9014 9015 /** 9016 * Converts the given source String as an upper-case using the {@link Locale#ROOT} locale in a null-safe manner. 9017 * 9018 * @param source A source String or null. 9019 * @return the given source String as an upper-case using the {@link Locale#ROOT} locale or null. 9020 * @since 3.10 9021 */ 9022 public static String toRootUpperCase(final String source) { 9023 return source == null ? null : source.toUpperCase(Locale.ROOT); 9024 } 9025 9026 /** 9027 * Converts a {@code byte[]} to a String using the specified character encoding. 9028 * 9029 * @param bytes 9030 * the byte array to read from 9031 * @param charsetName 9032 * the encoding to use, if null then use the platform default 9033 * @return a new String 9034 * @throws NullPointerException 9035 * if the input is null 9036 * @deprecated use {@link StringUtils#toEncodedString(byte[], Charset)} instead of String constants in your code 9037 * @since 3.1 9038 */ 9039 @Deprecated 9040 public static String toString(final byte[] bytes, final String charsetName) { 9041 return new String(bytes, Charsets.toCharset(charsetName)); 9042 } 9043 9044 private static String toStringOrEmpty(final Object obj) { 9045 return Objects.toString(obj, EMPTY); 9046 } 9047 9048 /** 9049 * Removes control characters (char <= 32) from both 9050 * ends of this String, handling {@code null} by returning 9051 * {@code null}. 9052 * 9053 * <p>The String is trimmed using {@link String#trim()}. 9054 * Trim removes start and end characters <= 32. 9055 * To strip whitespace use {@link #strip(String)}.</p> 9056 * 9057 * <p>To trim your choice of characters, use the 9058 * {@link #strip(String, String)} methods.</p> 9059 * 9060 * <pre> 9061 * StringUtils.trim(null) = null 9062 * StringUtils.trim("") = "" 9063 * StringUtils.trim(" ") = "" 9064 * StringUtils.trim("abc") = "abc" 9065 * StringUtils.trim(" abc ") = "abc" 9066 * </pre> 9067 * 9068 * @param str the String to be trimmed, may be null 9069 * @return the trimmed string, {@code null} if null String input 9070 */ 9071 public static String trim(final String str) { 9072 return str == null ? null : str.trim(); 9073 } 9074 9075 /** 9076 * Removes control characters (char <= 32) from both 9077 * ends of this String returning an empty String ("") if the String 9078 * is empty ("") after the trim or if it is {@code null}. 9079 * 9080 * <p>The String is trimmed using {@link String#trim()}. 9081 * Trim removes start and end characters <= 32. 9082 * To strip whitespace use {@link #stripToEmpty(String)}. 9083 * 9084 * <pre> 9085 * StringUtils.trimToEmpty(null) = "" 9086 * StringUtils.trimToEmpty("") = "" 9087 * StringUtils.trimToEmpty(" ") = "" 9088 * StringUtils.trimToEmpty("abc") = "abc" 9089 * StringUtils.trimToEmpty(" abc ") = "abc" 9090 * </pre> 9091 * 9092 * @param str the String to be trimmed, may be null 9093 * @return the trimmed String, or an empty String if {@code null} input 9094 * @since 2.0 9095 */ 9096 public static String trimToEmpty(final String str) { 9097 return str == null ? EMPTY : str.trim(); 9098 } 9099 9100 /** 9101 * Removes control characters (char <= 32) from both 9102 * ends of this String returning {@code null} if the String is 9103 * empty ("") after the trim or if it is {@code null}. 9104 * 9105 * <p>The String is trimmed using {@link String#trim()}. 9106 * Trim removes start and end characters <= 32. 9107 * To strip whitespace use {@link #stripToNull(String)}. 9108 * 9109 * <pre> 9110 * StringUtils.trimToNull(null) = null 9111 * StringUtils.trimToNull("") = null 9112 * StringUtils.trimToNull(" ") = null 9113 * StringUtils.trimToNull("abc") = "abc" 9114 * StringUtils.trimToNull(" abc ") = "abc" 9115 * </pre> 9116 * 9117 * @param str the String to be trimmed, may be null 9118 * @return the trimmed String, 9119 * {@code null} if only chars <= 32, empty or null String input 9120 * @since 2.0 9121 */ 9122 public static String trimToNull(final String str) { 9123 final String ts = trim(str); 9124 return isEmpty(ts) ? null : ts; 9125 } 9126 9127 /** 9128 * Truncates a String. This will turn 9129 * "Now is the time for all good men" into "Now is the time for". 9130 * 9131 * <p>Specifically:</p> 9132 * <ul> 9133 * <li>If {@code str} is less than {@code maxWidth} characters 9134 * long, return it.</li> 9135 * <li>Else truncate it to {@code substring(str, 0, maxWidth)}.</li> 9136 * <li>If {@code maxWidth} is less than {@code 0}, throw an 9137 * {@link IllegalArgumentException}.</li> 9138 * <li>In no case will it return a String of length greater than 9139 * {@code maxWidth}.</li> 9140 * </ul> 9141 * 9142 * <pre> 9143 * StringUtils.truncate(null, 0) = null 9144 * StringUtils.truncate(null, 2) = null 9145 * StringUtils.truncate("", 4) = "" 9146 * StringUtils.truncate("abcdefg", 4) = "abcd" 9147 * StringUtils.truncate("abcdefg", 6) = "abcdef" 9148 * StringUtils.truncate("abcdefg", 7) = "abcdefg" 9149 * StringUtils.truncate("abcdefg", 8) = "abcdefg" 9150 * StringUtils.truncate("abcdefg", -1) = throws an IllegalArgumentException 9151 * </pre> 9152 * 9153 * @param str the String to truncate, may be null 9154 * @param maxWidth maximum length of result String, must be positive 9155 * @return truncated String, {@code null} if null String input 9156 * @throws IllegalArgumentException If {@code maxWidth} is less than {@code 0} 9157 * @since 3.5 9158 */ 9159 public static String truncate(final String str, final int maxWidth) { 9160 return truncate(str, 0, maxWidth); 9161 } 9162 9163 /** 9164 * Truncates a String. This will turn 9165 * "Now is the time for all good men" into "is the time for all". 9166 * 9167 * <p>Works like {@code truncate(String, int)}, but allows you to specify 9168 * a "left edge" offset. 9169 * 9170 * <p>Specifically:</p> 9171 * <ul> 9172 * <li>If {@code str} is less than {@code maxWidth} characters 9173 * long, return it.</li> 9174 * <li>Else truncate it to {@code substring(str, offset, maxWidth)}.</li> 9175 * <li>If {@code maxWidth} is less than {@code 0}, throw an 9176 * {@link IllegalArgumentException}.</li> 9177 * <li>If {@code offset} is less than {@code 0}, throw an 9178 * {@link IllegalArgumentException}.</li> 9179 * <li>In no case will it return a String of length greater than 9180 * {@code maxWidth}.</li> 9181 * </ul> 9182 * 9183 * <pre> 9184 * StringUtils.truncate(null, 0, 0) = null 9185 * StringUtils.truncate(null, 2, 4) = null 9186 * StringUtils.truncate("", 0, 10) = "" 9187 * StringUtils.truncate("", 2, 10) = "" 9188 * StringUtils.truncate("abcdefghij", 0, 3) = "abc" 9189 * StringUtils.truncate("abcdefghij", 5, 6) = "fghij" 9190 * StringUtils.truncate("raspberry peach", 10, 15) = "peach" 9191 * StringUtils.truncate("abcdefghijklmno", 0, 10) = "abcdefghij" 9192 * StringUtils.truncate("abcdefghijklmno", -1, 10) = throws an IllegalArgumentException 9193 * StringUtils.truncate("abcdefghijklmno", Integer.MIN_VALUE, 10) = throws an IllegalArgumentException 9194 * StringUtils.truncate("abcdefghijklmno", Integer.MIN_VALUE, Integer.MAX_VALUE) = throws an IllegalArgumentException 9195 * StringUtils.truncate("abcdefghijklmno", 0, Integer.MAX_VALUE) = "abcdefghijklmno" 9196 * StringUtils.truncate("abcdefghijklmno", 1, 10) = "bcdefghijk" 9197 * StringUtils.truncate("abcdefghijklmno", 2, 10) = "cdefghijkl" 9198 * StringUtils.truncate("abcdefghijklmno", 3, 10) = "defghijklm" 9199 * StringUtils.truncate("abcdefghijklmno", 4, 10) = "efghijklmn" 9200 * StringUtils.truncate("abcdefghijklmno", 5, 10) = "fghijklmno" 9201 * StringUtils.truncate("abcdefghijklmno", 5, 5) = "fghij" 9202 * StringUtils.truncate("abcdefghijklmno", 5, 3) = "fgh" 9203 * StringUtils.truncate("abcdefghijklmno", 10, 3) = "klm" 9204 * StringUtils.truncate("abcdefghijklmno", 10, Integer.MAX_VALUE) = "klmno" 9205 * StringUtils.truncate("abcdefghijklmno", 13, 1) = "n" 9206 * StringUtils.truncate("abcdefghijklmno", 13, Integer.MAX_VALUE) = "no" 9207 * StringUtils.truncate("abcdefghijklmno", 14, 1) = "o" 9208 * StringUtils.truncate("abcdefghijklmno", 14, Integer.MAX_VALUE) = "o" 9209 * StringUtils.truncate("abcdefghijklmno", 15, 1) = "" 9210 * StringUtils.truncate("abcdefghijklmno", 15, Integer.MAX_VALUE) = "" 9211 * StringUtils.truncate("abcdefghijklmno", Integer.MAX_VALUE, Integer.MAX_VALUE) = "" 9212 * StringUtils.truncate("abcdefghij", 3, -1) = throws an IllegalArgumentException 9213 * StringUtils.truncate("abcdefghij", -2, 4) = throws an IllegalArgumentException 9214 * </pre> 9215 * 9216 * @param str the String to truncate, may be null 9217 * @param offset left edge of source String 9218 * @param maxWidth maximum length of result String, must be positive 9219 * @return truncated String, {@code null} if null String input 9220 * @throws IllegalArgumentException If {@code offset} or {@code maxWidth} is less than {@code 0} 9221 * @since 3.5 9222 */ 9223 public static String truncate(final String str, final int offset, final int maxWidth) { 9224 if (offset < 0) { 9225 throw new IllegalArgumentException("offset cannot be negative"); 9226 } 9227 if (maxWidth < 0) { 9228 throw new IllegalArgumentException("maxWith cannot be negative"); 9229 } 9230 if (str == null) { 9231 return null; 9232 } 9233 if (offset > str.length()) { 9234 return EMPTY; 9235 } 9236 if (str.length() > maxWidth) { 9237 final int ix = Math.min(offset + maxWidth, str.length()); 9238 return str.substring(offset, ix); 9239 } 9240 return str.substring(offset); 9241 } 9242 9243 /** 9244 * Uncapitalizes a String, changing the first character to lower case as 9245 * per {@link Character#toLowerCase(int)}. No other characters are changed. 9246 * 9247 * <p>For a word based algorithm, see {@link org.apache.commons.text.WordUtils#uncapitalize(String)}. 9248 * A {@code null} input String returns {@code null}.</p> 9249 * 9250 * <pre> 9251 * StringUtils.uncapitalize(null) = null 9252 * StringUtils.uncapitalize("") = "" 9253 * StringUtils.uncapitalize("cat") = "cat" 9254 * StringUtils.uncapitalize("Cat") = "cat" 9255 * StringUtils.uncapitalize("CAT") = "cAT" 9256 * </pre> 9257 * 9258 * @param str the String to uncapitalize, may be null 9259 * @return the uncapitalized String, {@code null} if null String input 9260 * @see org.apache.commons.text.WordUtils#uncapitalize(String) 9261 * @see #capitalize(String) 9262 * @since 2.0 9263 */ 9264 public static String uncapitalize(final String str) { 9265 final int strLen = length(str); 9266 if (strLen == 0) { 9267 return str; 9268 } 9269 9270 final int firstCodePoint = str.codePointAt(0); 9271 final int newCodePoint = Character.toLowerCase(firstCodePoint); 9272 if (firstCodePoint == newCodePoint) { 9273 // already capitalized 9274 return str; 9275 } 9276 9277 final int[] newCodePoints = new int[strLen]; // cannot be longer than the char array 9278 int outOffset = 0; 9279 newCodePoints[outOffset++] = newCodePoint; // copy the first code point 9280 for (int inOffset = Character.charCount(firstCodePoint); inOffset < strLen; ) { 9281 final int codePoint = str.codePointAt(inOffset); 9282 newCodePoints[outOffset++] = codePoint; // copy the remaining ones 9283 inOffset += Character.charCount(codePoint); 9284 } 9285 return new String(newCodePoints, 0, outOffset); 9286 } 9287 9288 /** 9289 * Unwraps a given string from a character. 9290 * 9291 * <pre> 9292 * StringUtils.unwrap(null, null) = null 9293 * StringUtils.unwrap(null, '\0') = null 9294 * StringUtils.unwrap(null, '1') = null 9295 * StringUtils.unwrap("a", 'a') = "a" 9296 * StringUtils.unwrap("aa", 'a') = "" 9297 * StringUtils.unwrap("\'abc\'", '\'') = "abc" 9298 * StringUtils.unwrap("AABabcBAA", 'A') = "ABabcBA" 9299 * StringUtils.unwrap("A", '#') = "A" 9300 * StringUtils.unwrap("#A", '#') = "#A" 9301 * StringUtils.unwrap("A#", '#') = "A#" 9302 * </pre> 9303 * 9304 * @param str 9305 * the String to be unwrapped, can be null 9306 * @param wrapChar 9307 * the character used to unwrap 9308 * @return unwrapped String or the original string 9309 * if it is not quoted properly with the wrapChar 9310 * @since 3.6 9311 */ 9312 public static String unwrap(final String str, final char wrapChar) { 9313 if (isEmpty(str) || wrapChar == CharUtils.NUL || str.length() == 1) { 9314 return str; 9315 } 9316 9317 if (str.charAt(0) == wrapChar && str.charAt(str.length() - 1) == wrapChar) { 9318 final int startIndex = 0; 9319 final int endIndex = str.length() - 1; 9320 9321 return str.substring(startIndex + 1, endIndex); 9322 } 9323 9324 return str; 9325 } 9326 9327 /** 9328 * Unwraps a given string from another string. 9329 * 9330 * <pre> 9331 * StringUtils.unwrap(null, null) = null 9332 * StringUtils.unwrap(null, "") = null 9333 * StringUtils.unwrap(null, "1") = null 9334 * StringUtils.unwrap("a", "a") = "a" 9335 * StringUtils.unwrap("aa", "a") = "" 9336 * StringUtils.unwrap("\'abc\'", "\'") = "abc" 9337 * StringUtils.unwrap("\"abc\"", "\"") = "abc" 9338 * StringUtils.unwrap("AABabcBAA", "AA") = "BabcB" 9339 * StringUtils.unwrap("A", "#") = "A" 9340 * StringUtils.unwrap("#A", "#") = "#A" 9341 * StringUtils.unwrap("A#", "#") = "A#" 9342 * </pre> 9343 * 9344 * @param str 9345 * the String to be unwrapped, can be null 9346 * @param wrapToken 9347 * the String used to unwrap 9348 * @return unwrapped String or the original string 9349 * if it is not quoted properly with the wrapToken 9350 * @since 3.6 9351 */ 9352 public static String unwrap(final String str, final String wrapToken) { 9353 if (isEmpty(str) || isEmpty(wrapToken) || str.length() < 2 * wrapToken.length()) { 9354 return str; 9355 } 9356 9357 if (startsWith(str, wrapToken) && endsWith(str, wrapToken)) { 9358 return str.substring(wrapToken.length(), str.lastIndexOf(wrapToken)); 9359 } 9360 9361 return str; 9362 } 9363 9364 /** 9365 * Converts a String to upper case as per {@link String#toUpperCase()}. 9366 * 9367 * <p>A {@code null} input String returns {@code null}.</p> 9368 * 9369 * <pre> 9370 * StringUtils.upperCase(null) = null 9371 * StringUtils.upperCase("") = "" 9372 * StringUtils.upperCase("aBc") = "ABC" 9373 * </pre> 9374 * 9375 * <p><strong>Note:</strong> As described in the documentation for {@link String#toUpperCase()}, 9376 * the result of this method is affected by the current locale. 9377 * For platform-independent case transformations, the method {@link #upperCase(String, Locale)} 9378 * should be used with a specific locale (e.g. {@link Locale#ENGLISH}).</p> 9379 * 9380 * @param str the String to upper case, may be null 9381 * @return the upper-cased String, {@code null} if null String input 9382 */ 9383 public static String upperCase(final String str) { 9384 if (str == null) { 9385 return null; 9386 } 9387 return str.toUpperCase(); 9388 } 9389 9390 /** 9391 * Converts a String to upper case as per {@link String#toUpperCase(Locale)}. 9392 * 9393 * <p>A {@code null} input String returns {@code null}.</p> 9394 * 9395 * <pre> 9396 * StringUtils.upperCase(null, Locale.ENGLISH) = null 9397 * StringUtils.upperCase("", Locale.ENGLISH) = "" 9398 * StringUtils.upperCase("aBc", Locale.ENGLISH) = "ABC" 9399 * </pre> 9400 * 9401 * @param str the String to upper case, may be null 9402 * @param locale the locale that defines the case transformation rules, must not be null 9403 * @return the upper-cased String, {@code null} if null String input 9404 * @since 2.5 9405 */ 9406 public static String upperCase(final String str, final Locale locale) { 9407 if (str == null) { 9408 return null; 9409 } 9410 return str.toUpperCase(LocaleUtils.toLocale(locale)); 9411 } 9412 9413 /** 9414 * Returns the string representation of the {@code char} array or null. 9415 * 9416 * @param value the character array. 9417 * @return a String or null 9418 * @see String#valueOf(char[]) 9419 * @since 3.9 9420 */ 9421 public static String valueOf(final char[] value) { 9422 return value == null ? null : String.valueOf(value); 9423 } 9424 9425 /** 9426 * Wraps a string with a char. 9427 * 9428 * <pre> 9429 * StringUtils.wrap(null, *) = null 9430 * StringUtils.wrap("", *) = "" 9431 * StringUtils.wrap("ab", '\0') = "ab" 9432 * StringUtils.wrap("ab", 'x') = "xabx" 9433 * StringUtils.wrap("ab", '\'') = "'ab'" 9434 * StringUtils.wrap("\"ab\"", '\"') = "\"\"ab\"\"" 9435 * </pre> 9436 * 9437 * @param str 9438 * the string to be wrapped, may be {@code null} 9439 * @param wrapWith 9440 * the char that will wrap {@code str} 9441 * @return the wrapped string, or {@code null} if {@code str == null} 9442 * @since 3.4 9443 */ 9444 public static String wrap(final String str, final char wrapWith) { 9445 9446 if (isEmpty(str) || wrapWith == CharUtils.NUL) { 9447 return str; 9448 } 9449 9450 return wrapWith + str + wrapWith; 9451 } 9452 9453 /** 9454 * Wraps a String with another String. 9455 * 9456 * <p> 9457 * A {@code null} input String returns {@code null}. 9458 * </p> 9459 * 9460 * <pre> 9461 * StringUtils.wrap(null, *) = null 9462 * StringUtils.wrap("", *) = "" 9463 * StringUtils.wrap("ab", null) = "ab" 9464 * StringUtils.wrap("ab", "x") = "xabx" 9465 * StringUtils.wrap("ab", "\"") = "\"ab\"" 9466 * StringUtils.wrap("\"ab\"", "\"") = "\"\"ab\"\"" 9467 * StringUtils.wrap("ab", "'") = "'ab'" 9468 * StringUtils.wrap("'abcd'", "'") = "''abcd''" 9469 * StringUtils.wrap("\"abcd\"", "'") = "'\"abcd\"'" 9470 * StringUtils.wrap("'abcd'", "\"") = "\"'abcd'\"" 9471 * </pre> 9472 * 9473 * @param str 9474 * the String to be wrapper, may be null 9475 * @param wrapWith 9476 * the String that will wrap str 9477 * @return wrapped String, {@code null} if null String input 9478 * @since 3.4 9479 */ 9480 public static String wrap(final String str, final String wrapWith) { 9481 9482 if (isEmpty(str) || isEmpty(wrapWith)) { 9483 return str; 9484 } 9485 9486 return wrapWith.concat(str).concat(wrapWith); 9487 } 9488 9489 /** 9490 * Wraps a string with a char if that char is missing from the start or end of the given string. 9491 * 9492 * <p>A new {@link String} will not be created if {@code str} is already wrapped.</p> 9493 * 9494 * <pre> 9495 * StringUtils.wrapIfMissing(null, *) = null 9496 * StringUtils.wrapIfMissing("", *) = "" 9497 * StringUtils.wrapIfMissing("ab", '\0') = "ab" 9498 * StringUtils.wrapIfMissing("ab", 'x') = "xabx" 9499 * StringUtils.wrapIfMissing("ab", '\'') = "'ab'" 9500 * StringUtils.wrapIfMissing("\"ab\"", '\"') = "\"ab\"" 9501 * StringUtils.wrapIfMissing("/", '/') = "/" 9502 * StringUtils.wrapIfMissing("a/b/c", '/') = "/a/b/c/" 9503 * StringUtils.wrapIfMissing("/a/b/c", '/') = "/a/b/c/" 9504 * StringUtils.wrapIfMissing("a/b/c/", '/') = "/a/b/c/" 9505 * </pre> 9506 * 9507 * @param str 9508 * the string to be wrapped, may be {@code null} 9509 * @param wrapWith 9510 * the char that will wrap {@code str} 9511 * @return the wrapped string, or {@code null} if {@code str == null} 9512 * @since 3.5 9513 */ 9514 public static String wrapIfMissing(final String str, final char wrapWith) { 9515 if (isEmpty(str) || wrapWith == CharUtils.NUL) { 9516 return str; 9517 } 9518 final boolean wrapStart = str.charAt(0) != wrapWith; 9519 final boolean wrapEnd = str.charAt(str.length() - 1) != wrapWith; 9520 if (!wrapStart && !wrapEnd) { 9521 return str; 9522 } 9523 9524 final StringBuilder builder = new StringBuilder(str.length() + 2); 9525 if (wrapStart) { 9526 builder.append(wrapWith); 9527 } 9528 builder.append(str); 9529 if (wrapEnd) { 9530 builder.append(wrapWith); 9531 } 9532 return builder.toString(); 9533 } 9534 9535 /** 9536 * Wraps a string with a string if that string is missing from the start or end of the given string. 9537 * 9538 * <p>A new {@link String} will not be created if {@code str} is already wrapped.</p> 9539 * 9540 * <pre> 9541 * StringUtils.wrapIfMissing(null, *) = null 9542 * StringUtils.wrapIfMissing("", *) = "" 9543 * StringUtils.wrapIfMissing("ab", null) = "ab" 9544 * StringUtils.wrapIfMissing("ab", "x") = "xabx" 9545 * StringUtils.wrapIfMissing("ab", "\"") = "\"ab\"" 9546 * StringUtils.wrapIfMissing("\"ab\"", "\"") = "\"ab\"" 9547 * StringUtils.wrapIfMissing("ab", "'") = "'ab'" 9548 * StringUtils.wrapIfMissing("'abcd'", "'") = "'abcd'" 9549 * StringUtils.wrapIfMissing("\"abcd\"", "'") = "'\"abcd\"'" 9550 * StringUtils.wrapIfMissing("'abcd'", "\"") = "\"'abcd'\"" 9551 * StringUtils.wrapIfMissing("/", "/") = "/" 9552 * StringUtils.wrapIfMissing("a/b/c", "/") = "/a/b/c/" 9553 * StringUtils.wrapIfMissing("/a/b/c", "/") = "/a/b/c/" 9554 * StringUtils.wrapIfMissing("a/b/c/", "/") = "/a/b/c/" 9555 * </pre> 9556 * 9557 * @param str 9558 * the string to be wrapped, may be {@code null} 9559 * @param wrapWith 9560 * the string that will wrap {@code str} 9561 * @return the wrapped string, or {@code null} if {@code str == null} 9562 * @since 3.5 9563 */ 9564 public static String wrapIfMissing(final String str, final String wrapWith) { 9565 if (isEmpty(str) || isEmpty(wrapWith)) { 9566 return str; 9567 } 9568 9569 final boolean wrapStart = !str.startsWith(wrapWith); 9570 final boolean wrapEnd = !str.endsWith(wrapWith); 9571 if (!wrapStart && !wrapEnd) { 9572 return str; 9573 } 9574 9575 final StringBuilder builder = new StringBuilder(str.length() + wrapWith.length() + wrapWith.length()); 9576 if (wrapStart) { 9577 builder.append(wrapWith); 9578 } 9579 builder.append(str); 9580 if (wrapEnd) { 9581 builder.append(wrapWith); 9582 } 9583 return builder.toString(); 9584 } 9585 9586 /** 9587 * {@link StringUtils} instances should NOT be constructed in 9588 * standard programming. Instead, the class should be used as 9589 * {@code StringUtils.trim(" foo ");}. 9590 * 9591 * <p>This constructor is public to permit tools that require a JavaBean 9592 * instance to operate.</p> 9593 * 9594 * @deprecated TODO Make private in 4.0. 9595 */ 9596 @Deprecated 9597 public StringUtils() { 9598 // empty 9599 } 9600 9601 }