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 edu.internet2.middleware.grouperClientExt.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.StringJoiner; 31 import java.util.function.Supplier; 32 import java.util.regex.Pattern; 33 34 import edu.internet2.middleware.grouperClientExt.org.apache.commons.lang3.function.ToBooleanBiFunction; 35 36 /** 37 * <p>Operations on {@link java.lang.String} that are 38 * {@code null} safe.</p> 39 * 40 * <ul> 41 * <li><b>IsEmpty/IsBlank</b> 42 * - checks if a String contains text</li> 43 * <li><b>Trim/Strip</b> 44 * - removes leading and trailing whitespace</li> 45 * <li><b>Equals/Compare</b> 46 * - compares two strings in a null-safe manner</li> 47 * <li><b>startsWith</b> 48 * - check if a String starts with a prefix in a null-safe manner</li> 49 * <li><b>endsWith</b> 50 * - check if a String ends with a suffix in a null-safe manner</li> 51 * <li><b>IndexOf/LastIndexOf/Contains</b> 52 * - null-safe index-of checks 53 * <li><b>IndexOfAny/LastIndexOfAny/IndexOfAnyBut/LastIndexOfAnyBut</b> 54 * - index-of any of a set of Strings</li> 55 * <li><b>ContainsOnly/ContainsNone/ContainsAny</b> 56 * - checks if String contains only/none/any of these characters</li> 57 * <li><b>Substring/Left/Right/Mid</b> 58 * - null-safe substring extractions</li> 59 * <li><b>SubstringBefore/SubstringAfter/SubstringBetween</b> 60 * - substring extraction relative to other strings</li> 61 * <li><b>Split/Join</b> 62 * - splits a String into an array of substrings and vice versa</li> 63 * <li><b>Remove/Delete</b> 64 * - removes part of a String</li> 65 * <li><b>Replace/Overlay</b> 66 * - Searches a String and replaces one String with another</li> 67 * <li><b>Chomp/Chop</b> 68 * - removes the last part of a String</li> 69 * <li><b>AppendIfMissing</b> 70 * - appends a suffix to the end of the String if not present</li> 71 * <li><b>PrependIfMissing</b> 72 * - prepends a prefix to the start of the String if not present</li> 73 * <li><b>LeftPad/RightPad/Center/Repeat</b> 74 * - pads a String</li> 75 * <li><b>UpperCase/LowerCase/SwapCase/Capitalize/Uncapitalize</b> 76 * - changes the case of a String</li> 77 * <li><b>CountMatches</b> 78 * - counts the number of occurrences of one String in another</li> 79 * <li><b>IsAlpha/IsNumeric/IsWhitespace/IsAsciiPrintable</b> 80 * - checks the characters in a String</li> 81 * <li><b>DefaultString</b> 82 * - protects against a null input String</li> 83 * <li><b>Rotate</b> 84 * - rotate (circular shift) a String</li> 85 * <li><b>Reverse/ReverseDelimited</b> 86 * - reverses a String</li> 87 * <li><b>Abbreviate</b> 88 * - abbreviates a string using ellipses or another given String</li> 89 * <li><b>Difference</b> 90 * - compares Strings and reports on their differences</li> 91 * <li><b>LevenshteinDistance</b> 92 * - the number of changes needed to change one String into another</li> 93 * </ul> 94 * 95 * <p>The {@code StringUtils} class defines certain words related to 96 * String handling.</p> 97 * 98 * <ul> 99 * <li>null - {@code null}</li> 100 * <li>empty - a zero-length string ({@code ""})</li> 101 * <li>space - the space character ({@code ' '}, char 32)</li> 102 * <li>whitespace - the characters defined by {@link Character#isWhitespace(char)}</li> 103 * <li>trim - the characters <= 32 as in {@link String#trim()}</li> 104 * </ul> 105 * 106 * <p>{@code StringUtils} handles {@code null} input Strings quietly. 107 * That is to say that a {@code null} input will return {@code null}. 108 * Where a {@code boolean} or {@code int} is being returned 109 * details vary by method.</p> 110 * 111 * <p>A side effect of the {@code null} handling is that a 112 * {@code NullPointerException} should be considered a bug in 113 * {@code StringUtils}.</p> 114 * 115 * <p>Methods in this class include sample code in their Javadoc comments to explain their operation. 116 * The symbol {@code *} is used to indicate any input including {@code null}.</p> 117 * 118 * <p>#ThreadSafe#</p> 119 * @see java.lang.String 120 * @since 1.0 121 */ 122 //@Immutable 123 public class StringUtils { 124 125 private static final int STRING_BUILDER_SIZE = 256; 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="http://docs.oracle.com/javase/specs/jls/se7/html/jls-3.html#jls-3.10.6">JLF: Escape Sequences 160 * for Character and String Literals</a> 161 * @since 3.2 162 */ 163 public static final String LF = "\n"; 164 165 /** 166 * A String for carriage return CR ("\r"). 167 * 168 * @see <a href="http://docs.oracle.com/javase/specs/jls/se7/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 * <p>The maximum size to which the padding constant(s) can expand.</p> 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 * <p>Abbreviates a String using ellipses. This will turn 192 * "Now is the time for all good men" into "Now is the time for..."</p> 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 * {@code 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 * <p>Abbreviates a String using ellipses. This will turn 227 * "Now is the time for all good men" into "...is the time for..."</p> 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 * <p>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.</p> 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 * {@code 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 * <p>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.</p> 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 } else if (isAnyEmpty(str, abbrevMarker)) { 344 return str; 345 } 346 final int abbrevMarkerLength = abbrevMarker.length(); 347 final int minAbbrevWidth = abbrevMarkerLength + 1; 348 final int minAbbrevWidthOffset = abbrevMarkerLength + abbrevMarkerLength + 1; 349 350 if (maxWidth < minAbbrevWidth) { 351 throw new IllegalArgumentException(String.format("Minimum abbreviation width is %d", minAbbrevWidth)); 352 } 353 final int strLen = str.length(); 354 if (strLen <= maxWidth) { 355 return str; 356 } 357 if (offset > strLen) { 358 offset = strLen; 359 } 360 if (strLen - offset < maxWidth - abbrevMarkerLength) { 361 offset = strLen - (maxWidth - abbrevMarkerLength); 362 } 363 if (offset <= abbrevMarkerLength+1) { 364 return str.substring(0, maxWidth - abbrevMarkerLength) + abbrevMarker; 365 } 366 if (maxWidth < minAbbrevWidthOffset) { 367 throw new IllegalArgumentException(String.format("Minimum abbreviation width with offset is %d", minAbbrevWidthOffset)); 368 } 369 if (offset + maxWidth - abbrevMarkerLength < strLen) { 370 return abbrevMarker + abbreviate(str.substring(offset), abbrevMarker, maxWidth - abbrevMarkerLength); 371 } 372 return abbrevMarker + str.substring(strLen - (maxWidth - abbrevMarkerLength)); 373 } 374 375 /** 376 * <p>Abbreviates a String to the length passed, replacing the middle characters with the supplied 377 * replacement String.</p> 378 * 379 * <p>This abbreviation only occurs if the following criteria is met:</p> 380 * <ul> 381 * <li>Neither the String for abbreviation nor the replacement String are null or empty </li> 382 * <li>The length to truncate to is less than the length of the supplied String</li> 383 * <li>The length to truncate to is greater than 0</li> 384 * <li>The abbreviated String will have enough room for the length supplied replacement String 385 * and the first and last characters of the supplied String for abbreviation</li> 386 * </ul> 387 * <p>Otherwise, the returned String will be the same as the supplied String for abbreviation. 388 * </p> 389 * 390 * <pre> 391 * StringUtils.abbreviateMiddle(null, null, 0) = null 392 * StringUtils.abbreviateMiddle("abc", null, 0) = "abc" 393 * StringUtils.abbreviateMiddle("abc", ".", 0) = "abc" 394 * StringUtils.abbreviateMiddle("abc", ".", 3) = "abc" 395 * StringUtils.abbreviateMiddle("abcdef", ".", 4) = "ab.f" 396 * </pre> 397 * 398 * @param str the String to abbreviate, may be null 399 * @param middle the String to replace the middle characters with, may be null 400 * @param length the length to abbreviate {@code str} to. 401 * @return the abbreviated String if the above criteria is met, or the original String supplied for abbreviation. 402 * @since 2.5 403 */ 404 public static String abbreviateMiddle(final String str, final String middle, final int length) { 405 if (isAnyEmpty(str, middle) || length >= str.length() || length < middle.length()+2) { 406 return str; 407 } 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 413 return str.substring(0, startOffset) + 414 middle + 415 str.substring(endOffset); 416 } 417 418 /** 419 * Appends the suffix to the end of the string if the string does not 420 * already end with the suffix. 421 * 422 * @param str The string. 423 * @param suffix The suffix to append to the end of the string. 424 * @param ignoreCase Indicates whether the compare should ignore case. 425 * @param suffixes Additional suffixes that are valid terminators (optional). 426 * 427 * @return A new String if suffix was appended, the same string otherwise. 428 */ 429 private static String appendIfMissing(final String str, final CharSequence suffix, final boolean ignoreCase, final CharSequence... suffixes) { 430 if (str == null || isEmpty(suffix) || endsWith(str, suffix, ignoreCase)) { 431 return str; 432 } 433 if (ArrayUtils.isNotEmpty(suffixes)) { 434 for (final CharSequence s : suffixes) { 435 if (endsWith(str, s, ignoreCase)) { 436 return str; 437 } 438 } 439 } 440 return str + suffix.toString(); 441 } 442 443 /** 444 * Appends the suffix to the end of the string if the string does not 445 * already end with any of the suffixes. 446 * 447 * <pre> 448 * StringUtils.appendIfMissing(null, null) = null 449 * StringUtils.appendIfMissing("abc", null) = "abc" 450 * StringUtils.appendIfMissing("", "xyz") = "xyz" 451 * StringUtils.appendIfMissing("abc", "xyz") = "abcxyz" 452 * StringUtils.appendIfMissing("abcxyz", "xyz") = "abcxyz" 453 * StringUtils.appendIfMissing("abcXYZ", "xyz") = "abcXYZxyz" 454 * </pre> 455 * <p>With additional suffixes,</p> 456 * <pre> 457 * StringUtils.appendIfMissing(null, null, null) = null 458 * StringUtils.appendIfMissing("abc", null, null) = "abc" 459 * StringUtils.appendIfMissing("", "xyz", null) = "xyz" 460 * StringUtils.appendIfMissing("abc", "xyz", new CharSequence[]{null}) = "abcxyz" 461 * StringUtils.appendIfMissing("abc", "xyz", "") = "abc" 462 * StringUtils.appendIfMissing("abc", "xyz", "mno") = "abcxyz" 463 * StringUtils.appendIfMissing("abcxyz", "xyz", "mno") = "abcxyz" 464 * StringUtils.appendIfMissing("abcmno", "xyz", "mno") = "abcmno" 465 * StringUtils.appendIfMissing("abcXYZ", "xyz", "mno") = "abcXYZxyz" 466 * StringUtils.appendIfMissing("abcMNO", "xyz", "mno") = "abcMNOxyz" 467 * </pre> 468 * 469 * @param str The string. 470 * @param suffix The suffix to append to the end of the string. 471 * @param suffixes Additional suffixes that are valid terminators. 472 * 473 * @return A new String if suffix was appended, the same string otherwise. 474 * 475 * @since 3.2 476 */ 477 public static String appendIfMissing(final String str, final CharSequence suffix, final CharSequence... suffixes) { 478 return appendIfMissing(str, suffix, false, suffixes); 479 } 480 481 /** 482 * Appends the suffix to the end of the string if the string does not 483 * already end, case insensitive, with any of the suffixes. 484 * 485 * <pre> 486 * StringUtils.appendIfMissingIgnoreCase(null, null) = null 487 * StringUtils.appendIfMissingIgnoreCase("abc", null) = "abc" 488 * StringUtils.appendIfMissingIgnoreCase("", "xyz") = "xyz" 489 * StringUtils.appendIfMissingIgnoreCase("abc", "xyz") = "abcxyz" 490 * StringUtils.appendIfMissingIgnoreCase("abcxyz", "xyz") = "abcxyz" 491 * StringUtils.appendIfMissingIgnoreCase("abcXYZ", "xyz") = "abcXYZ" 492 * </pre> 493 * <p>With additional suffixes,</p> 494 * <pre> 495 * StringUtils.appendIfMissingIgnoreCase(null, null, null) = null 496 * StringUtils.appendIfMissingIgnoreCase("abc", null, null) = "abc" 497 * StringUtils.appendIfMissingIgnoreCase("", "xyz", null) = "xyz" 498 * StringUtils.appendIfMissingIgnoreCase("abc", "xyz", new CharSequence[]{null}) = "abcxyz" 499 * StringUtils.appendIfMissingIgnoreCase("abc", "xyz", "") = "abc" 500 * StringUtils.appendIfMissingIgnoreCase("abc", "xyz", "mno") = "abcxyz" 501 * StringUtils.appendIfMissingIgnoreCase("abcxyz", "xyz", "mno") = "abcxyz" 502 * StringUtils.appendIfMissingIgnoreCase("abcmno", "xyz", "mno") = "abcmno" 503 * StringUtils.appendIfMissingIgnoreCase("abcXYZ", "xyz", "mno") = "abcXYZ" 504 * StringUtils.appendIfMissingIgnoreCase("abcMNO", "xyz", "mno") = "abcMNO" 505 * </pre> 506 * 507 * @param str The string. 508 * @param suffix The suffix to append to the end of the string. 509 * @param suffixes Additional suffixes that are valid terminators. 510 * 511 * @return A new String if suffix was appended, the same string otherwise. 512 * 513 * @since 3.2 514 */ 515 public static String appendIfMissingIgnoreCase(final String str, final CharSequence suffix, final CharSequence... suffixes) { 516 return appendIfMissing(str, suffix, true, suffixes); 517 } 518 519 /** 520 * <p>Capitalizes a String changing the first character to title case as 521 * per {@link Character#toTitleCase(int)}. No other characters are changed.</p> 522 * 523 * <p>For a word based algorithm, see {@link edu.internet2.middleware.grouperClientExt.org.apache.commons.lang3.text.WordUtils#capitalize(String)}. 524 * A {@code null} input String returns {@code null}.</p> 525 * 526 * <pre> 527 * StringUtils.capitalize(null) = null 528 * StringUtils.capitalize("") = "" 529 * StringUtils.capitalize("cat") = "Cat" 530 * StringUtils.capitalize("cAt") = "CAt" 531 * StringUtils.capitalize("'cat'") = "'cat'" 532 * </pre> 533 * 534 * @param str the String to capitalize, may be null 535 * @return the capitalized String, {@code null} if null String input 536 * @see edu.internet2.middleware.grouperClientExt.org.apache.commons.lang3.text.WordUtils#capitalize(String) 537 * @see #uncapitalize(String) 538 * @since 2.0 539 */ 540 public static String capitalize(final String str) { 541 final int strLen = length(str); 542 if (strLen == 0) { 543 return str; 544 } 545 546 final int firstCodepoint = str.codePointAt(0); 547 final int newCodePoint = Character.toTitleCase(firstCodepoint); 548 if (firstCodepoint == newCodePoint) { 549 // already capitalized 550 return str; 551 } 552 553 final int[] newCodePoints = new int[strLen]; // cannot be longer than the char array 554 int outOffset = 0; 555 newCodePoints[outOffset++] = newCodePoint; // copy the first codepoint 556 for (int inOffset = Character.charCount(firstCodepoint); inOffset < strLen; ) { 557 final int codepoint = str.codePointAt(inOffset); 558 newCodePoints[outOffset++] = codepoint; // copy the remaining ones 559 inOffset += Character.charCount(codepoint); 560 } 561 return new String(newCodePoints, 0, outOffset); 562 } 563 564 /** 565 * <p>Centers a String in a larger String of size {@code size} 566 * using the space character (' ').</p> 567 * 568 * <p>If the size is less than the String length, the original String is returned. 569 * A {@code null} String returns {@code null}. 570 * A negative size is treated as zero.</p> 571 * 572 * <p>Equivalent to {@code center(str, size, " ")}.</p> 573 * 574 * <pre> 575 * StringUtils.center(null, *) = null 576 * StringUtils.center("", 4) = " " 577 * StringUtils.center("ab", -1) = "ab" 578 * StringUtils.center("ab", 4) = " ab " 579 * StringUtils.center("abcd", 2) = "abcd" 580 * StringUtils.center("a", 4) = " a " 581 * </pre> 582 * 583 * @param str the String to center, may be null 584 * @param size the int size of new String, negative treated as zero 585 * @return centered String, {@code null} if null String input 586 */ 587 public static String center(final String str, final int size) { 588 return center(str, size, ' '); 589 } 590 591 /** 592 * <p>Centers a String in a larger String of size {@code size}. 593 * Uses a supplied character as the value to pad the String with.</p> 594 * 595 * <p>If the size is less than the String length, the String is returned. 596 * A {@code null} String returns {@code null}. 597 * A negative size is treated as zero.</p> 598 * 599 * <pre> 600 * StringUtils.center(null, *, *) = null 601 * StringUtils.center("", 4, ' ') = " " 602 * StringUtils.center("ab", -1, ' ') = "ab" 603 * StringUtils.center("ab", 4, ' ') = " ab " 604 * StringUtils.center("abcd", 2, ' ') = "abcd" 605 * StringUtils.center("a", 4, ' ') = " a " 606 * StringUtils.center("a", 4, 'y') = "yayy" 607 * </pre> 608 * 609 * @param str the String to center, may be null 610 * @param size the int size of new String, negative treated as zero 611 * @param padChar the character to pad the new String with 612 * @return centered String, {@code null} if null String input 613 * @since 2.0 614 */ 615 public static String center(String str, final int size, final char padChar) { 616 if (str == null || size <= 0) { 617 return str; 618 } 619 final int strLen = str.length(); 620 final int pads = size - strLen; 621 if (pads <= 0) { 622 return str; 623 } 624 str = leftPad(str, strLen + pads / 2, padChar); 625 str = rightPad(str, size, padChar); 626 return str; 627 } 628 629 /** 630 * <p>Centers a String in a larger String of size {@code size}. 631 * Uses a supplied String as the value to pad the String with.</p> 632 * 633 * <p>If the size is less than the String length, the String is returned. 634 * A {@code null} String returns {@code null}. 635 * A negative size is treated as zero.</p> 636 * 637 * <pre> 638 * StringUtils.center(null, *, *) = null 639 * StringUtils.center("", 4, " ") = " " 640 * StringUtils.center("ab", -1, " ") = "ab" 641 * StringUtils.center("ab", 4, " ") = " ab " 642 * StringUtils.center("abcd", 2, " ") = "abcd" 643 * StringUtils.center("a", 4, " ") = " a " 644 * StringUtils.center("a", 4, "yz") = "yayz" 645 * StringUtils.center("abc", 7, null) = " abc " 646 * StringUtils.center("abc", 7, "") = " abc " 647 * </pre> 648 * 649 * @param str the String to center, may be null 650 * @param size the int size of new String, negative treated as zero 651 * @param padStr the String to pad the new String with, must not be null or empty 652 * @return centered String, {@code null} if null String input 653 * @throws IllegalArgumentException if padStr is {@code null} or empty 654 */ 655 public static String center(String str, final int size, String padStr) { 656 if (str == null || size <= 0) { 657 return str; 658 } 659 if (isEmpty(padStr)) { 660 padStr = SPACE; 661 } 662 final int strLen = str.length(); 663 final int pads = size - strLen; 664 if (pads <= 0) { 665 return str; 666 } 667 str = leftPad(str, strLen + pads / 2, padStr); 668 str = rightPad(str, size, padStr); 669 return str; 670 } 671 672 /** 673 * <p>Removes one newline from end of a String if it's there, 674 * otherwise leave it alone. A newline is "{@code \n}", 675 * "{@code \r}", or "{@code \r\n}".</p> 676 * 677 * <p>NOTE: This method changed in 2.0. 678 * It now more closely matches Perl chomp.</p> 679 * 680 * <pre> 681 * StringUtils.chomp(null) = null 682 * StringUtils.chomp("") = "" 683 * StringUtils.chomp("abc \r") = "abc " 684 * StringUtils.chomp("abc\n") = "abc" 685 * StringUtils.chomp("abc\r\n") = "abc" 686 * StringUtils.chomp("abc\r\n\r\n") = "abc\r\n" 687 * StringUtils.chomp("abc\n\r") = "abc\n" 688 * StringUtils.chomp("abc\n\rabc") = "abc\n\rabc" 689 * StringUtils.chomp("\r") = "" 690 * StringUtils.chomp("\n") = "" 691 * StringUtils.chomp("\r\n") = "" 692 * </pre> 693 * 694 * @param str the String to chomp a newline from, may be null 695 * @return String without newline, {@code null} if null String input 696 */ 697 public static String chomp(final String str) { 698 if (isEmpty(str)) { 699 return str; 700 } 701 702 if (str.length() == 1) { 703 final char ch = str.charAt(0); 704 if (ch == CharUtils.CR || ch == CharUtils.LF) { 705 return EMPTY; 706 } 707 return str; 708 } 709 710 int lastIdx = str.length() - 1; 711 final char last = str.charAt(lastIdx); 712 713 if (last == CharUtils.LF) { 714 if (str.charAt(lastIdx - 1) == CharUtils.CR) { 715 lastIdx--; 716 } 717 } else if (last != CharUtils.CR) { 718 lastIdx++; 719 } 720 return str.substring(0, lastIdx); 721 } 722 723 /** 724 * <p>Removes {@code separator} from the end of 725 * {@code str} if it's there, otherwise leave it alone.</p> 726 * 727 * <p>NOTE: This method changed in version 2.0. 728 * It now more closely matches Perl chomp. 729 * For the previous behavior, use {@link #substringBeforeLast(String, String)}. 730 * This method uses {@link String#endsWith(String)}.</p> 731 * 732 * <pre> 733 * StringUtils.chomp(null, *) = null 734 * StringUtils.chomp("", *) = "" 735 * StringUtils.chomp("foobar", "bar") = "foo" 736 * StringUtils.chomp("foobar", "baz") = "foobar" 737 * StringUtils.chomp("foo", "foo") = "" 738 * StringUtils.chomp("foo ", "foo") = "foo " 739 * StringUtils.chomp(" foo", "foo") = " " 740 * StringUtils.chomp("foo", "foooo") = "foo" 741 * StringUtils.chomp("foo", "") = "foo" 742 * StringUtils.chomp("foo", null) = "foo" 743 * </pre> 744 * 745 * @param str the String to chomp from, may be null 746 * @param separator separator String, may be null 747 * @return String without trailing separator, {@code null} if null String input 748 * @deprecated This feature will be removed in Lang 4.0, use {@link StringUtils#removeEnd(String, String)} instead 749 */ 750 @Deprecated 751 public static String chomp(final String str, final String separator) { 752 return removeEnd(str, separator); 753 } 754 755 /** 756 * <p>Remove the last character from a String.</p> 757 * 758 * <p>If the String ends in {@code \r\n}, then remove both 759 * of them.</p> 760 * 761 * <pre> 762 * StringUtils.chop(null) = null 763 * StringUtils.chop("") = "" 764 * StringUtils.chop("abc \r") = "abc " 765 * StringUtils.chop("abc\n") = "abc" 766 * StringUtils.chop("abc\r\n") = "abc" 767 * StringUtils.chop("abc") = "ab" 768 * StringUtils.chop("abc\nabc") = "abc\nab" 769 * StringUtils.chop("a") = "" 770 * StringUtils.chop("\r") = "" 771 * StringUtils.chop("\n") = "" 772 * StringUtils.chop("\r\n") = "" 773 * </pre> 774 * 775 * @param str the String to chop last character from, may be null 776 * @return String without last character, {@code null} if null String input 777 */ 778 public static String chop(final String str) { 779 if (str == null) { 780 return null; 781 } 782 final int strLen = str.length(); 783 if (strLen < 2) { 784 return EMPTY; 785 } 786 final int lastIdx = strLen - 1; 787 final String ret = str.substring(0, lastIdx); 788 final char last = str.charAt(lastIdx); 789 if (last == CharUtils.LF && ret.charAt(lastIdx - 1) == CharUtils.CR) { 790 return ret.substring(0, lastIdx - 1); 791 } 792 return ret; 793 } 794 795 /** 796 * <p>Compare two Strings lexicographically, as per {@link String#compareTo(String)}, returning :</p> 797 * <ul> 798 * <li>{@code int = 0}, if {@code str1} is equal to {@code str2} (or both {@code null})</li> 799 * <li>{@code int < 0}, if {@code str1} is less than {@code str2}</li> 800 * <li>{@code int > 0}, if {@code str1} is greater than {@code str2}</li> 801 * </ul> 802 * 803 * <p>This is a {@code null} safe version of :</p> 804 * <blockquote><pre>str1.compareTo(str2)</pre></blockquote> 805 * 806 * <p>{@code null} value is considered less than non-{@code null} value. 807 * Two {@code null} references are considered equal.</p> 808 * 809 * <pre> 810 * StringUtils.compare(null, null) = 0 811 * StringUtils.compare(null , "a") < 0 812 * StringUtils.compare("a", null) > 0 813 * StringUtils.compare("abc", "abc") = 0 814 * StringUtils.compare("a", "b") < 0 815 * StringUtils.compare("b", "a") > 0 816 * StringUtils.compare("a", "B") > 0 817 * StringUtils.compare("ab", "abc") < 0 818 * </pre> 819 * 820 * @see #compare(String, String, boolean) 821 * @see String#compareTo(String) 822 * @param str1 the String to compare from 823 * @param str2 the String to compare to 824 * @return < 0, 0, > 0, if {@code str1} is respectively less, equal or greater than {@code str2} 825 * @since 3.5 826 */ 827 public static int compare(final String str1, final String str2) { 828 return compare(str1, str2, true); 829 } 830 831 /** 832 * <p>Compare two Strings lexicographically, as per {@link String#compareTo(String)}, returning :</p> 833 * <ul> 834 * <li>{@code int = 0}, if {@code str1} is equal to {@code str2} (or both {@code null})</li> 835 * <li>{@code int < 0}, if {@code str1} is less than {@code str2}</li> 836 * <li>{@code int > 0}, if {@code str1} is greater than {@code str2}</li> 837 * </ul> 838 * 839 * <p>This is a {@code null} safe version of :</p> 840 * <blockquote><pre>str1.compareTo(str2)</pre></blockquote> 841 * 842 * <p>{@code null} inputs are handled according to the {@code nullIsLess} parameter. 843 * Two {@code null} references are considered equal.</p> 844 * 845 * <pre> 846 * StringUtils.compare(null, null, *) = 0 847 * StringUtils.compare(null , "a", true) < 0 848 * StringUtils.compare(null , "a", false) > 0 849 * StringUtils.compare("a", null, true) > 0 850 * StringUtils.compare("a", null, false) < 0 851 * StringUtils.compare("abc", "abc", *) = 0 852 * StringUtils.compare("a", "b", *) < 0 853 * StringUtils.compare("b", "a", *) > 0 854 * StringUtils.compare("a", "B", *) > 0 855 * StringUtils.compare("ab", "abc", *) < 0 856 * </pre> 857 * 858 * @see String#compareTo(String) 859 * @param str1 the String to compare from 860 * @param str2 the String to compare to 861 * @param nullIsLess whether consider {@code null} value less than non-{@code null} value 862 * @return < 0, 0, > 0, if {@code str1} is respectively less, equal ou greater than {@code str2} 863 * @since 3.5 864 */ 865 public static int compare(final String str1, final String str2, final boolean nullIsLess) { 866 if (str1 == str2) { // NOSONARLINT this intentionally uses == to allow for both null 867 return 0; 868 } 869 if (str1 == null) { 870 return nullIsLess ? -1 : 1; 871 } 872 if (str2 == null) { 873 return nullIsLess ? 1 : - 1; 874 } 875 return str1.compareTo(str2); 876 } 877 878 /** 879 * <p>Compare two Strings lexicographically, ignoring case differences, 880 * as per {@link String#compareToIgnoreCase(String)}, returning :</p> 881 * <ul> 882 * <li>{@code int = 0}, if {@code str1} is equal to {@code str2} (or both {@code null})</li> 883 * <li>{@code int < 0}, if {@code str1} is less than {@code str2}</li> 884 * <li>{@code int > 0}, if {@code str1} is greater than {@code str2}</li> 885 * </ul> 886 * 887 * <p>This is a {@code null} safe version of :</p> 888 * <blockquote><pre>str1.compareToIgnoreCase(str2)</pre></blockquote> 889 * 890 * <p>{@code null} value is considered less than non-{@code null} value. 891 * Two {@code null} references are considered equal. 892 * Comparison is case insensitive.</p> 893 * 894 * <pre> 895 * StringUtils.compareIgnoreCase(null, null) = 0 896 * StringUtils.compareIgnoreCase(null , "a") < 0 897 * StringUtils.compareIgnoreCase("a", null) > 0 898 * StringUtils.compareIgnoreCase("abc", "abc") = 0 899 * StringUtils.compareIgnoreCase("abc", "ABC") = 0 900 * StringUtils.compareIgnoreCase("a", "b") < 0 901 * StringUtils.compareIgnoreCase("b", "a") > 0 902 * StringUtils.compareIgnoreCase("a", "B") < 0 903 * StringUtils.compareIgnoreCase("A", "b") < 0 904 * StringUtils.compareIgnoreCase("ab", "ABC") < 0 905 * </pre> 906 * 907 * @see #compareIgnoreCase(String, String, boolean) 908 * @see String#compareToIgnoreCase(String) 909 * @param str1 the String to compare from 910 * @param str2 the String to compare to 911 * @return < 0, 0, > 0, if {@code str1} is respectively less, equal ou greater than {@code str2}, 912 * ignoring case differences. 913 * @since 3.5 914 */ 915 public static int compareIgnoreCase(final String str1, final String str2) { 916 return compareIgnoreCase(str1, str2, true); 917 } 918 919 /** 920 * <p>Compare two Strings lexicographically, ignoring case differences, 921 * as per {@link String#compareToIgnoreCase(String)}, returning :</p> 922 * <ul> 923 * <li>{@code int = 0}, if {@code str1} is equal to {@code str2} (or both {@code null})</li> 924 * <li>{@code int < 0}, if {@code str1} is less than {@code str2}</li> 925 * <li>{@code int > 0}, if {@code str1} is greater than {@code str2}</li> 926 * </ul> 927 * 928 * <p>This is a {@code null} safe version of :</p> 929 * <blockquote><pre>str1.compareToIgnoreCase(str2)</pre></blockquote> 930 * 931 * <p>{@code null} inputs are handled according to the {@code nullIsLess} parameter. 932 * Two {@code null} references are considered equal. 933 * Comparison is case insensitive.</p> 934 * 935 * <pre> 936 * StringUtils.compareIgnoreCase(null, null, *) = 0 937 * StringUtils.compareIgnoreCase(null , "a", true) < 0 938 * StringUtils.compareIgnoreCase(null , "a", false) > 0 939 * StringUtils.compareIgnoreCase("a", null, true) > 0 940 * StringUtils.compareIgnoreCase("a", null, false) < 0 941 * StringUtils.compareIgnoreCase("abc", "abc", *) = 0 942 * StringUtils.compareIgnoreCase("abc", "ABC", *) = 0 943 * StringUtils.compareIgnoreCase("a", "b", *) < 0 944 * StringUtils.compareIgnoreCase("b", "a", *) > 0 945 * StringUtils.compareIgnoreCase("a", "B", *) < 0 946 * StringUtils.compareIgnoreCase("A", "b", *) < 0 947 * StringUtils.compareIgnoreCase("ab", "abc", *) < 0 948 * </pre> 949 * 950 * @see String#compareToIgnoreCase(String) 951 * @param str1 the String to compare from 952 * @param str2 the String to compare to 953 * @param nullIsLess whether consider {@code null} value less than non-{@code null} value 954 * @return < 0, 0, > 0, if {@code str1} is respectively less, equal ou greater than {@code str2}, 955 * ignoring case differences. 956 * @since 3.5 957 */ 958 public static int compareIgnoreCase(final String str1, final String str2, final boolean nullIsLess) { 959 if (str1 == str2) { // NOSONARLINT this intentionally uses == to allow for both null 960 return 0; 961 } 962 if (str1 == null) { 963 return nullIsLess ? -1 : 1; 964 } 965 if (str2 == null) { 966 return nullIsLess ? 1 : - 1; 967 } 968 return str1.compareToIgnoreCase(str2); 969 } 970 971 /** 972 * <p>Checks if CharSequence contains a search CharSequence, handling {@code null}. 973 * This method uses {@link String#indexOf(String)} if possible.</p> 974 * 975 * <p>A {@code null} CharSequence will return {@code false}.</p> 976 * 977 * <pre> 978 * StringUtils.contains(null, *) = false 979 * StringUtils.contains(*, null) = false 980 * StringUtils.contains("", "") = true 981 * StringUtils.contains("abc", "") = true 982 * StringUtils.contains("abc", "a") = true 983 * StringUtils.contains("abc", "z") = false 984 * </pre> 985 * 986 * @param seq the CharSequence to check, may be null 987 * @param searchSeq the CharSequence to find, may be null 988 * @return true if the CharSequence contains the search CharSequence, 989 * false if not or {@code null} string input 990 * @since 2.0 991 * @since 3.0 Changed signature from contains(String, String) to contains(CharSequence, CharSequence) 992 */ 993 public static boolean contains(final CharSequence seq, final CharSequence searchSeq) { 994 if (seq == null || searchSeq == null) { 995 return false; 996 } 997 return CharSequenceUtils.indexOf(seq, searchSeq, 0) >= 0; 998 } 999 1000 /** 1001 * <p>Checks if CharSequence contains a search character, handling {@code null}. 1002 * This method uses {@link String#indexOf(int)} if possible.</p> 1003 * 1004 * <p>A {@code null} or empty ("") CharSequence will return {@code false}.</p> 1005 * 1006 * <pre> 1007 * StringUtils.contains(null, *) = false 1008 * StringUtils.contains("", *) = false 1009 * StringUtils.contains("abc", 'a') = true 1010 * StringUtils.contains("abc", 'z') = false 1011 * </pre> 1012 * 1013 * @param seq the CharSequence to check, may be null 1014 * @param searchChar the character to find 1015 * @return true if the CharSequence contains the search character, 1016 * false if not or {@code null} string input 1017 * @since 2.0 1018 * @since 3.0 Changed signature from contains(String, int) to contains(CharSequence, int) 1019 */ 1020 public static boolean contains(final CharSequence seq, final int searchChar) { 1021 if (isEmpty(seq)) { 1022 return false; 1023 } 1024 return CharSequenceUtils.indexOf(seq, searchChar, 0) >= 0; 1025 } 1026 1027 /** 1028 * <p>Checks if the CharSequence contains any character in the given 1029 * set of characters.</p> 1030 * 1031 * <p>A {@code null} CharSequence will return {@code false}. 1032 * A {@code null} or zero length search array will return {@code false}.</p> 1033 * 1034 * <pre> 1035 * StringUtils.containsAny(null, *) = false 1036 * StringUtils.containsAny("", *) = false 1037 * StringUtils.containsAny(*, null) = false 1038 * StringUtils.containsAny(*, []) = false 1039 * StringUtils.containsAny("zzabyycdxx", ['z', 'a']) = true 1040 * StringUtils.containsAny("zzabyycdxx", ['b', 'y']) = true 1041 * StringUtils.containsAny("zzabyycdxx", ['z', 'y']) = true 1042 * StringUtils.containsAny("aba", ['z']) = false 1043 * </pre> 1044 * 1045 * @param cs the CharSequence to check, may be null 1046 * @param searchChars the chars to search for, may be null 1047 * @return the {@code true} if any of the chars are found, 1048 * {@code false} if no match or null input 1049 * @since 2.4 1050 * @since 3.0 Changed signature from containsAny(String, char[]) to containsAny(CharSequence, char...) 1051 */ 1052 public static boolean containsAny(final CharSequence cs, final char... searchChars) { 1053 if (isEmpty(cs) || ArrayUtils.isEmpty(searchChars)) { 1054 return false; 1055 } 1056 final int csLength = cs.length(); 1057 final int searchLength = searchChars.length; 1058 final int csLast = csLength - 1; 1059 final int searchLast = searchLength - 1; 1060 for (int i = 0; i < csLength; i++) { 1061 final char ch = cs.charAt(i); 1062 for (int j = 0; j < searchLength; j++) { 1063 if (searchChars[j] == ch) { 1064 if (Character.isHighSurrogate(ch)) { 1065 if (j == searchLast) { 1066 // missing low surrogate, fine, like String.indexOf(String) 1067 return true; 1068 } 1069 if (i < csLast && searchChars[j + 1] == cs.charAt(i + 1)) { 1070 return true; 1071 } 1072 } else { 1073 // ch is in the Basic Multilingual Plane 1074 return true; 1075 } 1076 } 1077 } 1078 } 1079 return false; 1080 } 1081 1082 /** 1083 * <p> 1084 * Checks if the CharSequence contains any character in the given set of characters. 1085 * </p> 1086 * 1087 * <p> 1088 * A {@code null} CharSequence will return {@code false}. A {@code null} search CharSequence will return 1089 * {@code false}. 1090 * </p> 1091 * 1092 * <pre> 1093 * StringUtils.containsAny(null, *) = false 1094 * StringUtils.containsAny("", *) = false 1095 * StringUtils.containsAny(*, null) = false 1096 * StringUtils.containsAny(*, "") = false 1097 * StringUtils.containsAny("zzabyycdxx", "za") = true 1098 * StringUtils.containsAny("zzabyycdxx", "by") = true 1099 * StringUtils.containsAny("zzabyycdxx", "zy") = true 1100 * StringUtils.containsAny("zzabyycdxx", "\tx") = true 1101 * StringUtils.containsAny("zzabyycdxx", "$.#yF") = true 1102 * StringUtils.containsAny("aba", "z") = false 1103 * </pre> 1104 * 1105 * @param cs 1106 * the CharSequence to check, may be null 1107 * @param searchChars 1108 * the chars to search for, may be null 1109 * @return the {@code true} if any of the chars are found, {@code false} if no match or null input 1110 * @since 2.4 1111 * @since 3.0 Changed signature from containsAny(String, String) to containsAny(CharSequence, CharSequence) 1112 */ 1113 public static boolean containsAny(final CharSequence cs, final CharSequence searchChars) { 1114 if (searchChars == null) { 1115 return false; 1116 } 1117 return containsAny(cs, CharSequenceUtils.toCharArray(searchChars)); 1118 } 1119 1120 /** 1121 * <p> 1122 * Checks if the CharSequence contains any of the CharSequences in the given array. 1123 * </p> 1124 * 1125 * <p> 1126 * A {@code null} {@code cs} CharSequence will return {@code false}. A {@code null} or zero length search array will 1127 * return {@code false}. 1128 * </p> 1129 * 1130 * <pre> 1131 * StringUtils.containsAny(null, *) = false 1132 * StringUtils.containsAny("", *) = false 1133 * StringUtils.containsAny(*, null) = false 1134 * StringUtils.containsAny(*, []) = false 1135 * StringUtils.containsAny("abcd", "ab", null) = true 1136 * StringUtils.containsAny("abcd", "ab", "cd") = true 1137 * StringUtils.containsAny("abc", "d", "abc") = true 1138 * </pre> 1139 * 1140 * 1141 * @param cs The CharSequence to check, may be null 1142 * @param searchCharSequences The array of CharSequences to search for, may be null. Individual CharSequences may be 1143 * null as well. 1144 * @return {@code true} if any of the search CharSequences are found, {@code false} otherwise 1145 * @since 3.4 1146 */ 1147 public static boolean containsAny(final CharSequence cs, final CharSequence... searchCharSequences) { 1148 return containsAny(StringUtils::contains, cs, searchCharSequences); 1149 } 1150 1151 /** 1152 * <p> 1153 * Checks if the CharSequence contains any of the CharSequences in the given array. 1154 * </p> 1155 * 1156 * <p> 1157 * A {@code null} {@code cs} CharSequence will return {@code false}. A {@code null} or zero length search array will 1158 * return {@code false}. 1159 * </p> 1160 * 1161 * @param cs The CharSequence to check, may be null 1162 * @param searchCharSequences The array of CharSequences to search for, may be null. Individual CharSequences may be 1163 * null as well. 1164 * @return {@code true} if any of the search CharSequences are found, {@code false} otherwise 1165 * @since 3.12.0 1166 */ 1167 private static boolean containsAny(final ToBooleanBiFunction<CharSequence, CharSequence> test, 1168 final CharSequence cs, final CharSequence... searchCharSequences) { 1169 if (isEmpty(cs) || ArrayUtils.isEmpty(searchCharSequences)) { 1170 return false; 1171 } 1172 for (final CharSequence searchCharSequence : searchCharSequences) { 1173 if (test.applyAsBoolean(cs, searchCharSequence)) { 1174 return true; 1175 } 1176 } 1177 return false; 1178 } 1179 1180 /** 1181 * <p> 1182 * Checks if the CharSequence contains any of the CharSequences in the given array, ignoring case. 1183 * </p> 1184 * 1185 * <p> 1186 * A {@code null} {@code cs} CharSequence will return {@code false}. A {@code null} or zero length search array will 1187 * return {@code false}. 1188 * </p> 1189 * 1190 * <pre> 1191 * StringUtils.containsAny(null, *) = false 1192 * StringUtils.containsAny("", *) = false 1193 * StringUtils.containsAny(*, null) = false 1194 * StringUtils.containsAny(*, []) = false 1195 * StringUtils.containsAny("abcd", "ab", null) = true 1196 * StringUtils.containsAny("abcd", "ab", "cd") = true 1197 * StringUtils.containsAny("abc", "d", "abc") = true 1198 * StringUtils.containsAny("abc", "D", "ABC") = true 1199 * StringUtils.containsAny("ABC", "d", "abc") = true 1200 * </pre> 1201 * 1202 * 1203 * @param cs The CharSequence to check, may be null 1204 * @param searchCharSequences The array of CharSequences to search for, may be null. Individual CharSequences may be 1205 * null as well. 1206 * @return {@code true} if any of the search CharSequences are found, {@code false} otherwise 1207 * @since 3.12.0 1208 */ 1209 public static boolean containsAnyIgnoreCase(final CharSequence cs, final CharSequence... searchCharSequences) { 1210 return containsAny(StringUtils::containsIgnoreCase, cs, searchCharSequences); 1211 } 1212 1213 /** 1214 * <p>Checks if CharSequence contains a search CharSequence irrespective of case, 1215 * handling {@code null}. Case-insensitivity is defined as by 1216 * {@link String#equalsIgnoreCase(String)}. 1217 * 1218 * <p>A {@code null} CharSequence will return {@code false}.</p> 1219 * 1220 * <pre> 1221 * StringUtils.containsIgnoreCase(null, *) = false 1222 * StringUtils.containsIgnoreCase(*, null) = false 1223 * StringUtils.containsIgnoreCase("", "") = true 1224 * StringUtils.containsIgnoreCase("abc", "") = true 1225 * StringUtils.containsIgnoreCase("abc", "a") = true 1226 * StringUtils.containsIgnoreCase("abc", "z") = false 1227 * StringUtils.containsIgnoreCase("abc", "A") = true 1228 * StringUtils.containsIgnoreCase("abc", "Z") = false 1229 * </pre> 1230 * 1231 * @param str the CharSequence to check, may be null 1232 * @param searchStr the CharSequence to find, may be null 1233 * @return true if the CharSequence contains the search CharSequence irrespective of 1234 * case or false if not or {@code null} string input 1235 * @since 3.0 Changed signature from containsIgnoreCase(String, String) to containsIgnoreCase(CharSequence, CharSequence) 1236 */ 1237 public static boolean containsIgnoreCase(final CharSequence str, final CharSequence searchStr) { 1238 if (str == null || searchStr == null) { 1239 return false; 1240 } 1241 final int len = searchStr.length(); 1242 final int max = str.length() - len; 1243 for (int i = 0; i <= max; i++) { 1244 if (CharSequenceUtils.regionMatches(str, true, i, searchStr, 0, len)) { 1245 return true; 1246 } 1247 } 1248 return false; 1249 } 1250 1251 /** 1252 * <p>Checks that the CharSequence does not contain certain characters.</p> 1253 * 1254 * <p>A {@code null} CharSequence will return {@code true}. 1255 * A {@code null} invalid character array will return {@code true}. 1256 * An empty CharSequence (length()=0) always returns true.</p> 1257 * 1258 * <pre> 1259 * StringUtils.containsNone(null, *) = true 1260 * StringUtils.containsNone(*, null) = true 1261 * StringUtils.containsNone("", *) = true 1262 * StringUtils.containsNone("ab", '') = true 1263 * StringUtils.containsNone("abab", 'xyz') = true 1264 * StringUtils.containsNone("ab1", 'xyz') = true 1265 * StringUtils.containsNone("abz", 'xyz') = false 1266 * </pre> 1267 * 1268 * @param cs the CharSequence to check, may be null 1269 * @param searchChars an array of invalid chars, may be null 1270 * @return true if it contains none of the invalid chars, or is null 1271 * @since 2.0 1272 * @since 3.0 Changed signature from containsNone(String, char[]) to containsNone(CharSequence, char...) 1273 */ 1274 public static boolean containsNone(final CharSequence cs, final char... searchChars) { 1275 if (cs == null || searchChars == null) { 1276 return true; 1277 } 1278 final int csLen = cs.length(); 1279 final int csLast = csLen - 1; 1280 final int searchLen = searchChars.length; 1281 final int searchLast = searchLen - 1; 1282 for (int i = 0; i < csLen; i++) { 1283 final char ch = cs.charAt(i); 1284 for (int j = 0; j < searchLen; j++) { 1285 if (searchChars[j] == ch) { 1286 if (Character.isHighSurrogate(ch)) { 1287 if (j == searchLast) { 1288 // missing low surrogate, fine, like String.indexOf(String) 1289 return false; 1290 } 1291 if (i < csLast && searchChars[j + 1] == cs.charAt(i + 1)) { 1292 return false; 1293 } 1294 } else { 1295 // ch is in the Basic Multilingual Plane 1296 return false; 1297 } 1298 } 1299 } 1300 } 1301 return true; 1302 } 1303 1304 /** 1305 * <p>Checks that the CharSequence does not contain certain characters.</p> 1306 * 1307 * <p>A {@code null} CharSequence will return {@code true}. 1308 * A {@code null} invalid character array will return {@code true}. 1309 * An empty String ("") always returns true.</p> 1310 * 1311 * <pre> 1312 * StringUtils.containsNone(null, *) = true 1313 * StringUtils.containsNone(*, null) = true 1314 * StringUtils.containsNone("", *) = true 1315 * StringUtils.containsNone("ab", "") = true 1316 * StringUtils.containsNone("abab", "xyz") = true 1317 * StringUtils.containsNone("ab1", "xyz") = true 1318 * StringUtils.containsNone("abz", "xyz") = false 1319 * </pre> 1320 * 1321 * @param cs the CharSequence to check, may be null 1322 * @param invalidChars a String of invalid chars, may be null 1323 * @return true if it contains none of the invalid chars, or is null 1324 * @since 2.0 1325 * @since 3.0 Changed signature from containsNone(String, String) to containsNone(CharSequence, String) 1326 */ 1327 public static boolean containsNone(final CharSequence cs, final String invalidChars) { 1328 if (invalidChars == null) { 1329 return true; 1330 } 1331 return containsNone(cs, invalidChars.toCharArray()); 1332 } 1333 1334 /** 1335 * <p>Checks if the CharSequence contains only certain characters.</p> 1336 * 1337 * <p>A {@code null} CharSequence will return {@code false}. 1338 * A {@code null} valid character array will return {@code false}. 1339 * An empty CharSequence (length()=0) always returns {@code true}.</p> 1340 * 1341 * <pre> 1342 * StringUtils.containsOnly(null, *) = false 1343 * StringUtils.containsOnly(*, null) = false 1344 * StringUtils.containsOnly("", *) = true 1345 * StringUtils.containsOnly("ab", '') = false 1346 * StringUtils.containsOnly("abab", 'abc') = true 1347 * StringUtils.containsOnly("ab1", 'abc') = false 1348 * StringUtils.containsOnly("abz", 'abc') = false 1349 * </pre> 1350 * 1351 * @param cs the String to check, may be null 1352 * @param valid an array of valid chars, may be null 1353 * @return true if it only contains valid chars and is non-null 1354 * @since 3.0 Changed signature from containsOnly(String, char[]) to containsOnly(CharSequence, char...) 1355 */ 1356 public static boolean containsOnly(final CharSequence cs, final char... valid) { 1357 // All these pre-checks are to maintain API with an older version 1358 if (valid == null || cs == null) { 1359 return false; 1360 } 1361 if (cs.length() == 0) { 1362 return true; 1363 } 1364 if (valid.length == 0) { 1365 return false; 1366 } 1367 return indexOfAnyBut(cs, valid) == INDEX_NOT_FOUND; 1368 } 1369 1370 /** 1371 * <p>Checks if the CharSequence contains only certain characters.</p> 1372 * 1373 * <p>A {@code null} CharSequence will return {@code false}. 1374 * A {@code null} valid character String will return {@code false}. 1375 * An empty String (length()=0) always returns {@code true}.</p> 1376 * 1377 * <pre> 1378 * StringUtils.containsOnly(null, *) = false 1379 * StringUtils.containsOnly(*, null) = false 1380 * StringUtils.containsOnly("", *) = true 1381 * StringUtils.containsOnly("ab", "") = false 1382 * StringUtils.containsOnly("abab", "abc") = true 1383 * StringUtils.containsOnly("ab1", "abc") = false 1384 * StringUtils.containsOnly("abz", "abc") = false 1385 * </pre> 1386 * 1387 * @param cs the CharSequence to check, may be null 1388 * @param validChars a String of valid chars, may be null 1389 * @return true if it only contains valid chars and is non-null 1390 * @since 2.0 1391 * @since 3.0 Changed signature from containsOnly(String, String) to containsOnly(CharSequence, String) 1392 */ 1393 public static boolean containsOnly(final CharSequence cs, final String validChars) { 1394 if (cs == null || validChars == null) { 1395 return false; 1396 } 1397 return containsOnly(cs, validChars.toCharArray()); 1398 } 1399 1400 /** 1401 * <p>Check whether the given CharSequence contains any whitespace characters.</p> 1402 * 1403 * <p>Whitespace is defined by {@link Character#isWhitespace(char)}.</p> 1404 * 1405 * @param seq the CharSequence to check (may be {@code null}) 1406 * @return {@code true} if the CharSequence is not empty and 1407 * contains at least 1 (breaking) whitespace character 1408 * @since 3.0 1409 */ 1410 // From org.springframework.util.StringUtils, under Apache License 2.0 1411 public static boolean containsWhitespace(final CharSequence seq) { 1412 if (isEmpty(seq)) { 1413 return false; 1414 } 1415 final int strLen = seq.length(); 1416 for (int i = 0; i < strLen; i++) { 1417 if (Character.isWhitespace(seq.charAt(i))) { 1418 return true; 1419 } 1420 } 1421 return false; 1422 } 1423 1424 private static void convertRemainingAccentCharacters(final StringBuilder decomposed) { 1425 for (int i = 0; i < decomposed.length(); i++) { 1426 if (decomposed.charAt(i) == '\u0141') { 1427 decomposed.setCharAt(i, 'L'); 1428 } else if (decomposed.charAt(i) == '\u0142') { 1429 decomposed.setCharAt(i, 'l'); 1430 } 1431 } 1432 } 1433 1434 /** 1435 * <p>Counts how many times the char appears in the given string.</p> 1436 * 1437 * <p>A {@code null} or empty ("") String input returns {@code 0}.</p> 1438 * 1439 * <pre> 1440 * StringUtils.countMatches(null, *) = 0 1441 * StringUtils.countMatches("", *) = 0 1442 * StringUtils.countMatches("abba", 0) = 0 1443 * StringUtils.countMatches("abba", 'a') = 2 1444 * StringUtils.countMatches("abba", 'b') = 2 1445 * StringUtils.countMatches("abba", 'x') = 0 1446 * </pre> 1447 * 1448 * @param str the CharSequence to check, may be null 1449 * @param ch the char to count 1450 * @return the number of occurrences, 0 if the CharSequence is {@code null} 1451 * @since 3.4 1452 */ 1453 public static int countMatches(final CharSequence str, final char ch) { 1454 if (isEmpty(str)) { 1455 return 0; 1456 } 1457 int count = 0; 1458 // We could also call str.toCharArray() for faster look ups but that would generate more garbage. 1459 for (int i = 0; i < str.length(); i++) { 1460 if (ch == str.charAt(i)) { 1461 count++; 1462 } 1463 } 1464 return count; 1465 } 1466 1467 /** 1468 * <p>Counts how many times the substring appears in the larger string. 1469 * Note that the code only counts non-overlapping matches.</p> 1470 * 1471 * <p>A {@code null} or empty ("") String input returns {@code 0}.</p> 1472 * 1473 * <pre> 1474 * StringUtils.countMatches(null, *) = 0 1475 * StringUtils.countMatches("", *) = 0 1476 * StringUtils.countMatches("abba", null) = 0 1477 * StringUtils.countMatches("abba", "") = 0 1478 * StringUtils.countMatches("abba", "a") = 2 1479 * StringUtils.countMatches("abba", "ab") = 1 1480 * StringUtils.countMatches("abba", "xxx") = 0 1481 * StringUtils.countMatches("ababa", "aba") = 1 1482 * </pre> 1483 * 1484 * @param str the CharSequence to check, may be null 1485 * @param sub the substring to count, may be null 1486 * @return the number of occurrences, 0 if either CharSequence is {@code null} 1487 * @since 3.0 Changed signature from countMatches(String, String) to countMatches(CharSequence, CharSequence) 1488 */ 1489 public static int countMatches(final CharSequence str, final CharSequence sub) { 1490 if (isEmpty(str) || isEmpty(sub)) { 1491 return 0; 1492 } 1493 int count = 0; 1494 int idx = 0; 1495 while ((idx = CharSequenceUtils.indexOf(str, sub, idx)) != INDEX_NOT_FOUND) { 1496 count++; 1497 idx += sub.length(); 1498 } 1499 return count; 1500 } 1501 1502 /** 1503 * <p>Returns either the passed in CharSequence, or if the CharSequence is 1504 * whitespace, empty ("") or {@code null}, the value of {@code defaultStr}.</p> 1505 * 1506 * <p>Whitespace is defined by {@link Character#isWhitespace(char)}.</p> 1507 * 1508 * <pre> 1509 * StringUtils.defaultIfBlank(null, "NULL") = "NULL" 1510 * StringUtils.defaultIfBlank("", "NULL") = "NULL" 1511 * StringUtils.defaultIfBlank(" ", "NULL") = "NULL" 1512 * StringUtils.defaultIfBlank("bat", "NULL") = "bat" 1513 * StringUtils.defaultIfBlank("", null) = null 1514 * </pre> 1515 * @param <T> the specific kind of CharSequence 1516 * @param str the CharSequence to check, may be null 1517 * @param defaultStr the default CharSequence to return 1518 * if the input is whitespace, empty ("") or {@code null}, may be null 1519 * @return the passed in CharSequence, or the default 1520 * @see StringUtils#defaultString(String, String) 1521 */ 1522 public static <T extends CharSequence> T defaultIfBlank(final T str, final T defaultStr) { 1523 return isBlank(str) ? defaultStr : str; 1524 } 1525 1526 /** 1527 * <p>Returns either the passed in CharSequence, or if the CharSequence is 1528 * empty or {@code null}, the value of {@code defaultStr}.</p> 1529 * 1530 * <pre> 1531 * StringUtils.defaultIfEmpty(null, "NULL") = "NULL" 1532 * StringUtils.defaultIfEmpty("", "NULL") = "NULL" 1533 * StringUtils.defaultIfEmpty(" ", "NULL") = " " 1534 * StringUtils.defaultIfEmpty("bat", "NULL") = "bat" 1535 * StringUtils.defaultIfEmpty("", null) = null 1536 * </pre> 1537 * @param <T> the specific kind of CharSequence 1538 * @param str the CharSequence to check, may be null 1539 * @param defaultStr the default CharSequence to return 1540 * if the input is empty ("") or {@code null}, may be null 1541 * @return the passed in CharSequence, or the default 1542 * @see StringUtils#defaultString(String, String) 1543 */ 1544 public static <T extends CharSequence> T defaultIfEmpty(final T str, final T defaultStr) { 1545 return isEmpty(str) ? defaultStr : str; 1546 } 1547 1548 /** 1549 * <p>Returns either the passed in String, 1550 * or if the String is {@code null}, an empty String ("").</p> 1551 * 1552 * <pre> 1553 * StringUtils.defaultString(null) = "" 1554 * StringUtils.defaultString("") = "" 1555 * StringUtils.defaultString("bat") = "bat" 1556 * </pre> 1557 * 1558 * @see ObjectUtils#toString(Object) 1559 * @see String#valueOf(Object) 1560 * @param str the String to check, may be null 1561 * @return the passed in String, or the empty String if it 1562 * was {@code null} 1563 */ 1564 public static String defaultString(final String str) { 1565 return defaultString(str, EMPTY); 1566 } 1567 1568 /** 1569 * <p>Returns either the passed in String, or if the String is 1570 * {@code null}, the value of {@code defaultStr}.</p> 1571 * 1572 * <pre> 1573 * StringUtils.defaultString(null, "NULL") = "NULL" 1574 * StringUtils.defaultString("", "NULL") = "" 1575 * StringUtils.defaultString("bat", "NULL") = "bat" 1576 * </pre> 1577 * 1578 * @see ObjectUtils#toString(Object,String) 1579 * @see String#valueOf(Object) 1580 * @param str the String to check, may be null 1581 * @param defaultStr the default String to return 1582 * if the input is {@code null}, may be null 1583 * @return the passed in String, or the default if it was {@code null} 1584 */ 1585 public static String defaultString(final String str, final String defaultStr) { 1586 return str == null ? defaultStr : str; 1587 } 1588 1589 /** 1590 * <p>Deletes all whitespaces from a String as defined by 1591 * {@link Character#isWhitespace(char)}.</p> 1592 * 1593 * <pre> 1594 * StringUtils.deleteWhitespace(null) = null 1595 * StringUtils.deleteWhitespace("") = "" 1596 * StringUtils.deleteWhitespace("abc") = "abc" 1597 * StringUtils.deleteWhitespace(" ab c ") = "abc" 1598 * </pre> 1599 * 1600 * @param str the String to delete whitespace from, may be null 1601 * @return the String without whitespaces, {@code null} if null String input 1602 */ 1603 public static String deleteWhitespace(final String str) { 1604 if (isEmpty(str)) { 1605 return str; 1606 } 1607 final int sz = str.length(); 1608 final char[] chs = new char[sz]; 1609 int count = 0; 1610 for (int i = 0; i < sz; i++) { 1611 if (!Character.isWhitespace(str.charAt(i))) { 1612 chs[count++] = str.charAt(i); 1613 } 1614 } 1615 if (count == sz) { 1616 return str; 1617 } 1618 if (count == 0) { 1619 return EMPTY; 1620 } 1621 return new String(chs, 0, count); 1622 } 1623 1624 /** 1625 * <p>Compares two Strings, and returns the portion where they differ. 1626 * More precisely, return the remainder of the second String, 1627 * starting from where it's different from the first. This means that 1628 * the difference between "abc" and "ab" is the empty String and not "c". </p> 1629 * 1630 * <p>For example, 1631 * {@code difference("i am a machine", "i am a robot") -> "robot"}.</p> 1632 * 1633 * <pre> 1634 * StringUtils.difference(null, null) = null 1635 * StringUtils.difference("", "") = "" 1636 * StringUtils.difference("", "abc") = "abc" 1637 * StringUtils.difference("abc", "") = "" 1638 * StringUtils.difference("abc", "abc") = "" 1639 * StringUtils.difference("abc", "ab") = "" 1640 * StringUtils.difference("ab", "abxyz") = "xyz" 1641 * StringUtils.difference("abcde", "abxyz") = "xyz" 1642 * StringUtils.difference("abcde", "xyz") = "xyz" 1643 * </pre> 1644 * 1645 * @param str1 the first String, may be null 1646 * @param str2 the second String, may be null 1647 * @return the portion of str2 where it differs from str1; returns the 1648 * empty String if they are equal 1649 * @see #indexOfDifference(CharSequence,CharSequence) 1650 * @since 2.0 1651 */ 1652 public static String difference(final String str1, final String str2) { 1653 if (str1 == null) { 1654 return str2; 1655 } 1656 if (str2 == null) { 1657 return str1; 1658 } 1659 final int at = indexOfDifference(str1, str2); 1660 if (at == INDEX_NOT_FOUND) { 1661 return EMPTY; 1662 } 1663 return str2.substring(at); 1664 } 1665 1666 /** 1667 * <p>Check if a CharSequence ends with a specified suffix.</p> 1668 * 1669 * <p>{@code null}s are handled without exceptions. Two {@code null} 1670 * references are considered to be equal. The comparison is case sensitive.</p> 1671 * 1672 * <pre> 1673 * StringUtils.endsWith(null, null) = true 1674 * StringUtils.endsWith(null, "def") = false 1675 * StringUtils.endsWith("abcdef", null) = false 1676 * StringUtils.endsWith("abcdef", "def") = true 1677 * StringUtils.endsWith("ABCDEF", "def") = false 1678 * StringUtils.endsWith("ABCDEF", "cde") = false 1679 * StringUtils.endsWith("ABCDEF", "") = true 1680 * </pre> 1681 * 1682 * @see java.lang.String#endsWith(String) 1683 * @param str the CharSequence to check, may be null 1684 * @param suffix the suffix to find, may be null 1685 * @return {@code true} if the CharSequence ends with the suffix, case sensitive, or 1686 * both {@code null} 1687 * @since 2.4 1688 * @since 3.0 Changed signature from endsWith(String, String) to endsWith(CharSequence, CharSequence) 1689 */ 1690 public static boolean endsWith(final CharSequence str, final CharSequence suffix) { 1691 return endsWith(str, suffix, false); 1692 } 1693 1694 /** 1695 * <p>Check if a CharSequence ends with a specified suffix (optionally case insensitive).</p> 1696 * 1697 * @see java.lang.String#endsWith(String) 1698 * @param str the CharSequence to check, may be null 1699 * @param suffix the suffix to find, may be null 1700 * @param ignoreCase indicates whether the compare should ignore case 1701 * (case insensitive) or not. 1702 * @return {@code true} if the CharSequence starts with the prefix or 1703 * both {@code null} 1704 */ 1705 private static boolean endsWith(final CharSequence str, final CharSequence suffix, final boolean ignoreCase) { 1706 if (str == null || suffix == null) { 1707 return str == suffix; 1708 } 1709 if (suffix.length() > str.length()) { 1710 return false; 1711 } 1712 final int strOffset = str.length() - suffix.length(); 1713 return CharSequenceUtils.regionMatches(str, ignoreCase, strOffset, suffix, 0, suffix.length()); 1714 } 1715 1716 /** 1717 * <p>Check if a CharSequence ends with any of the provided case-sensitive suffixes.</p> 1718 * 1719 * <pre> 1720 * StringUtils.endsWithAny(null, null) = false 1721 * StringUtils.endsWithAny(null, new String[] {"abc"}) = false 1722 * StringUtils.endsWithAny("abcxyz", null) = false 1723 * StringUtils.endsWithAny("abcxyz", new String[] {""}) = true 1724 * StringUtils.endsWithAny("abcxyz", new String[] {"xyz"}) = true 1725 * StringUtils.endsWithAny("abcxyz", new String[] {null, "xyz", "abc"}) = true 1726 * StringUtils.endsWithAny("abcXYZ", "def", "XYZ") = true 1727 * StringUtils.endsWithAny("abcXYZ", "def", "xyz") = false 1728 * </pre> 1729 * 1730 * @param sequence the CharSequence to check, may be null 1731 * @param searchStrings the case-sensitive CharSequences to find, may be empty or contain {@code null} 1732 * @see StringUtils#endsWith(CharSequence, CharSequence) 1733 * @return {@code true} if the input {@code sequence} is {@code null} AND no {@code searchStrings} are provided, or 1734 * the input {@code sequence} ends in any of the provided case-sensitive {@code searchStrings}. 1735 * @since 3.0 1736 */ 1737 public static boolean endsWithAny(final CharSequence sequence, final CharSequence... searchStrings) { 1738 if (isEmpty(sequence) || ArrayUtils.isEmpty(searchStrings)) { 1739 return false; 1740 } 1741 for (final CharSequence searchString : searchStrings) { 1742 if (endsWith(sequence, searchString)) { 1743 return true; 1744 } 1745 } 1746 return false; 1747 } 1748 1749 /** 1750 * <p>Case insensitive check if a CharSequence ends with a specified suffix.</p> 1751 * 1752 * <p>{@code null}s are handled without exceptions. Two {@code null} 1753 * references are considered to be equal. The comparison is case insensitive.</p> 1754 * 1755 * <pre> 1756 * StringUtils.endsWithIgnoreCase(null, null) = true 1757 * StringUtils.endsWithIgnoreCase(null, "def") = false 1758 * StringUtils.endsWithIgnoreCase("abcdef", null) = false 1759 * StringUtils.endsWithIgnoreCase("abcdef", "def") = true 1760 * StringUtils.endsWithIgnoreCase("ABCDEF", "def") = true 1761 * StringUtils.endsWithIgnoreCase("ABCDEF", "cde") = false 1762 * </pre> 1763 * 1764 * @see java.lang.String#endsWith(String) 1765 * @param str the CharSequence to check, may be null 1766 * @param suffix the suffix to find, may be null 1767 * @return {@code true} if the CharSequence ends with the suffix, case insensitive, or 1768 * both {@code null} 1769 * @since 2.4 1770 * @since 3.0 Changed signature from endsWithIgnoreCase(String, String) to endsWithIgnoreCase(CharSequence, CharSequence) 1771 */ 1772 public static boolean endsWithIgnoreCase(final CharSequence str, final CharSequence suffix) { 1773 return endsWith(str, suffix, true); 1774 } 1775 1776 /** 1777 * <p>Compares two CharSequences, returning {@code true} if they represent 1778 * equal sequences of characters.</p> 1779 * 1780 * <p>{@code null}s are handled without exceptions. Two {@code null} 1781 * references are considered to be equal. The comparison is <strong>case sensitive</strong>.</p> 1782 * 1783 * <pre> 1784 * StringUtils.equals(null, null) = true 1785 * StringUtils.equals(null, "abc") = false 1786 * StringUtils.equals("abc", null) = false 1787 * StringUtils.equals("abc", "abc") = true 1788 * StringUtils.equals("abc", "ABC") = false 1789 * </pre> 1790 * 1791 * @param cs1 the first CharSequence, may be {@code null} 1792 * @param cs2 the second CharSequence, may be {@code null} 1793 * @return {@code true} if the CharSequences are equal (case-sensitive), or both {@code null} 1794 * @since 3.0 Changed signature from equals(String, String) to equals(CharSequence, CharSequence) 1795 * @see Object#equals(Object) 1796 * @see #equalsIgnoreCase(CharSequence, CharSequence) 1797 */ 1798 public static boolean equals(final CharSequence cs1, final CharSequence cs2) { 1799 if (cs1 == cs2) { 1800 return true; 1801 } 1802 if (cs1 == null || cs2 == null) { 1803 return false; 1804 } 1805 if (cs1.length() != cs2.length()) { 1806 return false; 1807 } 1808 if (cs1 instanceof String && cs2 instanceof String) { 1809 return cs1.equals(cs2); 1810 } 1811 // Step-wise comparison 1812 final int length = cs1.length(); 1813 for (int i = 0; i < length; i++) { 1814 if (cs1.charAt(i) != cs2.charAt(i)) { 1815 return false; 1816 } 1817 } 1818 return true; 1819 } 1820 1821 /** 1822 * <p>Compares given {@code string} to a CharSequences vararg of {@code searchStrings}, 1823 * returning {@code true} if the {@code string} is equal to any of the {@code searchStrings}.</p> 1824 * 1825 * <pre> 1826 * StringUtils.equalsAny(null, (CharSequence[]) null) = false 1827 * StringUtils.equalsAny(null, null, null) = true 1828 * StringUtils.equalsAny(null, "abc", "def") = false 1829 * StringUtils.equalsAny("abc", null, "def") = false 1830 * StringUtils.equalsAny("abc", "abc", "def") = true 1831 * StringUtils.equalsAny("abc", "ABC", "DEF") = false 1832 * </pre> 1833 * 1834 * @param string to compare, may be {@code null}. 1835 * @param searchStrings a vararg of strings, may be {@code null}. 1836 * @return {@code true} if the string is equal (case-sensitive) to any other element of {@code searchStrings}; 1837 * {@code false} if {@code searchStrings} is null or contains no matches. 1838 * @since 3.5 1839 */ 1840 public static boolean equalsAny(final CharSequence string, final CharSequence... searchStrings) { 1841 if (ArrayUtils.isNotEmpty(searchStrings)) { 1842 for (final CharSequence next : searchStrings) { 1843 if (equals(string, next)) { 1844 return true; 1845 } 1846 } 1847 } 1848 return false; 1849 } 1850 1851 /** 1852 * <p>Compares given {@code string} to a CharSequences vararg of {@code searchStrings}, 1853 * returning {@code true} if the {@code string} is equal to any of the {@code searchStrings}, ignoring case.</p> 1854 * 1855 * <pre> 1856 * StringUtils.equalsAnyIgnoreCase(null, (CharSequence[]) null) = false 1857 * StringUtils.equalsAnyIgnoreCase(null, null, null) = true 1858 * StringUtils.equalsAnyIgnoreCase(null, "abc", "def") = false 1859 * StringUtils.equalsAnyIgnoreCase("abc", null, "def") = false 1860 * StringUtils.equalsAnyIgnoreCase("abc", "abc", "def") = true 1861 * StringUtils.equalsAnyIgnoreCase("abc", "ABC", "DEF") = true 1862 * </pre> 1863 * 1864 * @param string to compare, may be {@code null}. 1865 * @param searchStrings a vararg of strings, may be {@code null}. 1866 * @return {@code true} if the string is equal (case-insensitive) to any other element of {@code searchStrings}; 1867 * {@code false} if {@code searchStrings} is null or contains no matches. 1868 * @since 3.5 1869 */ 1870 public static boolean equalsAnyIgnoreCase(final CharSequence string, final CharSequence...searchStrings) { 1871 if (ArrayUtils.isNotEmpty(searchStrings)) { 1872 for (final CharSequence next : searchStrings) { 1873 if (equalsIgnoreCase(string, next)) { 1874 return true; 1875 } 1876 } 1877 } 1878 return false; 1879 } 1880 1881 /** 1882 * <p>Compares two CharSequences, returning {@code true} if they represent 1883 * equal sequences of characters, ignoring case.</p> 1884 * 1885 * <p>{@code null}s are handled without exceptions. Two {@code null} 1886 * references are considered equal. The comparison is <strong>case insensitive</strong>.</p> 1887 * 1888 * <pre> 1889 * StringUtils.equalsIgnoreCase(null, null) = true 1890 * StringUtils.equalsIgnoreCase(null, "abc") = false 1891 * StringUtils.equalsIgnoreCase("abc", null) = false 1892 * StringUtils.equalsIgnoreCase("abc", "abc") = true 1893 * StringUtils.equalsIgnoreCase("abc", "ABC") = true 1894 * </pre> 1895 * 1896 * @param cs1 the first CharSequence, may be {@code null} 1897 * @param cs2 the second CharSequence, may be {@code null} 1898 * @return {@code true} if the CharSequences are equal (case-insensitive), or both {@code null} 1899 * @since 3.0 Changed signature from equalsIgnoreCase(String, String) to equalsIgnoreCase(CharSequence, CharSequence) 1900 * @see #equals(CharSequence, CharSequence) 1901 */ 1902 public static boolean equalsIgnoreCase(final CharSequence cs1, final CharSequence cs2) { 1903 if (cs1 == cs2) { 1904 return true; 1905 } 1906 if (cs1 == null || cs2 == null) { 1907 return false; 1908 } 1909 if (cs1.length() != cs2.length()) { 1910 return false; 1911 } 1912 return CharSequenceUtils.regionMatches(cs1, true, 0, cs2, 0, cs1.length()); 1913 } 1914 1915 /** 1916 * <p>Returns the first value in the array which is not empty (""), 1917 * {@code null} or whitespace only.</p> 1918 * 1919 * <p>Whitespace is defined by {@link Character#isWhitespace(char)}.</p> 1920 * 1921 * <p>If all values are blank or the array is {@code null} 1922 * or empty then {@code null} is returned.</p> 1923 * 1924 * <pre> 1925 * StringUtils.firstNonBlank(null, null, null) = null 1926 * StringUtils.firstNonBlank(null, "", " ") = null 1927 * StringUtils.firstNonBlank("abc") = "abc" 1928 * StringUtils.firstNonBlank(null, "xyz") = "xyz" 1929 * StringUtils.firstNonBlank(null, "", " ", "xyz") = "xyz" 1930 * StringUtils.firstNonBlank(null, "xyz", "abc") = "xyz" 1931 * StringUtils.firstNonBlank() = null 1932 * </pre> 1933 * 1934 * @param <T> the specific kind of CharSequence 1935 * @param values the values to test, may be {@code null} or empty 1936 * @return the first value from {@code values} which is not blank, 1937 * or {@code null} if there are no non-blank values 1938 * @since 3.8 1939 */ 1940 @SafeVarargs 1941 public static <T extends CharSequence> T firstNonBlank(final T... values) { 1942 if (values != null) { 1943 for (final T val : values) { 1944 if (isNotBlank(val)) { 1945 return val; 1946 } 1947 } 1948 } 1949 return null; 1950 } 1951 1952 /** 1953 * <p>Returns the first value in the array which is not empty.</p> 1954 * 1955 * <p>If all values are empty or the array is {@code null} 1956 * or empty then {@code null} is returned.</p> 1957 * 1958 * <pre> 1959 * StringUtils.firstNonEmpty(null, null, null) = null 1960 * StringUtils.firstNonEmpty(null, null, "") = null 1961 * StringUtils.firstNonEmpty(null, "", " ") = " " 1962 * StringUtils.firstNonEmpty("abc") = "abc" 1963 * StringUtils.firstNonEmpty(null, "xyz") = "xyz" 1964 * StringUtils.firstNonEmpty("", "xyz") = "xyz" 1965 * StringUtils.firstNonEmpty(null, "xyz", "abc") = "xyz" 1966 * StringUtils.firstNonEmpty() = null 1967 * </pre> 1968 * 1969 * @param <T> the specific kind of CharSequence 1970 * @param values the values to test, may be {@code null} or empty 1971 * @return the first value from {@code values} which is not empty, 1972 * or {@code null} if there are no non-empty values 1973 * @since 3.8 1974 */ 1975 @SafeVarargs 1976 public static <T extends CharSequence> T firstNonEmpty(final T... values) { 1977 if (values != null) { 1978 for (final T val : values) { 1979 if (isNotEmpty(val)) { 1980 return val; 1981 } 1982 } 1983 } 1984 return null; 1985 } 1986 1987 /** 1988 * Calls {@link String#getBytes(Charset)} in a null-safe manner. 1989 * 1990 * @param string input string 1991 * @param charset The {@link Charset} to encode the {@code String}. If null, then use the default Charset. 1992 * @return The empty byte[] if {@code string} is null, the result of {@link String#getBytes(Charset)} otherwise. 1993 * @see String#getBytes(Charset) 1994 * @since 3.10 1995 */ 1996 public static byte[] getBytes(final String string, final Charset charset) { 1997 return string == null ? ArrayUtils.EMPTY_BYTE_ARRAY : string.getBytes(Charsets.toCharset(charset)); 1998 } 1999 2000 /** 2001 * Calls {@link String#getBytes(String)} in a null-safe manner. 2002 * 2003 * @param string input string 2004 * @param charset The {@link Charset} name to encode the {@code String}. If null, then use the default Charset. 2005 * @return The empty byte[] if {@code string} is null, the result of {@link String#getBytes(String)} otherwise. 2006 * @throws UnsupportedEncodingException Thrown when the named charset is not supported. 2007 * @see String#getBytes(String) 2008 * @since 3.10 2009 */ 2010 public static byte[] getBytes(final String string, final String charset) throws UnsupportedEncodingException { 2011 return string == null ? ArrayUtils.EMPTY_BYTE_ARRAY : string.getBytes(Charsets.toCharsetName(charset)); 2012 } 2013 2014 /** 2015 * <p>Compares all Strings in an array and returns the initial sequence of 2016 * characters that is common to all of them.</p> 2017 * 2018 * <p>For example, 2019 * {@code getCommonPrefix(new String[] {"i am a machine", "i am a robot"}) -> "i am a "}</p> 2020 * 2021 * <pre> 2022 * StringUtils.getCommonPrefix(null) = "" 2023 * StringUtils.getCommonPrefix(new String[] {}) = "" 2024 * StringUtils.getCommonPrefix(new String[] {"abc"}) = "abc" 2025 * StringUtils.getCommonPrefix(new String[] {null, null}) = "" 2026 * StringUtils.getCommonPrefix(new String[] {"", ""}) = "" 2027 * StringUtils.getCommonPrefix(new String[] {"", null}) = "" 2028 * StringUtils.getCommonPrefix(new String[] {"abc", null, null}) = "" 2029 * StringUtils.getCommonPrefix(new String[] {null, null, "abc"}) = "" 2030 * StringUtils.getCommonPrefix(new String[] {"", "abc"}) = "" 2031 * StringUtils.getCommonPrefix(new String[] {"abc", ""}) = "" 2032 * StringUtils.getCommonPrefix(new String[] {"abc", "abc"}) = "abc" 2033 * StringUtils.getCommonPrefix(new String[] {"abc", "a"}) = "a" 2034 * StringUtils.getCommonPrefix(new String[] {"ab", "abxyz"}) = "ab" 2035 * StringUtils.getCommonPrefix(new String[] {"abcde", "abxyz"}) = "ab" 2036 * StringUtils.getCommonPrefix(new String[] {"abcde", "xyz"}) = "" 2037 * StringUtils.getCommonPrefix(new String[] {"xyz", "abcde"}) = "" 2038 * StringUtils.getCommonPrefix(new String[] {"i am a machine", "i am a robot"}) = "i am a " 2039 * </pre> 2040 * 2041 * @param strs array of String objects, entries may be null 2042 * @return the initial sequence of characters that are common to all Strings 2043 * in the array; empty String if the array is null, the elements are all null 2044 * or if there is no common prefix. 2045 * @since 2.4 2046 */ 2047 public static String getCommonPrefix(final String... strs) { 2048 if (ArrayUtils.isEmpty(strs)) { 2049 return EMPTY; 2050 } 2051 final int smallestIndexOfDiff = indexOfDifference(strs); 2052 if (smallestIndexOfDiff == INDEX_NOT_FOUND) { 2053 // all strings were identical 2054 if (strs[0] == null) { 2055 return EMPTY; 2056 } 2057 return strs[0]; 2058 } else if (smallestIndexOfDiff == 0) { 2059 // there were no common initial characters 2060 return EMPTY; 2061 } else { 2062 // we found a common initial character sequence 2063 return strs[0].substring(0, smallestIndexOfDiff); 2064 } 2065 } 2066 2067 /** 2068 * <p>Checks if a String {@code str} contains Unicode digits, 2069 * if yes then concatenate all the digits in {@code str} and return it as a String.</p> 2070 * 2071 * <p>An empty ("") String will be returned if no digits found in {@code str}.</p> 2072 * 2073 * <pre> 2074 * StringUtils.getDigits(null) = null 2075 * StringUtils.getDigits("") = "" 2076 * StringUtils.getDigits("abc") = "" 2077 * StringUtils.getDigits("1000$") = "1000" 2078 * StringUtils.getDigits("1123~45") = "112345" 2079 * StringUtils.getDigits("(541) 754-3010") = "5417543010" 2080 * StringUtils.getDigits("\u0967\u0968\u0969") = "\u0967\u0968\u0969" 2081 * </pre> 2082 * 2083 * @param str the String to extract digits from, may be null 2084 * @return String with only digits, 2085 * or an empty ("") String if no digits found, 2086 * or {@code null} String if {@code str} is null 2087 * @since 3.6 2088 */ 2089 public static String getDigits(final String str) { 2090 if (isEmpty(str)) { 2091 return str; 2092 } 2093 final int sz = str.length(); 2094 final StringBuilder strDigits = new StringBuilder(sz); 2095 for (int i = 0; i < sz; i++) { 2096 final char tempChar = str.charAt(i); 2097 if (Character.isDigit(tempChar)) { 2098 strDigits.append(tempChar); 2099 } 2100 } 2101 return strDigits.toString(); 2102 } 2103 2104 /** 2105 * <p>Find the Fuzzy Distance which indicates the similarity score between two Strings.</p> 2106 * 2107 * <p>This string matching algorithm is similar to the algorithms of editors such as Sublime Text, 2108 * TextMate, Atom and others. One point is given for every matched character. Subsequent 2109 * matches yield two bonus points. A higher score indicates a higher similarity.</p> 2110 * 2111 * <pre> 2112 * StringUtils.getFuzzyDistance(null, null, null) = IllegalArgumentException 2113 * StringUtils.getFuzzyDistance("", "", Locale.ENGLISH) = 0 2114 * StringUtils.getFuzzyDistance("Workshop", "b", Locale.ENGLISH) = 0 2115 * StringUtils.getFuzzyDistance("Room", "o", Locale.ENGLISH) = 1 2116 * StringUtils.getFuzzyDistance("Workshop", "w", Locale.ENGLISH) = 1 2117 * StringUtils.getFuzzyDistance("Workshop", "ws", Locale.ENGLISH) = 2 2118 * StringUtils.getFuzzyDistance("Workshop", "wo", Locale.ENGLISH) = 4 2119 * StringUtils.getFuzzyDistance("Apache Software Foundation", "asf", Locale.ENGLISH) = 3 2120 * </pre> 2121 * 2122 * @param term a full term that should be matched against, must not be null 2123 * @param query the query that will be matched against a term, must not be null 2124 * @param locale This string matching logic is case insensitive. A locale is necessary to normalize 2125 * both Strings to lower case. 2126 * @return result score 2127 * @throws IllegalArgumentException if either String input {@code null} or Locale input {@code null} 2128 * @since 3.4 2129 * @deprecated as of 3.6, use commons-text 2130 * <a href="https://commons.apache.org/proper/commons-text/javadocs/api-release/org/apache/commons/text/similarity/FuzzyScore.html"> 2131 * FuzzyScore</a> instead 2132 */ 2133 @Deprecated 2134 public static int getFuzzyDistance(final CharSequence term, final CharSequence query, final Locale locale) { 2135 if (term == null || query == null) { 2136 throw new IllegalArgumentException("Strings must not be null"); 2137 } else if (locale == null) { 2138 throw new IllegalArgumentException("Locale must not be null"); 2139 } 2140 2141 // fuzzy logic is case insensitive. We normalize the Strings to lower 2142 // case right from the start. Turning characters to lower case 2143 // via Character.toLowerCase(char) is unfortunately insufficient 2144 // as it does not accept a locale. 2145 final String termLowerCase = term.toString().toLowerCase(locale); 2146 final String queryLowerCase = query.toString().toLowerCase(locale); 2147 2148 // the resulting score 2149 int score = 0; 2150 2151 // the position in the term which will be scanned next for potential 2152 // query character matches 2153 int termIndex = 0; 2154 2155 // index of the previously matched character in the term 2156 int previousMatchingCharacterIndex = Integer.MIN_VALUE; 2157 2158 for (int queryIndex = 0; queryIndex < queryLowerCase.length(); queryIndex++) { 2159 final char queryChar = queryLowerCase.charAt(queryIndex); 2160 2161 boolean termCharacterMatchFound = false; 2162 for (; termIndex < termLowerCase.length() && !termCharacterMatchFound; termIndex++) { 2163 final char termChar = termLowerCase.charAt(termIndex); 2164 2165 if (queryChar == termChar) { 2166 // simple character matches result in one point 2167 score++; 2168 2169 // subsequent character matches further improve 2170 // the score. 2171 if (previousMatchingCharacterIndex + 1 == termIndex) { 2172 score += 2; 2173 } 2174 2175 previousMatchingCharacterIndex = termIndex; 2176 2177 // we can leave the nested loop. Every character in the 2178 // query can match at most one character in the term. 2179 termCharacterMatchFound = true; 2180 } 2181 } 2182 } 2183 2184 return score; 2185 } 2186 2187 /** 2188 * <p>Returns either the passed in CharSequence, or if the CharSequence is 2189 * whitespace, empty ("") or {@code null}, the value supplied by {@code defaultStrSupplier}.</p> 2190 * 2191 * <p>Whitespace is defined by {@link Character#isWhitespace(char)}.</p> 2192 * 2193 * <p>Caller responsible for thread-safety and exception handling of default value supplier</p> 2194 * 2195 * <pre> 2196 * {@code 2197 * StringUtils.getIfBlank(null, () -> "NULL") = "NULL" 2198 * StringUtils.getIfBlank("", () -> "NULL") = "NULL" 2199 * StringUtils.getIfBlank(" ", () -> "NULL") = "NULL" 2200 * StringUtils.getIfBlank("bat", () -> "NULL") = "bat" 2201 * StringUtils.getIfBlank("", () -> null) = null 2202 * StringUtils.getIfBlank("", null) = null 2203 * }</pre> 2204 * @param <T> the specific kind of CharSequence 2205 * @param str the CharSequence to check, may be null 2206 * @param defaultSupplier the supplier of default CharSequence to return 2207 * if the input is whitespace, empty ("") or {@code null}, may be null 2208 * @return the passed in CharSequence, or the default 2209 * @see StringUtils#defaultString(String, String) 2210 * @since 3.10 2211 */ 2212 public static <T extends CharSequence> T getIfBlank(final T str, final Supplier<T> defaultSupplier) { 2213 return isBlank(str) ? defaultSupplier == null ? null : defaultSupplier.get() : str; 2214 } 2215 2216 /** 2217 * <p>Returns either the passed in CharSequence, or if the CharSequence is 2218 * empty or {@code null}, the value supplied by {@code defaultStrSupplier}.</p> 2219 * 2220 * <p>Caller responsible for thread-safety and exception handling of default value supplier</p> 2221 * 2222 * <pre> 2223 * {@code 2224 * StringUtils.getIfEmpty(null, () -> "NULL") = "NULL" 2225 * StringUtils.getIfEmpty("", () -> "NULL") = "NULL" 2226 * StringUtils.getIfEmpty(" ", () -> "NULL") = " " 2227 * StringUtils.getIfEmpty("bat", () -> "NULL") = "bat" 2228 * StringUtils.getIfEmpty("", () -> null) = null 2229 * StringUtils.getIfEmpty("", null) = null 2230 * } 2231 * </pre> 2232 * @param <T> the specific kind of CharSequence 2233 * @param str the CharSequence to check, may be null 2234 * @param defaultSupplier the supplier of default CharSequence to return 2235 * if the input is empty ("") or {@code null}, may be null 2236 * @return the passed in CharSequence, or the default 2237 * @see StringUtils#defaultString(String, String) 2238 * @since 3.10 2239 */ 2240 public static <T extends CharSequence> T getIfEmpty(final T str, final Supplier<T> defaultSupplier) { 2241 return isEmpty(str) ? defaultSupplier == null ? null : defaultSupplier.get() : str; 2242 } 2243 2244 /** 2245 * <p>Find the Jaro Winkler Distance which indicates the similarity score between two Strings.</p> 2246 * 2247 * <p>The Jaro measure is the weighted sum of percentage of matched characters from each file and transposed characters. 2248 * Winkler increased this measure for matching initial characters.</p> 2249 * 2250 * <p>This implementation is based on the Jaro Winkler similarity algorithm 2251 * from <a href="http://en.wikipedia.org/wiki/Jaro%E2%80%93Winkler_distance">http://en.wikipedia.org/wiki/Jaro%E2%80%93Winkler_distance</a>.</p> 2252 * 2253 * <pre> 2254 * StringUtils.getJaroWinklerDistance(null, null) = IllegalArgumentException 2255 * StringUtils.getJaroWinklerDistance("", "") = 0.0 2256 * StringUtils.getJaroWinklerDistance("", "a") = 0.0 2257 * StringUtils.getJaroWinklerDistance("aaapppp", "") = 0.0 2258 * StringUtils.getJaroWinklerDistance("frog", "fog") = 0.93 2259 * StringUtils.getJaroWinklerDistance("fly", "ant") = 0.0 2260 * StringUtils.getJaroWinklerDistance("elephant", "hippo") = 0.44 2261 * StringUtils.getJaroWinklerDistance("hippo", "elephant") = 0.44 2262 * StringUtils.getJaroWinklerDistance("hippo", "zzzzzzzz") = 0.0 2263 * StringUtils.getJaroWinklerDistance("hello", "hallo") = 0.88 2264 * StringUtils.getJaroWinklerDistance("ABC Corporation", "ABC Corp") = 0.93 2265 * StringUtils.getJaroWinklerDistance("D N H Enterprises Inc", "D & H Enterprises, Inc.") = 0.95 2266 * StringUtils.getJaroWinklerDistance("My Gym Children's Fitness Center", "My Gym. Childrens Fitness") = 0.92 2267 * StringUtils.getJaroWinklerDistance("PENNSYLVANIA", "PENNCISYLVNIA") = 0.88 2268 * </pre> 2269 * 2270 * @param first the first String, must not be null 2271 * @param second the second String, must not be null 2272 * @return result distance 2273 * @throws IllegalArgumentException if either String input {@code null} 2274 * @since 3.3 2275 * @deprecated as of 3.6, use commons-text 2276 * <a href="https://commons.apache.org/proper/commons-text/javadocs/api-release/org/apache/commons/text/similarity/JaroWinklerDistance.html"> 2277 * JaroWinklerDistance</a> instead 2278 */ 2279 @Deprecated 2280 public static double getJaroWinklerDistance(final CharSequence first, final CharSequence second) { 2281 final double DEFAULT_SCALING_FACTOR = 0.1; 2282 2283 if (first == null || second == null) { 2284 throw new IllegalArgumentException("Strings must not be null"); 2285 } 2286 2287 final int[] mtp = matches(first, second); 2288 final double m = mtp[0]; 2289 if (m == 0) { 2290 return 0D; 2291 } 2292 final double j = (m / first.length() + m / second.length() + (m - mtp[1]) / m) / 3; 2293 final double jw = j < 0.7D ? j : j + Math.min(DEFAULT_SCALING_FACTOR, 1D / mtp[3]) * mtp[2] * (1D - j); 2294 return Math.round(jw * 100.0D) / 100.0D; 2295 } 2296 2297 /** 2298 * <p>Find the Levenshtein distance between two Strings.</p> 2299 * 2300 * <p>This is the number of changes needed to change one String into 2301 * another, where each change is a single character modification (deletion, 2302 * insertion or substitution).</p> 2303 * 2304 * <p>The implementation uses a single-dimensional array of length s.length() + 1. See 2305 * <a href="http://blog.softwx.net/2014/12/optimizing-levenshtein-algorithm-in-c.html"> 2306 * http://blog.softwx.net/2014/12/optimizing-levenshtein-algorithm-in-c.html</a> for details.</p> 2307 * 2308 * <pre> 2309 * StringUtils.getLevenshteinDistance(null, *) = IllegalArgumentException 2310 * StringUtils.getLevenshteinDistance(*, null) = IllegalArgumentException 2311 * StringUtils.getLevenshteinDistance("", "") = 0 2312 * StringUtils.getLevenshteinDistance("", "a") = 1 2313 * StringUtils.getLevenshteinDistance("aaapppp", "") = 7 2314 * StringUtils.getLevenshteinDistance("frog", "fog") = 1 2315 * StringUtils.getLevenshteinDistance("fly", "ant") = 3 2316 * StringUtils.getLevenshteinDistance("elephant", "hippo") = 7 2317 * StringUtils.getLevenshteinDistance("hippo", "elephant") = 7 2318 * StringUtils.getLevenshteinDistance("hippo", "zzzzzzzz") = 8 2319 * StringUtils.getLevenshteinDistance("hello", "hallo") = 1 2320 * </pre> 2321 * 2322 * @param s the first String, must not be null 2323 * @param t the second String, must not be null 2324 * @return result distance 2325 * @throws IllegalArgumentException if either String input {@code null} 2326 * @since 3.0 Changed signature from getLevenshteinDistance(String, String) to 2327 * getLevenshteinDistance(CharSequence, CharSequence) 2328 * @deprecated as of 3.6, use commons-text 2329 * <a href="https://commons.apache.org/proper/commons-text/javadocs/api-release/org/apache/commons/text/similarity/LevenshteinDistance.html"> 2330 * LevenshteinDistance</a> instead 2331 */ 2332 @Deprecated 2333 public static int getLevenshteinDistance(CharSequence s, CharSequence t) { 2334 if (s == null || t == null) { 2335 throw new IllegalArgumentException("Strings must not be null"); 2336 } 2337 2338 int n = s.length(); 2339 int m = t.length(); 2340 2341 if (n == 0) { 2342 return m; 2343 } else if (m == 0) { 2344 return n; 2345 } 2346 2347 if (n > m) { 2348 // swap the input strings to consume less memory 2349 final CharSequence tmp = s; 2350 s = t; 2351 t = tmp; 2352 n = m; 2353 m = t.length(); 2354 } 2355 2356 final int[] p = new int[n + 1]; 2357 // indexes into strings s and t 2358 int i; // iterates through s 2359 int j; // iterates through t 2360 int upper_left; 2361 int upper; 2362 2363 char t_j; // jth character of t 2364 int cost; 2365 2366 for (i = 0; i <= n; i++) { 2367 p[i] = i; 2368 } 2369 2370 for (j = 1; j <= m; j++) { 2371 upper_left = p[0]; 2372 t_j = t.charAt(j - 1); 2373 p[0] = j; 2374 2375 for (i = 1; i <= n; i++) { 2376 upper = p[i]; 2377 cost = s.charAt(i - 1) == t_j ? 0 : 1; 2378 // minimum of cell to the left+1, to the top+1, diagonally left and up +cost 2379 p[i] = Math.min(Math.min(p[i - 1] + 1, p[i] + 1), upper_left + cost); 2380 upper_left = upper; 2381 } 2382 } 2383 2384 return p[n]; 2385 } 2386 2387 /** 2388 * <p>Find the Levenshtein distance between two Strings if it's less than or equal to a given 2389 * threshold.</p> 2390 * 2391 * <p>This is the number of changes needed to change one String into 2392 * another, where each change is a single character modification (deletion, 2393 * insertion or substitution).</p> 2394 * 2395 * <p>This implementation follows from Algorithms on Strings, Trees and Sequences by Dan Gusfield 2396 * and Chas Emerick's implementation of the Levenshtein distance algorithm from 2397 * <a href="http://www.merriampark.com/ld.htm">http://www.merriampark.com/ld.htm</a></p> 2398 * 2399 * <pre> 2400 * StringUtils.getLevenshteinDistance(null, *, *) = IllegalArgumentException 2401 * StringUtils.getLevenshteinDistance(*, null, *) = IllegalArgumentException 2402 * StringUtils.getLevenshteinDistance(*, *, -1) = IllegalArgumentException 2403 * StringUtils.getLevenshteinDistance("", "", 0) = 0 2404 * StringUtils.getLevenshteinDistance("aaapppp", "", 8) = 7 2405 * StringUtils.getLevenshteinDistance("aaapppp", "", 7) = 7 2406 * StringUtils.getLevenshteinDistance("aaapppp", "", 6)) = -1 2407 * StringUtils.getLevenshteinDistance("elephant", "hippo", 7) = 7 2408 * StringUtils.getLevenshteinDistance("elephant", "hippo", 6) = -1 2409 * StringUtils.getLevenshteinDistance("hippo", "elephant", 7) = 7 2410 * StringUtils.getLevenshteinDistance("hippo", "elephant", 6) = -1 2411 * </pre> 2412 * 2413 * @param s the first String, must not be null 2414 * @param t the second String, must not be null 2415 * @param threshold the target threshold, must not be negative 2416 * @return result distance, or {@code -1} if the distance would be greater than the threshold 2417 * @throws IllegalArgumentException if either String input {@code null} or negative threshold 2418 * @deprecated as of 3.6, use commons-text 2419 * <a href="https://commons.apache.org/proper/commons-text/javadocs/api-release/org/apache/commons/text/similarity/LevenshteinDistance.html"> 2420 * LevenshteinDistance</a> instead 2421 */ 2422 @Deprecated 2423 public static int getLevenshteinDistance(CharSequence s, CharSequence t, final int threshold) { 2424 if (s == null || t == null) { 2425 throw new IllegalArgumentException("Strings must not be null"); 2426 } 2427 if (threshold < 0) { 2428 throw new IllegalArgumentException("Threshold must not be negative"); 2429 } 2430 2431 /* 2432 This implementation only computes the distance if it's less than or equal to the 2433 threshold value, returning -1 if it's greater. The advantage is performance: unbounded 2434 distance is O(nm), but a bound of k allows us to reduce it to O(km) time by only 2435 computing a diagonal stripe of width 2k + 1 of the cost table. 2436 It is also possible to use this to compute the unbounded Levenshtein distance by starting 2437 the threshold at 1 and doubling each time until the distance is found; this is O(dm), where 2438 d is the distance. 2439 2440 One subtlety comes from needing to ignore entries on the border of our stripe 2441 eg. 2442 p[] = |#|#|#|* 2443 d[] = *|#|#|#| 2444 We must ignore the entry to the left of the leftmost member 2445 We must ignore the entry above the rightmost member 2446 2447 Another subtlety comes from our stripe running off the matrix if the strings aren't 2448 of the same size. Since string s is always swapped to be the shorter of the two, 2449 the stripe will always run off to the upper right instead of the lower left of the matrix. 2450 2451 As a concrete example, suppose s is of length 5, t is of length 7, and our threshold is 1. 2452 In this case we're going to walk a stripe of length 3. The matrix would look like so: 2453 2454 1 2 3 4 5 2455 1 |#|#| | | | 2456 2 |#|#|#| | | 2457 3 | |#|#|#| | 2458 4 | | |#|#|#| 2459 5 | | | |#|#| 2460 6 | | | | |#| 2461 7 | | | | | | 2462 2463 Note how the stripe leads off the table as there is no possible way to turn a string of length 5 2464 into one of length 7 in edit distance of 1. 2465 2466 Additionally, this implementation decreases memory usage by using two 2467 single-dimensional arrays and swapping them back and forth instead of allocating 2468 an entire n by m matrix. This requires a few minor changes, such as immediately returning 2469 when it's detected that the stripe has run off the matrix and initially filling the arrays with 2470 large values so that entries we don't compute are ignored. 2471 2472 See Algorithms on Strings, Trees and Sequences by Dan Gusfield for some discussion. 2473 */ 2474 2475 int n = s.length(); // length of s 2476 int m = t.length(); // length of t 2477 2478 // if one string is empty, the edit distance is necessarily the length of the other 2479 if (n == 0) { 2480 return m <= threshold ? m : -1; 2481 } else if (m == 0) { 2482 return n <= threshold ? n : -1; 2483 } else if (Math.abs(n - m) > threshold) { 2484 // no need to calculate the distance if the length difference is greater than the threshold 2485 return -1; 2486 } 2487 2488 if (n > m) { 2489 // swap the two strings to consume less memory 2490 final CharSequence tmp = s; 2491 s = t; 2492 t = tmp; 2493 n = m; 2494 m = t.length(); 2495 } 2496 2497 int[] p = new int[n + 1]; // 'previous' cost array, horizontally 2498 int[] d = new int[n + 1]; // cost array, horizontally 2499 int[] _d; // placeholder to assist in swapping p and d 2500 2501 // fill in starting table values 2502 final int boundary = Math.min(n, threshold) + 1; 2503 for (int i = 0; i < boundary; i++) { 2504 p[i] = i; 2505 } 2506 // these fills ensure that the value above the rightmost entry of our 2507 // stripe will be ignored in following loop iterations 2508 Arrays.fill(p, boundary, p.length, Integer.MAX_VALUE); 2509 Arrays.fill(d, Integer.MAX_VALUE); 2510 2511 // iterates through t 2512 for (int j = 1; j <= m; j++) { 2513 final char t_j = t.charAt(j - 1); // jth character of t 2514 d[0] = j; 2515 2516 // compute stripe indices, constrain to array size 2517 final int min = Math.max(1, j - threshold); 2518 final int max = j > Integer.MAX_VALUE - threshold ? n : Math.min(n, j + threshold); 2519 2520 // the stripe may lead off of the table if s and t are of different sizes 2521 if (min > max) { 2522 return -1; 2523 } 2524 2525 // ignore entry left of leftmost 2526 if (min > 1) { 2527 d[min - 1] = Integer.MAX_VALUE; 2528 } 2529 2530 // iterates through [min, max] in s 2531 for (int i = min; i <= max; i++) { 2532 if (s.charAt(i - 1) == t_j) { 2533 // diagonally left and up 2534 d[i] = p[i - 1]; 2535 } else { 2536 // 1 + minimum of cell to the left, to the top, diagonally left and up 2537 d[i] = 1 + Math.min(Math.min(d[i - 1], p[i]), p[i - 1]); 2538 } 2539 } 2540 2541 // copy current distance counts to 'previous row' distance counts 2542 _d = p; 2543 p = d; 2544 d = _d; 2545 } 2546 2547 // if p[n] is greater than the threshold, there's no guarantee on it being the correct 2548 // distance 2549 if (p[n] <= threshold) { 2550 return p[n]; 2551 } 2552 return -1; 2553 } 2554 2555 /** 2556 * <p>Finds the first index within a CharSequence, handling {@code null}. 2557 * This method uses {@link String#indexOf(String, int)} if possible.</p> 2558 * 2559 * <p>A {@code null} CharSequence will return {@code -1}.</p> 2560 * 2561 * <pre> 2562 * StringUtils.indexOf(null, *) = -1 2563 * StringUtils.indexOf(*, null) = -1 2564 * StringUtils.indexOf("", "") = 0 2565 * StringUtils.indexOf("", *) = -1 (except when * = "") 2566 * StringUtils.indexOf("aabaabaa", "a") = 0 2567 * StringUtils.indexOf("aabaabaa", "b") = 2 2568 * StringUtils.indexOf("aabaabaa", "ab") = 1 2569 * StringUtils.indexOf("aabaabaa", "") = 0 2570 * </pre> 2571 * 2572 * @param seq the CharSequence to check, may be null 2573 * @param searchSeq the CharSequence to find, may be null 2574 * @return the first index of the search CharSequence, 2575 * -1 if no match or {@code null} string input 2576 * @since 2.0 2577 * @since 3.0 Changed signature from indexOf(String, String) to indexOf(CharSequence, CharSequence) 2578 */ 2579 public static int indexOf(final CharSequence seq, final CharSequence searchSeq) { 2580 if (seq == null || searchSeq == null) { 2581 return INDEX_NOT_FOUND; 2582 } 2583 return CharSequenceUtils.indexOf(seq, searchSeq, 0); 2584 } 2585 2586 /** 2587 * <p>Finds the first index within a CharSequence, handling {@code null}. 2588 * This method uses {@link String#indexOf(String, int)} if possible.</p> 2589 * 2590 * <p>A {@code null} CharSequence will return {@code -1}. 2591 * A negative start position is treated as zero. 2592 * An empty ("") search CharSequence always matches. 2593 * A start position greater than the string length only matches 2594 * an empty search CharSequence.</p> 2595 * 2596 * <pre> 2597 * StringUtils.indexOf(null, *, *) = -1 2598 * StringUtils.indexOf(*, null, *) = -1 2599 * StringUtils.indexOf("", "", 0) = 0 2600 * StringUtils.indexOf("", *, 0) = -1 (except when * = "") 2601 * StringUtils.indexOf("aabaabaa", "a", 0) = 0 2602 * StringUtils.indexOf("aabaabaa", "b", 0) = 2 2603 * StringUtils.indexOf("aabaabaa", "ab", 0) = 1 2604 * StringUtils.indexOf("aabaabaa", "b", 3) = 5 2605 * StringUtils.indexOf("aabaabaa", "b", 9) = -1 2606 * StringUtils.indexOf("aabaabaa", "b", -1) = 2 2607 * StringUtils.indexOf("aabaabaa", "", 2) = 2 2608 * StringUtils.indexOf("abc", "", 9) = 3 2609 * </pre> 2610 * 2611 * @param seq the CharSequence to check, may be null 2612 * @param searchSeq the CharSequence to find, may be null 2613 * @param startPos the start position, negative treated as zero 2614 * @return the first index of the search CharSequence (always ≥ startPos), 2615 * -1 if no match or {@code null} string input 2616 * @since 2.0 2617 * @since 3.0 Changed signature from indexOf(String, String, int) to indexOf(CharSequence, CharSequence, int) 2618 */ 2619 public static int indexOf(final CharSequence seq, final CharSequence searchSeq, final int startPos) { 2620 if (seq == null || searchSeq == null) { 2621 return INDEX_NOT_FOUND; 2622 } 2623 return CharSequenceUtils.indexOf(seq, searchSeq, startPos); 2624 } 2625 2626 /** 2627 * Returns the index within {@code seq} of the first occurrence of 2628 * the specified character. If a character with value 2629 * {@code searchChar} occurs in the character sequence represented by 2630 * {@code seq} {@code CharSequence} object, then the index (in Unicode 2631 * code units) of the first such occurrence is returned. For 2632 * values of {@code searchChar} in the range from 0 to 0xFFFF 2633 * (inclusive), this is the smallest value <i>k</i> such that: 2634 * <blockquote><pre> 2635 * this.charAt(<i>k</i>) == searchChar 2636 * </pre></blockquote> 2637 * is true. For other values of {@code searchChar}, it is the 2638 * smallest value <i>k</i> such that: 2639 * <blockquote><pre> 2640 * this.codePointAt(<i>k</i>) == searchChar 2641 * </pre></blockquote> 2642 * is true. In either case, if no such character occurs in {@code seq}, 2643 * then {@code INDEX_NOT_FOUND (-1)} is returned. 2644 * 2645 * <p>Furthermore, a {@code null} or empty ("") CharSequence will 2646 * return {@code INDEX_NOT_FOUND (-1)}.</p> 2647 * 2648 * <pre> 2649 * StringUtils.indexOf(null, *) = -1 2650 * StringUtils.indexOf("", *) = -1 2651 * StringUtils.indexOf("aabaabaa", 'a') = 0 2652 * StringUtils.indexOf("aabaabaa", 'b') = 2 2653 * </pre> 2654 * 2655 * @param seq the CharSequence to check, may be null 2656 * @param searchChar the character to find 2657 * @return the first index of the search character, 2658 * -1 if no match or {@code null} string input 2659 * @since 2.0 2660 * @since 3.0 Changed signature from indexOf(String, int) to indexOf(CharSequence, int) 2661 * @since 3.6 Updated {@link CharSequenceUtils} call to behave more like {@code String} 2662 */ 2663 public static int indexOf(final CharSequence seq, final int searchChar) { 2664 if (isEmpty(seq)) { 2665 return INDEX_NOT_FOUND; 2666 } 2667 return CharSequenceUtils.indexOf(seq, searchChar, 0); 2668 } 2669 2670 /** 2671 * 2672 * Returns the index within {@code seq} of the first occurrence of the 2673 * specified character, starting the search at the specified index. 2674 * <p> 2675 * If a character with value {@code searchChar} occurs in the 2676 * character sequence represented by the {@code seq} {@code CharSequence} 2677 * object at an index no smaller than {@code startPos}, then 2678 * the index of the first such occurrence is returned. For values 2679 * of {@code searchChar} in the range from 0 to 0xFFFF (inclusive), 2680 * this is the smallest value <i>k</i> such that: 2681 * <blockquote><pre> 2682 * (this.charAt(<i>k</i>) == searchChar) && (<i>k</i> >= startPos) 2683 * </pre></blockquote> 2684 * is true. For other values of {@code searchChar}, it is the 2685 * smallest value <i>k</i> such that: 2686 * <blockquote><pre> 2687 * (this.codePointAt(<i>k</i>) == searchChar) && (<i>k</i> >= startPos) 2688 * </pre></blockquote> 2689 * is true. In either case, if no such character occurs in {@code seq} 2690 * at or after position {@code startPos}, then 2691 * {@code -1} is returned. 2692 * 2693 * <p> 2694 * There is no restriction on the value of {@code startPos}. If it 2695 * is negative, it has the same effect as if it were zero: this entire 2696 * string may be searched. If it is greater than the length of this 2697 * string, it has the same effect as if it were equal to the length of 2698 * this string: {@code (INDEX_NOT_FOUND) -1} is returned. Furthermore, a 2699 * {@code null} or empty ("") CharSequence will 2700 * return {@code (INDEX_NOT_FOUND) -1}. 2701 * 2702 * <p>All indices are specified in {@code char} values 2703 * (Unicode code units). 2704 * 2705 * <pre> 2706 * StringUtils.indexOf(null, *, *) = -1 2707 * StringUtils.indexOf("", *, *) = -1 2708 * StringUtils.indexOf("aabaabaa", 'b', 0) = 2 2709 * StringUtils.indexOf("aabaabaa", 'b', 3) = 5 2710 * StringUtils.indexOf("aabaabaa", 'b', 9) = -1 2711 * StringUtils.indexOf("aabaabaa", 'b', -1) = 2 2712 * </pre> 2713 * 2714 * @param seq the CharSequence to check, may be null 2715 * @param searchChar the character to find 2716 * @param startPos the start position, negative treated as zero 2717 * @return the first index of the search character (always ≥ startPos), 2718 * -1 if no match or {@code null} string input 2719 * @since 2.0 2720 * @since 3.0 Changed signature from indexOf(String, int, int) to indexOf(CharSequence, int, int) 2721 * @since 3.6 Updated {@link CharSequenceUtils} call to behave more like {@code String} 2722 */ 2723 public static int indexOf(final CharSequence seq, final int searchChar, final int startPos) { 2724 if (isEmpty(seq)) { 2725 return INDEX_NOT_FOUND; 2726 } 2727 return CharSequenceUtils.indexOf(seq, searchChar, startPos); 2728 } 2729 2730 /** 2731 * <p>Search a CharSequence to find the first index of any 2732 * character in the given set of characters.</p> 2733 * 2734 * <p>A {@code null} String will return {@code -1}. 2735 * A {@code null} or zero length search array will return {@code -1}.</p> 2736 * 2737 * <pre> 2738 * StringUtils.indexOfAny(null, *) = -1 2739 * StringUtils.indexOfAny("", *) = -1 2740 * StringUtils.indexOfAny(*, null) = -1 2741 * StringUtils.indexOfAny(*, []) = -1 2742 * StringUtils.indexOfAny("zzabyycdxx", ['z', 'a']) = 0 2743 * StringUtils.indexOfAny("zzabyycdxx", ['b', 'y']) = 3 2744 * StringUtils.indexOfAny("aba", ['z']) = -1 2745 * </pre> 2746 * 2747 * @param cs the CharSequence to check, may be null 2748 * @param searchChars the chars to search for, may be null 2749 * @return the index of any of the chars, -1 if no match or null input 2750 * @since 2.0 2751 * @since 3.0 Changed signature from indexOfAny(String, char[]) to indexOfAny(CharSequence, char...) 2752 */ 2753 public static int indexOfAny(final CharSequence cs, final char... searchChars) { 2754 if (isEmpty(cs) || ArrayUtils.isEmpty(searchChars)) { 2755 return INDEX_NOT_FOUND; 2756 } 2757 final int csLen = cs.length(); 2758 final int csLast = csLen - 1; 2759 final int searchLen = searchChars.length; 2760 final int searchLast = searchLen - 1; 2761 for (int i = 0; i < csLen; i++) { 2762 final char ch = cs.charAt(i); 2763 for (int j = 0; j < searchLen; j++) { 2764 if (searchChars[j] == ch) { 2765 if (i < csLast && j < searchLast && Character.isHighSurrogate(ch)) { 2766 // ch is a supplementary character 2767 if (searchChars[j + 1] == cs.charAt(i + 1)) { 2768 return i; 2769 } 2770 } else { 2771 return i; 2772 } 2773 } 2774 } 2775 } 2776 return INDEX_NOT_FOUND; 2777 } 2778 2779 /** 2780 * <p>Find the first index of any of a set of potential substrings.</p> 2781 * 2782 * <p>A {@code null} CharSequence will return {@code -1}. 2783 * A {@code null} or zero length search array will return {@code -1}. 2784 * A {@code null} search array entry will be ignored, but a search 2785 * array containing "" will return {@code 0} if {@code str} is not 2786 * null. This method uses {@link String#indexOf(String)} if possible.</p> 2787 * 2788 * <pre> 2789 * StringUtils.indexOfAny(null, *) = -1 2790 * StringUtils.indexOfAny(*, null) = -1 2791 * StringUtils.indexOfAny(*, []) = -1 2792 * StringUtils.indexOfAny("zzabyycdxx", ["ab", "cd"]) = 2 2793 * StringUtils.indexOfAny("zzabyycdxx", ["cd", "ab"]) = 2 2794 * StringUtils.indexOfAny("zzabyycdxx", ["mn", "op"]) = -1 2795 * StringUtils.indexOfAny("zzabyycdxx", ["zab", "aby"]) = 1 2796 * StringUtils.indexOfAny("zzabyycdxx", [""]) = 0 2797 * StringUtils.indexOfAny("", [""]) = 0 2798 * StringUtils.indexOfAny("", ["a"]) = -1 2799 * </pre> 2800 * 2801 * @param str the CharSequence to check, may be null 2802 * @param searchStrs the CharSequences to search for, may be null 2803 * @return the first index of any of the searchStrs in str, -1 if no match 2804 * @since 3.0 Changed signature from indexOfAny(String, String[]) to indexOfAny(CharSequence, CharSequence...) 2805 */ 2806 public static int indexOfAny(final CharSequence str, final CharSequence... searchStrs) { 2807 if (str == null || searchStrs == null) { 2808 return INDEX_NOT_FOUND; 2809 } 2810 2811 // String's can't have a MAX_VALUEth index. 2812 int ret = Integer.MAX_VALUE; 2813 2814 int tmp = 0; 2815 for (final CharSequence search : searchStrs) { 2816 if (search == null) { 2817 continue; 2818 } 2819 tmp = CharSequenceUtils.indexOf(str, search, 0); 2820 if (tmp == INDEX_NOT_FOUND) { 2821 continue; 2822 } 2823 2824 if (tmp < ret) { 2825 ret = tmp; 2826 } 2827 } 2828 2829 return ret == Integer.MAX_VALUE ? INDEX_NOT_FOUND : ret; 2830 } 2831 2832 /** 2833 * <p>Search a CharSequence to find the first index of any 2834 * character in the given set of characters.</p> 2835 * 2836 * <p>A {@code null} String will return {@code -1}. 2837 * A {@code null} search string will return {@code -1}.</p> 2838 * 2839 * <pre> 2840 * StringUtils.indexOfAny(null, *) = -1 2841 * StringUtils.indexOfAny("", *) = -1 2842 * StringUtils.indexOfAny(*, null) = -1 2843 * StringUtils.indexOfAny(*, "") = -1 2844 * StringUtils.indexOfAny("zzabyycdxx", "za") = 0 2845 * StringUtils.indexOfAny("zzabyycdxx", "by") = 3 2846 * StringUtils.indexOfAny("aba", "z") = -1 2847 * </pre> 2848 * 2849 * @param cs the CharSequence to check, may be null 2850 * @param searchChars the chars to search for, may be null 2851 * @return the index of any of the chars, -1 if no match or null input 2852 * @since 2.0 2853 * @since 3.0 Changed signature from indexOfAny(String, String) to indexOfAny(CharSequence, String) 2854 */ 2855 public static int indexOfAny(final CharSequence cs, final String searchChars) { 2856 if (isEmpty(cs) || isEmpty(searchChars)) { 2857 return INDEX_NOT_FOUND; 2858 } 2859 return indexOfAny(cs, searchChars.toCharArray()); 2860 } 2861 2862 /** 2863 * <p>Searches a CharSequence to find the first index of any 2864 * character not in the given set of characters.</p> 2865 * 2866 * <p>A {@code null} CharSequence will return {@code -1}. 2867 * A {@code null} or zero length search array will return {@code -1}.</p> 2868 * 2869 * <pre> 2870 * StringUtils.indexOfAnyBut(null, *) = -1 2871 * StringUtils.indexOfAnyBut("", *) = -1 2872 * StringUtils.indexOfAnyBut(*, null) = -1 2873 * StringUtils.indexOfAnyBut(*, []) = -1 2874 * StringUtils.indexOfAnyBut("zzabyycdxx", new char[] {'z', 'a'} ) = 3 2875 * StringUtils.indexOfAnyBut("aba", new char[] {'z'} ) = 0 2876 * StringUtils.indexOfAnyBut("aba", new char[] {'a', 'b'} ) = -1 2877 2878 * </pre> 2879 * 2880 * @param cs the CharSequence to check, may be null 2881 * @param searchChars the chars to search for, may be null 2882 * @return the index of any of the chars, -1 if no match or null input 2883 * @since 2.0 2884 * @since 3.0 Changed signature from indexOfAnyBut(String, char[]) to indexOfAnyBut(CharSequence, char...) 2885 */ 2886 public static int indexOfAnyBut(final CharSequence cs, final char... searchChars) { 2887 if (isEmpty(cs) || ArrayUtils.isEmpty(searchChars)) { 2888 return INDEX_NOT_FOUND; 2889 } 2890 final int csLen = cs.length(); 2891 final int csLast = csLen - 1; 2892 final int searchLen = searchChars.length; 2893 final int searchLast = searchLen - 1; 2894 outer: 2895 for (int i = 0; i < csLen; i++) { 2896 final char ch = cs.charAt(i); 2897 for (int j = 0; j < searchLen; j++) { 2898 if (searchChars[j] == ch) { 2899 if (i < csLast && j < searchLast && Character.isHighSurrogate(ch)) { 2900 if (searchChars[j + 1] == cs.charAt(i + 1)) { 2901 continue outer; 2902 } 2903 } else { 2904 continue outer; 2905 } 2906 } 2907 } 2908 return i; 2909 } 2910 return INDEX_NOT_FOUND; 2911 } 2912 2913 /** 2914 * <p>Search a CharSequence to find the first index of any 2915 * character not in the given set of characters.</p> 2916 * 2917 * <p>A {@code null} CharSequence will return {@code -1}. 2918 * A {@code null} or empty search string will return {@code -1}.</p> 2919 * 2920 * <pre> 2921 * StringUtils.indexOfAnyBut(null, *) = -1 2922 * StringUtils.indexOfAnyBut("", *) = -1 2923 * StringUtils.indexOfAnyBut(*, null) = -1 2924 * StringUtils.indexOfAnyBut(*, "") = -1 2925 * StringUtils.indexOfAnyBut("zzabyycdxx", "za") = 3 2926 * StringUtils.indexOfAnyBut("zzabyycdxx", "") = -1 2927 * StringUtils.indexOfAnyBut("aba", "ab") = -1 2928 * </pre> 2929 * 2930 * @param seq the CharSequence to check, may be null 2931 * @param searchChars the chars to search for, may be null 2932 * @return the index of any of the chars, -1 if no match or null input 2933 * @since 2.0 2934 * @since 3.0 Changed signature from indexOfAnyBut(String, String) to indexOfAnyBut(CharSequence, CharSequence) 2935 */ 2936 public static int indexOfAnyBut(final CharSequence seq, final CharSequence searchChars) { 2937 if (isEmpty(seq) || isEmpty(searchChars)) { 2938 return INDEX_NOT_FOUND; 2939 } 2940 final int strLen = seq.length(); 2941 for (int i = 0; i < strLen; i++) { 2942 final char ch = seq.charAt(i); 2943 final boolean chFound = CharSequenceUtils.indexOf(searchChars, ch, 0) >= 0; 2944 if (i + 1 < strLen && Character.isHighSurrogate(ch)) { 2945 final char ch2 = seq.charAt(i + 1); 2946 if (chFound && CharSequenceUtils.indexOf(searchChars, ch2, 0) < 0) { 2947 return i; 2948 } 2949 } else if (!chFound) { 2950 return i; 2951 } 2952 } 2953 return INDEX_NOT_FOUND; 2954 } 2955 2956 /** 2957 * <p>Compares all CharSequences in an array and returns the index at which the 2958 * CharSequences begin to differ.</p> 2959 * 2960 * <p>For example, 2961 * {@code indexOfDifference(new String[] {"i am a machine", "i am a robot"}) -> 7}</p> 2962 * 2963 * <pre> 2964 * StringUtils.indexOfDifference(null) = -1 2965 * StringUtils.indexOfDifference(new String[] {}) = -1 2966 * StringUtils.indexOfDifference(new String[] {"abc"}) = -1 2967 * StringUtils.indexOfDifference(new String[] {null, null}) = -1 2968 * StringUtils.indexOfDifference(new String[] {"", ""}) = -1 2969 * StringUtils.indexOfDifference(new String[] {"", null}) = 0 2970 * StringUtils.indexOfDifference(new String[] {"abc", null, null}) = 0 2971 * StringUtils.indexOfDifference(new String[] {null, null, "abc"}) = 0 2972 * StringUtils.indexOfDifference(new String[] {"", "abc"}) = 0 2973 * StringUtils.indexOfDifference(new String[] {"abc", ""}) = 0 2974 * StringUtils.indexOfDifference(new String[] {"abc", "abc"}) = -1 2975 * StringUtils.indexOfDifference(new String[] {"abc", "a"}) = 1 2976 * StringUtils.indexOfDifference(new String[] {"ab", "abxyz"}) = 2 2977 * StringUtils.indexOfDifference(new String[] {"abcde", "abxyz"}) = 2 2978 * StringUtils.indexOfDifference(new String[] {"abcde", "xyz"}) = 0 2979 * StringUtils.indexOfDifference(new String[] {"xyz", "abcde"}) = 0 2980 * StringUtils.indexOfDifference(new String[] {"i am a machine", "i am a robot"}) = 7 2981 * </pre> 2982 * 2983 * @param css array of CharSequences, entries may be null 2984 * @return the index where the strings begin to differ; -1 if they are all equal 2985 * @since 2.4 2986 * @since 3.0 Changed signature from indexOfDifference(String...) to indexOfDifference(CharSequence...) 2987 */ 2988 public static int indexOfDifference(final CharSequence... css) { 2989 if (ArrayUtils.getLength(css) <= 1) { 2990 return INDEX_NOT_FOUND; 2991 } 2992 boolean anyStringNull = false; 2993 boolean allStringsNull = true; 2994 final int arrayLen = css.length; 2995 int shortestStrLen = Integer.MAX_VALUE; 2996 int longestStrLen = 0; 2997 2998 // find the min and max string lengths; this avoids checking to make 2999 // sure we are not exceeding the length of the string each time through 3000 // the bottom loop. 3001 for (final CharSequence cs : css) { 3002 if (cs == null) { 3003 anyStringNull = true; 3004 shortestStrLen = 0; 3005 } else { 3006 allStringsNull = false; 3007 shortestStrLen = Math.min(cs.length(), shortestStrLen); 3008 longestStrLen = Math.max(cs.length(), longestStrLen); 3009 } 3010 } 3011 3012 // handle lists containing all nulls or all empty strings 3013 if (allStringsNull || longestStrLen == 0 && !anyStringNull) { 3014 return INDEX_NOT_FOUND; 3015 } 3016 3017 // handle lists containing some nulls or some empty strings 3018 if (shortestStrLen == 0) { 3019 return 0; 3020 } 3021 3022 // find the position with the first difference across all strings 3023 int firstDiff = -1; 3024 for (int stringPos = 0; stringPos < shortestStrLen; stringPos++) { 3025 final char comparisonChar = css[0].charAt(stringPos); 3026 for (int arrayPos = 1; arrayPos < arrayLen; arrayPos++) { 3027 if (css[arrayPos].charAt(stringPos) != comparisonChar) { 3028 firstDiff = stringPos; 3029 break; 3030 } 3031 } 3032 if (firstDiff != -1) { 3033 break; 3034 } 3035 } 3036 3037 if (firstDiff == -1 && shortestStrLen != longestStrLen) { 3038 // we compared all of the characters up to the length of the 3039 // shortest string and didn't find a match, but the string lengths 3040 // vary, so return the length of the shortest string. 3041 return shortestStrLen; 3042 } 3043 return firstDiff; 3044 } 3045 3046 /** 3047 * <p>Compares two CharSequences, and returns the index at which the 3048 * CharSequences begin to differ.</p> 3049 * 3050 * <p>For example, 3051 * {@code indexOfDifference("i am a machine", "i am a robot") -> 7}</p> 3052 * 3053 * <pre> 3054 * StringUtils.indexOfDifference(null, null) = -1 3055 * StringUtils.indexOfDifference("", "") = -1 3056 * StringUtils.indexOfDifference("", "abc") = 0 3057 * StringUtils.indexOfDifference("abc", "") = 0 3058 * StringUtils.indexOfDifference("abc", "abc") = -1 3059 * StringUtils.indexOfDifference("ab", "abxyz") = 2 3060 * StringUtils.indexOfDifference("abcde", "abxyz") = 2 3061 * StringUtils.indexOfDifference("abcde", "xyz") = 0 3062 * </pre> 3063 * 3064 * @param cs1 the first CharSequence, may be null 3065 * @param cs2 the second CharSequence, may be null 3066 * @return the index where cs1 and cs2 begin to differ; -1 if they are equal 3067 * @since 2.0 3068 * @since 3.0 Changed signature from indexOfDifference(String, String) to 3069 * indexOfDifference(CharSequence, CharSequence) 3070 */ 3071 public static int indexOfDifference(final CharSequence cs1, final CharSequence cs2) { 3072 if (cs1 == cs2) { 3073 return INDEX_NOT_FOUND; 3074 } 3075 if (cs1 == null || cs2 == null) { 3076 return 0; 3077 } 3078 int i; 3079 for (i = 0; i < cs1.length() && i < cs2.length(); ++i) { 3080 if (cs1.charAt(i) != cs2.charAt(i)) { 3081 break; 3082 } 3083 } 3084 if (i < cs2.length() || i < cs1.length()) { 3085 return i; 3086 } 3087 return INDEX_NOT_FOUND; 3088 } 3089 3090 /** 3091 * <p>Case in-sensitive find of the first index within a CharSequence.</p> 3092 * 3093 * <p>A {@code null} CharSequence will return {@code -1}. 3094 * A negative start position is treated as zero. 3095 * An empty ("") search CharSequence always matches. 3096 * A start position greater than the string length only matches 3097 * an empty search CharSequence.</p> 3098 * 3099 * <pre> 3100 * StringUtils.indexOfIgnoreCase(null, *) = -1 3101 * StringUtils.indexOfIgnoreCase(*, null) = -1 3102 * StringUtils.indexOfIgnoreCase("", "") = 0 3103 * StringUtils.indexOfIgnoreCase("aabaabaa", "a") = 0 3104 * StringUtils.indexOfIgnoreCase("aabaabaa", "b") = 2 3105 * StringUtils.indexOfIgnoreCase("aabaabaa", "ab") = 1 3106 * </pre> 3107 * 3108 * @param str the CharSequence to check, may be null 3109 * @param searchStr the CharSequence to find, may be null 3110 * @return the first index of the search CharSequence, 3111 * -1 if no match or {@code null} string input 3112 * @since 2.5 3113 * @since 3.0 Changed signature from indexOfIgnoreCase(String, String) to indexOfIgnoreCase(CharSequence, CharSequence) 3114 */ 3115 public static int indexOfIgnoreCase(final CharSequence str, final CharSequence searchStr) { 3116 return indexOfIgnoreCase(str, searchStr, 0); 3117 } 3118 3119 /** 3120 * <p>Case in-sensitive find of the first index within a CharSequence 3121 * from the specified position.</p> 3122 * 3123 * <p>A {@code null} CharSequence will return {@code -1}. 3124 * A negative start position is treated as zero. 3125 * An empty ("") search CharSequence always matches. 3126 * A start position greater than the string length only matches 3127 * an empty search CharSequence.</p> 3128 * 3129 * <pre> 3130 * StringUtils.indexOfIgnoreCase(null, *, *) = -1 3131 * StringUtils.indexOfIgnoreCase(*, null, *) = -1 3132 * StringUtils.indexOfIgnoreCase("", "", 0) = 0 3133 * StringUtils.indexOfIgnoreCase("aabaabaa", "A", 0) = 0 3134 * StringUtils.indexOfIgnoreCase("aabaabaa", "B", 0) = 2 3135 * StringUtils.indexOfIgnoreCase("aabaabaa", "AB", 0) = 1 3136 * StringUtils.indexOfIgnoreCase("aabaabaa", "B", 3) = 5 3137 * StringUtils.indexOfIgnoreCase("aabaabaa", "B", 9) = -1 3138 * StringUtils.indexOfIgnoreCase("aabaabaa", "B", -1) = 2 3139 * StringUtils.indexOfIgnoreCase("aabaabaa", "", 2) = 2 3140 * StringUtils.indexOfIgnoreCase("abc", "", 9) = -1 3141 * </pre> 3142 * 3143 * @param str the CharSequence to check, may be null 3144 * @param searchStr the CharSequence to find, may be null 3145 * @param startPos the start position, negative treated as zero 3146 * @return the first index of the search CharSequence (always ≥ startPos), 3147 * -1 if no match or {@code null} string input 3148 * @since 2.5 3149 * @since 3.0 Changed signature from indexOfIgnoreCase(String, String, int) to indexOfIgnoreCase(CharSequence, CharSequence, int) 3150 */ 3151 public static int indexOfIgnoreCase(final CharSequence str, final CharSequence searchStr, int startPos) { 3152 if (str == null || searchStr == null) { 3153 return INDEX_NOT_FOUND; 3154 } 3155 if (startPos < 0) { 3156 startPos = 0; 3157 } 3158 final int endLimit = str.length() - searchStr.length() + 1; 3159 if (startPos > endLimit) { 3160 return INDEX_NOT_FOUND; 3161 } 3162 if (searchStr.length() == 0) { 3163 return startPos; 3164 } 3165 for (int i = startPos; i < endLimit; i++) { 3166 if (CharSequenceUtils.regionMatches(str, true, i, searchStr, 0, searchStr.length())) { 3167 return i; 3168 } 3169 } 3170 return INDEX_NOT_FOUND; 3171 } 3172 3173 /** 3174 * <p>Checks if all of the CharSequences are empty (""), null or whitespace only.</p> 3175 * 3176 * <p>Whitespace is defined by {@link Character#isWhitespace(char)}.</p> 3177 * 3178 * <pre> 3179 * StringUtils.isAllBlank(null) = true 3180 * StringUtils.isAllBlank(null, "foo") = false 3181 * StringUtils.isAllBlank(null, null) = true 3182 * StringUtils.isAllBlank("", "bar") = false 3183 * StringUtils.isAllBlank("bob", "") = false 3184 * StringUtils.isAllBlank(" bob ", null) = false 3185 * StringUtils.isAllBlank(" ", "bar") = false 3186 * StringUtils.isAllBlank("foo", "bar") = false 3187 * StringUtils.isAllBlank(new String[] {}) = true 3188 * </pre> 3189 * 3190 * @param css the CharSequences to check, may be null or empty 3191 * @return {@code true} if all of the CharSequences are empty or null or whitespace only 3192 * @since 3.6 3193 */ 3194 public static boolean isAllBlank(final CharSequence... css) { 3195 if (ArrayUtils.isEmpty(css)) { 3196 return true; 3197 } 3198 for (final CharSequence cs : css) { 3199 if (isNotBlank(cs)) { 3200 return false; 3201 } 3202 } 3203 return true; 3204 } 3205 3206 /** 3207 * <p>Checks if all of the CharSequences are empty ("") or null.</p> 3208 * 3209 * <pre> 3210 * StringUtils.isAllEmpty(null) = true 3211 * StringUtils.isAllEmpty(null, "") = true 3212 * StringUtils.isAllEmpty(new String[] {}) = true 3213 * StringUtils.isAllEmpty(null, "foo") = false 3214 * StringUtils.isAllEmpty("", "bar") = false 3215 * StringUtils.isAllEmpty("bob", "") = false 3216 * StringUtils.isAllEmpty(" bob ", null) = false 3217 * StringUtils.isAllEmpty(" ", "bar") = false 3218 * StringUtils.isAllEmpty("foo", "bar") = false 3219 * </pre> 3220 * 3221 * @param css the CharSequences to check, may be null or empty 3222 * @return {@code true} if all of the CharSequences are empty or null 3223 * @since 3.6 3224 */ 3225 public static boolean isAllEmpty(final CharSequence... css) { 3226 if (ArrayUtils.isEmpty(css)) { 3227 return true; 3228 } 3229 for (final CharSequence cs : css) { 3230 if (isNotEmpty(cs)) { 3231 return false; 3232 } 3233 } 3234 return true; 3235 } 3236 3237 /** 3238 * <p>Checks if the CharSequence contains only lowercase characters.</p> 3239 * 3240 * <p>{@code null} will return {@code false}. 3241 * An empty CharSequence (length()=0) will return {@code false}.</p> 3242 * 3243 * <pre> 3244 * StringUtils.isAllLowerCase(null) = false 3245 * StringUtils.isAllLowerCase("") = false 3246 * StringUtils.isAllLowerCase(" ") = false 3247 * StringUtils.isAllLowerCase("abc") = true 3248 * StringUtils.isAllLowerCase("abC") = false 3249 * StringUtils.isAllLowerCase("ab c") = false 3250 * StringUtils.isAllLowerCase("ab1c") = false 3251 * StringUtils.isAllLowerCase("ab/c") = false 3252 * </pre> 3253 * 3254 * @param cs the CharSequence to check, may be null 3255 * @return {@code true} if only contains lowercase characters, and is non-null 3256 * @since 2.5 3257 * @since 3.0 Changed signature from isAllLowerCase(String) to isAllLowerCase(CharSequence) 3258 */ 3259 public static boolean isAllLowerCase(final CharSequence cs) { 3260 if (isEmpty(cs)) { 3261 return false; 3262 } 3263 final int sz = cs.length(); 3264 for (int i = 0; i < sz; i++) { 3265 if (!Character.isLowerCase(cs.charAt(i))) { 3266 return false; 3267 } 3268 } 3269 return true; 3270 } 3271 3272 /** 3273 * <p>Checks if the CharSequence contains only uppercase characters.</p> 3274 * 3275 * <p>{@code null} will return {@code false}. 3276 * An empty String (length()=0) will return {@code false}.</p> 3277 * 3278 * <pre> 3279 * StringUtils.isAllUpperCase(null) = false 3280 * StringUtils.isAllUpperCase("") = false 3281 * StringUtils.isAllUpperCase(" ") = false 3282 * StringUtils.isAllUpperCase("ABC") = true 3283 * StringUtils.isAllUpperCase("aBC") = false 3284 * StringUtils.isAllUpperCase("A C") = false 3285 * StringUtils.isAllUpperCase("A1C") = false 3286 * StringUtils.isAllUpperCase("A/C") = false 3287 * </pre> 3288 * 3289 * @param cs the CharSequence to check, may be null 3290 * @return {@code true} if only contains uppercase characters, and is non-null 3291 * @since 2.5 3292 * @since 3.0 Changed signature from isAllUpperCase(String) to isAllUpperCase(CharSequence) 3293 */ 3294 public static boolean isAllUpperCase(final CharSequence cs) { 3295 if (isEmpty(cs)) { 3296 return false; 3297 } 3298 final int sz = cs.length(); 3299 for (int i = 0; i < sz; i++) { 3300 if (!Character.isUpperCase(cs.charAt(i))) { 3301 return false; 3302 } 3303 } 3304 return true; 3305 } 3306 3307 /** 3308 * <p>Checks if the CharSequence contains only Unicode letters.</p> 3309 * 3310 * <p>{@code null} will return {@code false}. 3311 * An empty CharSequence (length()=0) will return {@code false}.</p> 3312 * 3313 * <pre> 3314 * StringUtils.isAlpha(null) = false 3315 * StringUtils.isAlpha("") = false 3316 * StringUtils.isAlpha(" ") = false 3317 * StringUtils.isAlpha("abc") = true 3318 * StringUtils.isAlpha("ab2c") = false 3319 * StringUtils.isAlpha("ab-c") = false 3320 * </pre> 3321 * 3322 * @param cs the CharSequence to check, may be null 3323 * @return {@code true} if only contains letters, and is non-null 3324 * @since 3.0 Changed signature from isAlpha(String) to isAlpha(CharSequence) 3325 * @since 3.0 Changed "" to return false and not true 3326 */ 3327 public static boolean isAlpha(final CharSequence cs) { 3328 if (isEmpty(cs)) { 3329 return false; 3330 } 3331 final int sz = cs.length(); 3332 for (int i = 0; i < sz; i++) { 3333 if (!Character.isLetter(cs.charAt(i))) { 3334 return false; 3335 } 3336 } 3337 return true; 3338 } 3339 3340 /** 3341 * <p>Checks if the CharSequence contains only Unicode letters or digits.</p> 3342 * 3343 * <p>{@code null} will return {@code false}. 3344 * An empty CharSequence (length()=0) will return {@code false}.</p> 3345 * 3346 * <pre> 3347 * StringUtils.isAlphanumeric(null) = false 3348 * StringUtils.isAlphanumeric("") = false 3349 * StringUtils.isAlphanumeric(" ") = false 3350 * StringUtils.isAlphanumeric("abc") = true 3351 * StringUtils.isAlphanumeric("ab c") = false 3352 * StringUtils.isAlphanumeric("ab2c") = true 3353 * StringUtils.isAlphanumeric("ab-c") = false 3354 * </pre> 3355 * 3356 * @param cs the CharSequence to check, may be null 3357 * @return {@code true} if only contains letters or digits, 3358 * and is non-null 3359 * @since 3.0 Changed signature from isAlphanumeric(String) to isAlphanumeric(CharSequence) 3360 * @since 3.0 Changed "" to return false and not true 3361 */ 3362 public static boolean isAlphanumeric(final CharSequence cs) { 3363 if (isEmpty(cs)) { 3364 return false; 3365 } 3366 final int sz = cs.length(); 3367 for (int i = 0; i < sz; i++) { 3368 if (!Character.isLetterOrDigit(cs.charAt(i))) { 3369 return false; 3370 } 3371 } 3372 return true; 3373 } 3374 3375 /** 3376 * <p>Checks if the CharSequence contains only Unicode letters, digits 3377 * or space ({@code ' '}).</p> 3378 * 3379 * <p>{@code null} will return {@code false}. 3380 * An empty CharSequence (length()=0) will return {@code true}.</p> 3381 * 3382 * <pre> 3383 * StringUtils.isAlphanumericSpace(null) = false 3384 * StringUtils.isAlphanumericSpace("") = true 3385 * StringUtils.isAlphanumericSpace(" ") = true 3386 * StringUtils.isAlphanumericSpace("abc") = true 3387 * StringUtils.isAlphanumericSpace("ab c") = true 3388 * StringUtils.isAlphanumericSpace("ab2c") = true 3389 * StringUtils.isAlphanumericSpace("ab-c") = false 3390 * </pre> 3391 * 3392 * @param cs the CharSequence to check, may be null 3393 * @return {@code true} if only contains letters, digits or space, 3394 * and is non-null 3395 * @since 3.0 Changed signature from isAlphanumericSpace(String) to isAlphanumericSpace(CharSequence) 3396 */ 3397 public static boolean isAlphanumericSpace(final CharSequence cs) { 3398 if (cs == null) { 3399 return false; 3400 } 3401 final int sz = cs.length(); 3402 for (int i = 0; i < sz; i++) { 3403 final char nowChar = cs.charAt(i); 3404 if (nowChar != ' ' && !Character.isLetterOrDigit(nowChar) ) { 3405 return false; 3406 } 3407 } 3408 return true; 3409 } 3410 3411 /** 3412 * <p>Checks if the CharSequence contains only Unicode letters and 3413 * space (' ').</p> 3414 * 3415 * <p>{@code null} will return {@code false} 3416 * An empty CharSequence (length()=0) will return {@code true}.</p> 3417 * 3418 * <pre> 3419 * StringUtils.isAlphaSpace(null) = false 3420 * StringUtils.isAlphaSpace("") = true 3421 * StringUtils.isAlphaSpace(" ") = true 3422 * StringUtils.isAlphaSpace("abc") = true 3423 * StringUtils.isAlphaSpace("ab c") = true 3424 * StringUtils.isAlphaSpace("ab2c") = false 3425 * StringUtils.isAlphaSpace("ab-c") = false 3426 * </pre> 3427 * 3428 * @param cs the CharSequence to check, may be null 3429 * @return {@code true} if only contains letters and space, 3430 * and is non-null 3431 * @since 3.0 Changed signature from isAlphaSpace(String) to isAlphaSpace(CharSequence) 3432 */ 3433 public static boolean isAlphaSpace(final CharSequence cs) { 3434 if (cs == null) { 3435 return false; 3436 } 3437 final int sz = cs.length(); 3438 for (int i = 0; i < sz; i++) { 3439 final char nowChar = cs.charAt(i); 3440 if (nowChar != ' ' && !Character.isLetter(nowChar)) { 3441 return false; 3442 } 3443 } 3444 return true; 3445 } 3446 3447 /** 3448 * <p>Checks if any of the CharSequences are empty ("") or null or whitespace only.</p> 3449 * 3450 * <p>Whitespace is defined by {@link Character#isWhitespace(char)}.</p> 3451 * 3452 * <pre> 3453 * StringUtils.isAnyBlank((String) null) = true 3454 * StringUtils.isAnyBlank((String[]) null) = false 3455 * StringUtils.isAnyBlank(null, "foo") = true 3456 * StringUtils.isAnyBlank(null, null) = true 3457 * StringUtils.isAnyBlank("", "bar") = true 3458 * StringUtils.isAnyBlank("bob", "") = true 3459 * StringUtils.isAnyBlank(" bob ", null) = true 3460 * StringUtils.isAnyBlank(" ", "bar") = true 3461 * StringUtils.isAnyBlank(new String[] {}) = false 3462 * StringUtils.isAnyBlank(new String[]{""}) = true 3463 * StringUtils.isAnyBlank("foo", "bar") = false 3464 * </pre> 3465 * 3466 * @param css the CharSequences to check, may be null or empty 3467 * @return {@code true} if any of the CharSequences are empty or null or whitespace only 3468 * @since 3.2 3469 */ 3470 public static boolean isAnyBlank(final CharSequence... css) { 3471 if (ArrayUtils.isEmpty(css)) { 3472 return false; 3473 } 3474 for (final CharSequence cs : css) { 3475 if (isBlank(cs)) { 3476 return true; 3477 } 3478 } 3479 return false; 3480 } 3481 3482 /** 3483 * <p>Checks if any of the CharSequences are empty ("") or null.</p> 3484 * 3485 * <pre> 3486 * StringUtils.isAnyEmpty((String) null) = true 3487 * StringUtils.isAnyEmpty((String[]) null) = false 3488 * StringUtils.isAnyEmpty(null, "foo") = true 3489 * StringUtils.isAnyEmpty("", "bar") = true 3490 * StringUtils.isAnyEmpty("bob", "") = true 3491 * StringUtils.isAnyEmpty(" bob ", null) = true 3492 * StringUtils.isAnyEmpty(" ", "bar") = false 3493 * StringUtils.isAnyEmpty("foo", "bar") = false 3494 * StringUtils.isAnyEmpty(new String[]{}) = false 3495 * StringUtils.isAnyEmpty(new String[]{""}) = true 3496 * </pre> 3497 * 3498 * @param css the CharSequences to check, may be null or empty 3499 * @return {@code true} if any of the CharSequences are empty or null 3500 * @since 3.2 3501 */ 3502 public static boolean isAnyEmpty(final CharSequence... css) { 3503 if (ArrayUtils.isEmpty(css)) { 3504 return false; 3505 } 3506 for (final CharSequence cs : css) { 3507 if (isEmpty(cs)) { 3508 return true; 3509 } 3510 } 3511 return false; 3512 } 3513 3514 /** 3515 * <p>Checks if the CharSequence contains only ASCII printable characters.</p> 3516 * 3517 * <p>{@code null} will return {@code false}. 3518 * An empty CharSequence (length()=0) will return {@code true}.</p> 3519 * 3520 * <pre> 3521 * StringUtils.isAsciiPrintable(null) = false 3522 * StringUtils.isAsciiPrintable("") = true 3523 * StringUtils.isAsciiPrintable(" ") = true 3524 * StringUtils.isAsciiPrintable("Ceki") = true 3525 * StringUtils.isAsciiPrintable("ab2c") = true 3526 * StringUtils.isAsciiPrintable("!ab-c~") = true 3527 * StringUtils.isAsciiPrintable("\u0020") = true 3528 * StringUtils.isAsciiPrintable("\u0021") = true 3529 * StringUtils.isAsciiPrintable("\u007e") = true 3530 * StringUtils.isAsciiPrintable("\u007f") = false 3531 * StringUtils.isAsciiPrintable("Ceki G\u00fclc\u00fc") = false 3532 * </pre> 3533 * 3534 * @param cs the CharSequence to check, may be null 3535 * @return {@code true} if every character is in the range 3536 * 32 thru 126 3537 * @since 2.1 3538 * @since 3.0 Changed signature from isAsciiPrintable(String) to isAsciiPrintable(CharSequence) 3539 */ 3540 public static boolean isAsciiPrintable(final CharSequence cs) { 3541 if (cs == null) { 3542 return false; 3543 } 3544 final int sz = cs.length(); 3545 for (int i = 0; i < sz; i++) { 3546 if (!CharUtils.isAsciiPrintable(cs.charAt(i))) { 3547 return false; 3548 } 3549 } 3550 return true; 3551 } 3552 3553 /** 3554 * <p>Checks if a CharSequence is empty (""), null or whitespace only.</p> 3555 * 3556 * <p>Whitespace is defined by {@link Character#isWhitespace(char)}.</p> 3557 * 3558 * <pre> 3559 * StringUtils.isBlank(null) = true 3560 * StringUtils.isBlank("") = true 3561 * StringUtils.isBlank(" ") = true 3562 * StringUtils.isBlank("bob") = false 3563 * StringUtils.isBlank(" bob ") = false 3564 * </pre> 3565 * 3566 * @param cs the CharSequence to check, may be null 3567 * @return {@code true} if the CharSequence is null, empty or whitespace only 3568 * @since 2.0 3569 * @since 3.0 Changed signature from isBlank(String) to isBlank(CharSequence) 3570 */ 3571 public static boolean isBlank(final CharSequence cs) { 3572 final int strLen = length(cs); 3573 if (strLen == 0) { 3574 return true; 3575 } 3576 for (int i = 0; i < strLen; i++) { 3577 if (!Character.isWhitespace(cs.charAt(i))) { 3578 return false; 3579 } 3580 } 3581 return true; 3582 } 3583 3584 /** 3585 * <p>Checks if a CharSequence is empty ("") or null.</p> 3586 * 3587 * <pre> 3588 * StringUtils.isEmpty(null) = true 3589 * StringUtils.isEmpty("") = true 3590 * StringUtils.isEmpty(" ") = false 3591 * StringUtils.isEmpty("bob") = false 3592 * StringUtils.isEmpty(" bob ") = false 3593 * </pre> 3594 * 3595 * <p>NOTE: This method changed in Lang version 2.0. 3596 * It no longer trims the CharSequence. 3597 * That functionality is available in isBlank().</p> 3598 * 3599 * @param cs the CharSequence to check, may be null 3600 * @return {@code true} if the CharSequence is empty or null 3601 * @since 3.0 Changed signature from isEmpty(String) to isEmpty(CharSequence) 3602 */ 3603 public static boolean isEmpty(final CharSequence cs) { 3604 return cs == null || cs.length() == 0; 3605 } 3606 3607 /** 3608 * <p>Checks if the CharSequence contains mixed casing of both uppercase and lowercase characters.</p> 3609 * 3610 * <p>{@code null} will return {@code false}. An empty CharSequence ({@code length()=0}) will return 3611 * {@code false}.</p> 3612 * 3613 * <pre> 3614 * StringUtils.isMixedCase(null) = false 3615 * StringUtils.isMixedCase("") = false 3616 * StringUtils.isMixedCase("ABC") = false 3617 * StringUtils.isMixedCase("abc") = false 3618 * StringUtils.isMixedCase("aBc") = true 3619 * StringUtils.isMixedCase("A c") = true 3620 * StringUtils.isMixedCase("A1c") = true 3621 * StringUtils.isMixedCase("a/C") = true 3622 * StringUtils.isMixedCase("aC\t") = true 3623 * </pre> 3624 * 3625 * @param cs the CharSequence to check, may be null 3626 * @return {@code true} if the CharSequence contains both uppercase and lowercase characters 3627 * @since 3.5 3628 */ 3629 public static boolean isMixedCase(final CharSequence cs) { 3630 if (isEmpty(cs) || cs.length() == 1) { 3631 return false; 3632 } 3633 boolean containsUppercase = false; 3634 boolean containsLowercase = false; 3635 final int sz = cs.length(); 3636 for (int i = 0; i < sz; i++) { 3637 if (containsUppercase && containsLowercase) { 3638 return true; 3639 } else if (Character.isUpperCase(cs.charAt(i))) { 3640 containsUppercase = true; 3641 } else if (Character.isLowerCase(cs.charAt(i))) { 3642 containsLowercase = true; 3643 } 3644 } 3645 return containsUppercase && containsLowercase; 3646 } 3647 3648 /** 3649 * <p>Checks if none of the CharSequences are empty (""), null or whitespace only.</p> 3650 * 3651 * <p>Whitespace is defined by {@link Character#isWhitespace(char)}.</p> 3652 * 3653 * <pre> 3654 * StringUtils.isNoneBlank((String) null) = false 3655 * StringUtils.isNoneBlank((String[]) null) = true 3656 * StringUtils.isNoneBlank(null, "foo") = false 3657 * StringUtils.isNoneBlank(null, null) = false 3658 * StringUtils.isNoneBlank("", "bar") = false 3659 * StringUtils.isNoneBlank("bob", "") = false 3660 * StringUtils.isNoneBlank(" bob ", null) = false 3661 * StringUtils.isNoneBlank(" ", "bar") = false 3662 * StringUtils.isNoneBlank(new String[] {}) = true 3663 * StringUtils.isNoneBlank(new String[]{""}) = false 3664 * StringUtils.isNoneBlank("foo", "bar") = true 3665 * </pre> 3666 * 3667 * @param css the CharSequences to check, may be null or empty 3668 * @return {@code true} if none of the CharSequences are empty or null or whitespace only 3669 * @since 3.2 3670 */ 3671 public static boolean isNoneBlank(final CharSequence... css) { 3672 return !isAnyBlank(css); 3673 } 3674 3675 /** 3676 * <p>Checks if none of the CharSequences are empty ("") or null.</p> 3677 * 3678 * <pre> 3679 * StringUtils.isNoneEmpty((String) null) = false 3680 * StringUtils.isNoneEmpty((String[]) null) = true 3681 * StringUtils.isNoneEmpty(null, "foo") = false 3682 * StringUtils.isNoneEmpty("", "bar") = false 3683 * StringUtils.isNoneEmpty("bob", "") = false 3684 * StringUtils.isNoneEmpty(" bob ", null) = false 3685 * StringUtils.isNoneEmpty(new String[] {}) = true 3686 * StringUtils.isNoneEmpty(new String[]{""}) = false 3687 * StringUtils.isNoneEmpty(" ", "bar") = true 3688 * StringUtils.isNoneEmpty("foo", "bar") = true 3689 * </pre> 3690 * 3691 * @param css the CharSequences to check, may be null or empty 3692 * @return {@code true} if none of the CharSequences are empty or null 3693 * @since 3.2 3694 */ 3695 public static boolean isNoneEmpty(final CharSequence... css) { 3696 return !isAnyEmpty(css); 3697 } 3698 3699 /** 3700 * <p>Checks if a CharSequence is not empty (""), not null and not whitespace only.</p> 3701 * 3702 * <p>Whitespace is defined by {@link Character#isWhitespace(char)}.</p> 3703 * 3704 * <pre> 3705 * StringUtils.isNotBlank(null) = false 3706 * StringUtils.isNotBlank("") = false 3707 * StringUtils.isNotBlank(" ") = false 3708 * StringUtils.isNotBlank("bob") = true 3709 * StringUtils.isNotBlank(" bob ") = true 3710 * </pre> 3711 * 3712 * @param cs the CharSequence to check, may be null 3713 * @return {@code true} if the CharSequence is 3714 * not empty and not null and not whitespace only 3715 * @since 2.0 3716 * @since 3.0 Changed signature from isNotBlank(String) to isNotBlank(CharSequence) 3717 */ 3718 public static boolean isNotBlank(final CharSequence cs) { 3719 return !isBlank(cs); 3720 } 3721 3722 /** 3723 * <p>Checks if a CharSequence is not empty ("") and not null.</p> 3724 * 3725 * <pre> 3726 * StringUtils.isNotEmpty(null) = false 3727 * StringUtils.isNotEmpty("") = false 3728 * StringUtils.isNotEmpty(" ") = true 3729 * StringUtils.isNotEmpty("bob") = true 3730 * StringUtils.isNotEmpty(" bob ") = true 3731 * </pre> 3732 * 3733 * @param cs the CharSequence to check, may be null 3734 * @return {@code true} if the CharSequence is not empty and not null 3735 * @since 3.0 Changed signature from isNotEmpty(String) to isNotEmpty(CharSequence) 3736 */ 3737 public static boolean isNotEmpty(final CharSequence cs) { 3738 return !isEmpty(cs); 3739 } 3740 3741 /** 3742 * <p>Checks if the CharSequence contains only Unicode digits. 3743 * A decimal point is not a Unicode digit and returns false.</p> 3744 * 3745 * <p>{@code null} will return {@code false}. 3746 * An empty CharSequence (length()=0) will return {@code false}.</p> 3747 * 3748 * <p>Note that the method does not allow for a leading sign, either positive or negative. 3749 * Also, if a String passes the numeric test, it may still generate a NumberFormatException 3750 * when parsed by Integer.parseInt or Long.parseLong, e.g. if the value is outside the range 3751 * for int or long respectively.</p> 3752 * 3753 * <pre> 3754 * StringUtils.isNumeric(null) = false 3755 * StringUtils.isNumeric("") = false 3756 * StringUtils.isNumeric(" ") = false 3757 * StringUtils.isNumeric("123") = true 3758 * StringUtils.isNumeric("\u0967\u0968\u0969") = true 3759 * StringUtils.isNumeric("12 3") = false 3760 * StringUtils.isNumeric("ab2c") = false 3761 * StringUtils.isNumeric("12-3") = false 3762 * StringUtils.isNumeric("12.3") = false 3763 * StringUtils.isNumeric("-123") = false 3764 * StringUtils.isNumeric("+123") = false 3765 * </pre> 3766 * 3767 * @param cs the CharSequence to check, may be null 3768 * @return {@code true} if only contains digits, and is non-null 3769 * @since 3.0 Changed signature from isNumeric(String) to isNumeric(CharSequence) 3770 * @since 3.0 Changed "" to return false and not true 3771 */ 3772 public static boolean isNumeric(final CharSequence cs) { 3773 if (isEmpty(cs)) { 3774 return false; 3775 } 3776 final int sz = cs.length(); 3777 for (int i = 0; i < sz; i++) { 3778 if (!Character.isDigit(cs.charAt(i))) { 3779 return false; 3780 } 3781 } 3782 return true; 3783 } 3784 3785 /** 3786 * <p>Checks if the CharSequence contains only Unicode digits or space 3787 * ({@code ' '}). 3788 * A decimal point is not a Unicode digit and returns false.</p> 3789 * 3790 * <p>{@code null} will return {@code false}. 3791 * An empty CharSequence (length()=0) will return {@code true}.</p> 3792 * 3793 * <pre> 3794 * StringUtils.isNumericSpace(null) = false 3795 * StringUtils.isNumericSpace("") = true 3796 * StringUtils.isNumericSpace(" ") = true 3797 * StringUtils.isNumericSpace("123") = true 3798 * StringUtils.isNumericSpace("12 3") = true 3799 * StringUtils.isNumericSpace("\u0967\u0968\u0969") = true 3800 * StringUtils.isNumericSpace("\u0967\u0968 \u0969") = true 3801 * StringUtils.isNumericSpace("ab2c") = false 3802 * StringUtils.isNumericSpace("12-3") = false 3803 * StringUtils.isNumericSpace("12.3") = false 3804 * </pre> 3805 * 3806 * @param cs the CharSequence to check, may be null 3807 * @return {@code true} if only contains digits or space, 3808 * and is non-null 3809 * @since 3.0 Changed signature from isNumericSpace(String) to isNumericSpace(CharSequence) 3810 */ 3811 public static boolean isNumericSpace(final CharSequence cs) { 3812 if (cs == null) { 3813 return false; 3814 } 3815 final int sz = cs.length(); 3816 for (int i = 0; i < sz; i++) { 3817 final char nowChar = cs.charAt(i); 3818 if (nowChar != ' ' && !Character.isDigit(nowChar)) { 3819 return false; 3820 } 3821 } 3822 return true; 3823 } 3824 3825 /** 3826 * <p>Checks if the CharSequence contains only whitespace.</p> 3827 * 3828 * <p>Whitespace is defined by {@link Character#isWhitespace(char)}.</p> 3829 * 3830 * <p>{@code null} will return {@code false}. 3831 * An empty CharSequence (length()=0) will return {@code true}.</p> 3832 * 3833 * <pre> 3834 * StringUtils.isWhitespace(null) = false 3835 * StringUtils.isWhitespace("") = true 3836 * StringUtils.isWhitespace(" ") = true 3837 * StringUtils.isWhitespace("abc") = false 3838 * StringUtils.isWhitespace("ab2c") = false 3839 * StringUtils.isWhitespace("ab-c") = false 3840 * </pre> 3841 * 3842 * @param cs the CharSequence to check, may be null 3843 * @return {@code true} if only contains whitespace, and is non-null 3844 * @since 2.0 3845 * @since 3.0 Changed signature from isWhitespace(String) to isWhitespace(CharSequence) 3846 */ 3847 public static boolean isWhitespace(final CharSequence cs) { 3848 if (cs == null) { 3849 return false; 3850 } 3851 final int sz = cs.length(); 3852 for (int i = 0; i < sz; i++) { 3853 if (!Character.isWhitespace(cs.charAt(i))) { 3854 return false; 3855 } 3856 } 3857 return true; 3858 } 3859 3860 /** 3861 * <p> 3862 * Joins the elements of the provided array into a single String containing the provided list of elements. 3863 * </p> 3864 * 3865 * <p> 3866 * No delimiter is added before or after the list. Null objects or empty strings within the array are represented 3867 * by empty strings. 3868 * </p> 3869 * 3870 * <pre> 3871 * StringUtils.join(null, *) = null 3872 * StringUtils.join([], *) = "" 3873 * StringUtils.join([null], *) = "" 3874 * StringUtils.join([false, false], ';') = "false;false" 3875 * </pre> 3876 * 3877 * @param array 3878 * the array of values to join together, may be null 3879 * @param delimiter 3880 * the separator character to use 3881 * @return the joined String, {@code null} if null array input 3882 * @since 3.12.0 3883 */ 3884 public static String join(final boolean[] array, final char delimiter) { 3885 if (array == null) { 3886 return null; 3887 } 3888 return join(array, delimiter, 0, array.length); 3889 } 3890 3891 /** 3892 * <p> 3893 * Joins the elements of the provided array into a single String containing the provided list of elements. 3894 * </p> 3895 * 3896 * <p> 3897 * No delimiter is added before or after the list. Null objects or empty strings within the array are represented 3898 * by empty strings. 3899 * </p> 3900 * 3901 * <pre> 3902 * StringUtils.join(null, *) = null 3903 * StringUtils.join([], *) = "" 3904 * StringUtils.join([null], *) = "" 3905 * StringUtils.join([true, false, true], ';') = "true;false;true" 3906 * </pre> 3907 * 3908 * @param array 3909 * the array of values to join together, may be null 3910 * @param delimiter 3911 * the separator character to use 3912 * @param startIndex 3913 * the first index to start joining from. It is an error to pass in a start index past the end of the 3914 * array 3915 * @param endIndex 3916 * the index to stop joining from (exclusive). It is an error to pass in an end index past the end of 3917 * the array 3918 * @return the joined String, {@code null} if null array input 3919 * @since 3.12.0 3920 */ 3921 public static String join(final boolean[] array, final char delimiter, final int startIndex, final int endIndex) { 3922 if (array == null) { 3923 return null; 3924 } 3925 if (endIndex - startIndex <= 0) { 3926 return EMPTY; 3927 } 3928 final StringJoiner joiner = newStringJoiner(delimiter); 3929 for (int i = startIndex; i < endIndex; i++) { 3930 joiner.add(String.valueOf(array[i])); 3931 } 3932 return joiner.toString(); 3933 } 3934 3935 /** 3936 * <p> 3937 * Joins the elements of the provided array into a single String containing the provided list of elements. 3938 * </p> 3939 * 3940 * <p> 3941 * No delimiter is added before or after the list. Null objects or empty strings within the array are represented 3942 * by empty strings. 3943 * </p> 3944 * 3945 * <pre> 3946 * StringUtils.join(null, *) = null 3947 * StringUtils.join([], *) = "" 3948 * StringUtils.join([null], *) = "" 3949 * StringUtils.join([1, 2, 3], ';') = "1;2;3" 3950 * StringUtils.join([1, 2, 3], null) = "123" 3951 * </pre> 3952 * 3953 * @param array 3954 * the array of values to join together, may be null 3955 * @param delimiter 3956 * the separator character to use 3957 * @return the joined String, {@code null} if null array input 3958 * @since 3.2 3959 */ 3960 public static String join(final byte[] array, final char delimiter) { 3961 if (array == null) { 3962 return null; 3963 } 3964 return join(array, delimiter, 0, array.length); 3965 } 3966 3967 /** 3968 * <p> 3969 * Joins the elements of the provided array into a single String containing the provided list of elements. 3970 * </p> 3971 * 3972 * <p> 3973 * No delimiter is added before or after the list. Null objects or empty strings within the array are represented 3974 * by empty strings. 3975 * </p> 3976 * 3977 * <pre> 3978 * StringUtils.join(null, *) = null 3979 * StringUtils.join([], *) = "" 3980 * StringUtils.join([null], *) = "" 3981 * StringUtils.join([1, 2, 3], ';') = "1;2;3" 3982 * StringUtils.join([1, 2, 3], null) = "123" 3983 * </pre> 3984 * 3985 * @param array 3986 * the array of values to join together, may be null 3987 * @param delimiter 3988 * the separator character to use 3989 * @param startIndex 3990 * the first index to start joining from. It is an error to pass in a start index past the end of the 3991 * array 3992 * @param endIndex 3993 * the index to stop joining from (exclusive). It is an error to pass in an end index past the end of 3994 * the array 3995 * @return the joined String, {@code null} if null array input 3996 * @since 3.2 3997 */ 3998 public static String join(final byte[] array, final char delimiter, final int startIndex, final int endIndex) { 3999 if (array == null) { 4000 return null; 4001 } 4002 if (endIndex - startIndex <= 0) { 4003 return EMPTY; 4004 } 4005 final StringJoiner joiner = newStringJoiner(delimiter); 4006 for (int i = startIndex; i < endIndex; i++) { 4007 joiner.add(String.valueOf(array[i])); 4008 } 4009 return joiner.toString(); 4010 } 4011 4012 /** 4013 * <p> 4014 * Joins the elements of the provided array into a single String containing the provided list of elements. 4015 * </p> 4016 * 4017 * <p> 4018 * No delimiter is added before or after the list. Null objects or empty strings within the array are represented 4019 * by empty strings. 4020 * </p> 4021 * 4022 * <pre> 4023 * StringUtils.join(null, *) = null 4024 * StringUtils.join([], *) = "" 4025 * StringUtils.join([null], *) = "" 4026 * StringUtils.join([1, 2, 3], ';') = "1;2;3" 4027 * StringUtils.join([1, 2, 3], null) = "123" 4028 * </pre> 4029 * 4030 * @param array 4031 * the array of values to join together, may be null 4032 * @param delimiter 4033 * the separator character to use 4034 * @return the joined String, {@code null} if null array input 4035 * @since 3.2 4036 */ 4037 public static String join(final char[] array, final char delimiter) { 4038 if (array == null) { 4039 return null; 4040 } 4041 return join(array, delimiter, 0, array.length); 4042 } 4043 4044 /** 4045 * <p> 4046 * Joins the elements of the provided array into a single String containing the provided list of elements. 4047 * </p> 4048 * 4049 * <p> 4050 * No delimiter is added before or after the list. Null objects or empty strings within the array are represented 4051 * by empty strings. 4052 * </p> 4053 * 4054 * <pre> 4055 * StringUtils.join(null, *) = null 4056 * StringUtils.join([], *) = "" 4057 * StringUtils.join([null], *) = "" 4058 * StringUtils.join([1, 2, 3], ';') = "1;2;3" 4059 * StringUtils.join([1, 2, 3], null) = "123" 4060 * </pre> 4061 * 4062 * @param array 4063 * the array of values to join together, may be null 4064 * @param delimiter 4065 * the separator character to use 4066 * @param startIndex 4067 * the first index to start joining from. It is an error to pass in a start index past the end of the 4068 * array 4069 * @param endIndex 4070 * the index to stop joining from (exclusive). It is an error to pass in an end index past the end of 4071 * the array 4072 * @return the joined String, {@code null} if null array input 4073 * @since 3.2 4074 */ 4075 public static String join(final char[] array, final char delimiter, final int startIndex, final int endIndex) { 4076 if (array == null) { 4077 return null; 4078 } 4079 if (endIndex - startIndex <= 0) { 4080 return EMPTY; 4081 } 4082 final StringJoiner joiner = newStringJoiner(delimiter); 4083 for (int i = startIndex; i < endIndex; i++) { 4084 joiner.add(String.valueOf(array[i])); 4085 } 4086 return joiner.toString(); 4087 } 4088 4089 /** 4090 * <p> 4091 * Joins the elements of the provided array into a single String containing the provided list of elements. 4092 * </p> 4093 * 4094 * <p> 4095 * No delimiter is added before or after the list. Null objects or empty strings within the array are represented 4096 * by empty strings. 4097 * </p> 4098 * 4099 * <pre> 4100 * StringUtils.join(null, *) = null 4101 * StringUtils.join([], *) = "" 4102 * StringUtils.join([null], *) = "" 4103 * StringUtils.join([1, 2, 3], ';') = "1;2;3" 4104 * StringUtils.join([1, 2, 3], null) = "123" 4105 * </pre> 4106 * 4107 * @param array 4108 * the array of values to join together, may be null 4109 * @param delimiter 4110 * the separator character to use 4111 * @return the joined String, {@code null} if null array input 4112 * @since 3.2 4113 */ 4114 public static String join(final double[] array, final char delimiter) { 4115 if (array == null) { 4116 return null; 4117 } 4118 return join(array, delimiter, 0, array.length); 4119 } 4120 4121 /** 4122 * <p> 4123 * Joins the elements of the provided array into a single String containing the provided list of elements. 4124 * </p> 4125 * 4126 * <p> 4127 * No delimiter is added before or after the list. Null objects or empty strings within the array are represented 4128 * by empty strings. 4129 * </p> 4130 * 4131 * <pre> 4132 * StringUtils.join(null, *) = null 4133 * StringUtils.join([], *) = "" 4134 * StringUtils.join([null], *) = "" 4135 * StringUtils.join([1, 2, 3], ';') = "1;2;3" 4136 * StringUtils.join([1, 2, 3], null) = "123" 4137 * </pre> 4138 * 4139 * @param array 4140 * the array of values to join together, may be null 4141 * @param delimiter 4142 * the separator character to use 4143 * @param startIndex 4144 * the first index to start joining from. It is an error to pass in a start index past the end of the 4145 * array 4146 * @param endIndex 4147 * the index to stop joining from (exclusive). It is an error to pass in an end index past the end of 4148 * the array 4149 * @return the joined String, {@code null} if null array input 4150 * @since 3.2 4151 */ 4152 public static String join(final double[] array, final char delimiter, final int startIndex, final int endIndex) { 4153 if (array == null) { 4154 return null; 4155 } 4156 if (endIndex - startIndex <= 0) { 4157 return EMPTY; 4158 } 4159 final StringJoiner joiner = newStringJoiner(delimiter); 4160 for (int i = startIndex; i < endIndex; i++) { 4161 joiner.add(String.valueOf(array[i])); 4162 } 4163 return joiner.toString(); 4164 } 4165 4166 /** 4167 * <p> 4168 * Joins the elements of the provided array into a single String containing the provided list of elements. 4169 * </p> 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 * @return the joined String, {@code null} if null array input 4189 * @since 3.2 4190 */ 4191 public static String join(final float[] array, final char delimiter) { 4192 if (array == null) { 4193 return null; 4194 } 4195 return join(array, delimiter, 0, array.length); 4196 } 4197 4198 /** 4199 * <p> 4200 * Joins the elements of the provided array into a single String containing the provided list of elements. 4201 * </p> 4202 * 4203 * <p> 4204 * No delimiter is added before or after the list. Null objects or empty strings within the array are represented 4205 * by empty strings. 4206 * </p> 4207 * 4208 * <pre> 4209 * StringUtils.join(null, *) = null 4210 * StringUtils.join([], *) = "" 4211 * StringUtils.join([null], *) = "" 4212 * StringUtils.join([1, 2, 3], ';') = "1;2;3" 4213 * StringUtils.join([1, 2, 3], null) = "123" 4214 * </pre> 4215 * 4216 * @param array 4217 * the array of values to join together, may be null 4218 * @param delimiter 4219 * the separator character to use 4220 * @param startIndex 4221 * the first index to start joining from. It is an error to pass in a start index past the end of the 4222 * array 4223 * @param endIndex 4224 * the index to stop joining from (exclusive). It is an error to pass in an end index past the end of 4225 * the array 4226 * @return the joined String, {@code null} if null array input 4227 * @since 3.2 4228 */ 4229 public static String join(final float[] array, final char delimiter, final int startIndex, final int endIndex) { 4230 if (array == null) { 4231 return null; 4232 } 4233 if (endIndex - startIndex <= 0) { 4234 return EMPTY; 4235 } 4236 final StringJoiner joiner = newStringJoiner(delimiter); 4237 for (int i = startIndex; i < endIndex; i++) { 4238 joiner.add(String.valueOf(array[i])); 4239 } 4240 return joiner.toString(); 4241 } 4242 4243 /** 4244 * <p> 4245 * Joins the elements of the provided array into a single String containing the provided list of elements. 4246 * </p> 4247 * 4248 * <p> 4249 * No delimiter is added before or after the list. Null objects or empty strings within the array are represented 4250 * by empty strings. 4251 * </p> 4252 * 4253 * <pre> 4254 * StringUtils.join(null, *) = null 4255 * StringUtils.join([], *) = "" 4256 * StringUtils.join([null], *) = "" 4257 * StringUtils.join([1, 2, 3], ';') = "1;2;3" 4258 * StringUtils.join([1, 2, 3], null) = "123" 4259 * </pre> 4260 * 4261 * @param array 4262 * the array of values to join together, may be null 4263 * @param separator 4264 * the separator character to use 4265 * @return the joined String, {@code null} if null array input 4266 * @since 3.2 4267 */ 4268 public static String join(final int[] array, final char separator) { 4269 if (array == null) { 4270 return null; 4271 } 4272 return join(array, separator, 0, array.length); 4273 } 4274 4275 /** 4276 * <p> 4277 * Joins the elements of the provided array into a single String containing the provided list of elements. 4278 * </p> 4279 * 4280 * <p> 4281 * No delimiter is added before or after the list. Null objects or empty strings within the array are represented 4282 * by empty strings. 4283 * </p> 4284 * 4285 * <pre> 4286 * StringUtils.join(null, *) = null 4287 * StringUtils.join([], *) = "" 4288 * StringUtils.join([null], *) = "" 4289 * StringUtils.join([1, 2, 3], ';') = "1;2;3" 4290 * StringUtils.join([1, 2, 3], null) = "123" 4291 * </pre> 4292 * 4293 * @param array 4294 * the array of values to join together, may be null 4295 * @param delimiter 4296 * the separator character to use 4297 * @param startIndex 4298 * the first index to start joining from. It is an error to pass in a start index past the end of the 4299 * array 4300 * @param endIndex 4301 * the index to stop joining from (exclusive). It is an error to pass in an end index past the end of 4302 * the array 4303 * @return the joined String, {@code null} if null array input 4304 * @since 3.2 4305 */ 4306 public static String join(final int[] array, final char delimiter, final int startIndex, final int endIndex) { 4307 if (array == null) { 4308 return null; 4309 } 4310 if (endIndex - startIndex <= 0) { 4311 return EMPTY; 4312 } 4313 final StringJoiner joiner = newStringJoiner(delimiter); 4314 for (int i = startIndex; i < endIndex; i++) { 4315 joiner.add(String.valueOf(array[i])); 4316 } 4317 return joiner.toString(); 4318 } 4319 4320 /** 4321 * <p>Joins the elements of the provided {@code Iterable} into 4322 * a single String containing the provided elements.</p> 4323 * 4324 * <p>No delimiter is added before or after the list. Null objects or empty 4325 * strings within the iteration are represented by empty strings.</p> 4326 * 4327 * <p>See the examples here: {@link #join(Object[],char)}. </p> 4328 * 4329 * @param iterable the {@code Iterable} providing the values to join together, may be null 4330 * @param separator the separator character to use 4331 * @return the joined String, {@code null} if null iterator input 4332 * @since 2.3 4333 */ 4334 public static String join(final Iterable<?> iterable, final char separator) { 4335 if (iterable == null) { 4336 return null; 4337 } 4338 return join(iterable.iterator(), separator); 4339 } 4340 4341 /** 4342 * <p>Joins the elements of the provided {@code Iterable} into 4343 * a single String containing the provided elements.</p> 4344 * 4345 * <p>No delimiter is added before or after the list. 4346 * A {@code null} separator is the same as an empty String ("").</p> 4347 * 4348 * <p>See the examples here: {@link #join(Object[],String)}. </p> 4349 * 4350 * @param iterable the {@code Iterable} providing the values to join together, may be null 4351 * @param separator the separator character to use, null treated as "" 4352 * @return the joined String, {@code null} if null iterator input 4353 * @since 2.3 4354 */ 4355 public static String join(final Iterable<?> iterable, final String separator) { 4356 if (iterable == null) { 4357 return null; 4358 } 4359 return join(iterable.iterator(), separator); 4360 } 4361 4362 /** 4363 * <p>Joins the elements of the provided {@code Iterator} into 4364 * a single String containing the provided elements.</p> 4365 * 4366 * <p>No delimiter is added before or after the list. Null objects or empty 4367 * strings within the iteration are represented by empty strings.</p> 4368 * 4369 * <p>See the examples here: {@link #join(Object[],char)}. </p> 4370 * 4371 * @param iterator the {@code Iterator} of values to join together, may be null 4372 * @param separator the separator character to use 4373 * @return the joined String, {@code null} if null iterator input 4374 * @since 2.0 4375 */ 4376 public static String join(final Iterator<?> iterator, final char separator) { 4377 4378 // handle null, zero and one elements before building a buffer 4379 if (iterator == null) { 4380 return null; 4381 } 4382 if (!iterator.hasNext()) { 4383 return EMPTY; 4384 } 4385 final Object first = iterator.next(); 4386 if (!iterator.hasNext()) { 4387 return toStringOrEmpty(first); 4388 } 4389 4390 // two or more elements 4391 final StringBuilder buf = new StringBuilder(STRING_BUILDER_SIZE); // Java default is 16, probably too small 4392 if (first != null) { 4393 buf.append(first); 4394 } 4395 4396 while (iterator.hasNext()) { 4397 buf.append(separator); 4398 final Object obj = iterator.next(); 4399 if (obj != null) { 4400 buf.append(obj); 4401 } 4402 } 4403 4404 return buf.toString(); 4405 } 4406 4407 /** 4408 * <p>Joins the elements of the provided {@code Iterator} into 4409 * a single String containing the provided elements.</p> 4410 * 4411 * <p>No delimiter is added before or after the list. 4412 * A {@code null} separator is the same as an empty String ("").</p> 4413 * 4414 * <p>See the examples here: {@link #join(Object[],String)}. </p> 4415 * 4416 * @param iterator the {@code Iterator} of values to join together, may be null 4417 * @param separator the separator character to use, null treated as "" 4418 * @return the joined String, {@code null} if null iterator input 4419 */ 4420 public static String join(final Iterator<?> iterator, final String separator) { 4421 4422 // handle null, zero and one elements before building a buffer 4423 if (iterator == null) { 4424 return null; 4425 } 4426 if (!iterator.hasNext()) { 4427 return EMPTY; 4428 } 4429 final Object first = iterator.next(); 4430 if (!iterator.hasNext()) { 4431 return Objects.toString(first, ""); 4432 } 4433 4434 // two or more elements 4435 final StringBuilder buf = new StringBuilder(STRING_BUILDER_SIZE); // Java default is 16, probably too small 4436 if (first != null) { 4437 buf.append(first); 4438 } 4439 4440 while (iterator.hasNext()) { 4441 if (separator != null) { 4442 buf.append(separator); 4443 } 4444 final Object obj = iterator.next(); 4445 if (obj != null) { 4446 buf.append(obj); 4447 } 4448 } 4449 return buf.toString(); 4450 } 4451 4452 /** 4453 * <p>Joins the elements of the provided {@code List} into a single String 4454 * containing the provided list of elements.</p> 4455 * 4456 * <p>No delimiter is added before or after the list. 4457 * Null objects or empty strings within the array are represented by 4458 * empty strings.</p> 4459 * 4460 * <pre> 4461 * StringUtils.join(null, *) = null 4462 * StringUtils.join([], *) = "" 4463 * StringUtils.join([null], *) = "" 4464 * StringUtils.join(["a", "b", "c"], ';') = "a;b;c" 4465 * StringUtils.join(["a", "b", "c"], null) = "abc" 4466 * StringUtils.join([null, "", "a"], ';') = ";;a" 4467 * </pre> 4468 * 4469 * @param list the {@code List} of values to join together, may be null 4470 * @param separator the separator character to use 4471 * @param startIndex the first index to start joining from. It is 4472 * an error to pass in a start index past the end of the list 4473 * @param endIndex the index to stop joining from (exclusive). It is 4474 * an error to pass in an end index past the end of the list 4475 * @return the joined String, {@code null} if null list input 4476 * @since 3.8 4477 */ 4478 public static String join(final List<?> list, final char separator, final int startIndex, final int endIndex) { 4479 if (list == null) { 4480 return null; 4481 } 4482 final int noOfItems = endIndex - startIndex; 4483 if (noOfItems <= 0) { 4484 return EMPTY; 4485 } 4486 final List<?> subList = list.subList(startIndex, endIndex); 4487 return join(subList.iterator(), separator); 4488 } 4489 4490 /** 4491 * <p>Joins the elements of the provided {@code List} into a single String 4492 * containing the provided list of elements.</p> 4493 * 4494 * <p>No delimiter is added before or after the list. 4495 * Null objects or empty strings within the array are represented by 4496 * empty strings.</p> 4497 * 4498 * <pre> 4499 * StringUtils.join(null, *) = null 4500 * StringUtils.join([], *) = "" 4501 * StringUtils.join([null], *) = "" 4502 * StringUtils.join(["a", "b", "c"], ';') = "a;b;c" 4503 * StringUtils.join(["a", "b", "c"], null) = "abc" 4504 * StringUtils.join([null, "", "a"], ';') = ";;a" 4505 * </pre> 4506 * 4507 * @param list the {@code List} of values to join together, may be null 4508 * @param separator the separator character to use 4509 * @param startIndex the first index to start joining from. It is 4510 * an error to pass in a start index past the end of the list 4511 * @param endIndex the index to stop joining from (exclusive). It is 4512 * an error to pass in an end index past the end of the list 4513 * @return the joined String, {@code null} if null list input 4514 * @since 3.8 4515 */ 4516 public static String join(final List<?> list, final String separator, final int startIndex, final int endIndex) { 4517 if (list == null) { 4518 return null; 4519 } 4520 final int noOfItems = endIndex - startIndex; 4521 if (noOfItems <= 0) { 4522 return EMPTY; 4523 } 4524 final List<?> subList = list.subList(startIndex, endIndex); 4525 return join(subList.iterator(), separator); 4526 } 4527 4528 4529 /** 4530 * <p> 4531 * Joins the elements of the provided array into a single String containing the provided list of elements. 4532 * </p> 4533 * 4534 * <p> 4535 * No delimiter is added before or after the list. Null objects or empty strings within the array are represented 4536 * by empty strings. 4537 * </p> 4538 * 4539 * <pre> 4540 * StringUtils.join(null, *) = null 4541 * StringUtils.join([], *) = "" 4542 * StringUtils.join([null], *) = "" 4543 * StringUtils.join([1, 2, 3], ';') = "1;2;3" 4544 * StringUtils.join([1, 2, 3], null) = "123" 4545 * </pre> 4546 * 4547 * @param array 4548 * the array of values to join together, may be null 4549 * @param separator 4550 * the separator character to use 4551 * @return the joined String, {@code null} if null array input 4552 * @since 3.2 4553 */ 4554 public static String join(final long[] array, final char separator) { 4555 if (array == null) { 4556 return null; 4557 } 4558 return join(array, separator, 0, array.length); 4559 } 4560 4561 /** 4562 * <p> 4563 * Joins the elements of the provided array into a single String containing the provided list of elements. 4564 * </p> 4565 * 4566 * <p> 4567 * No delimiter is added before or after the list. Null objects or empty strings within the array are represented 4568 * by empty strings. 4569 * </p> 4570 * 4571 * <pre> 4572 * StringUtils.join(null, *) = null 4573 * StringUtils.join([], *) = "" 4574 * StringUtils.join([null], *) = "" 4575 * StringUtils.join([1, 2, 3], ';') = "1;2;3" 4576 * StringUtils.join([1, 2, 3], null) = "123" 4577 * </pre> 4578 * 4579 * @param array 4580 * the array of values to join together, may be null 4581 * @param delimiter 4582 * the separator character to use 4583 * @param startIndex 4584 * the first index to start joining from. It is an error to pass in a start index past the end of the 4585 * array 4586 * @param endIndex 4587 * the index to stop joining from (exclusive). It is an error to pass in an end index past the end of 4588 * the array 4589 * @return the joined String, {@code null} if null array input 4590 * @since 3.2 4591 */ 4592 public static String join(final long[] array, final char delimiter, final int startIndex, final int endIndex) { 4593 if (array == null) { 4594 return null; 4595 } 4596 if (endIndex - startIndex <= 0) { 4597 return EMPTY; 4598 } 4599 final StringJoiner joiner = newStringJoiner(delimiter); 4600 for (int i = startIndex; i < endIndex; i++) { 4601 joiner.add(String.valueOf(array[i])); 4602 } 4603 return joiner.toString(); 4604 } 4605 4606 /** 4607 * <p>Joins the elements of the provided array into a single String 4608 * containing the provided list of elements.</p> 4609 * 4610 * <p>No delimiter is added before or after the list. 4611 * Null objects or empty strings within the array are represented by 4612 * empty strings.</p> 4613 * 4614 * <pre> 4615 * StringUtils.join(null, *) = null 4616 * StringUtils.join([], *) = "" 4617 * StringUtils.join([null], *) = "" 4618 * StringUtils.join(["a", "b", "c"], ';') = "a;b;c" 4619 * StringUtils.join(["a", "b", "c"], null) = "abc" 4620 * StringUtils.join([null, "", "a"], ';') = ";;a" 4621 * </pre> 4622 * 4623 * @param array the array of values to join together, may be null 4624 * @param delimiter the separator character to use 4625 * @return the joined String, {@code null} if null array input 4626 * @since 2.0 4627 */ 4628 public static String join(final Object[] array, final char delimiter) { 4629 if (array == null) { 4630 return null; 4631 } 4632 return join(array, delimiter, 0, array.length); 4633 } 4634 4635 /** 4636 * <p>Joins the elements of the provided array into a single String 4637 * containing the provided list of elements.</p> 4638 * 4639 * <p>No delimiter is added before or after the list. 4640 * Null objects or empty strings within the array are represented by 4641 * empty strings.</p> 4642 * 4643 * <pre> 4644 * StringUtils.join(null, *) = null 4645 * StringUtils.join([], *) = "" 4646 * StringUtils.join([null], *) = "" 4647 * StringUtils.join(["a", "b", "c"], ';') = "a;b;c" 4648 * StringUtils.join(["a", "b", "c"], null) = "abc" 4649 * StringUtils.join([null, "", "a"], ';') = ";;a" 4650 * </pre> 4651 * 4652 * @param array the array of values to join together, may be null 4653 * @param delimiter the separator character to use 4654 * @param startIndex the first index to start joining from. It is 4655 * an error to pass in a start index past the end of the array 4656 * @param endIndex the index to stop joining from (exclusive). It is 4657 * an error to pass in an end index past the end of the array 4658 * @return the joined String, {@code null} if null array input 4659 * @since 2.0 4660 */ 4661 public static String join(final Object[] array, final char delimiter, final int startIndex, final int endIndex) { 4662 if (array == null) { 4663 return null; 4664 } 4665 if (endIndex - startIndex <= 0) { 4666 return EMPTY; 4667 } 4668 final StringJoiner joiner = newStringJoiner(delimiter); 4669 for (int i = startIndex; i < endIndex; i++) { 4670 joiner.add(toStringOrEmpty(array[i])); 4671 } 4672 return joiner.toString(); 4673 } 4674 4675 /** 4676 * <p>Joins the elements of the provided array into a single String 4677 * containing the provided list of elements.</p> 4678 * 4679 * <p>No delimiter is added before or after the list. 4680 * A {@code null} separator is the same as an empty String (""). 4681 * Null objects or empty strings within the array are represented by 4682 * empty strings.</p> 4683 * 4684 * <pre> 4685 * StringUtils.join(null, *) = null 4686 * StringUtils.join([], *) = "" 4687 * StringUtils.join([null], *) = "" 4688 * StringUtils.join(["a", "b", "c"], "--") = "a--b--c" 4689 * StringUtils.join(["a", "b", "c"], null) = "abc" 4690 * StringUtils.join(["a", "b", "c"], "") = "abc" 4691 * StringUtils.join([null, "", "a"], ',') = ",,a" 4692 * </pre> 4693 * 4694 * @param array the array of values to join together, may be null 4695 * @param delimiter the separator character to use, null treated as "" 4696 * @return the joined String, {@code null} if null array input 4697 */ 4698 public static String join(final Object[] array, final String delimiter) { 4699 if (array == null) { 4700 return null; 4701 } 4702 return join(array, delimiter, 0, array.length); 4703 } 4704 4705 /** 4706 * <p>Joins the elements of the provided array into a single String 4707 * containing the provided list of elements.</p> 4708 * 4709 * <p>No delimiter is added before or after the list. 4710 * A {@code null} separator is the same as an empty String (""). 4711 * Null objects or empty strings within the array are represented by 4712 * empty strings.</p> 4713 * 4714 * <pre> 4715 * StringUtils.join(null, *, *, *) = null 4716 * StringUtils.join([], *, *, *) = "" 4717 * StringUtils.join([null], *, *, *) = "" 4718 * StringUtils.join(["a", "b", "c"], "--", 0, 3) = "a--b--c" 4719 * StringUtils.join(["a", "b", "c"], "--", 1, 3) = "b--c" 4720 * StringUtils.join(["a", "b", "c"], "--", 2, 3) = "c" 4721 * StringUtils.join(["a", "b", "c"], "--", 2, 2) = "" 4722 * StringUtils.join(["a", "b", "c"], null, 0, 3) = "abc" 4723 * StringUtils.join(["a", "b", "c"], "", 0, 3) = "abc" 4724 * StringUtils.join([null, "", "a"], ',', 0, 3) = ",,a" 4725 * </pre> 4726 * 4727 * @param array the array of values to join together, may be null 4728 * @param delimiter the separator character to use, null treated as "" 4729 * @param startIndex the first index to start joining from. 4730 * @param endIndex the index to stop joining from (exclusive). 4731 * @return the joined String, {@code null} if null array input; or the empty string 4732 * if {@code endIndex - startIndex <= 0}. The number of joined entries is given by 4733 * {@code endIndex - startIndex} 4734 * @throws ArrayIndexOutOfBoundsException ife<br> 4735 * {@code startIndex < 0} or <br> 4736 * {@code startIndex >= array.length()} or <br> 4737 * {@code endIndex < 0} or <br> 4738 * {@code endIndex > array.length()} 4739 */ 4740 public static String join(final Object[] array, final String delimiter, final int startIndex, final int endIndex) { 4741 if (array == null) { 4742 return null; 4743 } 4744 if (endIndex - startIndex <= 0) { 4745 return EMPTY; 4746 } 4747 final StringJoiner joiner = new StringJoiner(toStringOrEmpty(delimiter)); 4748 for (int i = startIndex; i < endIndex; i++) { 4749 joiner.add(toStringOrEmpty(array[i])); 4750 } 4751 return joiner.toString(); 4752 } 4753 4754 /** 4755 * <p> 4756 * Joins the elements of the provided array into a single String containing the provided list of elements. 4757 * </p> 4758 * 4759 * <p> 4760 * No delimiter is added before or after the list. Null objects or empty strings within the array are represented 4761 * by empty strings. 4762 * </p> 4763 * 4764 * <pre> 4765 * StringUtils.join(null, *) = null 4766 * StringUtils.join([], *) = "" 4767 * StringUtils.join([null], *) = "" 4768 * StringUtils.join([1, 2, 3], ';') = "1;2;3" 4769 * StringUtils.join([1, 2, 3], null) = "123" 4770 * </pre> 4771 * 4772 * @param array 4773 * the array of values to join together, may be null 4774 * @param delimiter 4775 * the separator character to use 4776 * @return the joined String, {@code null} if null array input 4777 * @since 3.2 4778 */ 4779 public static String join(final short[] array, final char delimiter) { 4780 if (array == null) { 4781 return null; 4782 } 4783 return join(array, delimiter, 0, array.length); 4784 } 4785 4786 /** 4787 * <p> 4788 * Joins the elements of the provided array into a single String containing the provided list of elements. 4789 * </p> 4790 * 4791 * <p> 4792 * No delimiter is added before or after the list. Null objects or empty strings within the array are represented 4793 * by empty strings. 4794 * </p> 4795 * 4796 * <pre> 4797 * StringUtils.join(null, *) = null 4798 * StringUtils.join([], *) = "" 4799 * StringUtils.join([null], *) = "" 4800 * StringUtils.join([1, 2, 3], ';') = "1;2;3" 4801 * StringUtils.join([1, 2, 3], null) = "123" 4802 * </pre> 4803 * 4804 * @param array 4805 * the array of values to join together, may be null 4806 * @param delimiter 4807 * the separator character to use 4808 * @param startIndex 4809 * the first index to start joining from. It is an error to pass in a start index past the end of the 4810 * array 4811 * @param endIndex 4812 * the index to stop joining from (exclusive). It is an error to pass in an end index past the end of 4813 * the array 4814 * @return the joined String, {@code null} if null array input 4815 * @since 3.2 4816 */ 4817 public static String join(final short[] array, final char delimiter, final int startIndex, final int endIndex) { 4818 if (array == null) { 4819 return null; 4820 } 4821 if (endIndex - startIndex <= 0) { 4822 return EMPTY; 4823 } 4824 final StringJoiner joiner = newStringJoiner(delimiter); 4825 for (int i = startIndex; i < endIndex; i++) { 4826 joiner.add(String.valueOf(array[i])); 4827 } 4828 return joiner.toString(); 4829 } 4830 4831 /** 4832 * <p>Joins the elements of the provided array into a single String 4833 * containing the provided list of elements.</p> 4834 * 4835 * <p>No separator is added to the joined String. 4836 * Null objects or empty strings within the array are represented by 4837 * empty strings.</p> 4838 * 4839 * <pre> 4840 * StringUtils.join(null) = null 4841 * StringUtils.join([]) = "" 4842 * StringUtils.join([null]) = "" 4843 * StringUtils.join(["a", "b", "c"]) = "abc" 4844 * StringUtils.join([null, "", "a"]) = "a" 4845 * </pre> 4846 * 4847 * @param <T> the specific type of values to join together 4848 * @param elements the values to join together, may be null 4849 * @return the joined String, {@code null} if null array input 4850 * @since 2.0 4851 * @since 3.0 Changed signature to use varargs 4852 */ 4853 @SafeVarargs 4854 public static <T> String join(final T... elements) { 4855 return join(elements, null); 4856 } 4857 4858 /** 4859 * <p>Joins the elements of the provided varargs into a 4860 * single String containing the provided elements.</p> 4861 * 4862 * <p>No delimiter is added before or after the list. 4863 * {@code null} elements and separator are treated as empty Strings ("").</p> 4864 * 4865 * <pre> 4866 * StringUtils.joinWith(",", {"a", "b"}) = "a,b" 4867 * StringUtils.joinWith(",", {"a", "b",""}) = "a,b," 4868 * StringUtils.joinWith(",", {"a", null, "b"}) = "a,,b" 4869 * StringUtils.joinWith(null, {"a", "b"}) = "ab" 4870 * </pre> 4871 * 4872 * @param delimiter the separator character to use, null treated as "" 4873 * @param array the varargs providing the values to join together. {@code null} elements are treated as "" 4874 * @return the joined String. 4875 * @throws java.lang.IllegalArgumentException if a null varargs is provided 4876 * @since 3.5 4877 */ 4878 public static String joinWith(final String delimiter, final Object... array) { 4879 if (array == null) { 4880 throw new IllegalArgumentException("Object varargs must not be null"); 4881 } 4882 return join(array, delimiter); 4883 } 4884 4885 /** 4886 * <p>Finds the last index within a CharSequence, handling {@code null}. 4887 * This method uses {@link String#lastIndexOf(String)} if possible.</p> 4888 * 4889 * <p>A {@code null} CharSequence will return {@code -1}.</p> 4890 * 4891 * <pre> 4892 * StringUtils.lastIndexOf(null, *) = -1 4893 * StringUtils.lastIndexOf(*, null) = -1 4894 * StringUtils.lastIndexOf("", "") = 0 4895 * StringUtils.lastIndexOf("aabaabaa", "a") = 7 4896 * StringUtils.lastIndexOf("aabaabaa", "b") = 5 4897 * StringUtils.lastIndexOf("aabaabaa", "ab") = 4 4898 * StringUtils.lastIndexOf("aabaabaa", "") = 8 4899 * </pre> 4900 * 4901 * @param seq the CharSequence to check, may be null 4902 * @param searchSeq the CharSequence to find, may be null 4903 * @return the last index of the search String, 4904 * -1 if no match or {@code null} string input 4905 * @since 2.0 4906 * @since 3.0 Changed signature from lastIndexOf(String, String) to lastIndexOf(CharSequence, CharSequence) 4907 */ 4908 public static int lastIndexOf(final CharSequence seq, final CharSequence searchSeq) { 4909 if (seq == null) { 4910 return INDEX_NOT_FOUND; 4911 } 4912 return CharSequenceUtils.lastIndexOf(seq, searchSeq, seq.length()); 4913 } 4914 4915 /** 4916 * <p>Finds the last index within a CharSequence, handling {@code null}. 4917 * This method uses {@link String#lastIndexOf(String, int)} if possible.</p> 4918 * 4919 * <p>A {@code null} CharSequence will return {@code -1}. 4920 * A negative start position returns {@code -1}. 4921 * An empty ("") search CharSequence always matches unless the start position is negative. 4922 * A start position greater than the string length searches the whole string. 4923 * The search starts at the startPos and works backwards; matches starting after the start 4924 * position are ignored. 4925 * </p> 4926 * 4927 * <pre> 4928 * StringUtils.lastIndexOf(null, *, *) = -1 4929 * StringUtils.lastIndexOf(*, null, *) = -1 4930 * StringUtils.lastIndexOf("aabaabaa", "a", 8) = 7 4931 * StringUtils.lastIndexOf("aabaabaa", "b", 8) = 5 4932 * StringUtils.lastIndexOf("aabaabaa", "ab", 8) = 4 4933 * StringUtils.lastIndexOf("aabaabaa", "b", 9) = 5 4934 * StringUtils.lastIndexOf("aabaabaa", "b", -1) = -1 4935 * StringUtils.lastIndexOf("aabaabaa", "a", 0) = 0 4936 * StringUtils.lastIndexOf("aabaabaa", "b", 0) = -1 4937 * StringUtils.lastIndexOf("aabaabaa", "b", 1) = -1 4938 * StringUtils.lastIndexOf("aabaabaa", "b", 2) = 2 4939 * StringUtils.lastIndexOf("aabaabaa", "ba", 2) = 2 4940 * </pre> 4941 * 4942 * @param seq the CharSequence to check, may be null 4943 * @param searchSeq the CharSequence to find, may be null 4944 * @param startPos the start position, negative treated as zero 4945 * @return the last index of the search CharSequence (always ≤ startPos), 4946 * -1 if no match or {@code null} string input 4947 * @since 2.0 4948 * @since 3.0 Changed signature from lastIndexOf(String, String, int) to lastIndexOf(CharSequence, CharSequence, int) 4949 */ 4950 public static int lastIndexOf(final CharSequence seq, final CharSequence searchSeq, final int startPos) { 4951 return CharSequenceUtils.lastIndexOf(seq, searchSeq, startPos); 4952 } 4953 4954 /** 4955 * Returns the index within {@code seq} of the last occurrence of 4956 * the specified character. For values of {@code searchChar} in the 4957 * range from 0 to 0xFFFF (inclusive), the index (in Unicode code 4958 * units) returned is the largest value <i>k</i> such that: 4959 * <blockquote><pre> 4960 * this.charAt(<i>k</i>) == searchChar 4961 * </pre></blockquote> 4962 * is true. For other values of {@code searchChar}, it is the 4963 * largest value <i>k</i> such that: 4964 * <blockquote><pre> 4965 * this.codePointAt(<i>k</i>) == searchChar 4966 * </pre></blockquote> 4967 * is true. In either case, if no such character occurs in this 4968 * string, then {@code -1} is returned. Furthermore, a {@code null} or empty ("") 4969 * {@code CharSequence} will return {@code -1}. The 4970 * {@code seq} {@code CharSequence} object is searched backwards 4971 * starting at the last character. 4972 * 4973 * <pre> 4974 * StringUtils.lastIndexOf(null, *) = -1 4975 * StringUtils.lastIndexOf("", *) = -1 4976 * StringUtils.lastIndexOf("aabaabaa", 'a') = 7 4977 * StringUtils.lastIndexOf("aabaabaa", 'b') = 5 4978 * </pre> 4979 * 4980 * @param seq the {@code CharSequence} to check, may be null 4981 * @param searchChar the character to find 4982 * @return the last index of the search character, 4983 * -1 if no match or {@code null} string input 4984 * @since 2.0 4985 * @since 3.0 Changed signature from lastIndexOf(String, int) to lastIndexOf(CharSequence, int) 4986 * @since 3.6 Updated {@link CharSequenceUtils} call to behave more like {@code String} 4987 */ 4988 public static int lastIndexOf(final CharSequence seq, final int searchChar) { 4989 if (isEmpty(seq)) { 4990 return INDEX_NOT_FOUND; 4991 } 4992 return CharSequenceUtils.lastIndexOf(seq, searchChar, seq.length()); 4993 } 4994 4995 /** 4996 * Returns the index within {@code seq} of the last occurrence of 4997 * the specified character, searching backward starting at the 4998 * specified index. For values of {@code searchChar} in the range 4999 * from 0 to 0xFFFF (inclusive), the index returned is the largest 5000 * value <i>k</i> such that: 5001 * <blockquote><pre> 5002 * (this.charAt(<i>k</i>) == searchChar) && (<i>k</i> <= startPos) 5003 * </pre></blockquote> 5004 * is true. For other values of {@code searchChar}, it is the 5005 * largest value <i>k</i> such that: 5006 * <blockquote><pre> 5007 * (this.codePointAt(<i>k</i>) == searchChar) && (<i>k</i> <= startPos) 5008 * </pre></blockquote> 5009 * is true. In either case, if no such character occurs in {@code seq} 5010 * at or before position {@code startPos}, then 5011 * {@code -1} is returned. Furthermore, a {@code null} or empty ("") 5012 * {@code CharSequence} will return {@code -1}. A start position greater 5013 * than the string length searches the whole string. 5014 * The search starts at the {@code startPos} and works backwards; 5015 * matches starting after the start position are ignored. 5016 * 5017 * <p>All indices are specified in {@code char} values 5018 * (Unicode code units). 5019 * 5020 * <pre> 5021 * StringUtils.lastIndexOf(null, *, *) = -1 5022 * StringUtils.lastIndexOf("", *, *) = -1 5023 * StringUtils.lastIndexOf("aabaabaa", 'b', 8) = 5 5024 * StringUtils.lastIndexOf("aabaabaa", 'b', 4) = 2 5025 * StringUtils.lastIndexOf("aabaabaa", 'b', 0) = -1 5026 * StringUtils.lastIndexOf("aabaabaa", 'b', 9) = 5 5027 * StringUtils.lastIndexOf("aabaabaa", 'b', -1) = -1 5028 * StringUtils.lastIndexOf("aabaabaa", 'a', 0) = 0 5029 * </pre> 5030 * 5031 * @param seq the CharSequence to check, may be null 5032 * @param searchChar the character to find 5033 * @param startPos the start position 5034 * @return the last index of the search character (always ≤ startPos), 5035 * -1 if no match or {@code null} string input 5036 * @since 2.0 5037 * @since 3.0 Changed signature from lastIndexOf(String, int, int) to lastIndexOf(CharSequence, int, int) 5038 */ 5039 public static int lastIndexOf(final CharSequence seq, final int searchChar, final int startPos) { 5040 if (isEmpty(seq)) { 5041 return INDEX_NOT_FOUND; 5042 } 5043 return CharSequenceUtils.lastIndexOf(seq, searchChar, startPos); 5044 } 5045 5046 /** 5047 * <p>Find the latest index of any substring in a set of potential substrings.</p> 5048 * 5049 * <p>A {@code null} CharSequence will return {@code -1}. 5050 * A {@code null} search array will return {@code -1}. 5051 * A {@code null} or zero length search array entry will be ignored, 5052 * but a search array containing "" will return the length of {@code str} 5053 * if {@code str} is not null. This method uses {@link String#indexOf(String)} if possible</p> 5054 * 5055 * <pre> 5056 * StringUtils.lastIndexOfAny(null, *) = -1 5057 * StringUtils.lastIndexOfAny(*, null) = -1 5058 * StringUtils.lastIndexOfAny(*, []) = -1 5059 * StringUtils.lastIndexOfAny(*, [null]) = -1 5060 * StringUtils.lastIndexOfAny("zzabyycdxx", ["ab", "cd"]) = 6 5061 * StringUtils.lastIndexOfAny("zzabyycdxx", ["cd", "ab"]) = 6 5062 * StringUtils.lastIndexOfAny("zzabyycdxx", ["mn", "op"]) = -1 5063 * StringUtils.lastIndexOfAny("zzabyycdxx", ["mn", "op"]) = -1 5064 * StringUtils.lastIndexOfAny("zzabyycdxx", ["mn", ""]) = 10 5065 * </pre> 5066 * 5067 * @param str the CharSequence to check, may be null 5068 * @param searchStrs the CharSequences to search for, may be null 5069 * @return the last index of any of the CharSequences, -1 if no match 5070 * @since 3.0 Changed signature from lastIndexOfAny(String, String[]) to lastIndexOfAny(CharSequence, CharSequence) 5071 */ 5072 public static int lastIndexOfAny(final CharSequence str, final CharSequence... searchStrs) { 5073 if (str == null || searchStrs == null) { 5074 return INDEX_NOT_FOUND; 5075 } 5076 int ret = INDEX_NOT_FOUND; 5077 int tmp = 0; 5078 for (final CharSequence search : searchStrs) { 5079 if (search == null) { 5080 continue; 5081 } 5082 tmp = CharSequenceUtils.lastIndexOf(str, search, str.length()); 5083 if (tmp > ret) { 5084 ret = tmp; 5085 } 5086 } 5087 return ret; 5088 } 5089 5090 /** 5091 * <p>Case in-sensitive find of the last index within a CharSequence.</p> 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.</p> 5097 * 5098 * <pre> 5099 * StringUtils.lastIndexOfIgnoreCase(null, *) = -1 5100 * StringUtils.lastIndexOfIgnoreCase(*, null) = -1 5101 * StringUtils.lastIndexOfIgnoreCase("aabaabaa", "A") = 7 5102 * StringUtils.lastIndexOfIgnoreCase("aabaabaa", "B") = 5 5103 * StringUtils.lastIndexOfIgnoreCase("aabaabaa", "AB") = 4 5104 * </pre> 5105 * 5106 * @param str the CharSequence to check, may be null 5107 * @param searchStr the CharSequence to find, may be null 5108 * @return the first index of the search CharSequence, 5109 * -1 if no match or {@code null} string input 5110 * @since 2.5 5111 * @since 3.0 Changed signature from lastIndexOfIgnoreCase(String, String) to lastIndexOfIgnoreCase(CharSequence, CharSequence) 5112 */ 5113 public static int lastIndexOfIgnoreCase(final CharSequence str, final CharSequence searchStr) { 5114 if (str == null || searchStr == null) { 5115 return INDEX_NOT_FOUND; 5116 } 5117 return lastIndexOfIgnoreCase(str, searchStr, str.length()); 5118 } 5119 5120 /** 5121 * <p>Case in-sensitive find of the last index within a CharSequence 5122 * from the specified position.</p> 5123 * 5124 * <p>A {@code null} CharSequence will return {@code -1}. 5125 * A negative start position returns {@code -1}. 5126 * An empty ("") search CharSequence always matches unless the start position is negative. 5127 * A start position greater than the string length searches the whole string. 5128 * The search starts at the startPos and works backwards; matches starting after the start 5129 * position are ignored. 5130 * </p> 5131 * 5132 * <pre> 5133 * StringUtils.lastIndexOfIgnoreCase(null, *, *) = -1 5134 * StringUtils.lastIndexOfIgnoreCase(*, null, *) = -1 5135 * StringUtils.lastIndexOfIgnoreCase("aabaabaa", "A", 8) = 7 5136 * StringUtils.lastIndexOfIgnoreCase("aabaabaa", "B", 8) = 5 5137 * StringUtils.lastIndexOfIgnoreCase("aabaabaa", "AB", 8) = 4 5138 * StringUtils.lastIndexOfIgnoreCase("aabaabaa", "B", 9) = 5 5139 * StringUtils.lastIndexOfIgnoreCase("aabaabaa", "B", -1) = -1 5140 * StringUtils.lastIndexOfIgnoreCase("aabaabaa", "A", 0) = 0 5141 * StringUtils.lastIndexOfIgnoreCase("aabaabaa", "B", 0) = -1 5142 * </pre> 5143 * 5144 * @param str the CharSequence to check, may be null 5145 * @param searchStr the CharSequence to find, may be null 5146 * @param startPos the start position 5147 * @return the last index of the search CharSequence (always ≤ startPos), 5148 * -1 if no match or {@code null} input 5149 * @since 2.5 5150 * @since 3.0 Changed signature from lastIndexOfIgnoreCase(String, String, int) to lastIndexOfIgnoreCase(CharSequence, CharSequence, int) 5151 */ 5152 public static int lastIndexOfIgnoreCase(final CharSequence str, final CharSequence searchStr, int startPos) { 5153 if (str == null || searchStr == null) { 5154 return INDEX_NOT_FOUND; 5155 } 5156 final int searchStrLength = searchStr.length(); 5157 final int strLength = str.length(); 5158 if (startPos > strLength - searchStrLength) { 5159 startPos = strLength - searchStrLength; 5160 } 5161 if (startPos < 0) { 5162 return INDEX_NOT_FOUND; 5163 } 5164 if (searchStrLength == 0) { 5165 return startPos; 5166 } 5167 5168 for (int i = startPos; i >= 0; i--) { 5169 if (CharSequenceUtils.regionMatches(str, true, i, searchStr, 0, searchStrLength)) { 5170 return i; 5171 } 5172 } 5173 return INDEX_NOT_FOUND; 5174 } 5175 5176 /** 5177 * <p>Finds the n-th last index within a String, handling {@code null}. 5178 * This method uses {@link String#lastIndexOf(String)}.</p> 5179 * 5180 * <p>A {@code null} String will return {@code -1}.</p> 5181 * 5182 * <pre> 5183 * StringUtils.lastOrdinalIndexOf(null, *, *) = -1 5184 * StringUtils.lastOrdinalIndexOf(*, null, *) = -1 5185 * StringUtils.lastOrdinalIndexOf("", "", *) = 0 5186 * StringUtils.lastOrdinalIndexOf("aabaabaa", "a", 1) = 7 5187 * StringUtils.lastOrdinalIndexOf("aabaabaa", "a", 2) = 6 5188 * StringUtils.lastOrdinalIndexOf("aabaabaa", "b", 1) = 5 5189 * StringUtils.lastOrdinalIndexOf("aabaabaa", "b", 2) = 2 5190 * StringUtils.lastOrdinalIndexOf("aabaabaa", "ab", 1) = 4 5191 * StringUtils.lastOrdinalIndexOf("aabaabaa", "ab", 2) = 1 5192 * StringUtils.lastOrdinalIndexOf("aabaabaa", "", 1) = 8 5193 * StringUtils.lastOrdinalIndexOf("aabaabaa", "", 2) = 8 5194 * </pre> 5195 * 5196 * <p>Note that 'tail(CharSequence str, int n)' may be implemented as: </p> 5197 * 5198 * <pre> 5199 * str.substring(lastOrdinalIndexOf(str, "\n", n) + 1) 5200 * </pre> 5201 * 5202 * @param str the CharSequence to check, may be null 5203 * @param searchStr the CharSequence to find, may be null 5204 * @param ordinal the n-th last {@code searchStr} to find 5205 * @return the n-th last index of the search CharSequence, 5206 * {@code -1} ({@code INDEX_NOT_FOUND}) if no match or {@code null} string input 5207 * @since 2.5 5208 * @since 3.0 Changed signature from lastOrdinalIndexOf(String, String, int) to lastOrdinalIndexOf(CharSequence, CharSequence, int) 5209 */ 5210 public static int lastOrdinalIndexOf(final CharSequence str, final CharSequence searchStr, final int ordinal) { 5211 return ordinalIndexOf(str, searchStr, ordinal, true); 5212 } 5213 5214 /** 5215 * <p>Gets the leftmost {@code len} characters of a String.</p> 5216 * 5217 * <p>If {@code len} characters are not available, or the 5218 * String is {@code null}, the String will be returned without 5219 * an exception. An empty String is returned if len is negative.</p> 5220 * 5221 * <pre> 5222 * StringUtils.left(null, *) = null 5223 * StringUtils.left(*, -ve) = "" 5224 * StringUtils.left("", *) = "" 5225 * StringUtils.left("abc", 0) = "" 5226 * StringUtils.left("abc", 2) = "ab" 5227 * StringUtils.left("abc", 4) = "abc" 5228 * </pre> 5229 * 5230 * @param str the String to get the leftmost characters from, may be null 5231 * @param len the length of the required String 5232 * @return the leftmost characters, {@code null} if null String input 5233 */ 5234 public static String left(final String str, final int len) { 5235 if (str == null) { 5236 return null; 5237 } 5238 if (len < 0) { 5239 return EMPTY; 5240 } 5241 if (str.length() <= len) { 5242 return str; 5243 } 5244 return str.substring(0, len); 5245 } 5246 5247 /** 5248 * <p>Left pad a String with spaces (' ').</p> 5249 * 5250 * <p>The String is padded to the size of {@code size}.</p> 5251 * 5252 * <pre> 5253 * StringUtils.leftPad(null, *) = null 5254 * StringUtils.leftPad("", 3) = " " 5255 * StringUtils.leftPad("bat", 3) = "bat" 5256 * StringUtils.leftPad("bat", 5) = " bat" 5257 * StringUtils.leftPad("bat", 1) = "bat" 5258 * StringUtils.leftPad("bat", -1) = "bat" 5259 * </pre> 5260 * 5261 * @param str the String to pad out, may be null 5262 * @param size the size to pad to 5263 * @return left padded String or original String if no padding is necessary, 5264 * {@code null} if null String input 5265 */ 5266 public static String leftPad(final String str, final int size) { 5267 return leftPad(str, size, ' '); 5268 } 5269 5270 /** 5271 * <p>Left pad a String with a specified character.</p> 5272 * 5273 * <p>Pad to a size of {@code size}.</p> 5274 * 5275 * <pre> 5276 * StringUtils.leftPad(null, *, *) = null 5277 * StringUtils.leftPad("", 3, 'z') = "zzz" 5278 * StringUtils.leftPad("bat", 3, 'z') = "bat" 5279 * StringUtils.leftPad("bat", 5, 'z') = "zzbat" 5280 * StringUtils.leftPad("bat", 1, 'z') = "bat" 5281 * StringUtils.leftPad("bat", -1, 'z') = "bat" 5282 * </pre> 5283 * 5284 * @param str the String to pad out, may be null 5285 * @param size the size to pad to 5286 * @param padChar the character to pad with 5287 * @return left padded String or original String if no padding is necessary, 5288 * {@code null} if null String input 5289 * @since 2.0 5290 */ 5291 public static String leftPad(final String str, final int size, final char padChar) { 5292 if (str == null) { 5293 return null; 5294 } 5295 final int pads = size - str.length(); 5296 if (pads <= 0) { 5297 return str; // returns original String when possible 5298 } 5299 if (pads > PAD_LIMIT) { 5300 return leftPad(str, size, String.valueOf(padChar)); 5301 } 5302 return repeat(padChar, pads).concat(str); 5303 } 5304 5305 /** 5306 * <p>Left pad a String with a specified String.</p> 5307 * 5308 * <p>Pad to a size of {@code size}.</p> 5309 * 5310 * <pre> 5311 * StringUtils.leftPad(null, *, *) = null 5312 * StringUtils.leftPad("", 3, "z") = "zzz" 5313 * StringUtils.leftPad("bat", 3, "yz") = "bat" 5314 * StringUtils.leftPad("bat", 5, "yz") = "yzbat" 5315 * StringUtils.leftPad("bat", 8, "yz") = "yzyzybat" 5316 * StringUtils.leftPad("bat", 1, "yz") = "bat" 5317 * StringUtils.leftPad("bat", -1, "yz") = "bat" 5318 * StringUtils.leftPad("bat", 5, null) = " bat" 5319 * StringUtils.leftPad("bat", 5, "") = " bat" 5320 * </pre> 5321 * 5322 * @param str the String to pad out, may be null 5323 * @param size the size to pad to 5324 * @param padStr the String to pad with, null or empty treated as single space 5325 * @return left padded String or original String if no padding is necessary, 5326 * {@code null} if null String input 5327 */ 5328 public static String leftPad(final String str, final int size, String padStr) { 5329 if (str == null) { 5330 return null; 5331 } 5332 if (isEmpty(padStr)) { 5333 padStr = SPACE; 5334 } 5335 final int padLen = padStr.length(); 5336 final int strLen = str.length(); 5337 final int pads = size - strLen; 5338 if (pads <= 0) { 5339 return str; // returns original String when possible 5340 } 5341 if (padLen == 1 && pads <= PAD_LIMIT) { 5342 return leftPad(str, size, padStr.charAt(0)); 5343 } 5344 5345 if (pads == padLen) { 5346 return padStr.concat(str); 5347 } else if (pads < padLen) { 5348 return padStr.substring(0, pads).concat(str); 5349 } else { 5350 final char[] padding = new char[pads]; 5351 final char[] padChars = padStr.toCharArray(); 5352 for (int i = 0; i < pads; i++) { 5353 padding[i] = padChars[i % padLen]; 5354 } 5355 return new String(padding).concat(str); 5356 } 5357 } 5358 5359 /** 5360 * Gets a CharSequence length or {@code 0} if the CharSequence is 5361 * {@code null}. 5362 * 5363 * @param cs 5364 * a CharSequence or {@code null} 5365 * @return CharSequence length or {@code 0} if the CharSequence is 5366 * {@code null}. 5367 * @since 2.4 5368 * @since 3.0 Changed signature from length(String) to length(CharSequence) 5369 */ 5370 public static int length(final CharSequence cs) { 5371 return cs == null ? 0 : cs.length(); 5372 } 5373 5374 /** 5375 * <p>Converts a String to lower case as per {@link String#toLowerCase()}.</p> 5376 * 5377 * <p>A {@code null} input String returns {@code null}.</p> 5378 * 5379 * <pre> 5380 * StringUtils.lowerCase(null) = null 5381 * StringUtils.lowerCase("") = "" 5382 * StringUtils.lowerCase("aBc") = "abc" 5383 * </pre> 5384 * 5385 * <p><strong>Note:</strong> As described in the documentation for {@link String#toLowerCase()}, 5386 * the result of this method is affected by the current locale. 5387 * For platform-independent case transformations, the method {@link #lowerCase(String, Locale)} 5388 * should be used with a specific locale (e.g. {@link Locale#ENGLISH}).</p> 5389 * 5390 * @param str the String to lower case, may be null 5391 * @return the lower cased String, {@code null} if null String input 5392 */ 5393 public static String lowerCase(final String str) { 5394 if (str == null) { 5395 return null; 5396 } 5397 return str.toLowerCase(); 5398 } 5399 5400 /** 5401 * <p>Converts a String to lower case as per {@link String#toLowerCase(Locale)}.</p> 5402 * 5403 * <p>A {@code null} input String returns {@code null}.</p> 5404 * 5405 * <pre> 5406 * StringUtils.lowerCase(null, Locale.ENGLISH) = null 5407 * StringUtils.lowerCase("", Locale.ENGLISH) = "" 5408 * StringUtils.lowerCase("aBc", Locale.ENGLISH) = "abc" 5409 * </pre> 5410 * 5411 * @param str the String to lower case, may be null 5412 * @param locale the locale that defines the case transformation rules, must not be null 5413 * @return the lower cased String, {@code null} if null String input 5414 * @since 2.5 5415 */ 5416 public static String lowerCase(final String str, final Locale locale) { 5417 if (str == null) { 5418 return null; 5419 } 5420 return str.toLowerCase(LocaleUtils.toLocale(locale)); 5421 } 5422 5423 private static int[] matches(final CharSequence first, final CharSequence second) { 5424 final CharSequence max; 5425 final CharSequence min; 5426 if (first.length() > second.length()) { 5427 max = first; 5428 min = second; 5429 } else { 5430 max = second; 5431 min = first; 5432 } 5433 final int range = Math.max(max.length() / 2 - 1, 0); 5434 final int[] matchIndexes = new int[min.length()]; 5435 Arrays.fill(matchIndexes, -1); 5436 final boolean[] matchFlags = new boolean[max.length()]; 5437 int matches = 0; 5438 for (int mi = 0; mi < min.length(); mi++) { 5439 final char c1 = min.charAt(mi); 5440 for (int xi = Math.max(mi - range, 0), xn = Math.min(mi + range + 1, max.length()); xi < xn; xi++) { 5441 if (!matchFlags[xi] && c1 == max.charAt(xi)) { 5442 matchIndexes[mi] = xi; 5443 matchFlags[xi] = true; 5444 matches++; 5445 break; 5446 } 5447 } 5448 } 5449 final char[] ms1 = new char[matches]; 5450 final char[] ms2 = new char[matches]; 5451 for (int i = 0, si = 0; i < min.length(); i++) { 5452 if (matchIndexes[i] != -1) { 5453 ms1[si] = min.charAt(i); 5454 si++; 5455 } 5456 } 5457 for (int i = 0, si = 0; i < max.length(); i++) { 5458 if (matchFlags[i]) { 5459 ms2[si] = max.charAt(i); 5460 si++; 5461 } 5462 } 5463 int transpositions = 0; 5464 for (int mi = 0; mi < ms1.length; mi++) { 5465 if (ms1[mi] != ms2[mi]) { 5466 transpositions++; 5467 } 5468 } 5469 int prefix = 0; 5470 for (int mi = 0; mi < min.length(); mi++) { 5471 if (first.charAt(mi) == second.charAt(mi)) { 5472 prefix++; 5473 } else { 5474 break; 5475 } 5476 } 5477 return new int[] { matches, transpositions / 2, prefix, max.length() }; 5478 } 5479 5480 /** 5481 * <p>Gets {@code len} characters from the middle of a String.</p> 5482 * 5483 * <p>If {@code len} characters are not available, the remainder 5484 * of the String will be returned without an exception. If the 5485 * String is {@code null}, {@code null} will be returned. 5486 * An empty String is returned if len is negative or exceeds the 5487 * length of {@code str}.</p> 5488 * 5489 * <pre> 5490 * StringUtils.mid(null, *, *) = null 5491 * StringUtils.mid(*, *, -ve) = "" 5492 * StringUtils.mid("", 0, *) = "" 5493 * StringUtils.mid("abc", 0, 2) = "ab" 5494 * StringUtils.mid("abc", 0, 4) = "abc" 5495 * StringUtils.mid("abc", 2, 4) = "c" 5496 * StringUtils.mid("abc", 4, 2) = "" 5497 * StringUtils.mid("abc", -2, 2) = "ab" 5498 * </pre> 5499 * 5500 * @param str the String to get the characters from, may be null 5501 * @param pos the position to start from, negative treated as zero 5502 * @param len the length of the required String 5503 * @return the middle characters, {@code null} if null String input 5504 */ 5505 public static String mid(final String str, int pos, final int len) { 5506 if (str == null) { 5507 return null; 5508 } 5509 if (len < 0 || pos > str.length()) { 5510 return EMPTY; 5511 } 5512 if (pos < 0) { 5513 pos = 0; 5514 } 5515 if (str.length() <= pos + len) { 5516 return str.substring(pos); 5517 } 5518 return str.substring(pos, pos + len); 5519 } 5520 5521 private static StringJoiner newStringJoiner(final char delimiter) { 5522 return new StringJoiner(String.valueOf(delimiter)); 5523 } 5524 5525 /** 5526 * <p> 5527 * Similar to <a 5528 * href="http://www.w3.org/TR/xpath/#function-normalize-space">http://www.w3.org/TR/xpath/#function-normalize 5529 * -space</a> 5530 * </p> 5531 * <p> 5532 * The function returns the argument string with whitespace normalized by using 5533 * {@code {@link #trim(String)}} to remove leading and trailing whitespace 5534 * and then replacing sequences of whitespace characters by a single space. 5535 * </p> 5536 * In XML Whitespace characters are the same as those allowed by the <a 5537 * href="http://www.w3.org/TR/REC-xml/#NT-S">S</a> production, which is S ::= (#x20 | #x9 | #xD | #xA)+ 5538 * <p> 5539 * Java's regexp pattern \s defines whitespace as [ \t\n\x0B\f\r] 5540 * 5541 * <p>For reference:</p> 5542 * <ul> 5543 * <li>\x0B = vertical tab</li> 5544 * <li>\f = #xC = form feed</li> 5545 * <li>#x20 = space</li> 5546 * <li>#x9 = \t</li> 5547 * <li>#xA = \n</li> 5548 * <li>#xD = \r</li> 5549 * </ul> 5550 * 5551 * <p> 5552 * The difference is that Java's whitespace includes vertical tab and form feed, which this functional will also 5553 * normalize. Additionally {@code {@link #trim(String)}} removes control characters (char <= 32) from both 5554 * ends of this String. 5555 * </p> 5556 * 5557 * @see Pattern 5558 * @see #trim(String) 5559 * @see <a 5560 * href="http://www.w3.org/TR/xpath/#function-normalize-space">http://www.w3.org/TR/xpath/#function-normalize-space</a> 5561 * @param str the source String to normalize whitespaces from, may be null 5562 * @return the modified string with whitespace normalized, {@code null} if null String input 5563 * 5564 * @since 3.0 5565 */ 5566 public static String normalizeSpace(final String str) { 5567 // LANG-1020: Improved performance significantly by normalizing manually instead of using regex 5568 // See https://github.com/librucha/commons-lang-normalizespaces-benchmark for performance test 5569 if (isEmpty(str)) { 5570 return str; 5571 } 5572 final int size = str.length(); 5573 final char[] newChars = new char[size]; 5574 int count = 0; 5575 int whitespacesCount = 0; 5576 boolean startWhitespaces = true; 5577 for (int i = 0; i < size; i++) { 5578 final char actualChar = str.charAt(i); 5579 final boolean isWhitespace = Character.isWhitespace(actualChar); 5580 if (isWhitespace) { 5581 if (whitespacesCount == 0 && !startWhitespaces) { 5582 newChars[count++] = SPACE.charAt(0); 5583 } 5584 whitespacesCount++; 5585 } else { 5586 startWhitespaces = false; 5587 newChars[count++] = (actualChar == 160 ? 32 : actualChar); 5588 whitespacesCount = 0; 5589 } 5590 } 5591 if (startWhitespaces) { 5592 return EMPTY; 5593 } 5594 return new String(newChars, 0, count - (whitespacesCount > 0 ? 1 : 0)).trim(); 5595 } 5596 5597 /** 5598 * <p>Finds the n-th index within a CharSequence, handling {@code null}. 5599 * This method uses {@link String#indexOf(String)} if possible.</p> 5600 * <p><b>Note:</b> The code starts looking for a match at the start of the target, 5601 * incrementing the starting index by one after each successful match 5602 * (unless {@code searchStr} is an empty string in which case the position 5603 * is never incremented and {@code 0} is returned immediately). 5604 * This means that matches may overlap.</p> 5605 * <p>A {@code null} CharSequence will return {@code -1}.</p> 5606 * 5607 * <pre> 5608 * StringUtils.ordinalIndexOf(null, *, *) = -1 5609 * StringUtils.ordinalIndexOf(*, null, *) = -1 5610 * StringUtils.ordinalIndexOf("", "", *) = 0 5611 * StringUtils.ordinalIndexOf("aabaabaa", "a", 1) = 0 5612 * StringUtils.ordinalIndexOf("aabaabaa", "a", 2) = 1 5613 * StringUtils.ordinalIndexOf("aabaabaa", "b", 1) = 2 5614 * StringUtils.ordinalIndexOf("aabaabaa", "b", 2) = 5 5615 * StringUtils.ordinalIndexOf("aabaabaa", "ab", 1) = 1 5616 * StringUtils.ordinalIndexOf("aabaabaa", "ab", 2) = 4 5617 * StringUtils.ordinalIndexOf("aabaabaa", "", 1) = 0 5618 * StringUtils.ordinalIndexOf("aabaabaa", "", 2) = 0 5619 * </pre> 5620 * 5621 * <p>Matches may overlap:</p> 5622 * <pre> 5623 * StringUtils.ordinalIndexOf("ababab", "aba", 1) = 0 5624 * StringUtils.ordinalIndexOf("ababab", "aba", 2) = 2 5625 * StringUtils.ordinalIndexOf("ababab", "aba", 3) = -1 5626 * 5627 * StringUtils.ordinalIndexOf("abababab", "abab", 1) = 0 5628 * StringUtils.ordinalIndexOf("abababab", "abab", 2) = 2 5629 * StringUtils.ordinalIndexOf("abababab", "abab", 3) = 4 5630 * StringUtils.ordinalIndexOf("abababab", "abab", 4) = -1 5631 * </pre> 5632 * 5633 * <p>Note that 'head(CharSequence str, int n)' may be implemented as: </p> 5634 * 5635 * <pre> 5636 * str.substring(0, lastOrdinalIndexOf(str, "\n", n)) 5637 * </pre> 5638 * 5639 * @param str the CharSequence to check, may be null 5640 * @param searchStr the CharSequence to find, may be null 5641 * @param ordinal the n-th {@code searchStr} to find 5642 * @return the n-th index of the search CharSequence, 5643 * {@code -1} ({@code INDEX_NOT_FOUND}) if no match or {@code null} string input 5644 * @since 2.1 5645 * @since 3.0 Changed signature from ordinalIndexOf(String, String, int) to ordinalIndexOf(CharSequence, CharSequence, int) 5646 */ 5647 public static int ordinalIndexOf(final CharSequence str, final CharSequence searchStr, final int ordinal) { 5648 return ordinalIndexOf(str, searchStr, ordinal, false); 5649 } 5650 5651 /** 5652 * <p>Finds the n-th index within a String, handling {@code null}. 5653 * This method uses {@link String#indexOf(String)} if possible.</p> 5654 * <p>Note that matches may overlap<p> 5655 * 5656 * <p>A {@code null} CharSequence will return {@code -1}.</p> 5657 * 5658 * @param str the CharSequence to check, may be null 5659 * @param searchStr the CharSequence to find, may be null 5660 * @param ordinal the n-th {@code searchStr} to find, overlapping matches are allowed. 5661 * @param lastIndex true if lastOrdinalIndexOf() otherwise false if ordinalIndexOf() 5662 * @return the n-th index of the search CharSequence, 5663 * {@code -1} ({@code INDEX_NOT_FOUND}) if no match or {@code null} string input 5664 */ 5665 // Shared code between ordinalIndexOf(String, String, int) and lastOrdinalIndexOf(String, String, int) 5666 private static int ordinalIndexOf(final CharSequence str, final CharSequence searchStr, final int ordinal, final boolean lastIndex) { 5667 if (str == null || searchStr == null || ordinal <= 0) { 5668 return INDEX_NOT_FOUND; 5669 } 5670 if (searchStr.length() == 0) { 5671 return lastIndex ? str.length() : 0; 5672 } 5673 int found = 0; 5674 // set the initial index beyond the end of the string 5675 // this is to allow for the initial index decrement/increment 5676 int index = lastIndex ? str.length() : INDEX_NOT_FOUND; 5677 do { 5678 if (lastIndex) { 5679 index = CharSequenceUtils.lastIndexOf(str, searchStr, index - 1); // step backwards thru string 5680 } else { 5681 index = CharSequenceUtils.indexOf(str, searchStr, index + 1); // step forwards through string 5682 } 5683 if (index < 0) { 5684 return index; 5685 } 5686 found++; 5687 } while (found < ordinal); 5688 return index; 5689 } 5690 5691 /** 5692 * <p>Overlays part of a String with another String.</p> 5693 * 5694 * <p>A {@code null} string input returns {@code null}. 5695 * A negative index is treated as zero. 5696 * An index greater than the string length is treated as the string length. 5697 * The start index is always the smaller of the two indices.</p> 5698 * 5699 * <pre> 5700 * StringUtils.overlay(null, *, *, *) = null 5701 * StringUtils.overlay("", "abc", 0, 0) = "abc" 5702 * StringUtils.overlay("abcdef", null, 2, 4) = "abef" 5703 * StringUtils.overlay("abcdef", "", 2, 4) = "abef" 5704 * StringUtils.overlay("abcdef", "", 4, 2) = "abef" 5705 * StringUtils.overlay("abcdef", "zzzz", 2, 4) = "abzzzzef" 5706 * StringUtils.overlay("abcdef", "zzzz", 4, 2) = "abzzzzef" 5707 * StringUtils.overlay("abcdef", "zzzz", -1, 4) = "zzzzef" 5708 * StringUtils.overlay("abcdef", "zzzz", 2, 8) = "abzzzz" 5709 * StringUtils.overlay("abcdef", "zzzz", -2, -3) = "zzzzabcdef" 5710 * StringUtils.overlay("abcdef", "zzzz", 8, 10) = "abcdefzzzz" 5711 * </pre> 5712 * 5713 * @param str the String to do overlaying in, may be null 5714 * @param overlay the String to overlay, may be null 5715 * @param start the position to start overlaying at 5716 * @param end the position to stop overlaying before 5717 * @return overlayed String, {@code null} if null String input 5718 * @since 2.0 5719 */ 5720 public static String overlay(final String str, String overlay, int start, int end) { 5721 if (str == null) { 5722 return null; 5723 } 5724 if (overlay == null) { 5725 overlay = EMPTY; 5726 } 5727 final int len = str.length(); 5728 if (start < 0) { 5729 start = 0; 5730 } 5731 if (start > len) { 5732 start = len; 5733 } 5734 if (end < 0) { 5735 end = 0; 5736 } 5737 if (end > len) { 5738 end = len; 5739 } 5740 if (start > end) { 5741 final int temp = start; 5742 start = end; 5743 end = temp; 5744 } 5745 return str.substring(0, start) + 5746 overlay + 5747 str.substring(end); 5748 } 5749 5750 /** 5751 * Prepends the prefix to the start of the string if the string does not 5752 * already start with any of the prefixes. 5753 * 5754 * @param str The string. 5755 * @param prefix The prefix to prepend to the start of the string. 5756 * @param ignoreCase Indicates whether the compare should ignore case. 5757 * @param prefixes Additional prefixes that are valid (optional). 5758 * 5759 * @return A new String if prefix was prepended, the same string otherwise. 5760 */ 5761 private static String prependIfMissing(final String str, final CharSequence prefix, final boolean ignoreCase, final CharSequence... prefixes) { 5762 if (str == null || isEmpty(prefix) || startsWith(str, prefix, ignoreCase)) { 5763 return str; 5764 } 5765 if (ArrayUtils.isNotEmpty(prefixes)) { 5766 for (final CharSequence p : prefixes) { 5767 if (startsWith(str, p, ignoreCase)) { 5768 return str; 5769 } 5770 } 5771 } 5772 return prefix.toString() + str; 5773 } 5774 5775 /** 5776 * Prepends the prefix to the start of the string if the string does not 5777 * already start with any of the prefixes. 5778 * 5779 * <pre> 5780 * StringUtils.prependIfMissing(null, null) = null 5781 * StringUtils.prependIfMissing("abc", null) = "abc" 5782 * StringUtils.prependIfMissing("", "xyz") = "xyz" 5783 * StringUtils.prependIfMissing("abc", "xyz") = "xyzabc" 5784 * StringUtils.prependIfMissing("xyzabc", "xyz") = "xyzabc" 5785 * StringUtils.prependIfMissing("XYZabc", "xyz") = "xyzXYZabc" 5786 * </pre> 5787 * <p>With additional prefixes,</p> 5788 * <pre> 5789 * StringUtils.prependIfMissing(null, null, null) = null 5790 * StringUtils.prependIfMissing("abc", null, null) = "abc" 5791 * StringUtils.prependIfMissing("", "xyz", null) = "xyz" 5792 * StringUtils.prependIfMissing("abc", "xyz", new CharSequence[]{null}) = "xyzabc" 5793 * StringUtils.prependIfMissing("abc", "xyz", "") = "abc" 5794 * StringUtils.prependIfMissing("abc", "xyz", "mno") = "xyzabc" 5795 * StringUtils.prependIfMissing("xyzabc", "xyz", "mno") = "xyzabc" 5796 * StringUtils.prependIfMissing("mnoabc", "xyz", "mno") = "mnoabc" 5797 * StringUtils.prependIfMissing("XYZabc", "xyz", "mno") = "xyzXYZabc" 5798 * StringUtils.prependIfMissing("MNOabc", "xyz", "mno") = "xyzMNOabc" 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. 5804 * 5805 * @return A new String if prefix was prepended, the same string otherwise. 5806 * 5807 * @since 3.2 5808 */ 5809 public static String prependIfMissing(final String str, final CharSequence prefix, final CharSequence... prefixes) { 5810 return prependIfMissing(str, prefix, false, prefixes); 5811 } 5812 5813 /** 5814 * Prepends the prefix to the start of the string if the string does not 5815 * already start, case insensitive, with any of the prefixes. 5816 * 5817 * <pre> 5818 * StringUtils.prependIfMissingIgnoreCase(null, null) = null 5819 * StringUtils.prependIfMissingIgnoreCase("abc", null) = "abc" 5820 * StringUtils.prependIfMissingIgnoreCase("", "xyz") = "xyz" 5821 * StringUtils.prependIfMissingIgnoreCase("abc", "xyz") = "xyzabc" 5822 * StringUtils.prependIfMissingIgnoreCase("xyzabc", "xyz") = "xyzabc" 5823 * StringUtils.prependIfMissingIgnoreCase("XYZabc", "xyz") = "XYZabc" 5824 * </pre> 5825 * <p>With additional prefixes,</p> 5826 * <pre> 5827 * StringUtils.prependIfMissingIgnoreCase(null, null, null) = null 5828 * StringUtils.prependIfMissingIgnoreCase("abc", null, null) = "abc" 5829 * StringUtils.prependIfMissingIgnoreCase("", "xyz", null) = "xyz" 5830 * StringUtils.prependIfMissingIgnoreCase("abc", "xyz", new CharSequence[]{null}) = "xyzabc" 5831 * StringUtils.prependIfMissingIgnoreCase("abc", "xyz", "") = "abc" 5832 * StringUtils.prependIfMissingIgnoreCase("abc", "xyz", "mno") = "xyzabc" 5833 * StringUtils.prependIfMissingIgnoreCase("xyzabc", "xyz", "mno") = "xyzabc" 5834 * StringUtils.prependIfMissingIgnoreCase("mnoabc", "xyz", "mno") = "mnoabc" 5835 * StringUtils.prependIfMissingIgnoreCase("XYZabc", "xyz", "mno") = "XYZabc" 5836 * StringUtils.prependIfMissingIgnoreCase("MNOabc", "xyz", "mno") = "MNOabc" 5837 * </pre> 5838 * 5839 * @param str The string. 5840 * @param prefix The prefix to prepend to the start of the string. 5841 * @param prefixes Additional prefixes that are valid (optional). 5842 * 5843 * @return A new String if prefix was prepended, the same string otherwise. 5844 * 5845 * @since 3.2 5846 */ 5847 public static String prependIfMissingIgnoreCase(final String str, final CharSequence prefix, final CharSequence... prefixes) { 5848 return prependIfMissing(str, prefix, true, prefixes); 5849 } 5850 5851 /** 5852 * <p>Removes all occurrences of a character from within the source string.</p> 5853 * 5854 * <p>A {@code null} source string will return {@code null}. 5855 * An empty ("") source string will return the empty string.</p> 5856 * 5857 * <pre> 5858 * StringUtils.remove(null, *) = null 5859 * StringUtils.remove("", *) = "" 5860 * StringUtils.remove("queued", 'u') = "qeed" 5861 * StringUtils.remove("queued", 'z') = "queued" 5862 * </pre> 5863 * 5864 * @param str the source String to search, may be null 5865 * @param remove the char to search for and remove, may be null 5866 * @return the substring with the char removed if found, 5867 * {@code null} if null String input 5868 * @since 2.1 5869 */ 5870 public static String remove(final String str, final char remove) { 5871 if (isEmpty(str) || str.indexOf(remove) == INDEX_NOT_FOUND) { 5872 return str; 5873 } 5874 final char[] chars = str.toCharArray(); 5875 int pos = 0; 5876 for (int i = 0; i < chars.length; i++) { 5877 if (chars[i] != remove) { 5878 chars[pos++] = chars[i]; 5879 } 5880 } 5881 return new String(chars, 0, pos); 5882 } 5883 5884 /** 5885 * <p>Removes all occurrences of a substring from within the source string.</p> 5886 * 5887 * <p>A {@code null} source string will return {@code null}. 5888 * An empty ("") source string will return the empty string. 5889 * A {@code null} remove string will return the source string. 5890 * An empty ("") remove string will return the source string.</p> 5891 * 5892 * <pre> 5893 * StringUtils.remove(null, *) = null 5894 * StringUtils.remove("", *) = "" 5895 * StringUtils.remove(*, null) = * 5896 * StringUtils.remove(*, "") = * 5897 * StringUtils.remove("queued", "ue") = "qd" 5898 * StringUtils.remove("queued", "zz") = "queued" 5899 * </pre> 5900 * 5901 * @param str the source String to search, may be null 5902 * @param remove the String to search for and remove, may be null 5903 * @return the substring with the string removed if found, 5904 * {@code null} if null String input 5905 * @since 2.1 5906 */ 5907 public static String remove(final String str, final String remove) { 5908 if (isEmpty(str) || isEmpty(remove)) { 5909 return str; 5910 } 5911 return replace(str, remove, EMPTY, -1); 5912 } 5913 5914 /** 5915 * <p>Removes each substring of the text String that matches the given regular expression.</p> 5916 * 5917 * This method is a {@code null} safe equivalent to: 5918 * <ul> 5919 * <li>{@code text.replaceAll(regex, StringUtils.EMPTY)}</li> 5920 * <li>{@code Pattern.compile(regex).matcher(text).replaceAll(StringUtils.EMPTY)}</li> 5921 * </ul> 5922 * 5923 * <p>A {@code null} reference passed to this method is a no-op.</p> 5924 * 5925 * <p>Unlike in the {@link #removePattern(String, String)} method, the {@link Pattern#DOTALL} option 5926 * is NOT automatically added. 5927 * To use the DOTALL option prepend {@code "(?s)"} to the regex. 5928 * DOTALL is also known as single-line mode in Perl.</p> 5929 * 5930 * <pre> 5931 * StringUtils.removeAll(null, *) = null 5932 * StringUtils.removeAll("any", (String) null) = "any" 5933 * StringUtils.removeAll("any", "") = "any" 5934 * StringUtils.removeAll("any", ".*") = "" 5935 * StringUtils.removeAll("any", ".+") = "" 5936 * StringUtils.removeAll("abc", ".?") = "" 5937 * StringUtils.removeAll("A<__>\n<__>B", "<.*>") = "A\nB" 5938 * StringUtils.removeAll("A<__>\n<__>B", "(?s)<.*>") = "AB" 5939 * StringUtils.removeAll("ABCabc123abc", "[a-z]") = "ABC123" 5940 * </pre> 5941 * 5942 * @param text text to remove from, may be null 5943 * @param regex the regular expression to which this string is to be matched 5944 * @return the text with any removes processed, 5945 * {@code null} if null String input 5946 * 5947 * @throws java.util.regex.PatternSyntaxException 5948 * if the regular expression's syntax is invalid 5949 * 5950 * @see #replaceAll(String, String, String) 5951 * @see #removePattern(String, String) 5952 * @see String#replaceAll(String, String) 5953 * @see java.util.regex.Pattern 5954 * @see java.util.regex.Pattern#DOTALL 5955 * @since 3.5 5956 * 5957 * @deprecated Moved to RegExUtils. 5958 */ 5959 @Deprecated 5960 public static String removeAll(final String text, final String regex) { 5961 return RegExUtils.removeAll(text, regex); 5962 } 5963 5964 /** 5965 * <p>Removes a substring only if it is at the end of a source string, 5966 * otherwise returns the source string.</p> 5967 * 5968 * <p>A {@code null} source string will return {@code null}. 5969 * An empty ("") source string will return the empty string. 5970 * A {@code null} search string will return the source string.</p> 5971 * 5972 * <pre> 5973 * StringUtils.removeEnd(null, *) = null 5974 * StringUtils.removeEnd("", *) = "" 5975 * StringUtils.removeEnd(*, null) = * 5976 * StringUtils.removeEnd("www.domain.com", ".com.") = "www.domain.com" 5977 * StringUtils.removeEnd("www.domain.com", ".com") = "www.domain" 5978 * StringUtils.removeEnd("www.domain.com", "domain") = "www.domain.com" 5979 * StringUtils.removeEnd("abc", "") = "abc" 5980 * </pre> 5981 * 5982 * @param str the source String to search, may be null 5983 * @param remove the String to search for and remove, may be null 5984 * @return the substring with the string removed if found, 5985 * {@code null} if null String input 5986 * @since 2.1 5987 */ 5988 public static String removeEnd(final String str, final String remove) { 5989 if (isEmpty(str) || isEmpty(remove)) { 5990 return str; 5991 } 5992 if (str.endsWith(remove)) { 5993 return str.substring(0, str.length() - remove.length()); 5994 } 5995 return str; 5996 } 5997 5998 /** 5999 * <p>Case insensitive removal of a substring if it is at the end of a source string, 6000 * otherwise returns the source string.</p> 6001 * 6002 * <p>A {@code null} source string will return {@code null}. 6003 * An empty ("") source string will return the empty string. 6004 * A {@code null} search string will return the source string.</p> 6005 * 6006 * <pre> 6007 * StringUtils.removeEndIgnoreCase(null, *) = null 6008 * StringUtils.removeEndIgnoreCase("", *) = "" 6009 * StringUtils.removeEndIgnoreCase(*, null) = * 6010 * StringUtils.removeEndIgnoreCase("www.domain.com", ".com.") = "www.domain.com" 6011 * StringUtils.removeEndIgnoreCase("www.domain.com", ".com") = "www.domain" 6012 * StringUtils.removeEndIgnoreCase("www.domain.com", "domain") = "www.domain.com" 6013 * StringUtils.removeEndIgnoreCase("abc", "") = "abc" 6014 * StringUtils.removeEndIgnoreCase("www.domain.com", ".COM") = "www.domain") 6015 * StringUtils.removeEndIgnoreCase("www.domain.COM", ".com") = "www.domain") 6016 * </pre> 6017 * 6018 * @param str the source String to search, may be null 6019 * @param remove the String to search for (case insensitive) and remove, may be null 6020 * @return the substring with the string removed if found, 6021 * {@code null} if null String input 6022 * @since 2.4 6023 */ 6024 public static String removeEndIgnoreCase(final String str, final String remove) { 6025 if (isEmpty(str) || isEmpty(remove)) { 6026 return str; 6027 } 6028 if (endsWithIgnoreCase(str, remove)) { 6029 return str.substring(0, str.length() - remove.length()); 6030 } 6031 return str; 6032 } 6033 6034 /** 6035 * <p>Removes the first substring of the text string that matches the given regular expression.</p> 6036 * 6037 * This method is a {@code null} safe equivalent to: 6038 * <ul> 6039 * <li>{@code text.replaceFirst(regex, StringUtils.EMPTY)}</li> 6040 * <li>{@code Pattern.compile(regex).matcher(text).replaceFirst(StringUtils.EMPTY)}</li> 6041 * </ul> 6042 * 6043 * <p>A {@code null} reference passed to this method is a no-op.</p> 6044 * 6045 * <p>The {@link Pattern#DOTALL} option is NOT automatically added. 6046 * To use the DOTALL option prepend {@code "(?s)"} to the regex. 6047 * DOTALL is also known as single-line mode in Perl.</p> 6048 * 6049 * <pre> 6050 * StringUtils.removeFirst(null, *) = null 6051 * StringUtils.removeFirst("any", (String) null) = "any" 6052 * StringUtils.removeFirst("any", "") = "any" 6053 * StringUtils.removeFirst("any", ".*") = "" 6054 * StringUtils.removeFirst("any", ".+") = "" 6055 * StringUtils.removeFirst("abc", ".?") = "bc" 6056 * StringUtils.removeFirst("A<__>\n<__>B", "<.*>") = "A\n<__>B" 6057 * StringUtils.removeFirst("A<__>\n<__>B", "(?s)<.*>") = "AB" 6058 * StringUtils.removeFirst("ABCabc123", "[a-z]") = "ABCbc123" 6059 * StringUtils.removeFirst("ABCabc123abc", "[a-z]+") = "ABC123abc" 6060 * </pre> 6061 * 6062 * @param text text to remove from, may be null 6063 * @param regex the regular expression to which this string is to be matched 6064 * @return the text with the first replacement processed, 6065 * {@code null} if null String input 6066 * 6067 * @throws java.util.regex.PatternSyntaxException 6068 * if the regular expression's syntax is invalid 6069 * 6070 * @see #replaceFirst(String, String, String) 6071 * @see String#replaceFirst(String, String) 6072 * @see java.util.regex.Pattern 6073 * @see java.util.regex.Pattern#DOTALL 6074 * @since 3.5 6075 * 6076 * @deprecated Moved to RegExUtils. 6077 */ 6078 @Deprecated 6079 public static String removeFirst(final String text, final String regex) { 6080 return replaceFirst(text, regex, EMPTY); 6081 } 6082 6083 /** 6084 * <p> 6085 * Case insensitive removal of all occurrences of a substring from within 6086 * the source string. 6087 * </p> 6088 * 6089 * <p> 6090 * A {@code null} source string will return {@code null}. An empty ("") 6091 * source string will return the empty string. A {@code null} remove string 6092 * will return the source string. An empty ("") remove string will return 6093 * the source string. 6094 * </p> 6095 * 6096 * <pre> 6097 * StringUtils.removeIgnoreCase(null, *) = null 6098 * StringUtils.removeIgnoreCase("", *) = "" 6099 * StringUtils.removeIgnoreCase(*, null) = * 6100 * StringUtils.removeIgnoreCase(*, "") = * 6101 * StringUtils.removeIgnoreCase("queued", "ue") = "qd" 6102 * StringUtils.removeIgnoreCase("queued", "zz") = "queued" 6103 * StringUtils.removeIgnoreCase("quEUed", "UE") = "qd" 6104 * StringUtils.removeIgnoreCase("queued", "zZ") = "queued" 6105 * </pre> 6106 * 6107 * @param str 6108 * the source String to search, may be null 6109 * @param remove 6110 * the String to search for (case insensitive) and remove, may be 6111 * null 6112 * @return the substring with the string removed if found, {@code null} if 6113 * null String input 6114 * @since 3.5 6115 */ 6116 public static String removeIgnoreCase(final String str, final String remove) { 6117 return replaceIgnoreCase(str, remove, EMPTY, -1); 6118 } 6119 6120 /** 6121 * <p>Removes each substring of the source String that matches the given regular expression using the DOTALL option. 6122 * </p> 6123 * 6124 * This call is a {@code null} safe equivalent to: 6125 * <ul> 6126 * <li>{@code source.replaceAll("(?s)" + regex, StringUtils.EMPTY)}</li> 6127 * <li>{@code Pattern.compile(regex, Pattern.DOTALL).matcher(source).replaceAll(StringUtils.EMPTY)}</li> 6128 * </ul> 6129 * 6130 * <p>A {@code null} reference passed to this method is a no-op.</p> 6131 * 6132 * <pre> 6133 * StringUtils.removePattern(null, *) = null 6134 * StringUtils.removePattern("any", (String) null) = "any" 6135 * StringUtils.removePattern("A<__>\n<__>B", "<.*>") = "AB" 6136 * StringUtils.removePattern("ABCabc123", "[a-z]") = "ABC123" 6137 * </pre> 6138 * 6139 * @param source 6140 * the source string 6141 * @param regex 6142 * the regular expression to which this string is to be matched 6143 * @return The resulting {@code String} 6144 * @see #replacePattern(String, String, String) 6145 * @see String#replaceAll(String, String) 6146 * @see Pattern#DOTALL 6147 * @since 3.2 6148 * @since 3.5 Changed {@code null} reference passed to this method is a no-op. 6149 * 6150 * @deprecated Moved to RegExUtils. 6151 */ 6152 @Deprecated 6153 public static String removePattern(final String source, final String regex) { 6154 return RegExUtils.removePattern(source, regex); 6155 } 6156 6157 /** 6158 * <p>Removes a substring only if it is at the beginning of a source string, 6159 * otherwise returns the source string.</p> 6160 * 6161 * <p>A {@code null} source string will return {@code null}. 6162 * An empty ("") source string will return the empty string. 6163 * A {@code null} search string will return the source string.</p> 6164 * 6165 * <pre> 6166 * StringUtils.removeStart(null, *) = null 6167 * StringUtils.removeStart("", *) = "" 6168 * StringUtils.removeStart(*, null) = * 6169 * StringUtils.removeStart("www.domain.com", "www.") = "domain.com" 6170 * StringUtils.removeStart("domain.com", "www.") = "domain.com" 6171 * StringUtils.removeStart("www.domain.com", "domain") = "www.domain.com" 6172 * StringUtils.removeStart("abc", "") = "abc" 6173 * </pre> 6174 * 6175 * @param str the source String to search, may be null 6176 * @param remove the String to search for and remove, may be null 6177 * @return the substring with the string removed if found, 6178 * {@code null} if null String input 6179 * @since 2.1 6180 */ 6181 public static String removeStart(final String str, final String remove) { 6182 if (isEmpty(str) || isEmpty(remove)) { 6183 return str; 6184 } 6185 if (str.startsWith(remove)) { 6186 return str.substring(remove.length()); 6187 } 6188 return str; 6189 } 6190 6191 /** 6192 * <p>Case insensitive removal of a substring if it is at the beginning of a source string, 6193 * otherwise returns the source string.</p> 6194 * 6195 * <p>A {@code null} source string will return {@code null}. 6196 * An empty ("") source string will return the empty string. 6197 * A {@code null} search string will return the source string.</p> 6198 * 6199 * <pre> 6200 * StringUtils.removeStartIgnoreCase(null, *) = null 6201 * StringUtils.removeStartIgnoreCase("", *) = "" 6202 * StringUtils.removeStartIgnoreCase(*, null) = * 6203 * StringUtils.removeStartIgnoreCase("www.domain.com", "www.") = "domain.com" 6204 * StringUtils.removeStartIgnoreCase("www.domain.com", "WWW.") = "domain.com" 6205 * StringUtils.removeStartIgnoreCase("domain.com", "www.") = "domain.com" 6206 * StringUtils.removeStartIgnoreCase("www.domain.com", "domain") = "www.domain.com" 6207 * StringUtils.removeStartIgnoreCase("abc", "") = "abc" 6208 * </pre> 6209 * 6210 * @param str the source String to search, may be null 6211 * @param remove the String to search for (case insensitive) and remove, may be null 6212 * @return the substring with the string removed if found, 6213 * {@code null} if null String input 6214 * @since 2.4 6215 */ 6216 public static String removeStartIgnoreCase(final String str, final String remove) { 6217 if (str != null && startsWithIgnoreCase(str, remove)) { 6218 return str.substring(length(remove)); 6219 } 6220 return str; 6221 } 6222 6223 /** 6224 * <p>Returns padding using the specified delimiter repeated 6225 * to a given length.</p> 6226 * 6227 * <pre> 6228 * StringUtils.repeat('e', 0) = "" 6229 * StringUtils.repeat('e', 3) = "eee" 6230 * StringUtils.repeat('e', -2) = "" 6231 * </pre> 6232 * 6233 * <p>Note: this method does not support padding with 6234 * <a href="http://www.unicode.org/glossary/#supplementary_character">Unicode Supplementary Characters</a> 6235 * as they require a pair of {@code char}s to be represented. 6236 * If you are needing to support full I18N of your applications 6237 * consider using {@link #repeat(String, int)} instead. 6238 * </p> 6239 * 6240 * @param ch character to repeat 6241 * @param repeat number of times to repeat char, negative treated as zero 6242 * @return String with repeated character 6243 * @see #repeat(String, int) 6244 */ 6245 public static String repeat(final char ch, final int repeat) { 6246 if (repeat <= 0) { 6247 return EMPTY; 6248 } 6249 final char[] buf = new char[repeat]; 6250 Arrays.fill(buf, ch); 6251 return new String(buf); 6252 } 6253 6254 /** 6255 * <p>Repeat a String {@code repeat} times to form a 6256 * new String.</p> 6257 * 6258 * <pre> 6259 * StringUtils.repeat(null, 2) = null 6260 * StringUtils.repeat("", 0) = "" 6261 * StringUtils.repeat("", 2) = "" 6262 * StringUtils.repeat("a", 3) = "aaa" 6263 * StringUtils.repeat("ab", 2) = "abab" 6264 * StringUtils.repeat("a", -2) = "" 6265 * </pre> 6266 * 6267 * @param str the String to repeat, may be null 6268 * @param repeat number of times to repeat str, negative treated as zero 6269 * @return a new String consisting of the original String repeated, 6270 * {@code null} if null String input 6271 */ 6272 public static String repeat(final String str, final int repeat) { 6273 // Performance tuned for 2.0 (JDK1.4) 6274 if (str == null) { 6275 return null; 6276 } 6277 if (repeat <= 0) { 6278 return EMPTY; 6279 } 6280 final int inputLength = str.length(); 6281 if (repeat == 1 || inputLength == 0) { 6282 return str; 6283 } 6284 if (inputLength == 1 && repeat <= PAD_LIMIT) { 6285 return repeat(str.charAt(0), repeat); 6286 } 6287 6288 final int outputLength = inputLength * repeat; 6289 switch (inputLength) { 6290 case 1 : 6291 return repeat(str.charAt(0), repeat); 6292 case 2 : 6293 final char ch0 = str.charAt(0); 6294 final char ch1 = str.charAt(1); 6295 final char[] output2 = new char[outputLength]; 6296 for (int i = repeat * 2 - 2; i >= 0; i--, i--) { 6297 output2[i] = ch0; 6298 output2[i + 1] = ch1; 6299 } 6300 return new String(output2); 6301 default : 6302 final StringBuilder buf = new StringBuilder(outputLength); 6303 for (int i = 0; i < repeat; i++) { 6304 buf.append(str); 6305 } 6306 return buf.toString(); 6307 } 6308 } 6309 6310 /** 6311 * <p>Repeat a String {@code repeat} times to form a 6312 * new String, with a String separator injected each time. </p> 6313 * 6314 * <pre> 6315 * StringUtils.repeat(null, null, 2) = null 6316 * StringUtils.repeat(null, "x", 2) = null 6317 * StringUtils.repeat("", null, 0) = "" 6318 * StringUtils.repeat("", "", 2) = "" 6319 * StringUtils.repeat("", "x", 3) = "xxx" 6320 * StringUtils.repeat("?", ", ", 3) = "?, ?, ?" 6321 * </pre> 6322 * 6323 * @param str the String to repeat, may be null 6324 * @param separator the String to inject, may be null 6325 * @param repeat number of times to repeat str, negative treated as zero 6326 * @return a new String consisting of the original String repeated, 6327 * {@code null} if null String input 6328 * @since 2.5 6329 */ 6330 public static String repeat(final String str, final String separator, final int repeat) { 6331 if (str == null || separator == null) { 6332 return repeat(str, repeat); 6333 } 6334 // given that repeat(String, int) is quite optimized, better to rely on it than try and splice this into it 6335 final String result = repeat(str + separator, repeat); 6336 return removeEnd(result, separator); 6337 } 6338 6339 /** 6340 * <p>Replaces all occurrences of a String within another String.</p> 6341 * 6342 * <p>A {@code null} reference passed to this method is a no-op.</p> 6343 * 6344 * <pre> 6345 * StringUtils.replace(null, *, *) = null 6346 * StringUtils.replace("", *, *) = "" 6347 * StringUtils.replace("any", null, *) = "any" 6348 * StringUtils.replace("any", *, null) = "any" 6349 * StringUtils.replace("any", "", *) = "any" 6350 * StringUtils.replace("aba", "a", null) = "aba" 6351 * StringUtils.replace("aba", "a", "") = "b" 6352 * StringUtils.replace("aba", "a", "z") = "zbz" 6353 * </pre> 6354 * 6355 * @see #replace(String text, String searchString, String replacement, int max) 6356 * @param text text to search and replace in, may be null 6357 * @param searchString the String to search for, may be null 6358 * @param replacement the String to replace it with, may be null 6359 * @return the text with any replacements processed, 6360 * {@code null} if null String input 6361 */ 6362 public static String replace(final String text, final String searchString, final String replacement) { 6363 return replace(text, searchString, replacement, -1); 6364 } 6365 6366 /** 6367 * <p>Replaces a String with another String inside a larger String, 6368 * for the first {@code max} values of the search String.</p> 6369 * 6370 * <p>A {@code null} reference passed to this method is a no-op.</p> 6371 * 6372 * <pre> 6373 * StringUtils.replace(null, *, *, *) = null 6374 * StringUtils.replace("", *, *, *) = "" 6375 * StringUtils.replace("any", null, *, *) = "any" 6376 * StringUtils.replace("any", *, null, *) = "any" 6377 * StringUtils.replace("any", "", *, *) = "any" 6378 * StringUtils.replace("any", *, *, 0) = "any" 6379 * StringUtils.replace("abaa", "a", null, -1) = "abaa" 6380 * StringUtils.replace("abaa", "a", "", -1) = "b" 6381 * StringUtils.replace("abaa", "a", "z", 0) = "abaa" 6382 * StringUtils.replace("abaa", "a", "z", 1) = "zbaa" 6383 * StringUtils.replace("abaa", "a", "z", 2) = "zbza" 6384 * StringUtils.replace("abaa", "a", "z", -1) = "zbzz" 6385 * </pre> 6386 * 6387 * @param text text to search and replace in, may be null 6388 * @param searchString the String to search for, may be null 6389 * @param replacement the String to replace it with, may be null 6390 * @param max maximum number of values to replace, or {@code -1} if no maximum 6391 * @return the text with any replacements processed, 6392 * {@code null} if null String input 6393 */ 6394 public static String replace(final String text, final String searchString, final String replacement, final int max) { 6395 return replace(text, searchString, replacement, max, false); 6396 } 6397 6398 /** 6399 * <p>Replaces a String with another String inside a larger String, 6400 * for the first {@code max} values of the search String, 6401 * case sensitively/insensitively based on {@code ignoreCase} value.</p> 6402 * 6403 * <p>A {@code null} reference passed to this method is a no-op.</p> 6404 * 6405 * <pre> 6406 * StringUtils.replace(null, *, *, *, false) = null 6407 * StringUtils.replace("", *, *, *, false) = "" 6408 * StringUtils.replace("any", null, *, *, false) = "any" 6409 * StringUtils.replace("any", *, null, *, false) = "any" 6410 * StringUtils.replace("any", "", *, *, false) = "any" 6411 * StringUtils.replace("any", *, *, 0, false) = "any" 6412 * StringUtils.replace("abaa", "a", null, -1, false) = "abaa" 6413 * StringUtils.replace("abaa", "a", "", -1, false) = "b" 6414 * StringUtils.replace("abaa", "a", "z", 0, false) = "abaa" 6415 * StringUtils.replace("abaa", "A", "z", 1, false) = "abaa" 6416 * StringUtils.replace("abaa", "A", "z", 1, true) = "zbaa" 6417 * StringUtils.replace("abAa", "a", "z", 2, true) = "zbza" 6418 * StringUtils.replace("abAa", "a", "z", -1, true) = "zbzz" 6419 * </pre> 6420 * 6421 * @param text text to search and replace in, may be null 6422 * @param searchString the String to search for (case insensitive), may be null 6423 * @param replacement the String to replace it with, may be null 6424 * @param max maximum number of values to replace, or {@code -1} if no maximum 6425 * @param ignoreCase if true replace is case insensitive, otherwise case sensitive 6426 * @return the text with any replacements processed, 6427 * {@code null} if null String input 6428 */ 6429 private static String replace(final String text, String searchString, final String replacement, int max, final boolean ignoreCase) { 6430 if (isEmpty(text) || isEmpty(searchString) || replacement == null || max == 0) { 6431 return text; 6432 } 6433 if (ignoreCase) { 6434 searchString = searchString.toLowerCase(); 6435 } 6436 int start = 0; 6437 int end = ignoreCase ? indexOfIgnoreCase(text, searchString, start) : indexOf(text, searchString, start); 6438 if (end == INDEX_NOT_FOUND) { 6439 return text; 6440 } 6441 final int replLength = searchString.length(); 6442 int increase = Math.max(replacement.length() - replLength, 0); 6443 increase *= max < 0 ? 16 : Math.min(max, 64); 6444 final StringBuilder buf = new StringBuilder(text.length() + increase); 6445 while (end != INDEX_NOT_FOUND) { 6446 buf.append(text, start, end).append(replacement); 6447 start = end + replLength; 6448 if (--max == 0) { 6449 break; 6450 } 6451 end = ignoreCase ? indexOfIgnoreCase(text, searchString, start) : indexOf(text, searchString, start); 6452 } 6453 buf.append(text, start, text.length()); 6454 return buf.toString(); 6455 } 6456 6457 /** 6458 * <p>Replaces each substring of the text String that matches the given regular expression 6459 * with the given replacement.</p> 6460 * 6461 * This method is a {@code null} safe equivalent to: 6462 * <ul> 6463 * <li>{@code text.replaceAll(regex, replacement)}</li> 6464 * <li>{@code Pattern.compile(regex).matcher(text).replaceAll(replacement)}</li> 6465 * </ul> 6466 * 6467 * <p>A {@code null} reference passed to this method is a no-op.</p> 6468 * 6469 * <p>Unlike in the {@link #replacePattern(String, String, String)} method, the {@link Pattern#DOTALL} option 6470 * is NOT automatically added. 6471 * To use the DOTALL option prepend {@code "(?s)"} to the regex. 6472 * DOTALL is also known as single-line mode in Perl.</p> 6473 * 6474 * <pre> 6475 * StringUtils.replaceAll(null, *, *) = null 6476 * StringUtils.replaceAll("any", (String) null, *) = "any" 6477 * StringUtils.replaceAll("any", *, null) = "any" 6478 * StringUtils.replaceAll("", "", "zzz") = "zzz" 6479 * StringUtils.replaceAll("", ".*", "zzz") = "zzz" 6480 * StringUtils.replaceAll("", ".+", "zzz") = "" 6481 * StringUtils.replaceAll("abc", "", "ZZ") = "ZZaZZbZZcZZ" 6482 * StringUtils.replaceAll("<__>\n<__>", "<.*>", "z") = "z\nz" 6483 * StringUtils.replaceAll("<__>\n<__>", "(?s)<.*>", "z") = "z" 6484 * StringUtils.replaceAll("ABCabc123", "[a-z]", "_") = "ABC___123" 6485 * StringUtils.replaceAll("ABCabc123", "[^A-Z0-9]+", "_") = "ABC_123" 6486 * StringUtils.replaceAll("ABCabc123", "[^A-Z0-9]+", "") = "ABC123" 6487 * StringUtils.replaceAll("Lorem ipsum dolor sit", "( +)([a-z]+)", "_$2") = "Lorem_ipsum_dolor_sit" 6488 * </pre> 6489 * 6490 * @param text text to search and replace in, may be null 6491 * @param regex the regular expression to which this string is to be matched 6492 * @param replacement the string to be substituted for each match 6493 * @return the text with any replacements processed, 6494 * {@code null} if null String input 6495 * 6496 * @throws java.util.regex.PatternSyntaxException 6497 * if the regular expression's syntax is invalid 6498 * 6499 * @see #replacePattern(String, String, String) 6500 * @see String#replaceAll(String, String) 6501 * @see java.util.regex.Pattern 6502 * @see java.util.regex.Pattern#DOTALL 6503 * @since 3.5 6504 * 6505 * @deprecated Moved to RegExUtils. 6506 */ 6507 @Deprecated 6508 public static String replaceAll(final String text, final String regex, final String replacement) { 6509 return RegExUtils.replaceAll(text, regex, replacement); 6510 } 6511 6512 /** 6513 * <p>Replaces all occurrences of a character in a String with another. 6514 * This is a null-safe version of {@link String#replace(char, char)}.</p> 6515 * 6516 * <p>A {@code null} string input returns {@code null}. 6517 * An empty ("") string input returns an empty string.</p> 6518 * 6519 * <pre> 6520 * StringUtils.replaceChars(null, *, *) = null 6521 * StringUtils.replaceChars("", *, *) = "" 6522 * StringUtils.replaceChars("abcba", 'b', 'y') = "aycya" 6523 * StringUtils.replaceChars("abcba", 'z', 'y') = "abcba" 6524 * </pre> 6525 * 6526 * @param str String to replace characters in, may be null 6527 * @param searchChar the character to search for, may be null 6528 * @param replaceChar the character to replace, may be null 6529 * @return modified String, {@code null} if null string input 6530 * @since 2.0 6531 */ 6532 public static String replaceChars(final String str, final char searchChar, final char replaceChar) { 6533 if (str == null) { 6534 return null; 6535 } 6536 return str.replace(searchChar, replaceChar); 6537 } 6538 6539 /** 6540 * <p>Replaces multiple characters in a String in one go. 6541 * This method can also be used to delete characters.</p> 6542 * 6543 * <p>For example:<br> 6544 * {@code replaceChars("hello", "ho", "jy") = jelly}.</p> 6545 * 6546 * <p>A {@code null} string input returns {@code null}. 6547 * An empty ("") string input returns an empty string. 6548 * A null or empty set of search characters returns the input string.</p> 6549 * 6550 * <p>The length of the search characters should normally equal the length 6551 * of the replace characters. 6552 * If the search characters is longer, then the extra search characters 6553 * are deleted. 6554 * If the search characters is shorter, then the extra replace characters 6555 * are ignored.</p> 6556 * 6557 * <pre> 6558 * StringUtils.replaceChars(null, *, *) = null 6559 * StringUtils.replaceChars("", *, *) = "" 6560 * StringUtils.replaceChars("abc", null, *) = "abc" 6561 * StringUtils.replaceChars("abc", "", *) = "abc" 6562 * StringUtils.replaceChars("abc", "b", null) = "ac" 6563 * StringUtils.replaceChars("abc", "b", "") = "ac" 6564 * StringUtils.replaceChars("abcba", "bc", "yz") = "ayzya" 6565 * StringUtils.replaceChars("abcba", "bc", "y") = "ayya" 6566 * StringUtils.replaceChars("abcba", "bc", "yzx") = "ayzya" 6567 * </pre> 6568 * 6569 * @param str String to replace characters in, may be null 6570 * @param searchChars a set of characters to search for, may be null 6571 * @param replaceChars a set of characters to replace, may be null 6572 * @return modified String, {@code null} if null string input 6573 * @since 2.0 6574 */ 6575 public static String replaceChars(final String str, final String searchChars, String replaceChars) { 6576 if (isEmpty(str) || isEmpty(searchChars)) { 6577 return str; 6578 } 6579 if (replaceChars == null) { 6580 replaceChars = EMPTY; 6581 } 6582 boolean modified = false; 6583 final int replaceCharsLength = replaceChars.length(); 6584 final int strLength = str.length(); 6585 final StringBuilder buf = new StringBuilder(strLength); 6586 for (int i = 0; i < strLength; i++) { 6587 final char ch = str.charAt(i); 6588 final int index = searchChars.indexOf(ch); 6589 if (index >= 0) { 6590 modified = true; 6591 if (index < replaceCharsLength) { 6592 buf.append(replaceChars.charAt(index)); 6593 } 6594 } else { 6595 buf.append(ch); 6596 } 6597 } 6598 if (modified) { 6599 return buf.toString(); 6600 } 6601 return str; 6602 } 6603 6604 /** 6605 * <p> 6606 * Replaces all occurrences of Strings within another String. 6607 * </p> 6608 * 6609 * <p> 6610 * A {@code null} reference passed to this method is a no-op, or if 6611 * any "search string" or "string to replace" is null, that replace will be 6612 * ignored. This will not repeat. For repeating replaces, call the 6613 * overloaded method. 6614 * </p> 6615 * 6616 * <pre> 6617 * StringUtils.replaceEach(null, *, *) = null 6618 * StringUtils.replaceEach("", *, *) = "" 6619 * StringUtils.replaceEach("aba", null, null) = "aba" 6620 * StringUtils.replaceEach("aba", new String[0], null) = "aba" 6621 * StringUtils.replaceEach("aba", null, new String[0]) = "aba" 6622 * StringUtils.replaceEach("aba", new String[]{"a"}, null) = "aba" 6623 * StringUtils.replaceEach("aba", new String[]{"a"}, new String[]{""}) = "b" 6624 * StringUtils.replaceEach("aba", new String[]{null}, new String[]{"a"}) = "aba" 6625 * StringUtils.replaceEach("abcde", new String[]{"ab", "d"}, new String[]{"w", "t"}) = "wcte" 6626 * (example of how it does not repeat) 6627 * StringUtils.replaceEach("abcde", new String[]{"ab", "d"}, new String[]{"d", "t"}) = "dcte" 6628 * </pre> 6629 * 6630 * @param text 6631 * text to search and replace in, no-op if null 6632 * @param searchList 6633 * the Strings to search for, no-op if null 6634 * @param replacementList 6635 * the Strings to replace them with, no-op if null 6636 * @return the text with any replacements processed, {@code null} if 6637 * null String input 6638 * @throws IllegalArgumentException 6639 * if the lengths of the arrays are not the same (null is ok, 6640 * and/or size 0) 6641 * @since 2.4 6642 */ 6643 public static String replaceEach(final String text, final String[] searchList, final String[] replacementList) { 6644 return replaceEach(text, searchList, replacementList, false, 0); 6645 } 6646 6647 /** 6648 * <p> 6649 * Replace all occurrences of Strings within another String. 6650 * This is a private recursive helper method for {@link #replaceEachRepeatedly(String, String[], String[])} and 6651 * {@link #replaceEach(String, String[], String[])} 6652 * </p> 6653 * 6654 * <p> 6655 * A {@code null} reference passed to this method is a no-op, or if 6656 * any "search string" or "string to replace" is null, that replace will be 6657 * ignored. 6658 * </p> 6659 * 6660 * <pre> 6661 * StringUtils.replaceEach(null, *, *, *, *) = null 6662 * StringUtils.replaceEach("", *, *, *, *) = "" 6663 * StringUtils.replaceEach("aba", null, null, *, *) = "aba" 6664 * StringUtils.replaceEach("aba", new String[0], null, *, *) = "aba" 6665 * StringUtils.replaceEach("aba", null, new String[0], *, *) = "aba" 6666 * StringUtils.replaceEach("aba", new String[]{"a"}, null, *, *) = "aba" 6667 * StringUtils.replaceEach("aba", new String[]{"a"}, new String[]{""}, *, >=0) = "b" 6668 * StringUtils.replaceEach("aba", new String[]{null}, new String[]{"a"}, *, >=0) = "aba" 6669 * StringUtils.replaceEach("abcde", new String[]{"ab", "d"}, new String[]{"w", "t"}, *, >=0) = "wcte" 6670 * (example of how it repeats) 6671 * StringUtils.replaceEach("abcde", new String[]{"ab", "d"}, new String[]{"d", "t"}, false, >=0) = "dcte" 6672 * StringUtils.replaceEach("abcde", new String[]{"ab", "d"}, new String[]{"d", "t"}, true, >=2) = "tcte" 6673 * StringUtils.replaceEach("abcde", new String[]{"ab", "d"}, new String[]{"d", "ab"}, *, *) = IllegalStateException 6674 * </pre> 6675 * 6676 * @param text 6677 * text to search and replace in, no-op if null 6678 * @param searchList 6679 * the Strings to search for, no-op if null 6680 * @param replacementList 6681 * the Strings to replace them with, no-op if null 6682 * @param repeat if true, then replace repeatedly 6683 * until there are no more possible replacements or timeToLive < 0 6684 * @param timeToLive 6685 * if less than 0 then there is a circular reference and endless 6686 * loop 6687 * @return the text with any replacements processed, {@code null} if 6688 * null String input 6689 * @throws IllegalStateException 6690 * if the search is repeating and there is an endless loop due 6691 * to outputs of one being inputs to another 6692 * @throws IllegalArgumentException 6693 * if the lengths of the arrays are not the same (null is ok, 6694 * and/or size 0) 6695 * @since 2.4 6696 */ 6697 private static String replaceEach( 6698 final String text, final String[] searchList, final String[] replacementList, final boolean repeat, final int timeToLive) { 6699 6700 // mchyzer Performance note: This creates very few new objects (one major goal) 6701 // let me know if there are performance requests, we can create a harness to measure 6702 6703 // if recursing, this shouldn't be less than 0 6704 if (timeToLive < 0) { 6705 final Set<String> searchSet = new HashSet<>(Arrays.asList(searchList)); 6706 final Set<String> replacementSet = new HashSet<>(Arrays.asList(replacementList)); 6707 searchSet.retainAll(replacementSet); 6708 if (!searchSet.isEmpty()) { 6709 throw new IllegalStateException("Aborting to protect against StackOverflowError - " + 6710 "output of one loop is the input of another"); 6711 } 6712 } 6713 6714 if (isEmpty(text) || ArrayUtils.isEmpty(searchList) || ArrayUtils.isEmpty(replacementList) || (ArrayUtils.isNotEmpty(searchList) && timeToLive == -1)) { 6715 return text; 6716 } 6717 6718 final int searchLength = searchList.length; 6719 final int replacementLength = replacementList.length; 6720 6721 // make sure lengths are ok, these need to be equal 6722 if (searchLength != replacementLength) { 6723 throw new IllegalArgumentException("Search and Replace array lengths don't match: " 6724 + searchLength 6725 + " vs " 6726 + replacementLength); 6727 } 6728 6729 // keep track of which still have matches 6730 final boolean[] noMoreMatchesForReplIndex = new boolean[searchLength]; 6731 6732 // index on index that the match was found 6733 int textIndex = -1; 6734 int replaceIndex = -1; 6735 int tempIndex = -1; 6736 6737 // index of replace array that will replace the search string found 6738 // NOTE: logic duplicated below START 6739 for (int i = 0; i < searchLength; i++) { 6740 if (noMoreMatchesForReplIndex[i] || isEmpty(searchList[i]) || replacementList[i] == null) { 6741 continue; 6742 } 6743 tempIndex = text.indexOf(searchList[i]); 6744 6745 // see if we need to keep searching for this 6746 if (tempIndex == -1) { 6747 noMoreMatchesForReplIndex[i] = true; 6748 } else if (textIndex == -1 || tempIndex < textIndex) { 6749 textIndex = tempIndex; 6750 replaceIndex = i; 6751 } 6752 } 6753 // NOTE: logic mostly below END 6754 6755 // no search strings found, we are done 6756 if (textIndex == -1) { 6757 return text; 6758 } 6759 6760 int start = 0; 6761 6762 // get a good guess on the size of the result buffer so it doesn't have to double if it goes over a bit 6763 int increase = 0; 6764 6765 // count the replacement text elements that are larger than their corresponding text being replaced 6766 for (int i = 0; i < searchList.length; i++) { 6767 if (searchList[i] == null || replacementList[i] == null) { 6768 continue; 6769 } 6770 final int greater = replacementList[i].length() - searchList[i].length(); 6771 if (greater > 0) { 6772 increase += 3 * greater; // assume 3 matches 6773 } 6774 } 6775 // have upper-bound at 20% increase, then let Java take over 6776 increase = Math.min(increase, text.length() / 5); 6777 6778 final StringBuilder buf = new StringBuilder(text.length() + increase); 6779 6780 while (textIndex != -1) { 6781 6782 for (int i = start; i < textIndex; i++) { 6783 buf.append(text.charAt(i)); 6784 } 6785 buf.append(replacementList[replaceIndex]); 6786 6787 start = textIndex + searchList[replaceIndex].length(); 6788 6789 textIndex = -1; 6790 replaceIndex = -1; 6791 // find the next earliest match 6792 // NOTE: logic mostly duplicated above START 6793 for (int i = 0; i < searchLength; i++) { 6794 if (noMoreMatchesForReplIndex[i] || searchList[i] == null || 6795 searchList[i].isEmpty() || replacementList[i] == null) { 6796 continue; 6797 } 6798 tempIndex = text.indexOf(searchList[i], start); 6799 6800 // see if we need to keep searching for this 6801 if (tempIndex == -1) { 6802 noMoreMatchesForReplIndex[i] = true; 6803 } else if (textIndex == -1 || tempIndex < textIndex) { 6804 textIndex = tempIndex; 6805 replaceIndex = i; 6806 } 6807 } 6808 // NOTE: logic duplicated above END 6809 6810 } 6811 final int textLength = text.length(); 6812 for (int i = start; i < textLength; i++) { 6813 buf.append(text.charAt(i)); 6814 } 6815 final String result = buf.toString(); 6816 if (!repeat) { 6817 return result; 6818 } 6819 6820 return replaceEach(result, searchList, replacementList, repeat, timeToLive - 1); 6821 } 6822 6823 /** 6824 * <p> 6825 * Replaces all occurrences of Strings within another String. 6826 * </p> 6827 * 6828 * <p> 6829 * A {@code null} reference passed to this method is a no-op, or if 6830 * any "search string" or "string to replace" is null, that replace will be 6831 * ignored. 6832 * </p> 6833 * 6834 * <pre> 6835 * StringUtils.replaceEachRepeatedly(null, *, *) = null 6836 * StringUtils.replaceEachRepeatedly("", *, *) = "" 6837 * StringUtils.replaceEachRepeatedly("aba", null, null) = "aba" 6838 * StringUtils.replaceEachRepeatedly("aba", new String[0], null) = "aba" 6839 * StringUtils.replaceEachRepeatedly("aba", null, new String[0]) = "aba" 6840 * StringUtils.replaceEachRepeatedly("aba", new String[]{"a"}, null) = "aba" 6841 * StringUtils.replaceEachRepeatedly("aba", new String[]{"a"}, new String[]{""}) = "b" 6842 * StringUtils.replaceEachRepeatedly("aba", new String[]{null}, new String[]{"a"}) = "aba" 6843 * StringUtils.replaceEachRepeatedly("abcde", new String[]{"ab", "d"}, new String[]{"w", "t"}) = "wcte" 6844 * (example of how it repeats) 6845 * StringUtils.replaceEachRepeatedly("abcde", new String[]{"ab", "d"}, new String[]{"d", "t"}) = "tcte" 6846 * StringUtils.replaceEachRepeatedly("abcde", new String[]{"ab", "d"}, new String[]{"d", "ab"}) = IllegalStateException 6847 * </pre> 6848 * 6849 * @param text 6850 * text to search and replace in, no-op if null 6851 * @param searchList 6852 * the Strings to search for, no-op if null 6853 * @param replacementList 6854 * the Strings to replace them with, no-op if null 6855 * @return the text with any replacements processed, {@code null} if 6856 * null String input 6857 * @throws IllegalStateException 6858 * if the search is repeating and there is an endless loop due 6859 * to outputs of one being inputs to another 6860 * @throws IllegalArgumentException 6861 * if the lengths of the arrays are not the same (null is ok, 6862 * and/or size 0) 6863 * @since 2.4 6864 */ 6865 public static String replaceEachRepeatedly(final String text, final String[] searchList, final String[] replacementList) { 6866 // timeToLive should be 0 if not used or nothing to replace, else it's 6867 // the length of the replace array 6868 final int timeToLive = searchList == null ? 0 : searchList.length; 6869 return replaceEach(text, searchList, replacementList, true, timeToLive); 6870 } 6871 6872 /** 6873 * <p>Replaces the first substring of the text string that matches the given regular expression 6874 * with the given replacement.</p> 6875 * 6876 * This method is a {@code null} safe equivalent to: 6877 * <ul> 6878 * <li>{@code text.replaceFirst(regex, replacement)}</li> 6879 * <li>{@code Pattern.compile(regex).matcher(text).replaceFirst(replacement)}</li> 6880 * </ul> 6881 * 6882 * <p>A {@code null} reference passed to this method is a no-op.</p> 6883 * 6884 * <p>The {@link Pattern#DOTALL} option is NOT automatically added. 6885 * To use the DOTALL option prepend {@code "(?s)"} to the regex. 6886 * DOTALL is also known as single-line mode in Perl.</p> 6887 * 6888 * <pre> 6889 * StringUtils.replaceFirst(null, *, *) = null 6890 * StringUtils.replaceFirst("any", (String) null, *) = "any" 6891 * StringUtils.replaceFirst("any", *, null) = "any" 6892 * StringUtils.replaceFirst("", "", "zzz") = "zzz" 6893 * StringUtils.replaceFirst("", ".*", "zzz") = "zzz" 6894 * StringUtils.replaceFirst("", ".+", "zzz") = "" 6895 * StringUtils.replaceFirst("abc", "", "ZZ") = "ZZabc" 6896 * StringUtils.replaceFirst("<__>\n<__>", "<.*>", "z") = "z\n<__>" 6897 * StringUtils.replaceFirst("<__>\n<__>", "(?s)<.*>", "z") = "z" 6898 * StringUtils.replaceFirst("ABCabc123", "[a-z]", "_") = "ABC_bc123" 6899 * StringUtils.replaceFirst("ABCabc123abc", "[^A-Z0-9]+", "_") = "ABC_123abc" 6900 * StringUtils.replaceFirst("ABCabc123abc", "[^A-Z0-9]+", "") = "ABC123abc" 6901 * StringUtils.replaceFirst("Lorem ipsum dolor sit", "( +)([a-z]+)", "_$2") = "Lorem_ipsum dolor sit" 6902 * </pre> 6903 * 6904 * @param text text to search and replace in, may be null 6905 * @param regex the regular expression to which this string is to be matched 6906 * @param replacement the string to be substituted for the first match 6907 * @return the text with the first replacement processed, 6908 * {@code null} if null String input 6909 * 6910 * @throws java.util.regex.PatternSyntaxException 6911 * if the regular expression's syntax is invalid 6912 * 6913 * @see String#replaceFirst(String, String) 6914 * @see java.util.regex.Pattern 6915 * @see java.util.regex.Pattern#DOTALL 6916 * @since 3.5 6917 * 6918 * @deprecated Moved to RegExUtils. 6919 */ 6920 @Deprecated 6921 public static String replaceFirst(final String text, final String regex, final String replacement) { 6922 return RegExUtils.replaceFirst(text, regex, replacement); 6923 } 6924 6925 /** 6926 * <p>Case insensitively replaces all occurrences of a String within another String.</p> 6927 * 6928 * <p>A {@code null} reference passed to this method is a no-op.</p> 6929 * 6930 * <pre> 6931 * StringUtils.replaceIgnoreCase(null, *, *) = null 6932 * StringUtils.replaceIgnoreCase("", *, *) = "" 6933 * StringUtils.replaceIgnoreCase("any", null, *) = "any" 6934 * StringUtils.replaceIgnoreCase("any", *, null) = "any" 6935 * StringUtils.replaceIgnoreCase("any", "", *) = "any" 6936 * StringUtils.replaceIgnoreCase("aba", "a", null) = "aba" 6937 * StringUtils.replaceIgnoreCase("abA", "A", "") = "b" 6938 * StringUtils.replaceIgnoreCase("aba", "A", "z") = "zbz" 6939 * </pre> 6940 * 6941 * @see #replaceIgnoreCase(String text, String searchString, String replacement, int max) 6942 * @param text text to search and replace in, may be null 6943 * @param searchString the String to search for (case insensitive), may be null 6944 * @param replacement the String to replace it with, may be null 6945 * @return the text with any replacements processed, 6946 * {@code null} if null String input 6947 * @since 3.5 6948 */ 6949 public static String replaceIgnoreCase(final String text, final String searchString, final String replacement) { 6950 return replaceIgnoreCase(text, searchString, replacement, -1); 6951 } 6952 6953 /** 6954 * <p>Case insensitively replaces a String with another String inside a larger String, 6955 * for the first {@code max} values of the search String.</p> 6956 * 6957 * <p>A {@code null} reference passed to this method is a no-op.</p> 6958 * 6959 * <pre> 6960 * StringUtils.replaceIgnoreCase(null, *, *, *) = null 6961 * StringUtils.replaceIgnoreCase("", *, *, *) = "" 6962 * StringUtils.replaceIgnoreCase("any", null, *, *) = "any" 6963 * StringUtils.replaceIgnoreCase("any", *, null, *) = "any" 6964 * StringUtils.replaceIgnoreCase("any", "", *, *) = "any" 6965 * StringUtils.replaceIgnoreCase("any", *, *, 0) = "any" 6966 * StringUtils.replaceIgnoreCase("abaa", "a", null, -1) = "abaa" 6967 * StringUtils.replaceIgnoreCase("abaa", "a", "", -1) = "b" 6968 * StringUtils.replaceIgnoreCase("abaa", "a", "z", 0) = "abaa" 6969 * StringUtils.replaceIgnoreCase("abaa", "A", "z", 1) = "zbaa" 6970 * StringUtils.replaceIgnoreCase("abAa", "a", "z", 2) = "zbza" 6971 * StringUtils.replaceIgnoreCase("abAa", "a", "z", -1) = "zbzz" 6972 * </pre> 6973 * 6974 * @param text text to search and replace in, may be null 6975 * @param searchString the String to search for (case insensitive), may be null 6976 * @param replacement the String to replace it with, may be null 6977 * @param max maximum number of values to replace, or {@code -1} if no maximum 6978 * @return the text with any replacements processed, 6979 * {@code null} if null String input 6980 * @since 3.5 6981 */ 6982 public static String replaceIgnoreCase(final String text, final String searchString, final String replacement, final int max) { 6983 return replace(text, searchString, replacement, max, true); 6984 } 6985 6986 /** 6987 * <p>Replaces a String with another String inside a larger String, once.</p> 6988 * 6989 * <p>A {@code null} reference passed to this method is a no-op.</p> 6990 * 6991 * <pre> 6992 * StringUtils.replaceOnce(null, *, *) = null 6993 * StringUtils.replaceOnce("", *, *) = "" 6994 * StringUtils.replaceOnce("any", null, *) = "any" 6995 * StringUtils.replaceOnce("any", *, null) = "any" 6996 * StringUtils.replaceOnce("any", "", *) = "any" 6997 * StringUtils.replaceOnce("aba", "a", null) = "aba" 6998 * StringUtils.replaceOnce("aba", "a", "") = "ba" 6999 * StringUtils.replaceOnce("aba", "a", "z") = "zba" 7000 * </pre> 7001 * 7002 * @see #replace(String text, String searchString, String replacement, int max) 7003 * @param text text to search and replace in, may be null 7004 * @param searchString the String to search for, may be null 7005 * @param replacement the String to replace with, may be null 7006 * @return the text with any replacements processed, 7007 * {@code null} if null String input 7008 */ 7009 public static String replaceOnce(final String text, final String searchString, final String replacement) { 7010 return replace(text, searchString, replacement, 1); 7011 } 7012 7013 /** 7014 * <p>Case insensitively replaces a String with another String inside a larger String, once.</p> 7015 * 7016 * <p>A {@code null} reference passed to this method is a no-op.</p> 7017 * 7018 * <pre> 7019 * StringUtils.replaceOnceIgnoreCase(null, *, *) = null 7020 * StringUtils.replaceOnceIgnoreCase("", *, *) = "" 7021 * StringUtils.replaceOnceIgnoreCase("any", null, *) = "any" 7022 * StringUtils.replaceOnceIgnoreCase("any", *, null) = "any" 7023 * StringUtils.replaceOnceIgnoreCase("any", "", *) = "any" 7024 * StringUtils.replaceOnceIgnoreCase("aba", "a", null) = "aba" 7025 * StringUtils.replaceOnceIgnoreCase("aba", "a", "") = "ba" 7026 * StringUtils.replaceOnceIgnoreCase("aba", "a", "z") = "zba" 7027 * StringUtils.replaceOnceIgnoreCase("FoOFoofoo", "foo", "") = "Foofoo" 7028 * </pre> 7029 * 7030 * @see #replaceIgnoreCase(String text, String searchString, String replacement, int max) 7031 * @param text text to search and replace in, may be null 7032 * @param searchString the String to search for (case insensitive), may be null 7033 * @param replacement the String to replace with, may be null 7034 * @return the text with any replacements processed, 7035 * {@code null} if null String input 7036 * @since 3.5 7037 */ 7038 public static String replaceOnceIgnoreCase(final String text, final String searchString, final String replacement) { 7039 return replaceIgnoreCase(text, searchString, replacement, 1); 7040 } 7041 7042 /** 7043 * <p>Replaces each substring of the source String that matches the given regular expression with the given 7044 * replacement using the {@link Pattern#DOTALL} option. DOTALL is also known as single-line mode in Perl.</p> 7045 * 7046 * This call is a {@code null} safe equivalent to: 7047 * <ul> 7048 * <li>{@code source.replaceAll("(?s)" + regex, replacement)}</li> 7049 * <li>{@code Pattern.compile(regex, Pattern.DOTALL).matcher(source).replaceAll(replacement)}</li> 7050 * </ul> 7051 * 7052 * <p>A {@code null} reference passed to this method is a no-op.</p> 7053 * 7054 * <pre> 7055 * StringUtils.replacePattern(null, *, *) = null 7056 * StringUtils.replacePattern("any", (String) null, *) = "any" 7057 * StringUtils.replacePattern("any", *, null) = "any" 7058 * StringUtils.replacePattern("", "", "zzz") = "zzz" 7059 * StringUtils.replacePattern("", ".*", "zzz") = "zzz" 7060 * StringUtils.replacePattern("", ".+", "zzz") = "" 7061 * StringUtils.replacePattern("<__>\n<__>", "<.*>", "z") = "z" 7062 * StringUtils.replacePattern("ABCabc123", "[a-z]", "_") = "ABC___123" 7063 * StringUtils.replacePattern("ABCabc123", "[^A-Z0-9]+", "_") = "ABC_123" 7064 * StringUtils.replacePattern("ABCabc123", "[^A-Z0-9]+", "") = "ABC123" 7065 * StringUtils.replacePattern("Lorem ipsum dolor sit", "( +)([a-z]+)", "_$2") = "Lorem_ipsum_dolor_sit" 7066 * </pre> 7067 * 7068 * @param source 7069 * the source string 7070 * @param regex 7071 * the regular expression to which this string is to be matched 7072 * @param replacement 7073 * the string to be substituted for each match 7074 * @return The resulting {@code String} 7075 * @see #replaceAll(String, String, String) 7076 * @see String#replaceAll(String, String) 7077 * @see Pattern#DOTALL 7078 * @since 3.2 7079 * @since 3.5 Changed {@code null} reference passed to this method is a no-op. 7080 * 7081 * @deprecated Moved to RegExUtils. 7082 */ 7083 @Deprecated 7084 public static String replacePattern(final String source, final String regex, final String replacement) { 7085 return RegExUtils.replacePattern(source, regex, replacement); 7086 } 7087 7088 /** 7089 * <p>Reverses a String as per {@link StringBuilder#reverse()}.</p> 7090 * 7091 * <p>A {@code null} String returns {@code null}.</p> 7092 * 7093 * <pre> 7094 * StringUtils.reverse(null) = null 7095 * StringUtils.reverse("") = "" 7096 * StringUtils.reverse("bat") = "tab" 7097 * </pre> 7098 * 7099 * @param str the String to reverse, may be null 7100 * @return the reversed String, {@code null} if null String input 7101 */ 7102 public static String reverse(final String str) { 7103 if (str == null) { 7104 return null; 7105 } 7106 return new StringBuilder(str).reverse().toString(); 7107 } 7108 7109 /** 7110 * <p>Reverses a String that is delimited by a specific character.</p> 7111 * 7112 * <p>The Strings between the delimiters are not reversed. 7113 * Thus java.lang.String becomes String.lang.java (if the delimiter 7114 * is {@code '.'}).</p> 7115 * 7116 * <pre> 7117 * StringUtils.reverseDelimited(null, *) = null 7118 * StringUtils.reverseDelimited("", *) = "" 7119 * StringUtils.reverseDelimited("a.b.c", 'x') = "a.b.c" 7120 * StringUtils.reverseDelimited("a.b.c", ".") = "c.b.a" 7121 * </pre> 7122 * 7123 * @param str the String to reverse, may be null 7124 * @param separatorChar the separator character to use 7125 * @return the reversed String, {@code null} if null String input 7126 * @since 2.0 7127 */ 7128 public static String reverseDelimited(final String str, final char separatorChar) { 7129 if (str == null) { 7130 return null; 7131 } 7132 // could implement manually, but simple way is to reuse other, 7133 // probably slower, methods. 7134 final String[] strs = split(str, separatorChar); 7135 ArrayUtils.reverse(strs); 7136 return join(strs, separatorChar); 7137 } 7138 7139 /** 7140 * <p>Gets the rightmost {@code len} characters of a String.</p> 7141 * 7142 * <p>If {@code len} characters are not available, or the String 7143 * is {@code null}, the String will be returned without an 7144 * an exception. An empty String is returned if len is negative.</p> 7145 * 7146 * <pre> 7147 * StringUtils.right(null, *) = null 7148 * StringUtils.right(*, -ve) = "" 7149 * StringUtils.right("", *) = "" 7150 * StringUtils.right("abc", 0) = "" 7151 * StringUtils.right("abc", 2) = "bc" 7152 * StringUtils.right("abc", 4) = "abc" 7153 * </pre> 7154 * 7155 * @param str the String to get the rightmost characters from, may be null 7156 * @param len the length of the required String 7157 * @return the rightmost characters, {@code null} if null String input 7158 */ 7159 public static String right(final String str, final int len) { 7160 if (str == null) { 7161 return null; 7162 } 7163 if (len < 0) { 7164 return EMPTY; 7165 } 7166 if (str.length() <= len) { 7167 return str; 7168 } 7169 return str.substring(str.length() - len); 7170 } 7171 7172 /** 7173 * <p>Right pad a String with spaces (' ').</p> 7174 * 7175 * <p>The String is padded to the size of {@code size}.</p> 7176 * 7177 * <pre> 7178 * StringUtils.rightPad(null, *) = null 7179 * StringUtils.rightPad("", 3) = " " 7180 * StringUtils.rightPad("bat", 3) = "bat" 7181 * StringUtils.rightPad("bat", 5) = "bat " 7182 * StringUtils.rightPad("bat", 1) = "bat" 7183 * StringUtils.rightPad("bat", -1) = "bat" 7184 * </pre> 7185 * 7186 * @param str the String to pad out, may be null 7187 * @param size the size to pad to 7188 * @return right padded String or original String if no padding is necessary, 7189 * {@code null} if null String input 7190 */ 7191 public static String rightPad(final String str, final int size) { 7192 return rightPad(str, size, ' '); 7193 } 7194 7195 /** 7196 * <p>Right pad a String with a specified character.</p> 7197 * 7198 * <p>The String is padded to the size of {@code size}.</p> 7199 * 7200 * <pre> 7201 * StringUtils.rightPad(null, *, *) = null 7202 * StringUtils.rightPad("", 3, 'z') = "zzz" 7203 * StringUtils.rightPad("bat", 3, 'z') = "bat" 7204 * StringUtils.rightPad("bat", 5, 'z') = "batzz" 7205 * StringUtils.rightPad("bat", 1, 'z') = "bat" 7206 * StringUtils.rightPad("bat", -1, 'z') = "bat" 7207 * </pre> 7208 * 7209 * @param str the String to pad out, may be null 7210 * @param size the size to pad to 7211 * @param padChar the character to pad with 7212 * @return right padded String or original String if no padding is necessary, 7213 * {@code null} if null String input 7214 * @since 2.0 7215 */ 7216 public static String rightPad(final String str, final int size, final char padChar) { 7217 if (str == null) { 7218 return null; 7219 } 7220 final int pads = size - str.length(); 7221 if (pads <= 0) { 7222 return str; // returns original String when possible 7223 } 7224 if (pads > PAD_LIMIT) { 7225 return rightPad(str, size, String.valueOf(padChar)); 7226 } 7227 return str.concat(repeat(padChar, pads)); 7228 } 7229 7230 /** 7231 * <p>Right pad a String with a specified String.</p> 7232 * 7233 * <p>The String is padded to the size of {@code size}.</p> 7234 * 7235 * <pre> 7236 * StringUtils.rightPad(null, *, *) = null 7237 * StringUtils.rightPad("", 3, "z") = "zzz" 7238 * StringUtils.rightPad("bat", 3, "yz") = "bat" 7239 * StringUtils.rightPad("bat", 5, "yz") = "batyz" 7240 * StringUtils.rightPad("bat", 8, "yz") = "batyzyzy" 7241 * StringUtils.rightPad("bat", 1, "yz") = "bat" 7242 * StringUtils.rightPad("bat", -1, "yz") = "bat" 7243 * StringUtils.rightPad("bat", 5, null) = "bat " 7244 * StringUtils.rightPad("bat", 5, "") = "bat " 7245 * </pre> 7246 * 7247 * @param str the String to pad out, may be null 7248 * @param size the size to pad to 7249 * @param padStr the String to pad with, null or empty treated as single space 7250 * @return right padded String or original String if no padding is necessary, 7251 * {@code null} if null String input 7252 */ 7253 public static String rightPad(final String str, final int size, String padStr) { 7254 if (str == null) { 7255 return null; 7256 } 7257 if (isEmpty(padStr)) { 7258 padStr = SPACE; 7259 } 7260 final int padLen = padStr.length(); 7261 final int strLen = str.length(); 7262 final int pads = size - strLen; 7263 if (pads <= 0) { 7264 return str; // returns original String when possible 7265 } 7266 if (padLen == 1 && pads <= PAD_LIMIT) { 7267 return rightPad(str, size, padStr.charAt(0)); 7268 } 7269 7270 if (pads == padLen) { 7271 return str.concat(padStr); 7272 } else if (pads < padLen) { 7273 return str.concat(padStr.substring(0, pads)); 7274 } else { 7275 final char[] padding = new char[pads]; 7276 final char[] padChars = padStr.toCharArray(); 7277 for (int i = 0; i < pads; i++) { 7278 padding[i] = padChars[i % padLen]; 7279 } 7280 return str.concat(new String(padding)); 7281 } 7282 } 7283 7284 /** 7285 * <p>Rotate (circular shift) a String of {@code shift} characters.</p> 7286 * <ul> 7287 * <li>If {@code shift > 0}, right circular shift (ex : ABCDEF => FABCDE)</li> 7288 * <li>If {@code shift < 0}, left circular shift (ex : ABCDEF => BCDEFA)</li> 7289 * </ul> 7290 * 7291 * <pre> 7292 * StringUtils.rotate(null, *) = null 7293 * StringUtils.rotate("", *) = "" 7294 * StringUtils.rotate("abcdefg", 0) = "abcdefg" 7295 * StringUtils.rotate("abcdefg", 2) = "fgabcde" 7296 * StringUtils.rotate("abcdefg", -2) = "cdefgab" 7297 * StringUtils.rotate("abcdefg", 7) = "abcdefg" 7298 * StringUtils.rotate("abcdefg", -7) = "abcdefg" 7299 * StringUtils.rotate("abcdefg", 9) = "fgabcde" 7300 * StringUtils.rotate("abcdefg", -9) = "cdefgab" 7301 * </pre> 7302 * 7303 * @param str the String to rotate, may be null 7304 * @param shift number of time to shift (positive : right shift, negative : left shift) 7305 * @return the rotated String, 7306 * or the original String if {@code shift == 0}, 7307 * or {@code null} if null String input 7308 * @since 3.5 7309 */ 7310 public static String rotate(final String str, final int shift) { 7311 if (str == null) { 7312 return null; 7313 } 7314 7315 final int strLen = str.length(); 7316 if (shift == 0 || strLen == 0 || shift % strLen == 0) { 7317 return str; 7318 } 7319 7320 final StringBuilder builder = new StringBuilder(strLen); 7321 final int offset = - (shift % strLen); 7322 builder.append(substring(str, offset)); 7323 builder.append(substring(str, 0, offset)); 7324 return builder.toString(); 7325 } 7326 7327 /** 7328 * <p>Splits the provided text into an array, using whitespace as the 7329 * separator. 7330 * Whitespace is defined by {@link Character#isWhitespace(char)}.</p> 7331 * 7332 * <p>The separator is not included in the returned String array. 7333 * Adjacent separators are treated as one separator. 7334 * For more control over the split use the StrTokenizer class.</p> 7335 * 7336 * <p>A {@code null} input String returns {@code null}.</p> 7337 * 7338 * <pre> 7339 * StringUtils.split(null) = null 7340 * StringUtils.split("") = [] 7341 * StringUtils.split("abc def") = ["abc", "def"] 7342 * StringUtils.split("abc def") = ["abc", "def"] 7343 * StringUtils.split(" abc ") = ["abc"] 7344 * </pre> 7345 * 7346 * @param str the String to parse, may be null 7347 * @return an array of parsed Strings, {@code null} if null String input 7348 */ 7349 public static String[] split(final String str) { 7350 return split(str, null, -1); 7351 } 7352 7353 /** 7354 * <p>Splits the provided text into an array, separator specified. 7355 * This is an alternative to using StringTokenizer.</p> 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}.</p> 7362 * 7363 * <pre> 7364 * StringUtils.split(null, *) = null 7365 * StringUtils.split("", *) = [] 7366 * StringUtils.split("a.b.c", '.') = ["a", "b", "c"] 7367 * StringUtils.split("a..b.c", '.') = ["a", "b", "c"] 7368 * StringUtils.split("a:b:c", '.') = ["a:b:c"] 7369 * StringUtils.split("a b c", ' ') = ["a", "b", "c"] 7370 * </pre> 7371 * 7372 * @param str the String to parse, may be null 7373 * @param separatorChar the character used as the delimiter 7374 * @return an array of parsed Strings, {@code null} if null String input 7375 * @since 2.0 7376 */ 7377 public static String[] split(final String str, final char separatorChar) { 7378 return splitWorker(str, separatorChar, false); 7379 } 7380 7381 /** 7382 * <p>Splits the provided text into an array, separators specified. 7383 * This is an alternative to using StringTokenizer.</p> 7384 * 7385 * <p>The separator is not included in the returned String array. 7386 * Adjacent separators are treated as one separator. 7387 * For more control over the split use the StrTokenizer class.</p> 7388 * 7389 * <p>A {@code null} input String returns {@code null}. 7390 * A {@code null} separatorChars splits on whitespace.</p> 7391 * 7392 * <pre> 7393 * StringUtils.split(null, *) = null 7394 * StringUtils.split("", *) = [] 7395 * StringUtils.split("abc def", null) = ["abc", "def"] 7396 * StringUtils.split("abc def", " ") = ["abc", "def"] 7397 * StringUtils.split("abc def", " ") = ["abc", "def"] 7398 * StringUtils.split("ab:cd:ef", ":") = ["ab", "cd", "ef"] 7399 * </pre> 7400 * 7401 * @param str the String to parse, may be null 7402 * @param separatorChars the characters used as the delimiters, 7403 * {@code null} splits on whitespace 7404 * @return an array of parsed Strings, {@code null} if null String input 7405 */ 7406 public static String[] split(final String str, final String separatorChars) { 7407 return splitWorker(str, separatorChars, -1, false); 7408 } 7409 7410 /** 7411 * <p>Splits the provided text into an array with a maximum length, 7412 * separators specified.</p> 7413 * 7414 * <p>The separator is not included in the returned String array. 7415 * Adjacent separators are treated as one separator.</p> 7416 * 7417 * <p>A {@code null} input String returns {@code null}. 7418 * A {@code null} separatorChars splits on whitespace.</p> 7419 * 7420 * <p>If more than {@code max} delimited substrings are found, the last 7421 * returned string includes all characters after the first {@code max - 1} 7422 * returned strings (including separator characters).</p> 7423 * 7424 * <pre> 7425 * StringUtils.split(null, *, *) = null 7426 * StringUtils.split("", *, *) = [] 7427 * StringUtils.split("ab cd ef", null, 0) = ["ab", "cd", "ef"] 7428 * StringUtils.split("ab cd ef", null, 0) = ["ab", "cd", "ef"] 7429 * StringUtils.split("ab:cd:ef", ":", 0) = ["ab", "cd", "ef"] 7430 * StringUtils.split("ab:cd:ef", ":", 2) = ["ab", "cd:ef"] 7431 * </pre> 7432 * 7433 * @param str the String to parse, may be null 7434 * @param separatorChars the characters used as the delimiters, 7435 * {@code null} splits on whitespace 7436 * @param max the maximum number of elements to include in the 7437 * array. A zero or negative value implies no limit 7438 * @return an array of parsed Strings, {@code null} if null String input 7439 */ 7440 public static String[] split(final String str, final String separatorChars, final int max) { 7441 return splitWorker(str, separatorChars, max, false); 7442 } 7443 7444 /** 7445 * <p>Splits a String by Character type as returned by 7446 * {@code java.lang.Character.getType(char)}. Groups of contiguous 7447 * characters of the same type are returned as complete tokens. 7448 * <pre> 7449 * StringUtils.splitByCharacterType(null) = null 7450 * StringUtils.splitByCharacterType("") = [] 7451 * StringUtils.splitByCharacterType("ab de fg") = ["ab", " ", "de", " ", "fg"] 7452 * StringUtils.splitByCharacterType("ab de fg") = ["ab", " ", "de", " ", "fg"] 7453 * StringUtils.splitByCharacterType("ab:cd:ef") = ["ab", ":", "cd", ":", "ef"] 7454 * StringUtils.splitByCharacterType("number5") = ["number", "5"] 7455 * StringUtils.splitByCharacterType("fooBar") = ["foo", "B", "ar"] 7456 * StringUtils.splitByCharacterType("foo200Bar") = ["foo", "200", "B", "ar"] 7457 * StringUtils.splitByCharacterType("ASFRules") = ["ASFR", "ules"] 7458 * </pre> 7459 * @param str the String to split, may be {@code null} 7460 * @return an array of parsed Strings, {@code null} if null String input 7461 * @since 2.4 7462 */ 7463 public static String[] splitByCharacterType(final String str) { 7464 return splitByCharacterType(str, false); 7465 } 7466 7467 /** 7468 * <p>Splits a String by Character type as returned by 7469 * {@code java.lang.Character.getType(char)}. Groups of contiguous 7470 * characters of the same type are returned as complete tokens, with the 7471 * following exception: if {@code camelCase} is {@code true}, 7472 * the character of type {@code Character.UPPERCASE_LETTER}, if any, 7473 * immediately preceding a token of type {@code Character.LOWERCASE_LETTER} 7474 * will belong to the following token rather than to the preceding, if any, 7475 * {@code Character.UPPERCASE_LETTER} token. 7476 * @param str the String to split, may be {@code null} 7477 * @param camelCase whether to use so-called "camel-case" for letter types 7478 * @return an array of parsed Strings, {@code null} if null String input 7479 * @since 2.4 7480 */ 7481 private static String[] splitByCharacterType(final String str, final boolean camelCase) { 7482 if (str == null) { 7483 return null; 7484 } 7485 if (str.isEmpty()) { 7486 return ArrayUtils.EMPTY_STRING_ARRAY; 7487 } 7488 final char[] c = str.toCharArray(); 7489 final List<String> list = new ArrayList<>(); 7490 int tokenStart = 0; 7491 int currentType = Character.getType(c[tokenStart]); 7492 for (int pos = tokenStart + 1; pos < c.length; pos++) { 7493 final int type = Character.getType(c[pos]); 7494 if (type == currentType) { 7495 continue; 7496 } 7497 if (camelCase && type == Character.LOWERCASE_LETTER && currentType == Character.UPPERCASE_LETTER) { 7498 final int newTokenStart = pos - 1; 7499 if (newTokenStart != tokenStart) { 7500 list.add(new String(c, tokenStart, newTokenStart - tokenStart)); 7501 tokenStart = newTokenStart; 7502 } 7503 } else { 7504 list.add(new String(c, tokenStart, pos - tokenStart)); 7505 tokenStart = pos; 7506 } 7507 currentType = type; 7508 } 7509 list.add(new String(c, tokenStart, c.length - tokenStart)); 7510 return list.toArray(ArrayUtils.EMPTY_STRING_ARRAY); 7511 } 7512 7513 /** 7514 * <p>Splits a String by Character type as returned by 7515 * {@code java.lang.Character.getType(char)}. Groups of contiguous 7516 * characters of the same type are returned as complete tokens, with the 7517 * following exception: the character of type 7518 * {@code Character.UPPERCASE_LETTER}, if any, immediately 7519 * preceding a token of type {@code Character.LOWERCASE_LETTER} 7520 * will belong to the following token rather than to the preceding, if any, 7521 * {@code Character.UPPERCASE_LETTER} token. 7522 * <pre> 7523 * StringUtils.splitByCharacterTypeCamelCase(null) = null 7524 * StringUtils.splitByCharacterTypeCamelCase("") = [] 7525 * StringUtils.splitByCharacterTypeCamelCase("ab de fg") = ["ab", " ", "de", " ", "fg"] 7526 * StringUtils.splitByCharacterTypeCamelCase("ab de fg") = ["ab", " ", "de", " ", "fg"] 7527 * StringUtils.splitByCharacterTypeCamelCase("ab:cd:ef") = ["ab", ":", "cd", ":", "ef"] 7528 * StringUtils.splitByCharacterTypeCamelCase("number5") = ["number", "5"] 7529 * StringUtils.splitByCharacterTypeCamelCase("fooBar") = ["foo", "Bar"] 7530 * StringUtils.splitByCharacterTypeCamelCase("foo200Bar") = ["foo", "200", "Bar"] 7531 * StringUtils.splitByCharacterTypeCamelCase("ASFRules") = ["ASF", "Rules"] 7532 * </pre> 7533 * @param str the String to split, may be {@code null} 7534 * @return an array of parsed Strings, {@code null} if null String input 7535 * @since 2.4 7536 */ 7537 public static String[] splitByCharacterTypeCamelCase(final String str) { 7538 return splitByCharacterType(str, true); 7539 } 7540 7541 /** 7542 * <p>Splits the provided text into an array, separator string specified.</p> 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) = ["ab", "de", "fg"] 7554 * StringUtils.splitByWholeSeparator("ab de fg", null) = ["ab", "de", "fg"] 7555 * StringUtils.splitByWholeSeparator("ab:cd:ef", ":") = ["ab", "cd", "ef"] 7556 * StringUtils.splitByWholeSeparator("ab-!-cd-!-ef", "-!-") = ["ab", "cd", "ef"] 7557 * </pre> 7558 * 7559 * @param str the String to parse, may be null 7560 * @param separator String containing the String to be used as a delimiter, 7561 * {@code null} splits on whitespace 7562 * @return an array of parsed Strings, {@code null} if null String was input 7563 */ 7564 public static String[] splitByWholeSeparator(final String str, final String separator) { 7565 return splitByWholeSeparatorWorker(str, separator, -1, false); 7566 } 7567 7568 /** 7569 * <p>Splits the provided text into an array, separator string specified. 7570 * Returns a maximum of {@code max} substrings.</p> 7571 * 7572 * <p>The separator(s) will not be included in the returned String array. 7573 * Adjacent separators are treated as one separator.</p> 7574 * 7575 * <p>A {@code null} input String returns {@code null}. 7576 * A {@code null} separator splits on whitespace.</p> 7577 * 7578 * <pre> 7579 * StringUtils.splitByWholeSeparator(null, *, *) = null 7580 * StringUtils.splitByWholeSeparator("", *, *) = [] 7581 * StringUtils.splitByWholeSeparator("ab de fg", null, 0) = ["ab", "de", "fg"] 7582 * StringUtils.splitByWholeSeparator("ab de fg", null, 0) = ["ab", "de", "fg"] 7583 * StringUtils.splitByWholeSeparator("ab:cd:ef", ":", 2) = ["ab", "cd:ef"] 7584 * StringUtils.splitByWholeSeparator("ab-!-cd-!-ef", "-!-", 5) = ["ab", "cd", "ef"] 7585 * StringUtils.splitByWholeSeparator("ab-!-cd-!-ef", "-!-", 2) = ["ab", "cd-!-ef"] 7586 * </pre> 7587 * 7588 * @param str the String to parse, may be null 7589 * @param separator String containing the String to be used as a delimiter, 7590 * {@code null} splits on whitespace 7591 * @param max the maximum number of elements to include in the returned 7592 * array. A zero or negative value implies no limit. 7593 * @return an array of parsed Strings, {@code null} if null String was input 7594 */ 7595 public static String[] splitByWholeSeparator( final String str, final String separator, final int max) { 7596 return splitByWholeSeparatorWorker(str, separator, max, false); 7597 } 7598 7599 /** 7600 * <p>Splits the provided text into an array, separator string specified. </p> 7601 * 7602 * <p>The separator is not included in the returned String array. 7603 * Adjacent separators are treated as separators for empty tokens. 7604 * For more control over the split use the StrTokenizer class.</p> 7605 * 7606 * <p>A {@code null} input String returns {@code null}. 7607 * A {@code null} separator splits on whitespace.</p> 7608 * 7609 * <pre> 7610 * StringUtils.splitByWholeSeparatorPreserveAllTokens(null, *) = null 7611 * StringUtils.splitByWholeSeparatorPreserveAllTokens("", *) = [] 7612 * StringUtils.splitByWholeSeparatorPreserveAllTokens("ab de fg", null) = ["ab", "de", "fg"] 7613 * StringUtils.splitByWholeSeparatorPreserveAllTokens("ab de fg", null) = ["ab", "", "", "de", "fg"] 7614 * StringUtils.splitByWholeSeparatorPreserveAllTokens("ab:cd:ef", ":") = ["ab", "cd", "ef"] 7615 * StringUtils.splitByWholeSeparatorPreserveAllTokens("ab-!-cd-!-ef", "-!-") = ["ab", "cd", "ef"] 7616 * </pre> 7617 * 7618 * @param str the String to parse, may be null 7619 * @param separator String containing the String to be used as a delimiter, 7620 * {@code null} splits on whitespace 7621 * @return an array of parsed Strings, {@code null} if null String was input 7622 * @since 2.4 7623 */ 7624 public static String[] splitByWholeSeparatorPreserveAllTokens(final String str, final String separator) { 7625 return splitByWholeSeparatorWorker(str, separator, -1, true); 7626 } 7627 7628 /** 7629 * <p>Splits the provided text into an array, separator string specified. 7630 * Returns a maximum of {@code max} substrings.</p> 7631 * 7632 * <p>The separator is not included in the returned String array. 7633 * Adjacent separators are treated as separators for empty tokens. 7634 * For more control over the split use the StrTokenizer class.</p> 7635 * 7636 * <p>A {@code null} input String returns {@code null}. 7637 * A {@code null} separator splits on whitespace.</p> 7638 * 7639 * <pre> 7640 * StringUtils.splitByWholeSeparatorPreserveAllTokens(null, *, *) = null 7641 * StringUtils.splitByWholeSeparatorPreserveAllTokens("", *, *) = [] 7642 * StringUtils.splitByWholeSeparatorPreserveAllTokens("ab de fg", null, 0) = ["ab", "de", "fg"] 7643 * StringUtils.splitByWholeSeparatorPreserveAllTokens("ab de fg", null, 0) = ["ab", "", "", "de", "fg"] 7644 * StringUtils.splitByWholeSeparatorPreserveAllTokens("ab:cd:ef", ":", 2) = ["ab", "cd:ef"] 7645 * StringUtils.splitByWholeSeparatorPreserveAllTokens("ab-!-cd-!-ef", "-!-", 5) = ["ab", "cd", "ef"] 7646 * StringUtils.splitByWholeSeparatorPreserveAllTokens("ab-!-cd-!-ef", "-!-", 2) = ["ab", "cd-!-ef"] 7647 * </pre> 7648 * 7649 * @param str the String to parse, may be null 7650 * @param separator String containing the String to be used as a delimiter, 7651 * {@code null} splits on whitespace 7652 * @param max the maximum number of elements to include in the returned 7653 * array. A zero or negative value implies no limit. 7654 * @return an array of parsed Strings, {@code null} if null String was input 7655 * @since 2.4 7656 */ 7657 public static String[] splitByWholeSeparatorPreserveAllTokens(final String str, final String separator, final int max) { 7658 return splitByWholeSeparatorWorker(str, separator, max, true); 7659 } 7660 7661 /** 7662 * Performs the logic for the {@code splitByWholeSeparatorPreserveAllTokens} methods. 7663 * 7664 * @param str the String to parse, may be {@code null} 7665 * @param separator String containing the String to be used as a delimiter, 7666 * {@code null} splits on whitespace 7667 * @param max the maximum number of elements to include in the returned 7668 * array. A zero or negative value implies no limit. 7669 * @param preserveAllTokens if {@code true}, adjacent separators are 7670 * treated as empty token separators; if {@code false}, adjacent 7671 * separators are treated as one separator. 7672 * @return an array of parsed Strings, {@code null} if null String input 7673 * @since 2.4 7674 */ 7675 private static String[] splitByWholeSeparatorWorker( 7676 final String str, final String separator, final int max, final boolean preserveAllTokens) { 7677 if (str == null) { 7678 return null; 7679 } 7680 7681 final int len = str.length(); 7682 7683 if (len == 0) { 7684 return ArrayUtils.EMPTY_STRING_ARRAY; 7685 } 7686 7687 if (separator == null || EMPTY.equals(separator)) { 7688 // Split on whitespace. 7689 return splitWorker(str, null, max, preserveAllTokens); 7690 } 7691 7692 final int separatorLength = separator.length(); 7693 7694 final ArrayList<String> substrings = new ArrayList<>(); 7695 int numberOfSubstrings = 0; 7696 int beg = 0; 7697 int end = 0; 7698 while (end < len) { 7699 end = str.indexOf(separator, beg); 7700 7701 if (end > -1) { 7702 if (end > beg) { 7703 numberOfSubstrings += 1; 7704 7705 if (numberOfSubstrings == max) { 7706 end = len; 7707 substrings.add(str.substring(beg)); 7708 } else { 7709 // The following is OK, because String.substring( beg, end ) excludes 7710 // the character at the position 'end'. 7711 substrings.add(str.substring(beg, end)); 7712 7713 // Set the starting point for the next search. 7714 // The following is equivalent to beg = end + (separatorLength - 1) + 1, 7715 // which is the right calculation: 7716 beg = end + separatorLength; 7717 } 7718 } else { 7719 // We found a consecutive occurrence of the separator, so skip it. 7720 if (preserveAllTokens) { 7721 numberOfSubstrings += 1; 7722 if (numberOfSubstrings == max) { 7723 end = len; 7724 substrings.add(str.substring(beg)); 7725 } else { 7726 substrings.add(EMPTY); 7727 } 7728 } 7729 beg = end + separatorLength; 7730 } 7731 } else { 7732 // String.substring( beg ) goes from 'beg' to the end of the String. 7733 substrings.add(str.substring(beg)); 7734 end = len; 7735 } 7736 } 7737 7738 return substrings.toArray(ArrayUtils.EMPTY_STRING_ARRAY); 7739 } 7740 7741 /** 7742 * <p>Splits the provided text into an array, using whitespace as the 7743 * separator, preserving all tokens, including empty tokens created by 7744 * adjacent separators. This is an alternative to using StringTokenizer. 7745 * Whitespace is defined by {@link Character#isWhitespace(char)}.</p> 7746 * 7747 * <p>The separator is not included in the returned String array. 7748 * Adjacent separators are treated as separators for empty tokens. 7749 * For more control over the split use the StrTokenizer class.</p> 7750 * 7751 * <p>A {@code null} input String returns {@code null}.</p> 7752 * 7753 * <pre> 7754 * StringUtils.splitPreserveAllTokens(null) = null 7755 * StringUtils.splitPreserveAllTokens("") = [] 7756 * StringUtils.splitPreserveAllTokens("abc def") = ["abc", "def"] 7757 * StringUtils.splitPreserveAllTokens("abc def") = ["abc", "", "def"] 7758 * StringUtils.splitPreserveAllTokens(" abc ") = ["", "abc", ""] 7759 * </pre> 7760 * 7761 * @param str the String to parse, may be {@code null} 7762 * @return an array of parsed Strings, {@code null} if null String input 7763 * @since 2.1 7764 */ 7765 public static String[] splitPreserveAllTokens(final String str) { 7766 return splitWorker(str, null, -1, true); 7767 } 7768 7769 /** 7770 * <p>Splits the provided text into an array, separator specified, 7771 * preserving all tokens, including empty tokens created by adjacent 7772 * separators. This is an alternative to using StringTokenizer.</p> 7773 * 7774 * <p>The separator is not included in the returned String array. 7775 * Adjacent separators are treated as separators for empty tokens. 7776 * For more control over the split use the StrTokenizer class.</p> 7777 * 7778 * <p>A {@code null} input String returns {@code null}.</p> 7779 * 7780 * <pre> 7781 * StringUtils.splitPreserveAllTokens(null, *) = null 7782 * StringUtils.splitPreserveAllTokens("", *) = [] 7783 * StringUtils.splitPreserveAllTokens("a.b.c", '.') = ["a", "b", "c"] 7784 * StringUtils.splitPreserveAllTokens("a..b.c", '.') = ["a", "", "b", "c"] 7785 * StringUtils.splitPreserveAllTokens("a:b:c", '.') = ["a:b:c"] 7786 * StringUtils.splitPreserveAllTokens("a\tb\nc", null) = ["a", "b", "c"] 7787 * StringUtils.splitPreserveAllTokens("a b c", ' ') = ["a", "b", "c"] 7788 * StringUtils.splitPreserveAllTokens("a b c ", ' ') = ["a", "b", "c", ""] 7789 * StringUtils.splitPreserveAllTokens("a b c ", ' ') = ["a", "b", "c", "", ""] 7790 * StringUtils.splitPreserveAllTokens(" a b c", ' ') = ["", a", "b", "c"] 7791 * StringUtils.splitPreserveAllTokens(" a b c", ' ') = ["", "", a", "b", "c"] 7792 * StringUtils.splitPreserveAllTokens(" a b c ", ' ') = ["", a", "b", "c", ""] 7793 * </pre> 7794 * 7795 * @param str the String to parse, may be {@code null} 7796 * @param separatorChar the character used as the delimiter, 7797 * {@code null} splits on whitespace 7798 * @return an array of parsed Strings, {@code null} if null String input 7799 * @since 2.1 7800 */ 7801 public static String[] splitPreserveAllTokens(final String str, final char separatorChar) { 7802 return splitWorker(str, separatorChar, true); 7803 } 7804 7805 /** 7806 * <p>Splits the provided text into an array, separators specified, 7807 * preserving all tokens, including empty tokens created by adjacent 7808 * separators. This is an alternative to using StringTokenizer.</p> 7809 * 7810 * <p>The separator is not included in the returned String array. 7811 * Adjacent separators are treated as separators for empty tokens. 7812 * For more control over the split use the StrTokenizer class.</p> 7813 * 7814 * <p>A {@code null} input String returns {@code null}. 7815 * A {@code null} separatorChars splits on whitespace.</p> 7816 * 7817 * <pre> 7818 * StringUtils.splitPreserveAllTokens(null, *) = null 7819 * StringUtils.splitPreserveAllTokens("", *) = [] 7820 * StringUtils.splitPreserveAllTokens("abc def", null) = ["abc", "def"] 7821 * StringUtils.splitPreserveAllTokens("abc def", " ") = ["abc", "def"] 7822 * StringUtils.splitPreserveAllTokens("abc def", " ") = ["abc", "", def"] 7823 * StringUtils.splitPreserveAllTokens("ab:cd:ef", ":") = ["ab", "cd", "ef"] 7824 * StringUtils.splitPreserveAllTokens("ab:cd:ef:", ":") = ["ab", "cd", "ef", ""] 7825 * StringUtils.splitPreserveAllTokens("ab:cd:ef::", ":") = ["ab", "cd", "ef", "", ""] 7826 * StringUtils.splitPreserveAllTokens("ab::cd:ef", ":") = ["ab", "", cd", "ef"] 7827 * StringUtils.splitPreserveAllTokens(":cd:ef", ":") = ["", cd", "ef"] 7828 * StringUtils.splitPreserveAllTokens("::cd:ef", ":") = ["", "", cd", "ef"] 7829 * StringUtils.splitPreserveAllTokens(":cd:ef:", ":") = ["", cd", "ef", ""] 7830 * </pre> 7831 * 7832 * @param str the String to parse, may be {@code null} 7833 * @param separatorChars the characters used as the delimiters, 7834 * {@code null} splits on whitespace 7835 * @return an array of parsed Strings, {@code null} if null String input 7836 * @since 2.1 7837 */ 7838 public static String[] splitPreserveAllTokens(final String str, final String separatorChars) { 7839 return splitWorker(str, separatorChars, -1, true); 7840 } 7841 7842 /** 7843 * <p>Splits the provided text into an array with a maximum length, 7844 * separators specified, preserving all tokens, including empty tokens 7845 * created by adjacent separators.</p> 7846 * 7847 * <p>The separator is not included in the returned String array. 7848 * Adjacent separators are treated as separators for empty tokens. 7849 * Adjacent separators are treated as one separator.</p> 7850 * 7851 * <p>A {@code null} input String returns {@code null}. 7852 * A {@code null} separatorChars splits on whitespace.</p> 7853 * 7854 * <p>If more than {@code max} delimited substrings are found, the last 7855 * returned string includes all characters after the first {@code max - 1} 7856 * returned strings (including separator characters).</p> 7857 * 7858 * <pre> 7859 * StringUtils.splitPreserveAllTokens(null, *, *) = null 7860 * StringUtils.splitPreserveAllTokens("", *, *) = [] 7861 * StringUtils.splitPreserveAllTokens("ab de fg", null, 0) = ["ab", "de", "fg"] 7862 * StringUtils.splitPreserveAllTokens("ab de fg", null, 0) = ["ab", "", "", "de", "fg"] 7863 * StringUtils.splitPreserveAllTokens("ab:cd:ef", ":", 0) = ["ab", "cd", "ef"] 7864 * StringUtils.splitPreserveAllTokens("ab:cd:ef", ":", 2) = ["ab", "cd:ef"] 7865 * StringUtils.splitPreserveAllTokens("ab de fg", null, 2) = ["ab", " de fg"] 7866 * StringUtils.splitPreserveAllTokens("ab de fg", null, 3) = ["ab", "", " de fg"] 7867 * StringUtils.splitPreserveAllTokens("ab de fg", null, 4) = ["ab", "", "", "de fg"] 7868 * </pre> 7869 * 7870 * @param str the String to parse, may be {@code null} 7871 * @param separatorChars the characters used as the delimiters, 7872 * {@code null} splits on whitespace 7873 * @param max the maximum number of elements to include in the 7874 * array. A zero or negative value implies no limit 7875 * @return an array of parsed Strings, {@code null} if null String input 7876 * @since 2.1 7877 */ 7878 public static String[] splitPreserveAllTokens(final String str, final String separatorChars, final int max) { 7879 return splitWorker(str, separatorChars, max, true); 7880 } 7881 7882 /** 7883 * Performs the logic for the {@code split} and 7884 * {@code splitPreserveAllTokens} methods that do not return a 7885 * maximum array length. 7886 * 7887 * @param str the String to parse, may be {@code null} 7888 * @param separatorChar the separate character 7889 * @param preserveAllTokens if {@code true}, adjacent separators are 7890 * treated as empty token separators; if {@code false}, adjacent 7891 * separators are treated as one separator. 7892 * @return an array of parsed Strings, {@code null} if null String input 7893 */ 7894 private static String[] splitWorker(final String str, final char separatorChar, final boolean preserveAllTokens) { 7895 // Performance tuned for 2.0 (JDK1.4) 7896 7897 if (str == null) { 7898 return null; 7899 } 7900 final int len = str.length(); 7901 if (len == 0) { 7902 return ArrayUtils.EMPTY_STRING_ARRAY; 7903 } 7904 final List<String> list = new ArrayList<>(); 7905 int i = 0; 7906 int start = 0; 7907 boolean match = false; 7908 boolean lastMatch = false; 7909 while (i < len) { 7910 if (str.charAt(i) == separatorChar) { 7911 if (match || preserveAllTokens) { 7912 list.add(str.substring(start, i)); 7913 match = false; 7914 lastMatch = true; 7915 } 7916 start = ++i; 7917 continue; 7918 } 7919 lastMatch = false; 7920 match = true; 7921 i++; 7922 } 7923 if (match || preserveAllTokens && lastMatch) { 7924 list.add(str.substring(start, i)); 7925 } 7926 return list.toArray(ArrayUtils.EMPTY_STRING_ARRAY); 7927 } 7928 7929 /** 7930 * Performs the logic for the {@code split} and 7931 * {@code splitPreserveAllTokens} methods that return a maximum array 7932 * length. 7933 * 7934 * @param str the String to parse, may be {@code null} 7935 * @param separatorChars the separate character 7936 * @param max the maximum number of elements to include in the 7937 * array. A zero or negative value implies no limit. 7938 * @param preserveAllTokens if {@code true}, adjacent separators are 7939 * treated as empty token separators; if {@code false}, adjacent 7940 * separators are treated as one separator. 7941 * @return an array of parsed Strings, {@code null} if null String input 7942 */ 7943 private static String[] splitWorker(final String str, final String separatorChars, final int max, final boolean preserveAllTokens) { 7944 // Performance tuned for 2.0 (JDK1.4) 7945 // Direct code is quicker than StringTokenizer. 7946 // Also, StringTokenizer uses isSpace() not isWhitespace() 7947 7948 if (str == null) { 7949 return null; 7950 } 7951 final int len = str.length(); 7952 if (len == 0) { 7953 return ArrayUtils.EMPTY_STRING_ARRAY; 7954 } 7955 final List<String> list = new ArrayList<>(); 7956 int sizePlus1 = 1; 7957 int i = 0; 7958 int start = 0; 7959 boolean match = false; 7960 boolean lastMatch = false; 7961 if (separatorChars == null) { 7962 // Null separator means use whitespace 7963 while (i < len) { 7964 if (Character.isWhitespace(str.charAt(i))) { 7965 if (match || preserveAllTokens) { 7966 lastMatch = true; 7967 if (sizePlus1++ == max) { 7968 i = len; 7969 lastMatch = false; 7970 } 7971 list.add(str.substring(start, i)); 7972 match = false; 7973 } 7974 start = ++i; 7975 continue; 7976 } 7977 lastMatch = false; 7978 match = true; 7979 i++; 7980 } 7981 } else if (separatorChars.length() == 1) { 7982 // Optimise 1 character case 7983 final char sep = separatorChars.charAt(0); 7984 while (i < len) { 7985 if (str.charAt(i) == sep) { 7986 if (match || preserveAllTokens) { 7987 lastMatch = true; 7988 if (sizePlus1++ == max) { 7989 i = len; 7990 lastMatch = false; 7991 } 7992 list.add(str.substring(start, i)); 7993 match = false; 7994 } 7995 start = ++i; 7996 continue; 7997 } 7998 lastMatch = false; 7999 match = true; 8000 i++; 8001 } 8002 } else { 8003 // standard case 8004 while (i < len) { 8005 if (separatorChars.indexOf(str.charAt(i)) >= 0) { 8006 if (match || preserveAllTokens) { 8007 lastMatch = true; 8008 if (sizePlus1++ == max) { 8009 i = len; 8010 lastMatch = false; 8011 } 8012 list.add(str.substring(start, i)); 8013 match = false; 8014 } 8015 start = ++i; 8016 continue; 8017 } 8018 lastMatch = false; 8019 match = true; 8020 i++; 8021 } 8022 } 8023 if (match || preserveAllTokens && lastMatch) { 8024 list.add(str.substring(start, i)); 8025 } 8026 return list.toArray(ArrayUtils.EMPTY_STRING_ARRAY); 8027 } 8028 8029 /** 8030 * <p>Check if a CharSequence starts with a specified prefix.</p> 8031 * 8032 * <p>{@code null}s are handled without exceptions. Two {@code null} 8033 * references are considered to be equal. The comparison is case sensitive.</p> 8034 * 8035 * <pre> 8036 * StringUtils.startsWith(null, null) = true 8037 * StringUtils.startsWith(null, "abc") = false 8038 * StringUtils.startsWith("abcdef", null) = false 8039 * StringUtils.startsWith("abcdef", "abc") = true 8040 * StringUtils.startsWith("ABCDEF", "abc") = false 8041 * </pre> 8042 * 8043 * @see java.lang.String#startsWith(String) 8044 * @param str the CharSequence to check, may be null 8045 * @param prefix the prefix to find, may be null 8046 * @return {@code true} if the CharSequence starts with the prefix, case sensitive, or 8047 * both {@code null} 8048 * @since 2.4 8049 * @since 3.0 Changed signature from startsWith(String, String) to startsWith(CharSequence, CharSequence) 8050 */ 8051 public static boolean startsWith(final CharSequence str, final CharSequence prefix) { 8052 return startsWith(str, prefix, false); 8053 } 8054 8055 /** 8056 * <p>Check if a CharSequence starts with a specified prefix (optionally case insensitive).</p> 8057 * 8058 * @see java.lang.String#startsWith(String) 8059 * @param str the CharSequence to check, may be null 8060 * @param prefix the prefix to find, may be null 8061 * @param ignoreCase indicates whether the compare should ignore case 8062 * (case insensitive) or not. 8063 * @return {@code true} if the CharSequence starts with the prefix or 8064 * both {@code null} 8065 */ 8066 private static boolean startsWith(final CharSequence str, final CharSequence prefix, final boolean ignoreCase) { 8067 if (str == null || prefix == null) { 8068 return str == prefix; 8069 } 8070 // Get length once instead of twice in the unlikely case that it changes. 8071 final int preLen = prefix.length(); 8072 if (preLen > str.length()) { 8073 return false; 8074 } 8075 return CharSequenceUtils.regionMatches(str, ignoreCase, 0, prefix, 0, preLen); 8076 } 8077 8078 /** 8079 * <p>Check if a CharSequence starts with any of the provided case-sensitive prefixes.</p> 8080 * 8081 * <pre> 8082 * StringUtils.startsWithAny(null, null) = false 8083 * StringUtils.startsWithAny(null, new String[] {"abc"}) = false 8084 * StringUtils.startsWithAny("abcxyz", null) = false 8085 * StringUtils.startsWithAny("abcxyz", new String[] {""}) = true 8086 * StringUtils.startsWithAny("abcxyz", new String[] {"abc"}) = true 8087 * StringUtils.startsWithAny("abcxyz", new String[] {null, "xyz", "abc"}) = true 8088 * StringUtils.startsWithAny("abcxyz", null, "xyz", "ABCX") = false 8089 * StringUtils.startsWithAny("ABCXYZ", null, "xyz", "abc") = false 8090 * </pre> 8091 * 8092 * @param sequence the CharSequence to check, may be null 8093 * @param searchStrings the case-sensitive CharSequence prefixes, may be empty or contain {@code null} 8094 * @see StringUtils#startsWith(CharSequence, CharSequence) 8095 * @return {@code true} if the input {@code sequence} is {@code null} AND no {@code searchStrings} are provided, or 8096 * the input {@code sequence} begins with any of the provided case-sensitive {@code searchStrings}. 8097 * @since 2.5 8098 * @since 3.0 Changed signature from startsWithAny(String, String[]) to startsWithAny(CharSequence, CharSequence...) 8099 */ 8100 public static boolean startsWithAny(final CharSequence sequence, final CharSequence... searchStrings) { 8101 if (isEmpty(sequence) || ArrayUtils.isEmpty(searchStrings)) { 8102 return false; 8103 } 8104 for (final CharSequence searchString : searchStrings) { 8105 if (startsWith(sequence, searchString)) { 8106 return true; 8107 } 8108 } 8109 return false; 8110 } 8111 8112 /** 8113 * <p>Case insensitive check if a CharSequence starts with a specified prefix.</p> 8114 * 8115 * <p>{@code null}s are handled without exceptions. Two {@code null} 8116 * references are considered to be equal. The comparison is case insensitive.</p> 8117 * 8118 * <pre> 8119 * StringUtils.startsWithIgnoreCase(null, null) = true 8120 * StringUtils.startsWithIgnoreCase(null, "abc") = false 8121 * StringUtils.startsWithIgnoreCase("abcdef", null) = false 8122 * StringUtils.startsWithIgnoreCase("abcdef", "abc") = true 8123 * StringUtils.startsWithIgnoreCase("ABCDEF", "abc") = true 8124 * </pre> 8125 * 8126 * @see java.lang.String#startsWith(String) 8127 * @param str the CharSequence to check, may be null 8128 * @param prefix the prefix to find, may be null 8129 * @return {@code true} if the CharSequence starts with the prefix, case insensitive, or 8130 * both {@code null} 8131 * @since 2.4 8132 * @since 3.0 Changed signature from startsWithIgnoreCase(String, String) to startsWithIgnoreCase(CharSequence, CharSequence) 8133 */ 8134 public static boolean startsWithIgnoreCase(final CharSequence str, final CharSequence prefix) { 8135 return startsWith(str, prefix, true); 8136 } 8137 8138 /** 8139 * <p>Strips whitespace from the start and end of a String.</p> 8140 * 8141 * <p>This is similar to {@link #trim(String)} but removes whitespace. 8142 * Whitespace is defined by {@link Character#isWhitespace(char)}.</p> 8143 * 8144 * <p>A {@code null} input String returns {@code null}.</p> 8145 * 8146 * <pre> 8147 * StringUtils.strip(null) = null 8148 * StringUtils.strip("") = "" 8149 * StringUtils.strip(" ") = "" 8150 * StringUtils.strip("abc") = "abc" 8151 * StringUtils.strip(" abc") = "abc" 8152 * StringUtils.strip("abc ") = "abc" 8153 * StringUtils.strip(" abc ") = "abc" 8154 * StringUtils.strip(" ab c ") = "ab c" 8155 * </pre> 8156 * 8157 * @param str the String to remove whitespace from, may be null 8158 * @return the stripped String, {@code null} if null String input 8159 */ 8160 public static String strip(final String str) { 8161 return strip(str, null); 8162 } 8163 8164 /** 8165 * <p>Strips any of a set of characters from the start and end of a String. 8166 * This is similar to {@link String#trim()} but allows the characters 8167 * to be stripped to be controlled.</p> 8168 * 8169 * <p>A {@code null} input String returns {@code null}. 8170 * An empty string ("") input returns the empty string.</p> 8171 * 8172 * <p>If the stripChars String is {@code null}, whitespace is 8173 * stripped as defined by {@link Character#isWhitespace(char)}. 8174 * Alternatively use {@link #strip(String)}.</p> 8175 * 8176 * <pre> 8177 * StringUtils.strip(null, *) = null 8178 * StringUtils.strip("", *) = "" 8179 * StringUtils.strip("abc", null) = "abc" 8180 * StringUtils.strip(" abc", null) = "abc" 8181 * StringUtils.strip("abc ", null) = "abc" 8182 * StringUtils.strip(" abc ", null) = "abc" 8183 * StringUtils.strip(" abcyx", "xyz") = " abc" 8184 * </pre> 8185 * 8186 * @param str the String to remove characters from, may be null 8187 * @param stripChars the characters to remove, null treated as whitespace 8188 * @return the stripped String, {@code null} if null String input 8189 */ 8190 public static String strip(String str, final String stripChars) { 8191 str = stripStart(str, stripChars); 8192 return stripEnd(str, stripChars); 8193 } 8194 8195 /** 8196 * <p>Removes diacritics (~= accents) from a string. The case will not be altered.</p> 8197 * <p>For instance, 'à' will be replaced by 'a'.</p> 8198 * <p>Note that ligatures will be left as is.</p> 8199 * 8200 * <pre> 8201 * StringUtils.stripAccents(null) = null 8202 * StringUtils.stripAccents("") = "" 8203 * StringUtils.stripAccents("control") = "control" 8204 * StringUtils.stripAccents("éclair") = "eclair" 8205 * </pre> 8206 * 8207 * @param input String to be stripped 8208 * @return input text with diacritics removed 8209 * 8210 * @since 3.0 8211 */ 8212 // 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). 8213 public static String stripAccents(final String input) { 8214 if (input == null) { 8215 return null; 8216 } 8217 final StringBuilder decomposed = new StringBuilder(Normalizer.normalize(input, Normalizer.Form.NFD)); 8218 convertRemainingAccentCharacters(decomposed); 8219 // Note that this doesn't correctly remove ligatures... 8220 return STRIP_ACCENTS_PATTERN.matcher(decomposed).replaceAll(EMPTY); 8221 } 8222 8223 /** 8224 * <p>Strips whitespace from the start and end of every String in an array. 8225 * Whitespace is defined by {@link Character#isWhitespace(char)}.</p> 8226 * 8227 * <p>A new array is returned each time, except for length zero. 8228 * A {@code null} array will return {@code null}. 8229 * An empty array will return itself. 8230 * A {@code null} array entry will be ignored.</p> 8231 * 8232 * <pre> 8233 * StringUtils.stripAll(null) = null 8234 * StringUtils.stripAll([]) = [] 8235 * StringUtils.stripAll(["abc", " abc"]) = ["abc", "abc"] 8236 * StringUtils.stripAll(["abc ", null]) = ["abc", null] 8237 * </pre> 8238 * 8239 * @param strs the array to remove whitespace from, may be null 8240 * @return the stripped Strings, {@code null} if null array input 8241 */ 8242 public static String[] stripAll(final String... strs) { 8243 return stripAll(strs, null); 8244 } 8245 8246 /** 8247 * <p>Strips any of a set of characters from the start and end of every 8248 * String in an array.</p> 8249 * <p>Whitespace is defined by {@link Character#isWhitespace(char)}.</p> 8250 * 8251 * <p>A new array is returned each time, except for length zero. 8252 * A {@code null} array will return {@code null}. 8253 * An empty array will return itself. 8254 * A {@code null} array entry will be ignored. 8255 * A {@code null} stripChars will strip whitespace as defined by 8256 * {@link Character#isWhitespace(char)}.</p> 8257 * 8258 * <pre> 8259 * StringUtils.stripAll(null, *) = null 8260 * StringUtils.stripAll([], *) = [] 8261 * StringUtils.stripAll(["abc", " abc"], null) = ["abc", "abc"] 8262 * StringUtils.stripAll(["abc ", null], null) = ["abc", null] 8263 * StringUtils.stripAll(["abc ", null], "yz") = ["abc ", null] 8264 * StringUtils.stripAll(["yabcz", null], "yz") = ["abc", null] 8265 * </pre> 8266 * 8267 * @param strs the array to remove characters from, may be null 8268 * @param stripChars the characters to remove, null treated as whitespace 8269 * @return the stripped Strings, {@code null} if null array input 8270 */ 8271 public static String[] stripAll(final String[] strs, final String stripChars) { 8272 final int strsLen = ArrayUtils.getLength(strs); 8273 if (strsLen == 0) { 8274 return strs; 8275 } 8276 final String[] newArr = new String[strsLen]; 8277 for (int i = 0; i < strsLen; i++) { 8278 newArr[i] = strip(strs[i], stripChars); 8279 } 8280 return newArr; 8281 } 8282 8283 /** 8284 * <p>Strips any of a set of characters from the end of a String.</p> 8285 * 8286 * <p>A {@code null} input String returns {@code null}. 8287 * An empty string ("") input returns the empty string.</p> 8288 * 8289 * <p>If the stripChars String is {@code null}, whitespace is 8290 * stripped as defined by {@link Character#isWhitespace(char)}.</p> 8291 * 8292 * <pre> 8293 * StringUtils.stripEnd(null, *) = null 8294 * StringUtils.stripEnd("", *) = "" 8295 * StringUtils.stripEnd("abc", "") = "abc" 8296 * StringUtils.stripEnd("abc", null) = "abc" 8297 * StringUtils.stripEnd(" abc", null) = " abc" 8298 * StringUtils.stripEnd("abc ", null) = "abc" 8299 * StringUtils.stripEnd(" abc ", null) = " abc" 8300 * StringUtils.stripEnd(" abcyx", "xyz") = " abc" 8301 * StringUtils.stripEnd("120.00", ".0") = "12" 8302 * </pre> 8303 * 8304 * @param str the String to remove characters from, may be null 8305 * @param stripChars the set of characters to remove, null treated as whitespace 8306 * @return the stripped String, {@code null} if null String input 8307 */ 8308 public static String stripEnd(final String str, final String stripChars) { 8309 int end = length(str); 8310 if (end == 0) { 8311 return str; 8312 } 8313 8314 if (stripChars == null) { 8315 while (end != 0 && Character.isWhitespace(str.charAt(end - 1))) { 8316 end--; 8317 } 8318 } else if (stripChars.isEmpty()) { 8319 return str; 8320 } else { 8321 while (end != 0 && stripChars.indexOf(str.charAt(end - 1)) != INDEX_NOT_FOUND) { 8322 end--; 8323 } 8324 } 8325 return str.substring(0, end); 8326 } 8327 8328 /** 8329 * <p>Strips any of a set of characters from the start of a String.</p> 8330 * 8331 * <p>A {@code null} input String returns {@code null}. 8332 * An empty string ("") input returns the empty string.</p> 8333 * 8334 * <p>If the stripChars String is {@code null}, whitespace is 8335 * stripped as defined by {@link Character#isWhitespace(char)}.</p> 8336 * 8337 * <pre> 8338 * StringUtils.stripStart(null, *) = null 8339 * StringUtils.stripStart("", *) = "" 8340 * StringUtils.stripStart("abc", "") = "abc" 8341 * StringUtils.stripStart("abc", null) = "abc" 8342 * StringUtils.stripStart(" abc", null) = "abc" 8343 * StringUtils.stripStart("abc ", null) = "abc " 8344 * StringUtils.stripStart(" abc ", null) = "abc " 8345 * StringUtils.stripStart("yxabc ", "xyz") = "abc " 8346 * </pre> 8347 * 8348 * @param str the String to remove characters from, may be null 8349 * @param stripChars the characters to remove, null treated as whitespace 8350 * @return the stripped String, {@code null} if null String input 8351 */ 8352 public static String stripStart(final String str, final String stripChars) { 8353 final int strLen = length(str); 8354 if (strLen == 0) { 8355 return str; 8356 } 8357 int start = 0; 8358 if (stripChars == null) { 8359 while (start != strLen && Character.isWhitespace(str.charAt(start))) { 8360 start++; 8361 } 8362 } else if (stripChars.isEmpty()) { 8363 return str; 8364 } else { 8365 while (start != strLen && stripChars.indexOf(str.charAt(start)) != INDEX_NOT_FOUND) { 8366 start++; 8367 } 8368 } 8369 return str.substring(start); 8370 } 8371 8372 /** 8373 * <p>Strips whitespace from the start and end of a String returning 8374 * an empty String if {@code null} input.</p> 8375 * 8376 * <p>This is similar to {@link #trimToEmpty(String)} but removes whitespace. 8377 * Whitespace is defined by {@link Character#isWhitespace(char)}.</p> 8378 * 8379 * <pre> 8380 * StringUtils.stripToEmpty(null) = "" 8381 * StringUtils.stripToEmpty("") = "" 8382 * StringUtils.stripToEmpty(" ") = "" 8383 * StringUtils.stripToEmpty("abc") = "abc" 8384 * StringUtils.stripToEmpty(" abc") = "abc" 8385 * StringUtils.stripToEmpty("abc ") = "abc" 8386 * StringUtils.stripToEmpty(" abc ") = "abc" 8387 * StringUtils.stripToEmpty(" ab c ") = "ab c" 8388 * </pre> 8389 * 8390 * @param str the String to be stripped, may be null 8391 * @return the trimmed String, or an empty String if {@code null} input 8392 * @since 2.0 8393 */ 8394 public static String stripToEmpty(final String str) { 8395 return str == null ? EMPTY : strip(str, null); 8396 } 8397 8398 /** 8399 * <p>Strips whitespace from the start and end of a String returning 8400 * {@code null} if the String is empty ("") after the strip.</p> 8401 * 8402 * <p>This is similar to {@link #trimToNull(String)} but removes whitespace. 8403 * Whitespace is defined by {@link Character#isWhitespace(char)}.</p> 8404 * 8405 * <pre> 8406 * StringUtils.stripToNull(null) = null 8407 * StringUtils.stripToNull("") = null 8408 * StringUtils.stripToNull(" ") = null 8409 * StringUtils.stripToNull("abc") = "abc" 8410 * StringUtils.stripToNull(" abc") = "abc" 8411 * StringUtils.stripToNull("abc ") = "abc" 8412 * StringUtils.stripToNull(" abc ") = "abc" 8413 * StringUtils.stripToNull(" ab c ") = "ab c" 8414 * </pre> 8415 * 8416 * @param str the String to be stripped, may be null 8417 * @return the stripped String, 8418 * {@code null} if whitespace, empty or null String input 8419 * @since 2.0 8420 */ 8421 public static String stripToNull(String str) { 8422 if (str == null) { 8423 return null; 8424 } 8425 str = strip(str, null); 8426 return str.isEmpty() ? null : str; // NOSONARLINT str cannot be null here 8427 } 8428 8429 /** 8430 * <p>Gets a substring from the specified String avoiding exceptions.</p> 8431 * 8432 * <p>A negative start position can be used to start {@code n} 8433 * characters from the end of the String.</p> 8434 * 8435 * <p>A {@code null} String will return {@code null}. 8436 * An empty ("") String will return "".</p> 8437 * 8438 * <pre> 8439 * StringUtils.substring(null, *) = null 8440 * StringUtils.substring("", *) = "" 8441 * StringUtils.substring("abc", 0) = "abc" 8442 * StringUtils.substring("abc", 2) = "c" 8443 * StringUtils.substring("abc", 4) = "" 8444 * StringUtils.substring("abc", -2) = "bc" 8445 * StringUtils.substring("abc", -4) = "abc" 8446 * </pre> 8447 * 8448 * @param str the String to get the substring from, may be null 8449 * @param start the position to start from, negative means 8450 * count back from the end of the String by this many characters 8451 * @return substring from start position, {@code null} if null String input 8452 */ 8453 public static String substring(final String str, int start) { 8454 if (str == null) { 8455 return null; 8456 } 8457 8458 // handle negatives, which means last n characters 8459 if (start < 0) { 8460 start = str.length() + start; // remember start is negative 8461 } 8462 8463 if (start < 0) { 8464 start = 0; 8465 } 8466 if (start > str.length()) { 8467 return EMPTY; 8468 } 8469 8470 return str.substring(start); 8471 } 8472 8473 /** 8474 * <p>Gets a substring from the specified String avoiding exceptions.</p> 8475 * 8476 * <p>A negative start position can be used to start/end {@code n} 8477 * characters from the end of the String.</p> 8478 * 8479 * <p>The returned substring starts with the character in the {@code start} 8480 * position and ends before the {@code end} position. All position counting is 8481 * zero-based -- i.e., to start at the beginning of the string use 8482 * {@code start = 0}. Negative start and end positions can be used to 8483 * specify offsets relative to the end of the String.</p> 8484 * 8485 * <p>If {@code start} is not strictly to the left of {@code end}, "" 8486 * is returned.</p> 8487 * 8488 * <pre> 8489 * StringUtils.substring(null, *, *) = null 8490 * StringUtils.substring("", * , *) = ""; 8491 * StringUtils.substring("abc", 0, 2) = "ab" 8492 * StringUtils.substring("abc", 2, 0) = "" 8493 * StringUtils.substring("abc", 2, 4) = "c" 8494 * StringUtils.substring("abc", 4, 6) = "" 8495 * StringUtils.substring("abc", 2, 2) = "" 8496 * StringUtils.substring("abc", -2, -1) = "b" 8497 * StringUtils.substring("abc", -4, 2) = "ab" 8498 * </pre> 8499 * 8500 * @param str the String to get the substring from, may be null 8501 * @param start the position to start from, negative means 8502 * count back from the end of the String by this many characters 8503 * @param end the position to end at (exclusive), negative means 8504 * count back from the end of the String by this many characters 8505 * @return substring from start position to end position, 8506 * {@code null} if null String input 8507 */ 8508 public static String substring(final String str, int start, int end) { 8509 if (str == null) { 8510 return null; 8511 } 8512 8513 // handle negatives 8514 if (end < 0) { 8515 end = str.length() + end; // remember end is negative 8516 } 8517 if (start < 0) { 8518 start = str.length() + start; // remember start is negative 8519 } 8520 8521 // check length next 8522 if (end > str.length()) { 8523 end = str.length(); 8524 } 8525 8526 // if start is greater than end, return "" 8527 if (start > end) { 8528 return EMPTY; 8529 } 8530 8531 if (start < 0) { 8532 start = 0; 8533 } 8534 if (end < 0) { 8535 end = 0; 8536 } 8537 8538 return str.substring(start, end); 8539 } 8540 8541 /** 8542 * <p>Gets the substring after the first occurrence of a separator. 8543 * The separator is not returned.</p> 8544 * 8545 * <p>A {@code null} string input will return {@code null}. 8546 * An empty ("") string input will return the empty string. 8547 * 8548 * <p>If nothing is found, the empty string is returned.</p> 8549 * 8550 * <pre> 8551 * StringUtils.substringAfter(null, *) = null 8552 * StringUtils.substringAfter("", *) = "" 8553 * StringUtils.substringAfter("abc", 'a') = "bc" 8554 * StringUtils.substringAfter("abcba", 'b') = "cba" 8555 * StringUtils.substringAfter("abc", 'c') = "" 8556 * StringUtils.substringAfter("abc", 'd') = "" 8557 * StringUtils.substringAfter(" abc", 32) = "abc" 8558 * </pre> 8559 * 8560 * @param str the String to get a substring from, may be null 8561 * @param separator the character to search. 8562 * @return the substring after the first occurrence of the separator, 8563 * {@code null} if null String input 8564 * @since 3.11 8565 */ 8566 public static String substringAfter(final String str, final int separator) { 8567 if (isEmpty(str)) { 8568 return str; 8569 } 8570 final int pos = str.indexOf(separator); 8571 if (pos == INDEX_NOT_FOUND) { 8572 return EMPTY; 8573 } 8574 return str.substring(pos + 1); 8575 } 8576 8577 /** 8578 * <p>Gets the substring after the first occurrence of a separator. 8579 * The separator is not returned.</p> 8580 * 8581 * <p>A {@code null} string input will return {@code null}. 8582 * An empty ("") string input will return the empty string. 8583 * A {@code null} separator will return the empty string if the 8584 * input string is not {@code null}.</p> 8585 * 8586 * <p>If nothing is found, the empty string is returned.</p> 8587 * 8588 * <pre> 8589 * StringUtils.substringAfter(null, *) = null 8590 * StringUtils.substringAfter("", *) = "" 8591 * StringUtils.substringAfter(*, null) = "" 8592 * StringUtils.substringAfter("abc", "a") = "bc" 8593 * StringUtils.substringAfter("abcba", "b") = "cba" 8594 * StringUtils.substringAfter("abc", "c") = "" 8595 * StringUtils.substringAfter("abc", "d") = "" 8596 * StringUtils.substringAfter("abc", "") = "abc" 8597 * </pre> 8598 * 8599 * @param str the String to get a substring from, may be null 8600 * @param separator the String to search for, may be null 8601 * @return the substring after the first occurrence of the separator, 8602 * {@code null} if null String input 8603 * @since 2.0 8604 */ 8605 public static String substringAfter(final String str, final String separator) { 8606 if (isEmpty(str)) { 8607 return str; 8608 } 8609 if (separator == null) { 8610 return EMPTY; 8611 } 8612 final int pos = str.indexOf(separator); 8613 if (pos == INDEX_NOT_FOUND) { 8614 return EMPTY; 8615 } 8616 return str.substring(pos + separator.length()); 8617 } 8618 8619 /** 8620 * <p>Gets the substring after the last occurrence of a separator. 8621 * The separator is not returned.</p> 8622 * 8623 * <p>A {@code null} string input will return {@code null}. 8624 * An empty ("") string input will return the empty string. 8625 * 8626 * <p>If nothing is found, the empty string is returned.</p> 8627 * 8628 * <pre> 8629 * StringUtils.substringAfterLast(null, *) = null 8630 * StringUtils.substringAfterLast("", *) = "" 8631 * StringUtils.substringAfterLast("abc", 'a') = "bc" 8632 * StringUtils.substringAfterLast(" bc", 32) = "bc" 8633 * StringUtils.substringAfterLast("abcba", 'b') = "a" 8634 * StringUtils.substringAfterLast("abc", 'c') = "" 8635 * StringUtils.substringAfterLast("a", 'a') = "" 8636 * StringUtils.substringAfterLast("a", 'z') = "" 8637 * </pre> 8638 * 8639 * @param str the String to get a substring from, may be null 8640 * @param separator the String to search for, may be null 8641 * @return the substring after the last occurrence of the separator, 8642 * {@code null} if null String input 8643 * @since 3.11 8644 */ 8645 public static String substringAfterLast(final String str, final int separator) { 8646 if (isEmpty(str)) { 8647 return str; 8648 } 8649 final int pos = str.lastIndexOf(separator); 8650 if (pos == INDEX_NOT_FOUND || pos == str.length() - 1) { 8651 return EMPTY; 8652 } 8653 return str.substring(pos + 1); 8654 } 8655 8656 /** 8657 * <p>Gets the substring after the last occurrence of a separator. 8658 * The separator is not returned.</p> 8659 * 8660 * <p>A {@code null} string input will return {@code null}. 8661 * An empty ("") string input will return the empty string. 8662 * An empty or {@code null} separator will return the empty string if 8663 * the input string is not {@code null}.</p> 8664 * 8665 * <p>If nothing is found, the empty string is returned.</p> 8666 * 8667 * <pre> 8668 * StringUtils.substringAfterLast(null, *) = null 8669 * StringUtils.substringAfterLast("", *) = "" 8670 * StringUtils.substringAfterLast(*, "") = "" 8671 * StringUtils.substringAfterLast(*, null) = "" 8672 * StringUtils.substringAfterLast("abc", "a") = "bc" 8673 * StringUtils.substringAfterLast("abcba", "b") = "a" 8674 * StringUtils.substringAfterLast("abc", "c") = "" 8675 * StringUtils.substringAfterLast("a", "a") = "" 8676 * StringUtils.substringAfterLast("a", "z") = "" 8677 * </pre> 8678 * 8679 * @param str the String to get a substring from, may be null 8680 * @param separator the String to search for, may be null 8681 * @return the substring after the last occurrence of the separator, 8682 * {@code null} if null String input 8683 * @since 2.0 8684 */ 8685 public static String substringAfterLast(final String str, final String separator) { 8686 if (isEmpty(str)) { 8687 return str; 8688 } 8689 if (isEmpty(separator)) { 8690 return EMPTY; 8691 } 8692 final int pos = str.lastIndexOf(separator); 8693 if (pos == INDEX_NOT_FOUND || pos == str.length() - separator.length()) { 8694 return EMPTY; 8695 } 8696 return str.substring(pos + separator.length()); 8697 } 8698 8699 /** 8700 * <p> 8701 * Gets the substring before the first occurrence of a separator. The separator is not returned. 8702 * </p> 8703 * 8704 * <p> 8705 * A {@code null} string input will return {@code null}. An empty ("") string input will return the empty string. 8706 * </p> 8707 * 8708 * <p> 8709 * If nothing is found, the string input is returned. 8710 * </p> 8711 * 8712 * <pre> 8713 * StringUtils.substringBefore(null, *) = null 8714 * StringUtils.substringBefore("", *) = "" 8715 * StringUtils.substringBefore("abc", 'a') = "" 8716 * StringUtils.substringBefore("abcba", 'b') = "a" 8717 * StringUtils.substringBefore("abc", 'c') = "ab" 8718 * StringUtils.substringBefore("abc", 'd') = "abc" 8719 * </pre> 8720 * 8721 * @param str the String to get a substring from, may be null 8722 * @param separator the String to search for, may be null 8723 * @return the substring before the first occurrence of the separator, {@code null} if null String input 8724 * @since 3.12.0 8725 */ 8726 public static String substringBefore(final String str, final int separator) { 8727 if (isEmpty(str)) { 8728 return str; 8729 } 8730 final int pos = str.indexOf(separator); 8731 if (pos == INDEX_NOT_FOUND) { 8732 return str; 8733 } 8734 return str.substring(0, pos); 8735 } 8736 8737 /** 8738 * <p>Gets the substring before the first occurrence of a separator. 8739 * The separator is not returned.</p> 8740 * 8741 * <p>A {@code null} string input will return {@code null}. 8742 * An empty ("") string input will return the empty string. 8743 * A {@code null} separator will return the input string.</p> 8744 * 8745 * <p>If nothing is found, the string input is returned.</p> 8746 * 8747 * <pre> 8748 * StringUtils.substringBefore(null, *) = null 8749 * StringUtils.substringBefore("", *) = "" 8750 * StringUtils.substringBefore("abc", "a") = "" 8751 * StringUtils.substringBefore("abcba", "b") = "a" 8752 * StringUtils.substringBefore("abc", "c") = "ab" 8753 * StringUtils.substringBefore("abc", "d") = "abc" 8754 * StringUtils.substringBefore("abc", "") = "" 8755 * StringUtils.substringBefore("abc", null) = "abc" 8756 * </pre> 8757 * 8758 * @param str the String to get a substring from, may be null 8759 * @param separator the String to search for, may be null 8760 * @return the substring before the first occurrence of the separator, 8761 * {@code null} if null String input 8762 * @since 2.0 8763 */ 8764 public static String substringBefore(final String str, final String separator) { 8765 if (isEmpty(str) || separator == null) { 8766 return str; 8767 } 8768 if (separator.isEmpty()) { 8769 return EMPTY; 8770 } 8771 final int pos = str.indexOf(separator); 8772 if (pos == INDEX_NOT_FOUND) { 8773 return str; 8774 } 8775 return str.substring(0, pos); 8776 } 8777 8778 /** 8779 * <p>Gets the substring before the last occurrence of a separator. 8780 * The separator is not returned.</p> 8781 * 8782 * <p>A {@code null} string input will return {@code null}. 8783 * An empty ("") string input will return the empty string. 8784 * An empty or {@code null} separator will return the input string.</p> 8785 * 8786 * <p>If nothing is found, the string input is returned.</p> 8787 * 8788 * <pre> 8789 * StringUtils.substringBeforeLast(null, *) = null 8790 * StringUtils.substringBeforeLast("", *) = "" 8791 * StringUtils.substringBeforeLast("abcba", "b") = "abc" 8792 * StringUtils.substringBeforeLast("abc", "c") = "ab" 8793 * StringUtils.substringBeforeLast("a", "a") = "" 8794 * StringUtils.substringBeforeLast("a", "z") = "a" 8795 * StringUtils.substringBeforeLast("a", null) = "a" 8796 * StringUtils.substringBeforeLast("a", "") = "a" 8797 * </pre> 8798 * 8799 * @param str the String to get a substring from, may be null 8800 * @param separator the String to search for, may be null 8801 * @return the substring before the last occurrence of the separator, 8802 * {@code null} if null String input 8803 * @since 2.0 8804 */ 8805 public static String substringBeforeLast(final String str, final String separator) { 8806 if (isEmpty(str) || isEmpty(separator)) { 8807 return str; 8808 } 8809 final int pos = str.lastIndexOf(separator); 8810 if (pos == INDEX_NOT_FOUND) { 8811 return str; 8812 } 8813 return str.substring(0, pos); 8814 } 8815 8816 /** 8817 * <p>Gets the String that is nested in between two instances of the 8818 * same String.</p> 8819 * 8820 * <p>A {@code null} input String returns {@code null}. 8821 * A {@code null} tag returns {@code null}.</p> 8822 * 8823 * <pre> 8824 * StringUtils.substringBetween(null, *) = null 8825 * StringUtils.substringBetween("", "") = "" 8826 * StringUtils.substringBetween("", "tag") = null 8827 * StringUtils.substringBetween("tagabctag", null) = null 8828 * StringUtils.substringBetween("tagabctag", "") = "" 8829 * StringUtils.substringBetween("tagabctag", "tag") = "abc" 8830 * </pre> 8831 * 8832 * @param str the String containing the substring, may be null 8833 * @param tag the String before and after the substring, may be null 8834 * @return the substring, {@code null} if no match 8835 * @since 2.0 8836 */ 8837 public static String substringBetween(final String str, final String tag) { 8838 return substringBetween(str, tag, tag); 8839 } 8840 8841 /** 8842 * <p>Gets the String that is nested in between two Strings. 8843 * Only the first match is returned.</p> 8844 * 8845 * <p>A {@code null} input String returns {@code null}. 8846 * A {@code null} open/close returns {@code null} (no match). 8847 * An empty ("") open and close returns an empty string.</p> 8848 * 8849 * <pre> 8850 * StringUtils.substringBetween("wx[b]yz", "[", "]") = "b" 8851 * StringUtils.substringBetween(null, *, *) = null 8852 * StringUtils.substringBetween(*, null, *) = null 8853 * StringUtils.substringBetween(*, *, null) = null 8854 * StringUtils.substringBetween("", "", "") = "" 8855 * StringUtils.substringBetween("", "", "]") = null 8856 * StringUtils.substringBetween("", "[", "]") = null 8857 * StringUtils.substringBetween("yabcz", "", "") = "" 8858 * StringUtils.substringBetween("yabcz", "y", "z") = "abc" 8859 * StringUtils.substringBetween("yabczyabcz", "y", "z") = "abc" 8860 * </pre> 8861 * 8862 * @param str the String containing the substring, may be null 8863 * @param open the String before the substring, may be null 8864 * @param close the String after the substring, may be null 8865 * @return the substring, {@code null} if no match 8866 * @since 2.0 8867 */ 8868 public static String substringBetween(final String str, final String open, final String close) { 8869 if (!ObjectUtils.allNotNull(str, open, close)) { 8870 return null; 8871 } 8872 final int start = str.indexOf(open); 8873 if (start != INDEX_NOT_FOUND) { 8874 final int end = str.indexOf(close, start + open.length()); 8875 if (end != INDEX_NOT_FOUND) { 8876 return str.substring(start + open.length(), end); 8877 } 8878 } 8879 return null; 8880 } 8881 8882 /** 8883 * <p>Searches a String for substrings delimited by a start and end tag, 8884 * returning all matching substrings in an array.</p> 8885 * 8886 * <p>A {@code null} input String returns {@code null}. 8887 * A {@code null} open/close returns {@code null} (no match). 8888 * An empty ("") open/close returns {@code null} (no match).</p> 8889 * 8890 * <pre> 8891 * StringUtils.substringsBetween("[a][b][c]", "[", "]") = ["a","b","c"] 8892 * StringUtils.substringsBetween(null, *, *) = null 8893 * StringUtils.substringsBetween(*, null, *) = null 8894 * StringUtils.substringsBetween(*, *, null) = null 8895 * StringUtils.substringsBetween("", "[", "]") = [] 8896 * </pre> 8897 * 8898 * @param str the String containing the substrings, null returns null, empty returns empty 8899 * @param open the String identifying the start of the substring, empty returns null 8900 * @param close the String identifying the end of the substring, empty returns null 8901 * @return a String Array of substrings, or {@code null} if no match 8902 * @since 2.3 8903 */ 8904 public static String[] substringsBetween(final String str, final String open, final String close) { 8905 if (str == null || isEmpty(open) || isEmpty(close)) { 8906 return null; 8907 } 8908 final int strLen = str.length(); 8909 if (strLen == 0) { 8910 return ArrayUtils.EMPTY_STRING_ARRAY; 8911 } 8912 final int closeLen = close.length(); 8913 final int openLen = open.length(); 8914 final List<String> list = new ArrayList<>(); 8915 int pos = 0; 8916 while (pos < strLen - closeLen) { 8917 int start = str.indexOf(open, pos); 8918 if (start < 0) { 8919 break; 8920 } 8921 start += openLen; 8922 final int end = str.indexOf(close, start); 8923 if (end < 0) { 8924 break; 8925 } 8926 list.add(str.substring(start, end)); 8927 pos = end + closeLen; 8928 } 8929 if (list.isEmpty()) { 8930 return null; 8931 } 8932 return list.toArray(ArrayUtils.EMPTY_STRING_ARRAY); 8933 } 8934 8935 /** 8936 * <p>Swaps the case of a String changing upper and title case to 8937 * lower case, and lower case to upper case.</p> 8938 * 8939 * <ul> 8940 * <li>Upper case character converts to Lower case</li> 8941 * <li>Title case character converts to Lower case</li> 8942 * <li>Lower case character converts to Upper case</li> 8943 * </ul> 8944 * 8945 * <p>For a word based algorithm, see {@link edu.internet2.middleware.grouperClientExt.org.apache.commons.lang3.text.WordUtils#swapCase(String)}. 8946 * A {@code null} input String returns {@code null}.</p> 8947 * 8948 * <pre> 8949 * StringUtils.swapCase(null) = null 8950 * StringUtils.swapCase("") = "" 8951 * StringUtils.swapCase("The dog has a BONE") = "tHE DOG HAS A bone" 8952 * </pre> 8953 * 8954 * <p>NOTE: This method changed in Lang version 2.0. 8955 * It no longer performs a word based algorithm. 8956 * If you only use ASCII, you will notice no change. 8957 * That functionality is available in edu.internet2.middleware.grouperClientExt.org.apache.commons.lang3.text.WordUtils.</p> 8958 * 8959 * @param str the String to swap case, may be null 8960 * @return the changed String, {@code null} if null String input 8961 */ 8962 public static String swapCase(final String str) { 8963 if (isEmpty(str)) { 8964 return str; 8965 } 8966 8967 final int strLen = str.length(); 8968 final int[] newCodePoints = new int[strLen]; // cannot be longer than the char array 8969 int outOffset = 0; 8970 for (int i = 0; i < strLen; ) { 8971 final int oldCodepoint = str.codePointAt(i); 8972 final int newCodePoint; 8973 if (Character.isUpperCase(oldCodepoint) || Character.isTitleCase(oldCodepoint)) { 8974 newCodePoint = Character.toLowerCase(oldCodepoint); 8975 } else if (Character.isLowerCase(oldCodepoint)) { 8976 newCodePoint = Character.toUpperCase(oldCodepoint); 8977 } else { 8978 newCodePoint = oldCodepoint; 8979 } 8980 newCodePoints[outOffset++] = newCodePoint; 8981 i += Character.charCount(newCodePoint); 8982 } 8983 return new String(newCodePoints, 0, outOffset); 8984 } 8985 8986 /** 8987 * <p>Converts a {@code CharSequence} into an array of code points.</p> 8988 * 8989 * <p>Valid pairs of surrogate code units will be converted into a single supplementary 8990 * code point. Isolated surrogate code units (i.e. a high surrogate not followed by a low surrogate or 8991 * a low surrogate not preceded by a high surrogate) will be returned as-is.</p> 8992 * 8993 * <pre> 8994 * StringUtils.toCodePoints(null) = null 8995 * StringUtils.toCodePoints("") = [] // empty array 8996 * </pre> 8997 * 8998 * @param cs the character sequence to convert 8999 * @return an array of code points 9000 * @since 3.6 9001 */ 9002 public static int[] toCodePoints(final CharSequence cs) { 9003 if (cs == null) { 9004 return null; 9005 } 9006 if (cs.length() == 0) { 9007 return ArrayUtils.EMPTY_INT_ARRAY; 9008 } 9009 9010 final String s = cs.toString(); 9011 final int[] result = new int[s.codePointCount(0, s.length())]; 9012 int index = 0; 9013 for (int i = 0; i < result.length; i++) { 9014 result[i] = s.codePointAt(index); 9015 index += Character.charCount(result[i]); 9016 } 9017 return result; 9018 } 9019 9020 /** 9021 * Converts a {@code byte[]} to a String using the specified character encoding. 9022 * 9023 * @param bytes 9024 * the byte array to read from 9025 * @param charset 9026 * the encoding to use, if null then use the platform default 9027 * @return a new String 9028 * @throws NullPointerException 9029 * if {@code bytes} is null 9030 * @since 3.2 9031 * @since 3.3 No longer throws {@link UnsupportedEncodingException}. 9032 */ 9033 public static String toEncodedString(final byte[] bytes, final Charset charset) { 9034 return new String(bytes, Charsets.toCharset(charset)); 9035 } 9036 9037 /** 9038 * Converts the given source String as a lower-case using the {@link Locale#ROOT} locale in a null-safe manner. 9039 * 9040 * @param source A source String or null. 9041 * @return the given source String as a lower-case using the {@link Locale#ROOT} locale or null. 9042 * @since 3.10 9043 */ 9044 public static String toRootLowerCase(final String source) { 9045 return source == null ? null : source.toLowerCase(Locale.ROOT); 9046 } 9047 9048 /** 9049 * Converts the given source String as a upper-case using the {@link Locale#ROOT} locale in a null-safe manner. 9050 * 9051 * @param source A source String or null. 9052 * @return the given source String as a upper-case using the {@link Locale#ROOT} locale or null. 9053 * @since 3.10 9054 */ 9055 public static String toRootUpperCase(final String source) { 9056 return source == null ? null : source.toUpperCase(Locale.ROOT); 9057 } 9058 9059 /** 9060 * Converts a {@code byte[]} to a String using the specified character encoding. 9061 * 9062 * @param bytes 9063 * the byte array to read from 9064 * @param charsetName 9065 * the encoding to use, if null then use the platform default 9066 * @return a new String 9067 * @throws UnsupportedEncodingException 9068 * If the named charset is not supported 9069 * @throws NullPointerException 9070 * if the input is null 9071 * @deprecated use {@link StringUtils#toEncodedString(byte[], Charset)} instead of String constants in your code 9072 * @since 3.1 9073 */ 9074 @Deprecated 9075 public static String toString(final byte[] bytes, final String charsetName) throws UnsupportedEncodingException { 9076 return new String(bytes, Charsets.toCharset(charsetName)); 9077 } 9078 9079 private static String toStringOrEmpty(final Object obj) { 9080 return Objects.toString(obj, EMPTY); 9081 } 9082 9083 /** 9084 * <p>Removes control characters (char <= 32) from both 9085 * ends of this String, handling {@code null} by returning 9086 * {@code null}.</p> 9087 * 9088 * <p>The String is trimmed using {@link String#trim()}. 9089 * Trim removes start and end characters <= 32. 9090 * To strip whitespace use {@link #strip(String)}.</p> 9091 * 9092 * <p>To trim your choice of characters, use the 9093 * {@link #strip(String, String)} methods.</p> 9094 * 9095 * <pre> 9096 * StringUtils.trim(null) = null 9097 * StringUtils.trim("") = "" 9098 * StringUtils.trim(" ") = "" 9099 * StringUtils.trim("abc") = "abc" 9100 * StringUtils.trim(" abc ") = "abc" 9101 * </pre> 9102 * 9103 * @param str the String to be trimmed, may be null 9104 * @return the trimmed string, {@code null} if null String input 9105 */ 9106 public static String trim(final String str) { 9107 return str == null ? null : str.trim(); 9108 } 9109 9110 /** 9111 * <p>Removes control characters (char <= 32) from both 9112 * ends of this String returning an empty String ("") if the String 9113 * is empty ("") after the trim or if it is {@code null}. 9114 * 9115 * <p>The String is trimmed using {@link String#trim()}. 9116 * Trim removes start and end characters <= 32. 9117 * To strip whitespace use {@link #stripToEmpty(String)}.</p> 9118 * 9119 * <pre> 9120 * StringUtils.trimToEmpty(null) = "" 9121 * StringUtils.trimToEmpty("") = "" 9122 * StringUtils.trimToEmpty(" ") = "" 9123 * StringUtils.trimToEmpty("abc") = "abc" 9124 * StringUtils.trimToEmpty(" abc ") = "abc" 9125 * </pre> 9126 * 9127 * @param str the String to be trimmed, may be null 9128 * @return the trimmed String, or an empty String if {@code null} input 9129 * @since 2.0 9130 */ 9131 public static String trimToEmpty(final String str) { 9132 return str == null ? EMPTY : str.trim(); 9133 } 9134 9135 /** 9136 * <p>Removes control characters (char <= 32) from both 9137 * ends of this String returning {@code null} if the String is 9138 * empty ("") after the trim or if it is {@code null}. 9139 * 9140 * <p>The String is trimmed using {@link String#trim()}. 9141 * Trim removes start and end characters <= 32. 9142 * To strip whitespace use {@link #stripToNull(String)}.</p> 9143 * 9144 * <pre> 9145 * StringUtils.trimToNull(null) = null 9146 * StringUtils.trimToNull("") = null 9147 * StringUtils.trimToNull(" ") = null 9148 * StringUtils.trimToNull("abc") = "abc" 9149 * StringUtils.trimToNull(" abc ") = "abc" 9150 * </pre> 9151 * 9152 * @param str the String to be trimmed, may be null 9153 * @return the trimmed String, 9154 * {@code null} if only chars <= 32, empty or null String input 9155 * @since 2.0 9156 */ 9157 public static String trimToNull(final String str) { 9158 final String ts = trim(str); 9159 return isEmpty(ts) ? null : ts; 9160 } 9161 9162 /** 9163 * <p>Truncates a String. This will turn 9164 * "Now is the time for all good men" into "Now is the time for".</p> 9165 * 9166 * <p>Specifically:</p> 9167 * <ul> 9168 * <li>If {@code str} is less than {@code maxWidth} characters 9169 * long, return it.</li> 9170 * <li>Else truncate it to {@code substring(str, 0, maxWidth)}.</li> 9171 * <li>If {@code maxWidth} is less than {@code 0}, throw an 9172 * {@code IllegalArgumentException}.</li> 9173 * <li>In no case will it return a String of length greater than 9174 * {@code maxWidth}.</li> 9175 * </ul> 9176 * 9177 * <pre> 9178 * StringUtils.truncate(null, 0) = null 9179 * StringUtils.truncate(null, 2) = null 9180 * StringUtils.truncate("", 4) = "" 9181 * StringUtils.truncate("abcdefg", 4) = "abcd" 9182 * StringUtils.truncate("abcdefg", 6) = "abcdef" 9183 * StringUtils.truncate("abcdefg", 7) = "abcdefg" 9184 * StringUtils.truncate("abcdefg", 8) = "abcdefg" 9185 * StringUtils.truncate("abcdefg", -1) = throws an IllegalArgumentException 9186 * </pre> 9187 * 9188 * @param str the String to truncate, may be null 9189 * @param maxWidth maximum length of result String, must be positive 9190 * @return truncated String, {@code null} if null String input 9191 * @throws IllegalArgumentException If {@code maxWidth} is less than {@code 0} 9192 * @since 3.5 9193 */ 9194 public static String truncate(final String str, final int maxWidth) { 9195 return truncate(str, 0, maxWidth); 9196 } 9197 9198 /** 9199 * <p>Truncates a String. This will turn 9200 * "Now is the time for all good men" into "is the time for all".</p> 9201 * 9202 * <p>Works like {@code truncate(String, int)}, but allows you to specify 9203 * a "left edge" offset. 9204 * 9205 * <p>Specifically:</p> 9206 * <ul> 9207 * <li>If {@code str} is less than {@code maxWidth} characters 9208 * long, return it.</li> 9209 * <li>Else truncate it to {@code substring(str, offset, maxWidth)}.</li> 9210 * <li>If {@code maxWidth} is less than {@code 0}, throw an 9211 * {@code IllegalArgumentException}.</li> 9212 * <li>If {@code offset} is less than {@code 0}, throw an 9213 * {@code IllegalArgumentException}.</li> 9214 * <li>In no case will it return a String of length greater than 9215 * {@code maxWidth}.</li> 9216 * </ul> 9217 * 9218 * <pre> 9219 * StringUtils.truncate(null, 0, 0) = null 9220 * StringUtils.truncate(null, 2, 4) = null 9221 * StringUtils.truncate("", 0, 10) = "" 9222 * StringUtils.truncate("", 2, 10) = "" 9223 * StringUtils.truncate("abcdefghij", 0, 3) = "abc" 9224 * StringUtils.truncate("abcdefghij", 5, 6) = "fghij" 9225 * StringUtils.truncate("raspberry peach", 10, 15) = "peach" 9226 * StringUtils.truncate("abcdefghijklmno", 0, 10) = "abcdefghij" 9227 * StringUtils.truncate("abcdefghijklmno", -1, 10) = throws an IllegalArgumentException 9228 * StringUtils.truncate("abcdefghijklmno", Integer.MIN_VALUE, 10) = throws an IllegalArgumentException 9229 * StringUtils.truncate("abcdefghijklmno", Integer.MIN_VALUE, Integer.MAX_VALUE) = throws an IllegalArgumentException 9230 * StringUtils.truncate("abcdefghijklmno", 0, Integer.MAX_VALUE) = "abcdefghijklmno" 9231 * StringUtils.truncate("abcdefghijklmno", 1, 10) = "bcdefghijk" 9232 * StringUtils.truncate("abcdefghijklmno", 2, 10) = "cdefghijkl" 9233 * StringUtils.truncate("abcdefghijklmno", 3, 10) = "defghijklm" 9234 * StringUtils.truncate("abcdefghijklmno", 4, 10) = "efghijklmn" 9235 * StringUtils.truncate("abcdefghijklmno", 5, 10) = "fghijklmno" 9236 * StringUtils.truncate("abcdefghijklmno", 5, 5) = "fghij" 9237 * StringUtils.truncate("abcdefghijklmno", 5, 3) = "fgh" 9238 * StringUtils.truncate("abcdefghijklmno", 10, 3) = "klm" 9239 * StringUtils.truncate("abcdefghijklmno", 10, Integer.MAX_VALUE) = "klmno" 9240 * StringUtils.truncate("abcdefghijklmno", 13, 1) = "n" 9241 * StringUtils.truncate("abcdefghijklmno", 13, Integer.MAX_VALUE) = "no" 9242 * StringUtils.truncate("abcdefghijklmno", 14, 1) = "o" 9243 * StringUtils.truncate("abcdefghijklmno", 14, Integer.MAX_VALUE) = "o" 9244 * StringUtils.truncate("abcdefghijklmno", 15, 1) = "" 9245 * StringUtils.truncate("abcdefghijklmno", 15, Integer.MAX_VALUE) = "" 9246 * StringUtils.truncate("abcdefghijklmno", Integer.MAX_VALUE, Integer.MAX_VALUE) = "" 9247 * StringUtils.truncate("abcdefghij", 3, -1) = throws an IllegalArgumentException 9248 * StringUtils.truncate("abcdefghij", -2, 4) = throws an IllegalArgumentException 9249 * </pre> 9250 * 9251 * @param str the String to truncate, may be null 9252 * @param offset left edge of source String 9253 * @param maxWidth maximum length of result String, must be positive 9254 * @return truncated String, {@code null} if null String input 9255 * @throws IllegalArgumentException If {@code offset} or {@code maxWidth} is less than {@code 0} 9256 * @since 3.5 9257 */ 9258 public static String truncate(final String str, final int offset, final int maxWidth) { 9259 if (offset < 0) { 9260 throw new IllegalArgumentException("offset cannot be negative"); 9261 } 9262 if (maxWidth < 0) { 9263 throw new IllegalArgumentException("maxWith cannot be negative"); 9264 } 9265 if (str == null) { 9266 return null; 9267 } 9268 if (offset > str.length()) { 9269 return EMPTY; 9270 } 9271 if (str.length() > maxWidth) { 9272 final int ix = Math.min(offset + maxWidth, str.length()); 9273 return str.substring(offset, ix); 9274 } 9275 return str.substring(offset); 9276 } 9277 9278 /** 9279 * <p>Uncapitalizes a String, changing the first character to lower case as 9280 * per {@link Character#toLowerCase(int)}. No other characters are changed.</p> 9281 * 9282 * <p>For a word based algorithm, see {@link edu.internet2.middleware.grouperClientExt.org.apache.commons.lang3.text.WordUtils#uncapitalize(String)}. 9283 * A {@code null} input String returns {@code null}.</p> 9284 * 9285 * <pre> 9286 * StringUtils.uncapitalize(null) = null 9287 * StringUtils.uncapitalize("") = "" 9288 * StringUtils.uncapitalize("cat") = "cat" 9289 * StringUtils.uncapitalize("Cat") = "cat" 9290 * StringUtils.uncapitalize("CAT") = "cAT" 9291 * </pre> 9292 * 9293 * @param str the String to uncapitalize, may be null 9294 * @return the uncapitalized String, {@code null} if null String input 9295 * @see edu.internet2.middleware.grouperClientExt.org.apache.commons.lang3.text.WordUtils#uncapitalize(String) 9296 * @see #capitalize(String) 9297 * @since 2.0 9298 */ 9299 public static String uncapitalize(final String str) { 9300 final int strLen = length(str); 9301 if (strLen == 0) { 9302 return str; 9303 } 9304 9305 final int firstCodepoint = str.codePointAt(0); 9306 final int newCodePoint = Character.toLowerCase(firstCodepoint); 9307 if (firstCodepoint == newCodePoint) { 9308 // already capitalized 9309 return str; 9310 } 9311 9312 final int[] newCodePoints = new int[strLen]; // cannot be longer than the char array 9313 int outOffset = 0; 9314 newCodePoints[outOffset++] = newCodePoint; // copy the first codepoint 9315 for (int inOffset = Character.charCount(firstCodepoint); inOffset < strLen; ) { 9316 final int codepoint = str.codePointAt(inOffset); 9317 newCodePoints[outOffset++] = codepoint; // copy the remaining ones 9318 inOffset += Character.charCount(codepoint); 9319 } 9320 return new String(newCodePoints, 0, outOffset); 9321 } 9322 9323 /** 9324 * <p> 9325 * Unwraps a given string from a character. 9326 * </p> 9327 * 9328 * <pre> 9329 * StringUtils.unwrap(null, null) = null 9330 * StringUtils.unwrap(null, '\0') = null 9331 * StringUtils.unwrap(null, '1') = null 9332 * StringUtils.unwrap("a", 'a') = "a" 9333 * StringUtils.unwrap("aa", 'a') = "" 9334 * StringUtils.unwrap("\'abc\'", '\'') = "abc" 9335 * StringUtils.unwrap("AABabcBAA", 'A') = "ABabcBA" 9336 * StringUtils.unwrap("A", '#') = "A" 9337 * StringUtils.unwrap("#A", '#') = "#A" 9338 * StringUtils.unwrap("A#", '#') = "A#" 9339 * </pre> 9340 * 9341 * @param str 9342 * the String to be unwrapped, can be null 9343 * @param wrapChar 9344 * the character used to unwrap 9345 * @return unwrapped String or the original string 9346 * if it is not quoted properly with the wrapChar 9347 * @since 3.6 9348 */ 9349 public static String unwrap(final String str, final char wrapChar) { 9350 if (isEmpty(str) || wrapChar == CharUtils.NUL || str.length() == 1) { 9351 return str; 9352 } 9353 9354 if (str.charAt(0) == wrapChar && str.charAt(str.length() - 1) == wrapChar) { 9355 final int startIndex = 0; 9356 final int endIndex = str.length() - 1; 9357 9358 return str.substring(startIndex + 1, endIndex); 9359 } 9360 9361 return str; 9362 } 9363 9364 /** 9365 * <p> 9366 * Unwraps a given string from anther string. 9367 * </p> 9368 * 9369 * <pre> 9370 * StringUtils.unwrap(null, null) = null 9371 * StringUtils.unwrap(null, "") = null 9372 * StringUtils.unwrap(null, "1") = null 9373 * StringUtils.unwrap("a", "a") = "a" 9374 * StringUtils.unwrap("aa", "a") = "" 9375 * StringUtils.unwrap("\'abc\'", "\'") = "abc" 9376 * StringUtils.unwrap("\"abc\"", "\"") = "abc" 9377 * StringUtils.unwrap("AABabcBAA", "AA") = "BabcB" 9378 * StringUtils.unwrap("A", "#") = "A" 9379 * StringUtils.unwrap("#A", "#") = "#A" 9380 * StringUtils.unwrap("A#", "#") = "A#" 9381 * </pre> 9382 * 9383 * @param str 9384 * the String to be unwrapped, can be null 9385 * @param wrapToken 9386 * the String used to unwrap 9387 * @return unwrapped String or the original string 9388 * if it is not quoted properly with the wrapToken 9389 * @since 3.6 9390 */ 9391 public static String unwrap(final String str, final String wrapToken) { 9392 if (isEmpty(str) || isEmpty(wrapToken) || str.length() < 2 * wrapToken.length()) { 9393 return str; 9394 } 9395 9396 if (startsWith(str, wrapToken) && endsWith(str, wrapToken)) { 9397 final int startIndex = str.indexOf(wrapToken); 9398 final int endIndex = str.lastIndexOf(wrapToken); 9399 final int wrapLength = wrapToken.length(); 9400 9401 if (startIndex != -1 && endIndex != -1) { 9402 return str.substring(startIndex + wrapLength, endIndex); 9403 } 9404 } 9405 9406 return str; 9407 } 9408 9409 /** 9410 * <p>Converts a String to upper case as per {@link String#toUpperCase()}.</p> 9411 * 9412 * <p>A {@code null} input String returns {@code null}.</p> 9413 * 9414 * <pre> 9415 * StringUtils.upperCase(null) = null 9416 * StringUtils.upperCase("") = "" 9417 * StringUtils.upperCase("aBc") = "ABC" 9418 * </pre> 9419 * 9420 * <p><strong>Note:</strong> As described in the documentation for {@link String#toUpperCase()}, 9421 * the result of this method is affected by the current locale. 9422 * For platform-independent case transformations, the method {@link #lowerCase(String, Locale)} 9423 * should be used with a specific locale (e.g. {@link Locale#ENGLISH}).</p> 9424 * 9425 * @param str the String to upper case, may be null 9426 * @return the upper cased String, {@code null} if null String input 9427 */ 9428 public static String upperCase(final String str) { 9429 if (str == null) { 9430 return null; 9431 } 9432 return str.toUpperCase(); 9433 } 9434 9435 /** 9436 * <p>Converts a String to upper case as per {@link String#toUpperCase(Locale)}.</p> 9437 * 9438 * <p>A {@code null} input String returns {@code null}.</p> 9439 * 9440 * <pre> 9441 * StringUtils.upperCase(null, Locale.ENGLISH) = null 9442 * StringUtils.upperCase("", Locale.ENGLISH) = "" 9443 * StringUtils.upperCase("aBc", Locale.ENGLISH) = "ABC" 9444 * </pre> 9445 * 9446 * @param str the String to upper case, may be null 9447 * @param locale the locale that defines the case transformation rules, must not be null 9448 * @return the upper cased String, {@code null} if null String input 9449 * @since 2.5 9450 */ 9451 public static String upperCase(final String str, final Locale locale) { 9452 if (str == null) { 9453 return null; 9454 } 9455 return str.toUpperCase(LocaleUtils.toLocale(locale)); 9456 } 9457 9458 /** 9459 * Returns the string representation of the {@code char} array or null. 9460 * 9461 * @param value the character array. 9462 * @return a String or null 9463 * @see String#valueOf(char[]) 9464 * @since 3.9 9465 */ 9466 public static String valueOf(final char[] value) { 9467 return value == null ? null : String.valueOf(value); 9468 } 9469 9470 /** 9471 * <p> 9472 * Wraps a string with a char. 9473 * </p> 9474 * 9475 * <pre> 9476 * StringUtils.wrap(null, *) = null 9477 * StringUtils.wrap("", *) = "" 9478 * StringUtils.wrap("ab", '\0') = "ab" 9479 * StringUtils.wrap("ab", 'x') = "xabx" 9480 * StringUtils.wrap("ab", '\'') = "'ab'" 9481 * StringUtils.wrap("\"ab\"", '\"') = "\"\"ab\"\"" 9482 * </pre> 9483 * 9484 * @param str 9485 * the string to be wrapped, may be {@code null} 9486 * @param wrapWith 9487 * the char that will wrap {@code str} 9488 * @return the wrapped string, or {@code null} if {@code str==null} 9489 * @since 3.4 9490 */ 9491 public static String wrap(final String str, final char wrapWith) { 9492 9493 if (isEmpty(str) || wrapWith == CharUtils.NUL) { 9494 return str; 9495 } 9496 9497 return wrapWith + str + wrapWith; 9498 } 9499 9500 /** 9501 * <p> 9502 * Wraps a String with another String. 9503 * </p> 9504 * 9505 * <p> 9506 * A {@code null} input String returns {@code null}. 9507 * </p> 9508 * 9509 * <pre> 9510 * StringUtils.wrap(null, *) = null 9511 * StringUtils.wrap("", *) = "" 9512 * StringUtils.wrap("ab", null) = "ab" 9513 * StringUtils.wrap("ab", "x") = "xabx" 9514 * StringUtils.wrap("ab", "\"") = "\"ab\"" 9515 * StringUtils.wrap("\"ab\"", "\"") = "\"\"ab\"\"" 9516 * StringUtils.wrap("ab", "'") = "'ab'" 9517 * StringUtils.wrap("'abcd'", "'") = "''abcd''" 9518 * StringUtils.wrap("\"abcd\"", "'") = "'\"abcd\"'" 9519 * StringUtils.wrap("'abcd'", "\"") = "\"'abcd'\"" 9520 * </pre> 9521 * 9522 * @param str 9523 * the String to be wrapper, may be null 9524 * @param wrapWith 9525 * the String that will wrap str 9526 * @return wrapped String, {@code null} if null String input 9527 * @since 3.4 9528 */ 9529 public static String wrap(final String str, final String wrapWith) { 9530 9531 if (isEmpty(str) || isEmpty(wrapWith)) { 9532 return str; 9533 } 9534 9535 return wrapWith.concat(str).concat(wrapWith); 9536 } 9537 9538 /** 9539 * <p> 9540 * Wraps a string with a char if that char is missing from the start or end of the given string. 9541 * </p> 9542 * 9543 * <p>A new {@code String} will not be created if {@code str} is already wrapped.</p> 9544 * 9545 * <pre> 9546 * StringUtils.wrapIfMissing(null, *) = null 9547 * StringUtils.wrapIfMissing("", *) = "" 9548 * StringUtils.wrapIfMissing("ab", '\0') = "ab" 9549 * StringUtils.wrapIfMissing("ab", 'x') = "xabx" 9550 * StringUtils.wrapIfMissing("ab", '\'') = "'ab'" 9551 * StringUtils.wrapIfMissing("\"ab\"", '\"') = "\"ab\"" 9552 * StringUtils.wrapIfMissing("/", '/') = "/" 9553 * StringUtils.wrapIfMissing("a/b/c", '/') = "/a/b/c/" 9554 * StringUtils.wrapIfMissing("/a/b/c", '/') = "/a/b/c/" 9555 * StringUtils.wrapIfMissing("a/b/c/", '/') = "/a/b/c/" 9556 * </pre> 9557 * 9558 * @param str 9559 * the string to be wrapped, may be {@code null} 9560 * @param wrapWith 9561 * the char that will wrap {@code str} 9562 * @return the wrapped string, or {@code null} if {@code str==null} 9563 * @since 3.5 9564 */ 9565 public static String wrapIfMissing(final String str, final char wrapWith) { 9566 if (isEmpty(str) || wrapWith == CharUtils.NUL) { 9567 return str; 9568 } 9569 final boolean wrapStart = str.charAt(0) != wrapWith; 9570 final boolean wrapEnd = str.charAt(str.length() - 1) != wrapWith; 9571 if (!wrapStart && !wrapEnd) { 9572 return str; 9573 } 9574 9575 final StringBuilder builder = new StringBuilder(str.length() + 2); 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 * <p> 9588 * Wraps a string with a string if that string is missing from the start or end of the given string. 9589 * </p> 9590 * 9591 * <p>A new {@code String} will not be created if {@code str} is already wrapped.</p> 9592 * 9593 * <pre> 9594 * StringUtils.wrapIfMissing(null, *) = null 9595 * StringUtils.wrapIfMissing("", *) = "" 9596 * StringUtils.wrapIfMissing("ab", null) = "ab" 9597 * StringUtils.wrapIfMissing("ab", "x") = "xabx" 9598 * StringUtils.wrapIfMissing("ab", "\"") = "\"ab\"" 9599 * StringUtils.wrapIfMissing("\"ab\"", "\"") = "\"ab\"" 9600 * StringUtils.wrapIfMissing("ab", "'") = "'ab'" 9601 * StringUtils.wrapIfMissing("'abcd'", "'") = "'abcd'" 9602 * StringUtils.wrapIfMissing("\"abcd\"", "'") = "'\"abcd\"'" 9603 * StringUtils.wrapIfMissing("'abcd'", "\"") = "\"'abcd'\"" 9604 * StringUtils.wrapIfMissing("/", "/") = "/" 9605 * StringUtils.wrapIfMissing("a/b/c", "/") = "/a/b/c/" 9606 * StringUtils.wrapIfMissing("/a/b/c", "/") = "/a/b/c/" 9607 * StringUtils.wrapIfMissing("a/b/c/", "/") = "/a/b/c/" 9608 * </pre> 9609 * 9610 * @param str 9611 * the string to be wrapped, may be {@code null} 9612 * @param wrapWith 9613 * the string that will wrap {@code str} 9614 * @return the wrapped string, or {@code null} if {@code str==null} 9615 * @since 3.5 9616 */ 9617 public static String wrapIfMissing(final String str, final String wrapWith) { 9618 if (isEmpty(str) || isEmpty(wrapWith)) { 9619 return str; 9620 } 9621 9622 final boolean wrapStart = !str.startsWith(wrapWith); 9623 final boolean wrapEnd = !str.endsWith(wrapWith); 9624 if (!wrapStart && !wrapEnd) { 9625 return str; 9626 } 9627 9628 final StringBuilder builder = new StringBuilder(str.length() + wrapWith.length() + wrapWith.length()); 9629 if (wrapStart) { 9630 builder.append(wrapWith); 9631 } 9632 builder.append(str); 9633 if (wrapEnd) { 9634 builder.append(wrapWith); 9635 } 9636 return builder.toString(); 9637 } 9638 9639 /** 9640 * <p>{@code StringUtils} instances should NOT be constructed in 9641 * standard programming. Instead, the class should be used as 9642 * {@code StringUtils.trim(" foo ");}.</p> 9643 * 9644 * <p>This constructor is public to permit tools that require a JavaBean 9645 * instance to operate.</p> 9646 */ 9647 public StringUtils() { 9648 } 9649 9650 }