1 /* 2 * Licensed to the Apache Software Foundation (ASF) under one 3 * or more contributor license agreements. See the NOTICE file 4 * distributed with this work for additional information 5 * regarding copyright ownership. The ASF licenses this file 6 * to you under the Apache License, Version 2.0 (the 7 * "License"); you may not use this file except in compliance 8 * with the License. You may obtain a copy of the License at 9 * 10 * http://www.apache.org/licenses/LICENSE-2.0 11 * 12 * Unless required by applicable law or agreed to in writing, 13 * software distributed under the License is distributed on an 14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 * KIND, either express or implied. See the License for the 16 * specific language governing permissions and limitations 17 * under the License. 18 */ 19 package org.apache.maven.shared.utils; 20 21 import javax.annotation.Nonnull; 22 import javax.annotation.Nullable; 23 24 import java.util.Arrays; 25 import java.util.Iterator; 26 import java.util.Locale; 27 import java.util.Map; 28 import java.util.StringTokenizer; 29 30 /** 31 * <p>Common <code>String</code> manipulation routines.</p> 32 * 33 * <p>Originally from 34 * <a href="http://jakarta.apache.org/turbine/">Turbine</a>, the 35 * GenerationJavaCore library and Velocity. 36 * Later a lots methods from commons-lang StringUtils 37 * got added too. Gradually smaller additions and fixes have been made 38 * over the time by various ASF committers.</p> 39 * 40 * @author <a href="mailto:jon@latchkey.com">Jon S. Stevens</a> 41 * @author <a href="mailto:dlr@finemaltcoding.com">Daniel Rall</a> 42 * @author <a href="mailto:gcoladonato@yahoo.com">Greg Coladonato</a> 43 * @author <a href="mailto:bayard@generationjava.com">Henri Yandell</a> 44 * @author <a href="mailto:ed@apache.org">Ed Korthof</a> 45 * @author <a href="mailto:rand_mcneely@yahoo.com">Rand McNeely</a> 46 * @author Stephen Colebourne 47 * @author <a href="mailto:fredrik@westermarck.com">Fredrik Westermarck</a> 48 * @author Holger Krauth 49 * @author <a href="mailto:alex@purpletech.com">Alexander Day Chaffee</a> 50 * 51 */ 52 public class StringUtils { 53 /** 54 * <p><code>StringUtils</code> instances should NOT be constructed in 55 * standard programming. Instead, the class should be used as 56 * <code>StringUtils.trim(" foo ");</code>.</p> 57 * 58 * <p>This constructor is public to permit tools that require a JavaBean 59 * manager to operate.</p> 60 */ 61 public StringUtils() {} 62 63 // Empty 64 // -------------------------------------------------------------------------- 65 66 /** 67 * <p>Removes C0 control characters, including ASCII whitespace, from both 68 * ends of this String, handling <code>null</code> by returning 69 * an empty String.</p> 70 * 71 * @param str the String to check 72 * @return the trimmed text (never <code>null</code>) 73 * @see java.lang.String#trim() 74 */ 75 @Nonnull 76 public static String clean(String str) { 77 return (str == null ? "" : str.trim()); 78 } 79 80 /** 81 * <p>Removes C0 control characters, including ASCII whitespace, from both 82 * ends of this String, handling <code>null</code> by returning 83 * <code>null</code>.</p> 84 * 85 * @param str the String to check 86 * @return the trimmed text (or <code>null</code>) 87 * @see java.lang.String#trim() 88 */ 89 public static String trim(String str) { 90 return (str == null ? null : str.trim()); 91 } 92 93 /** 94 * <p>Deletes all whitespace from a String.</p> 95 * 96 * <p>Whitespace is defined by 97 * {@link Character#isWhitespace(char)}.</p> 98 * 99 * @param str String target to delete whitespace from 100 * @return the String without whitespace 101 */ 102 @Nonnull 103 public static String deleteWhitespace(@Nonnull String str) { 104 StringBuilder buffer = new StringBuilder(); 105 int sz = str.length(); 106 for (int i = 0; i < sz; i++) { 107 if (!Character.isWhitespace(str.charAt(i))) { 108 buffer.append(str.charAt(i)); 109 } 110 } 111 return buffer.toString(); 112 } 113 114 /** 115 * <p>Checks if a String is non <code>null</code> and is 116 * not empty (<code>length > 0</code>).</p> 117 * 118 * @param str the String to check 119 * @return true if the String is non-null, and not length zero 120 */ 121 public static boolean isNotEmpty(@Nullable String str) { 122 return ((str != null) && (str.length() > 0)); 123 } 124 125 /** 126 * <p>Checks if a (trimmed) String is <code>null</code> or empty.</p> 127 * 128 * <p><strong>Note:</strong> In future releases, this method will no longer trim the input string such that it works 129 * complementary to {@link #isNotEmpty(String)}. Code that wants to test for whitespace-only strings should be 130 * migrated to use {@link #isBlank(String)} instead.</p> 131 * 132 * @param str the String to check 133 * @return <code>true</code> if the String is <code>null</code>, or 134 * length zero once trimmed 135 */ 136 public static boolean isEmpty(@Nullable String str) { 137 return ((str == null) || (str.trim().length() == 0)); 138 } 139 140 /** 141 * <p> 142 * Checks if a String is whitespace, empty ("") or null. 143 * </p> 144 * 145 * <pre> 146 * StringUtils.isBlank(null) = true 147 * StringUtils.isBlank("") = true 148 * StringUtils.isBlank(" ") = true 149 * StringUtils.isBlank("bob") = false 150 * StringUtils.isBlank(" bob ") = false 151 * </pre> 152 * 153 * @param str the String to check, may be null 154 * @return <code>true</code> if the String is null, empty or whitespace 155 * 156 */ 157 public static boolean isBlank(@Nullable String str) { 158 int strLen; 159 // CHECKSTYLE_OFF: InnerAssignment 160 if (str == null || (strLen = str.length()) == 0) 161 // CHECKSTYLE_ON: InnerAssignment 162 { 163 return true; 164 } 165 for (int i = 0; i < strLen; i++) { 166 if (!Character.isWhitespace(str.charAt(i))) { 167 return false; 168 } 169 } 170 return true; 171 } 172 173 /** 174 * <p> 175 * Checks if a String is not empty (""), not null and not whitespace only. 176 * </p> 177 * 178 * <pre> 179 * StringUtils.isNotBlank(null) = false 180 * StringUtils.isNotBlank("") = false 181 * StringUtils.isNotBlank(" ") = false 182 * StringUtils.isNotBlank("bob") = true 183 * StringUtils.isNotBlank(" bob ") = true 184 * </pre> 185 * 186 * @param str the String to check, may be null 187 * @return <code>true</code> if the String is not empty and not null and not whitespace 188 * 189 */ 190 public static boolean isNotBlank(@Nullable String str) { 191 return !isBlank(str); 192 } 193 194 // Equals and IndexOf 195 // -------------------------------------------------------------------------- 196 197 /** 198 * <p>Compares two Strings, returning <code>true</code> if they are equal.</p> 199 * 200 * <p><code>null</code>s are handled without exceptions. Two <code>null</code> 201 * references are considered to be equal. The comparison is case sensitive.</p> 202 * 203 * @param str1 the first string 204 * @param str2 the second string 205 * @return <code>true</code> if the Strings are equal, case sensitive, or 206 * both <code>null</code> 207 * @see java.lang.String#equals(Object) 208 * @deprecated use {@code java.lang.Objects.equals()} 209 */ 210 @Deprecated 211 public static boolean equals(@Nullable String str1, @Nullable String str2) { 212 return (str1 == null ? str2 == null : str1.equals(str2)); 213 } 214 215 /** 216 * <p>Compares two Strings, returning <code>true</code> if they are equal ignoring 217 * the case.</p> 218 * 219 * <p><code>Nulls</code> are handled without exceptions. Two <code>null</code> 220 * references are considered equal. Comparison is case insensitive.</p> 221 * 222 * @param str1 the first string 223 * @param str2 the second string 224 * @return <code>true</code> if the Strings are equal, case insensitive, or 225 * both <code>null</code> 226 * @see java.lang.String#equalsIgnoreCase(String) 227 */ 228 public static boolean equalsIgnoreCase(String str1, String str2) { 229 return (str1 == null ? str2 == null : str1.equalsIgnoreCase(str2)); 230 } 231 232 /** 233 * <p>Find the first index of any of a set of potential substrings.</p> 234 * 235 * <p><code>null</code> String will return <code>-1</code>.</p> 236 * 237 * @param str the String to check 238 * @param searchStrs the Strings to search for 239 * @return the first index of any of the searchStrs in str 240 * @throws NullPointerException if any of searchStrs[i] is <code>null</code> 241 */ 242 public static int indexOfAny(String str, String... searchStrs) { 243 if ((str == null) || (searchStrs == null)) { 244 return -1; 245 } 246 // String's can't have a MAX_VALUEth index. 247 int ret = Integer.MAX_VALUE; 248 249 int tmp; 250 for (String searchStr : searchStrs) { 251 tmp = str.indexOf(searchStr); 252 if (tmp == -1) { 253 continue; 254 } 255 256 if (tmp < ret) { 257 ret = tmp; 258 } 259 } 260 261 return (ret == Integer.MAX_VALUE) ? -1 : ret; 262 } 263 264 /** 265 * <p>Find the latest index of any of a set of potential substrings.</p> 266 * 267 * <p><code>null</code> string will return <code>-1</code>.</p> 268 * 269 * @param str the String to check 270 * @param searchStrs the Strings to search for 271 * @return the last index of any of the Strings 272 * @throws NullPointerException if any of searchStrs[i] is <code>null</code> 273 */ 274 public static int lastIndexOfAny(String str, String... searchStrs) { 275 if ((str == null) || (searchStrs == null)) { 276 return -1; 277 } 278 int ret = -1; 279 int tmp; 280 for (String searchStr : searchStrs) { 281 tmp = str.lastIndexOf(searchStr); 282 if (tmp > ret) { 283 ret = tmp; 284 } 285 } 286 return ret; 287 } 288 289 // Substring 290 // -------------------------------------------------------------------------- 291 292 /** 293 * <p>Gets a substring from the specified string avoiding exceptions.</p> 294 * 295 * <p>A negative start position can be used to start <code>n</code> 296 * characters from the end of the String.</p> 297 * 298 * @param str the String to get the substring from 299 * @param start the position to start from, negative means 300 * count back from the end of the String by this many characters 301 * @return substring from start position 302 */ 303 public static String substring(String str, int start) { 304 if (str == null) { 305 return null; 306 } 307 308 // handle negatives, which means last n characters 309 if (start < 0) { 310 start = str.length() + start; // remember start is negative 311 } 312 313 if (start < 0) { 314 start = 0; 315 } 316 if (start > str.length()) { 317 return ""; 318 } 319 320 return str.substring(start); 321 } 322 323 /** 324 * <p>Gets a substring from the specified String avoiding exceptions.</p> 325 * 326 * <p>A negative start position can be used to start/end <code>n</code> 327 * characters from the end of the String.</p> 328 * 329 * @param str the String to get the substring from 330 * @param start the position to start from, negative means 331 * count back from the end of the string by this many characters 332 * @param end the position to end at (exclusive), negative means 333 * count back from the end of the String by this many characters 334 * @return substring from start position to end position 335 */ 336 public static String substring(String str, int start, int end) { 337 if (str == null) { 338 return null; 339 } 340 341 // handle negatives 342 if (end < 0) { 343 end = str.length() + end; // remember end is negative 344 } 345 if (start < 0) { 346 start = str.length() + start; // remember start is negative 347 } 348 349 // check length next 350 if (end > str.length()) { 351 // check this works. 352 end = str.length(); 353 } 354 355 // if start is greater than end, return "" 356 if (start > end) { 357 return ""; 358 } 359 360 if (start < 0) { 361 start = 0; 362 } 363 if (end < 0) { 364 end = 0; 365 } 366 367 return str.substring(start, end); 368 } 369 370 /** 371 * <p>Gets the leftmost <code>n</code> characters of a String.</p> 372 * 373 * <p>If <code>n</code> characters are not available, or the 374 * String is <code>null</code>, the String will be returned without 375 * an exception.</p> 376 * 377 * @param str the String to get the leftmost characters from 378 * @param len the length of the required String 379 * @return the leftmost characters 380 * @throws IllegalArgumentException if len is less than zero 381 */ 382 public static String left(String str, int len) { 383 if (len < 0) { 384 throw new IllegalArgumentException("Requested String length " + len + " is less than zero"); 385 } 386 if ((str == null) || (str.length() <= len)) { 387 return str; 388 } else { 389 return str.substring(0, len); 390 } 391 } 392 393 /** 394 * <p>Gets the rightmost <code>n</code> characters of a String.</p> 395 * 396 * <p>If <code>n</code> characters are not available, or the String 397 * is <code>null</code>, the String will be returned without an 398 * exception.</p> 399 * 400 * @param str the String to get the rightmost characters from 401 * @param len the length of the required String 402 * @return the leftmost characters 403 * @throws IllegalArgumentException if len is less than zero 404 */ 405 public static String right(String str, int len) { 406 if (len < 0) { 407 throw new IllegalArgumentException("Requested String length " + len + " is less than zero"); 408 } 409 if ((str == null) || (str.length() <= len)) { 410 return str; 411 } else { 412 return str.substring(str.length() - len); 413 } 414 } 415 416 /** 417 * <p>Gets <code>n</code> characters from the middle of a String.</p> 418 * 419 * <p>If <code>n</code> characters are not available, the remainder 420 * of the String will be returned without an exception. If the 421 * String is <code>null</code>, <code>null</code> will be returned.</p> 422 * 423 * @param str the String to get the characters from 424 * @param pos the position to start from 425 * @param len the length of the required String 426 * @return the leftmost characters 427 * @throws IndexOutOfBoundsException if pos is out of bounds 428 * @throws IllegalArgumentException if len is less than zero 429 */ 430 public static String mid(String str, int pos, int len) { 431 if ((pos < 0) || ((str != null) && (pos > str.length()))) { 432 throw new StringIndexOutOfBoundsException("String index " + pos + " is out of bounds"); 433 } 434 if (len < 0) { 435 throw new IllegalArgumentException("Requested String length " + len + " is less than zero"); 436 } 437 if (str == null) { 438 return null; 439 } 440 if (str.length() <= (pos + len)) { 441 return str.substring(pos); 442 } else { 443 return str.substring(pos, pos + len); 444 } 445 } 446 447 // Splitting 448 // -------------------------------------------------------------------------- 449 450 /** 451 * <p>Splits the provided text into a array, using whitespace as the 452 * separator.</p> 453 * 454 * <p>The separator is not included in the returned String array.</p> 455 * 456 * @param str the String to parse 457 * @return an array of parsed Strings 458 */ 459 @Nonnull 460 public static String[] split(@Nonnull String str) { 461 return split(str, null, -1); 462 } 463 464 /** 465 * @param text the text to be split 466 * @param separator the separator at which the text will be split 467 * @return the resulting array 468 * @see #split(String, String, int) 469 */ 470 @Nonnull 471 public static String[] split(@Nonnull String text, @Nullable String separator) { 472 return split(text, separator, -1); 473 } 474 475 /** 476 * <p>Splits the provided text into a array, based on a given separator.</p> 477 * 478 * <p>The separator is not included in the returned String array. The 479 * maximum number of splits to perform can be controlled. A <code>null</code> 480 * separator causes splitting on whitespace.</p> 481 * 482 * <p>This is useful for quickly splitting a String into 483 * an array of tokens, instead of an enumeration of tokens (as 484 * <code>StringTokenizer</code> does).</p> 485 * 486 * @param str the string to parse 487 * @param separator Characters used as the delimiters. If 488 * <code>null</code>, splits on whitespace. 489 * @param max the maximum number of elements to include in the 490 * array. A zero or negative value implies no limit. 491 * @return an array of parsed Strings 492 */ 493 @Nonnull 494 public static String[] split(@Nonnull String str, @Nullable String separator, int max) { 495 StringTokenizer tok; 496 if (separator == null) { 497 // Null separator means we're using StringTokenizer's default 498 // delimiter, which comprises all whitespace characters. 499 tok = new StringTokenizer(str); 500 } else { 501 tok = new StringTokenizer(str, separator); 502 } 503 504 int listSize = tok.countTokens(); 505 if ((max > 0) && (listSize > max)) { 506 listSize = max; 507 } 508 509 String[] list = new String[listSize]; 510 int i = 0; 511 int lastTokenBegin; 512 int lastTokenEnd = 0; 513 while (tok.hasMoreTokens()) { 514 if ((max > 0) && (i == listSize - 1)) { 515 // In the situation where we hit the max yet have 516 // tokens left over in our input, the last list 517 // element gets all remaining text. 518 String endToken = tok.nextToken(); 519 lastTokenBegin = str.indexOf(endToken, lastTokenEnd); 520 list[i] = str.substring(lastTokenBegin); 521 break; 522 } else { 523 list[i] = tok.nextToken(); 524 lastTokenBegin = str.indexOf(list[i], lastTokenEnd); 525 lastTokenEnd = lastTokenBegin + list[i].length(); 526 } 527 i++; 528 } 529 return list; 530 } 531 532 // Joining 533 // -------------------------------------------------------------------------- 534 535 /** 536 * <p>Concatenates elements of an array into a single String.</p> 537 * 538 * <p>The difference from join is that concatenate has no delimiter.</p> 539 * 540 * @param array the array of values to concatenate. 541 * @return the concatenated string. 542 */ 543 @Nonnull 544 public static String concatenate(@Nonnull Object... array) { 545 return join(array, ""); 546 } 547 548 /** 549 * <p>Joins the elements of the provided array into a single String 550 * containing the provided list of elements.</p> 551 * 552 * <p>No delimiter is added before or after the list. A 553 * <code>null</code> separator is the same as a blank String.</p> 554 * 555 * @param array the array of values to join together 556 * @param separator the separator character to use 557 * @return the joined String 558 * @deprecated use <code>java.lang.String.join(</code>) instead 559 */ 560 @Deprecated 561 @Nonnull 562 public static String join(@Nonnull Object[] array, @Nullable String separator) { 563 if (separator == null) { 564 separator = ""; 565 } 566 int arraySize = array.length; 567 int bufSize = (arraySize == 0 ? 0 : (array[0].toString().length() + separator.length()) * arraySize); 568 StringBuilder buf = new StringBuilder(bufSize); 569 570 for (int i = 0; i < arraySize; i++) { 571 if (i > 0) { 572 buf.append(separator); 573 } 574 buf.append(array[i]); 575 } 576 return buf.toString(); 577 } 578 579 /** 580 * <p>Joins the elements of the provided <code>Iterator</code> into 581 * a single String containing the provided elements.</p> 582 * 583 * <p>No delimiter is added before or after the list. A 584 * <code>null</code> separator is the same as a blank String.</p> 585 * 586 * @param iterator the <code>Iterator</code> of values to join together 587 * @param separator the separator character to use 588 * @return the joined String 589 * @deprecated use <code>java.lang.String.join(</code>) instead 590 */ 591 @Deprecated 592 @Nonnull 593 public static String join(@Nonnull Iterator<?> iterator, String separator) { 594 if (separator == null) { 595 separator = ""; 596 } 597 StringBuilder buf = new StringBuilder(256); // Java default is 16, probably too small 598 while (iterator.hasNext()) { 599 buf.append(iterator.next()); 600 if (iterator.hasNext()) { 601 buf.append(separator); 602 } 603 } 604 return buf.toString(); 605 } 606 607 // Replacing 608 // -------------------------------------------------------------------------- 609 610 /** 611 * <p>Replace a char with another char inside a larger String, once.</p> 612 * 613 * <p>A <code>null</code> reference passed to this method is a no-op.</p> 614 * 615 * @param text text to search and replace in 616 * @param repl char to search for 617 * @param with char to replace with 618 * @return the text with any replacements processed 619 * @see #replace(String text, char repl, char with, int max) 620 */ 621 public static String replaceOnce(@Nullable String text, char repl, char with) { 622 return replace(text, repl, with, 1); 623 } 624 625 /** 626 * <p>Replace all occurrences of a char within a string with another char.</p> 627 * 628 * <p>A <code>null</code> reference passed to this method is a no-op.</p> 629 * 630 * @param text text to search and replace in 631 * @param repl char to search for 632 * @param with char to replace with 633 * @return the text with any replacements processed 634 * @see #replace(String text, char repl, char with, int max) 635 */ 636 public static String replace(@Nullable String text, char repl, char with) { 637 return replace(text, repl, with, -1); 638 } 639 640 /** 641 * <p>Replace a char with another char inside a larger String, 642 * for the first <code>max</code> values of the search char.</p> 643 * 644 * <p>A <code>null</code> reference passed to this method is a no-op.</p> 645 * 646 * @param text text to search and replace in 647 * @param repl char to search for 648 * @param with char to replace with 649 * @param max maximum number of values to replace, or <code>-1</code> if no maximum 650 * @return the text with any replacements processed 651 */ 652 public static String replace(@Nullable String text, char repl, char with, int max) { 653 return replace(text, String.valueOf(repl), String.valueOf(with), max); 654 } 655 656 /** 657 * <p>Replace a String with another String inside a larger String, once.</p> 658 * 659 * <p>A <code>null</code> reference passed to this method is a no-op.</p> 660 * 661 * @param text text to search and replace in 662 * @param repl String to search for 663 * @param with String to replace with 664 * @return the text with any replacements processed 665 * @see #replace(String text, String repl, String with, int max) 666 */ 667 public static String replaceOnce(@Nullable String text, @Nullable String repl, @Nullable String with) { 668 return replace(text, repl, with, 1); 669 } 670 671 /** 672 * <p>Replace all occurrences of a String within another String.</p> 673 * 674 * <p>A <code>null</code> reference passed to this method is a no-op.</p> 675 * 676 * @param text text to search and replace in 677 * @param repl String to search for 678 * @param with String to replace with 679 * @return the text with any replacements processed 680 * @see #replace(String text, String repl, String with, int max) 681 */ 682 public static String replace(@Nullable String text, @Nullable String repl, @Nullable String with) { 683 return replace(text, repl, with, -1); 684 } 685 686 /** 687 * <p>Replace a String with another String inside a larger String, 688 * for the first <code>max</code> values of the search String.</p> 689 * 690 * <p>A <code>null</code> reference passed to this method is a no-op.</p> 691 * 692 * @param text text to search and replace in 693 * @param repl String to search for 694 * @param with String to replace with 695 * @param max maximum number of values to replace, or <code>-1</code> if no maximum 696 * @return the text with any replacements processed 697 */ 698 public static String replace(@Nullable String text, @Nullable String repl, @Nullable String with, int max) { 699 if ((text == null) || (repl == null) || (with == null) || (repl.length() == 0)) { 700 return text; 701 } 702 703 StringBuilder buf = new StringBuilder(text.length()); 704 int start = 0, end; 705 while ((end = text.indexOf(repl, start)) != -1) { 706 buf.append(text, start, end).append(with); 707 start = end + repl.length(); 708 709 if (--max == 0) { 710 break; 711 } 712 } 713 buf.append(text, start, text.length()); 714 return buf.toString(); 715 } 716 717 /** 718 * <p>Overlay a part of a String with another String.</p> 719 * 720 * @param text String to do overlaying in 721 * @param overlay String to overlay 722 * @param start position to start overlaying at 723 * @param end position to stop overlaying before 724 * @return String with overlaid text 725 * @throws NullPointerException if text or overlay is <code>null</code> 726 */ 727 @Nonnull 728 public static String overlayString(@Nonnull String text, @Nonnull String overlay, int start, int end) { 729 if (overlay == null) { 730 throw new NullPointerException("overlay is null"); 731 } 732 return new StringBuilder(start + overlay.length() + text.length() - end + 1) 733 .append(text, 0, start) 734 .append(overlay) 735 .append(text, end, text.length()) 736 .toString(); 737 } 738 739 // Centering 740 // -------------------------------------------------------------------------- 741 742 /** 743 * <p>Center a String in a larger String of size <code>n</code>.</p> 744 * 745 * <p>Uses spaces as the value to buffer the String with. 746 * Equivalent to <code>center(str, size, " ")</code>.</p> 747 * 748 * @param str String to center 749 * @param size int size of new String 750 * @return String containing centered String 751 * @throws NullPointerException if str is <code>null</code> 752 */ 753 @Nonnull 754 public static String center(@Nonnull String str, int size) { 755 return center(str, size, " "); 756 } 757 758 /** 759 * <p>Center a String in a larger String of size <code>n</code>.</p> 760 * 761 * <p>Uses a supplied String as the value to buffer the String with.</p> 762 * 763 * @param str String to center 764 * @param size int size of new String 765 * @param delim String to buffer the new String with 766 * @return String containing centered String 767 * @throws NullPointerException if str or delim is <code>null</code> 768 * @throws ArithmeticException if delim is the empty String 769 */ 770 @Nonnull 771 public static String center(@Nonnull String str, int size, @Nonnull String delim) { 772 int sz = str.length(); 773 int p = size - sz; 774 if (p < 1) { 775 return str; 776 } 777 str = leftPad(str, sz + p / 2, delim); 778 str = rightPad(str, size, delim); 779 return str; 780 } 781 782 // Chomping 783 // -------------------------------------------------------------------------- 784 785 /** 786 * <p>Remove the last newline, and everything after it from a String.</p> 787 * 788 * @param str String to chomp the newline from 789 * @return String without chomped newline 790 * @throws NullPointerException if str is <code>null</code> 791 */ 792 @Nonnull 793 public static String chomp(@Nonnull String str) { 794 return chomp(str, "\n"); 795 } 796 797 /** 798 * <p>Remove the last value of a supplied String, and everything after 799 * it from a String.</p> 800 * 801 * @param str String to chomp from 802 * @param sep String to chomp 803 * @return String without chomped ending 804 * @throws NullPointerException if str or sep is <code>null</code> 805 */ 806 @Nonnull 807 public static String chomp(@Nonnull String str, @Nonnull String sep) { 808 int idx = str.lastIndexOf(sep); 809 if (idx != -1) { 810 return str.substring(0, idx); 811 } else { 812 return str; 813 } 814 } 815 816 /** 817 * <p>Remove a newline if and only if it is at the end 818 * of the supplied String.</p> 819 * 820 * @param str String to chomp from 821 * @return String without chomped ending 822 * @throws NullPointerException if str is <code>null</code> 823 */ 824 @Nonnull 825 public static String chompLast(@Nonnull String str) { 826 return chompLast(str, "\n"); 827 } 828 829 /** 830 * <p>Remove a value if and only if the String ends with that value.</p> 831 * 832 * @param str String to chomp from 833 * @param sep String to chomp 834 * @return String without chomped ending 835 * @throws NullPointerException if str or sep is <code>null</code> 836 */ 837 @Nonnull 838 public static String chompLast(@Nonnull String str, @Nonnull String sep) { 839 if (str.length() == 0) { 840 return str; 841 } 842 String sub = str.substring(str.length() - sep.length()); 843 if (sep.equals(sub)) { 844 return str.substring(0, str.length() - sep.length()); 845 } else { 846 return str; 847 } 848 } 849 850 /** 851 * <p>Remove everything and return the last value of a supplied String, and 852 * everything after it from a String.</p> 853 * 854 * @param str String to chomp from 855 * @param sep String to chomp 856 * @return String chomped 857 * @throws NullPointerException if str or sep is <code>null</code> 858 */ 859 @Nonnull 860 public static String getChomp(@Nonnull String str, @Nonnull String sep) { 861 int idx = str.lastIndexOf(sep); 862 if (idx == str.length() - sep.length()) { 863 return sep; 864 } else if (idx != -1) { 865 return str.substring(idx); 866 } else { 867 return ""; 868 } 869 } 870 871 /** 872 * <p>Remove the first value of a supplied String, and everything before it 873 * from a String.</p> 874 * 875 * @param str String to chomp from 876 * @param sep String to chomp 877 * @return String without chomped beginning 878 * @throws NullPointerException if str or sep is <code>null</code> 879 */ 880 @Nonnull 881 public static String prechomp(@Nonnull String str, @Nonnull String sep) { 882 int idx = str.indexOf(sep); 883 if (idx != -1) { 884 return str.substring(idx + sep.length()); 885 } else { 886 return str; 887 } 888 } 889 890 /** 891 * <p>Remove and return everything before the first value of a 892 * supplied String from another String.</p> 893 * 894 * @param str String to chomp from 895 * @param sep String to chomp 896 * @return String prechomped 897 * @throws NullPointerException if str or sep is <code>null</code> 898 */ 899 @Nonnull 900 public static String getPrechomp(@Nonnull String str, @Nonnull String sep) { 901 int idx = str.indexOf(sep); 902 if (idx != -1) { 903 return str.substring(0, idx + sep.length()); 904 } else { 905 return ""; 906 } 907 } 908 909 // Chopping 910 // -------------------------------------------------------------------------- 911 912 /** 913 * <p>Remove the last character from a String.</p> 914 * 915 * <p>If the String ends in <code>\r\n</code>, then remove both 916 * of them.</p> 917 * 918 * @param str String to chop last character from 919 * @return String without last character 920 * @throws NullPointerException if str is <code>null</code> 921 */ 922 @Nonnull 923 public static String chop(@Nonnull String str) { 924 if ("".equals(str)) { 925 return ""; 926 } 927 if (str.length() == 1) { 928 return ""; 929 } 930 int lastIdx = str.length() - 1; 931 String ret = str.substring(0, lastIdx); 932 char last = str.charAt(lastIdx); 933 if (last == '\n') { 934 if (ret.charAt(lastIdx - 1) == '\r') { 935 return ret.substring(0, lastIdx - 1); 936 } 937 } 938 return ret; 939 } 940 941 /** 942 * <p>Remove <code>\n</code> from end of a String if it's there. 943 * If a <code>\r</code> precedes it, then remove that too.</p> 944 * 945 * @param str String to chop a newline from 946 * @return String without newline 947 * @throws NullPointerException if str is <code>null</code> 948 */ 949 @Nonnull 950 public static String chopNewline(@Nonnull String str) { 951 int lastIdx = str.length() - 1; 952 char last = str.charAt(lastIdx); 953 if (last == '\n') { 954 if (str.charAt(lastIdx - 1) == '\r') { 955 lastIdx--; 956 } 957 } else { 958 lastIdx++; 959 } 960 return str.substring(0, lastIdx); 961 } 962 963 // Conversion 964 // -------------------------------------------------------------------------- 965 966 // spec 3.10.6 967 968 /** 969 * <p>Escapes any values it finds into their String form.</p> 970 * 971 * <p>So a tab becomes the characters <code>'\\'</code> and 972 * <code>'t'</code>.</p> 973 * 974 * @param str String to escape values in 975 * @return String with escaped values 976 * @throws NullPointerException if str is <code>null</code> 977 */ 978 @Nonnull 979 public static String escape(@Nonnull String str) { 980 // improved with code from cybertiger@cyberiantiger.org 981 // unicode from him, and defaul for < 32's. 982 int sz = str.length(); 983 StringBuilder buffer = new StringBuilder(2 * sz); 984 for (int i = 0; i < sz; i++) { 985 char ch = str.charAt(i); 986 987 // handle unicode 988 // CHECKSTYLE_OFF: MagicNumber 989 if (ch > 0xfff) { 990 buffer.append("\\u").append(Integer.toHexString(ch)); 991 } else if (ch > 0xff) { 992 buffer.append("\\u0").append(Integer.toHexString(ch)); 993 } else if (ch > 0x7f) { 994 buffer.append("\\u00").append(Integer.toHexString(ch)); 995 } 996 // CHECKSTYLE_ON: MagicNumber 997 else if (ch < 32) { 998 switch (ch) { 999 case '\b': 1000 buffer.append('\\'); 1001 buffer.append('b'); 1002 break; 1003 case '\n': 1004 buffer.append('\\'); 1005 buffer.append('n'); 1006 break; 1007 case '\t': 1008 buffer.append('\\'); 1009 buffer.append('t'); 1010 break; 1011 case '\f': 1012 buffer.append('\\'); 1013 buffer.append('f'); 1014 break; 1015 case '\r': 1016 buffer.append('\\'); 1017 buffer.append('r'); 1018 break; 1019 default: 1020 if (ch > 0xf) { 1021 buffer.append("\\u00").append(Integer.toHexString(ch)); 1022 } else { 1023 buffer.append("\\u000").append(Integer.toHexString(ch)); 1024 } 1025 break; 1026 } 1027 } else { 1028 switch (ch) { 1029 case '\'': 1030 buffer.append('\\'); 1031 buffer.append('\''); 1032 break; 1033 case '"': 1034 buffer.append('\\'); 1035 buffer.append('"'); 1036 break; 1037 case '\\': 1038 buffer.append('\\'); 1039 buffer.append('\\'); 1040 break; 1041 default: 1042 buffer.append(ch); 1043 break; 1044 } 1045 } 1046 } 1047 return buffer.toString(); 1048 } 1049 1050 // Padding 1051 // -------------------------------------------------------------------------- 1052 1053 /** 1054 * <p>Repeat a String <code>n</code> times to form a 1055 * new string.</p> 1056 * 1057 * @param str String to repeat 1058 * @param repeat number of times to repeat str 1059 * @return String with repeated String 1060 * @throws NegativeArraySizeException if <code>repeat < 0</code> 1061 * @throws NullPointerException if str is <code>null</code> 1062 */ 1063 @Nonnull 1064 public static String repeat(@Nonnull String str, int repeat) { 1065 StringBuilder buffer = new StringBuilder(repeat * str.length()); 1066 for (int i = 0; i < repeat; i++) { 1067 buffer.append(str); 1068 } 1069 return buffer.toString(); 1070 } 1071 1072 /** 1073 * <p>Right pad a String with spaces.</p> 1074 * 1075 * <p>The String is padded to the size of <code>n</code>.</p> 1076 * 1077 * @param str String to repeat 1078 * @param size number of times to repeat str 1079 * @return right padded String 1080 * @throws NullPointerException if str is <code>null</code> 1081 */ 1082 @Nonnull 1083 public static String rightPad(@Nonnull String str, int size) { 1084 return rightPad(str, size, " "); 1085 } 1086 1087 /** 1088 * <p>Right pad a String with a specified string.</p> 1089 * 1090 * <p>The String is padded to the size of <code>n</code>.</p> 1091 * 1092 * @param str String to pad out 1093 * @param size size to pad to 1094 * @param delim String to pad with 1095 * @return right padded String 1096 * @throws NullPointerException if str or delim is <code>null</code> 1097 * @throws ArithmeticException if delim is the empty String 1098 */ 1099 @Nonnull 1100 public static String rightPad(@Nonnull String str, int size, @Nonnull String delim) { 1101 size = (size - str.length()) / delim.length(); 1102 if (size > 0) { 1103 str += repeat(delim, size); 1104 } 1105 return str; 1106 } 1107 1108 /** 1109 * <p>Left pad a String with spaces.</p> 1110 * 1111 * <p>The String is padded to the size of <code>n</code>.</p> 1112 * 1113 * @param str String to pad out 1114 * @param size size to pad to 1115 * @return left padded String 1116 * @throws NullPointerException if str or delim is <code>null</code> 1117 */ 1118 @Nonnull 1119 public static String leftPad(@Nonnull String str, int size) { 1120 return leftPad(str, size, " "); 1121 } 1122 1123 /** 1124 * Left pad a String with a specified string. Pad to a size of n. 1125 * 1126 * @param str String to pad out 1127 * @param size size to pad to 1128 * @param delim String to pad with 1129 * @return left padded String 1130 * @throws NullPointerException if str or delim is null 1131 * @throws ArithmeticException if delim is the empty string 1132 */ 1133 @Nonnull 1134 public static String leftPad(@Nonnull String str, int size, @Nonnull String delim) { 1135 size = (size - str.length()) / delim.length(); 1136 if (size > 0) { 1137 str = repeat(delim, size) + str; 1138 } 1139 return str; 1140 } 1141 1142 // Stripping 1143 // -------------------------------------------------------------------------- 1144 1145 /** 1146 * <p>Remove whitespace from the front and back of a String.</p> 1147 * 1148 * @param str the String to remove whitespace from 1149 * @return the stripped String 1150 */ 1151 public static String strip(String str) { 1152 return strip(str, null); 1153 } 1154 1155 /** 1156 * <p>Remove a specified String from the front and back of a 1157 * String.</p> 1158 * 1159 * <p>If whitespace is wanted to be removed, used the 1160 * {@link #strip(java.lang.String)} method.</p> 1161 * 1162 * @param str the String to remove a string from 1163 * @param delim the String to remove at start and end 1164 * @return the stripped String 1165 */ 1166 public static String strip(String str, @Nullable String delim) { 1167 str = stripStart(str, delim); 1168 return stripEnd(str, delim); 1169 } 1170 1171 /** 1172 * <p>Strip whitespace from the front and back of every String 1173 * in the array.</p> 1174 * 1175 * @param strs the Strings to remove whitespace from 1176 * @return the stripped Strings 1177 */ 1178 public static String[] stripAll(String... strs) { 1179 return stripAll(strs, null); 1180 } 1181 1182 /** 1183 * <p>Strip the specified delimiter from the front and back of 1184 * every String in the array.</p> 1185 * 1186 * @param strs the Strings to remove a String from 1187 * @param delimiter the String to remove at start and end 1188 * @return the stripped Strings 1189 */ 1190 public static String[] stripAll(String[] strs, @Nullable String delimiter) { 1191 if ((strs == null) || (strs.length == 0)) { 1192 return strs; 1193 } 1194 int sz = strs.length; 1195 String[] newArr = new String[sz]; 1196 for (int i = 0; i < sz; i++) { 1197 newArr[i] = strip(strs[i], delimiter); 1198 } 1199 return newArr; 1200 } 1201 1202 /** 1203 * <p>Strip any of a supplied String from the end of a String.</p> 1204 * 1205 * <p>If the strip String is <code>null</code>, whitespace is 1206 * stripped.</p> 1207 * 1208 * @param str the String to remove characters from 1209 * @param strip the String to remove 1210 * @return the stripped String 1211 */ 1212 public static String stripEnd(String str, @Nullable String strip) { 1213 if (str == null) { 1214 return null; 1215 } 1216 int end = str.length(); 1217 1218 if (strip == null) { 1219 while ((end != 0) && Character.isWhitespace(str.charAt(end - 1))) { 1220 end--; 1221 } 1222 } else { 1223 while ((end != 0) && (strip.indexOf(str.charAt(end - 1)) != -1)) { 1224 end--; 1225 } 1226 } 1227 return str.substring(0, end); 1228 } 1229 1230 /** 1231 * <p>Strip any of a supplied String from the start of a String.</p> 1232 * 1233 * <p>If the strip String is <code>null</code>, whitespace is 1234 * stripped.</p> 1235 * 1236 * @param str the String to remove characters from 1237 * @param strip the String to remove 1238 * @return the stripped String 1239 */ 1240 public static String stripStart(String str, @Nullable String strip) { 1241 if (str == null) { 1242 return null; 1243 } 1244 1245 int start = 0; 1246 1247 int sz = str.length(); 1248 1249 if (strip == null) { 1250 while ((start != sz) && Character.isWhitespace(str.charAt(start))) { 1251 start++; 1252 } 1253 } else { 1254 while ((start != sz) && (strip.indexOf(str.charAt(start)) != -1)) { 1255 start++; 1256 } 1257 } 1258 return str.substring(start); 1259 } 1260 1261 // Case conversion 1262 // -------------------------------------------------------------------------- 1263 1264 /** 1265 * <p>Convert a String to upper case, <code>null</code> String 1266 * returns <code>null</code>.</p> 1267 * 1268 * @param str the String to uppercase 1269 * @return the upper cased String 1270 */ 1271 public static String upperCase(String str) { 1272 if (str == null) { 1273 return null; 1274 } 1275 return str.toUpperCase(); 1276 } 1277 1278 /** 1279 * <p>Convert a String to lower case, <code>null</code> String 1280 * returns <code>null</code>.</p> 1281 * 1282 * @param str the string to lowercase 1283 * @return the lower cased String 1284 */ 1285 public static String lowerCase(String str) { 1286 if (str == null) { 1287 return null; 1288 } 1289 return str.toLowerCase(); 1290 } 1291 1292 /** 1293 * <p>Uncapitalise a String.</p> 1294 * 1295 * <p>That is, convert the first character into lower-case. 1296 * <code>null</code> is returned as <code>null</code>.</p> 1297 * 1298 * @param str the String to uncapitalise 1299 * @return uncapitalised String 1300 */ 1301 public static String uncapitalise(String str) { 1302 if (str == null) { 1303 return null; 1304 } else { 1305 int length = str.length(); 1306 if (length == 0) { 1307 return ""; 1308 } else { 1309 return new StringBuffer(length) 1310 .append(Character.toLowerCase(str.charAt(0))) 1311 .append(str, 1, length) 1312 .toString(); 1313 } 1314 } 1315 } 1316 1317 /** 1318 * <p>Capitalise a String.</p> 1319 * 1320 * <p>That is, convert the first character into title-case. 1321 * <code>null</code> is returned as <code>null</code>.</p> 1322 * 1323 * @param str the String to capitalise 1324 * @return capitalised String 1325 */ 1326 public static String capitalise(String str) { 1327 if (str == null) { 1328 return null; 1329 } else { 1330 int length = str.length(); 1331 if (length == 0) { 1332 return ""; 1333 } else { 1334 return new StringBuilder(length) 1335 .append(Character.toTitleCase(str.charAt(0))) 1336 .append(str, 1, length) 1337 .toString(); 1338 } 1339 } 1340 } 1341 1342 /** 1343 * <p>Swaps the case of String.</p> 1344 * 1345 * <p>Properly looks after making sure the start of words 1346 * are Titlecase and not Uppercase.</p> 1347 * 1348 * <p><code>null</code> is returned as <code>null</code>.</p> 1349 * 1350 * @param str the String to swap the case of 1351 * @return the modified String 1352 */ 1353 public static String swapCase(String str) { 1354 if (str == null) { 1355 return null; 1356 } 1357 int sz = str.length(); 1358 StringBuilder buffer = new StringBuilder(sz); 1359 1360 boolean whitespace = false; 1361 char ch; 1362 char tmp; 1363 1364 for (int i = 0; i < sz; i++) { 1365 ch = str.charAt(i); 1366 if (Character.isUpperCase(ch)) { 1367 tmp = Character.toLowerCase(ch); 1368 } else if (Character.isTitleCase(ch)) { 1369 tmp = Character.toLowerCase(ch); 1370 } else if (Character.isLowerCase(ch)) { 1371 if (whitespace) { 1372 tmp = Character.toTitleCase(ch); 1373 } else { 1374 tmp = Character.toUpperCase(ch); 1375 } 1376 } else { 1377 tmp = ch; 1378 } 1379 buffer.append(tmp); 1380 whitespace = Character.isWhitespace(ch); 1381 } 1382 return buffer.toString(); 1383 } 1384 1385 /** 1386 * <p>Capitalise all the words in a String.</p> 1387 * 1388 * <p>Uses {@link Character#isWhitespace(char)} as a 1389 * separator between words.</p> 1390 * 1391 * <p><code>null</code> will return <code>null</code>.</p> 1392 * 1393 * @param str the String to capitalise 1394 * @return capitalised String 1395 */ 1396 public static String capitaliseAllWords(String str) { 1397 if (str == null) { 1398 return null; 1399 } 1400 int sz = str.length(); 1401 StringBuilder buffer = new StringBuilder(sz); 1402 boolean space = true; 1403 for (int i = 0; i < sz; i++) { 1404 char ch = str.charAt(i); 1405 if (Character.isWhitespace(ch)) { 1406 buffer.append(ch); 1407 space = true; 1408 } else if (space) { 1409 buffer.append(Character.toTitleCase(ch)); 1410 space = false; 1411 } else { 1412 buffer.append(ch); 1413 } 1414 } 1415 return buffer.toString(); 1416 } 1417 1418 /** 1419 * <p>Uncapitalise all the words in a string.</p> 1420 * 1421 * <p>Uses {@link Character#isWhitespace(char)} as a 1422 * separator between words.</p> 1423 * 1424 * <p><code>null</code> will return <code>null</code>.</p> 1425 * 1426 * @param str the string to uncapitalise 1427 * @return uncapitalised string 1428 */ 1429 public static String uncapitaliseAllWords(String str) { 1430 if (str == null) { 1431 return null; 1432 } 1433 int sz = str.length(); 1434 StringBuilder buffer = new StringBuilder(sz); 1435 boolean space = true; 1436 for (int i = 0; i < sz; i++) { 1437 char ch = str.charAt(i); 1438 if (Character.isWhitespace(ch)) { 1439 buffer.append(ch); 1440 space = true; 1441 } else if (space) { 1442 buffer.append(Character.toLowerCase(ch)); 1443 space = false; 1444 } else { 1445 buffer.append(ch); 1446 } 1447 } 1448 return buffer.toString(); 1449 } 1450 1451 // Nested extraction 1452 // -------------------------------------------------------------------------- 1453 1454 /** 1455 * <p>Get the String that is nested in between two instances of the 1456 * same String.</p> 1457 * 1458 * <p>If <code>str</code> is <code>null</code>, will 1459 * return <code>null</code>.</p> 1460 * 1461 * @param str the String containing nested-string 1462 * @param tag the String before and after nested-string 1463 * @return the String that was nested, or <code>null</code> 1464 * @throws NullPointerException if tag is <code>null</code> 1465 */ 1466 public static String getNestedString(String str, @Nonnull String tag) { 1467 return getNestedString(str, tag, tag); 1468 } 1469 1470 /** 1471 * <p>Get the String that is nested in between two Strings.</p> 1472 * 1473 * @param str the String containing nested-string 1474 * @param open the String before nested-string 1475 * @param close the String after nested-string 1476 * @return the String that was nested, or <code>null</code> 1477 * @throws NullPointerException if open or close is <code>null</code> 1478 */ 1479 public static String getNestedString(String str, @Nonnull String open, @Nonnull String close) { 1480 if (str == null) { 1481 return null; 1482 } 1483 int start = str.indexOf(open); 1484 if (start != -1) { 1485 int end = str.indexOf(close, start + open.length()); 1486 if (end != -1) { 1487 return str.substring(start + open.length(), end); 1488 } 1489 } 1490 return null; 1491 } 1492 1493 /** 1494 * <p>How many times is the substring in the larger String.</p> 1495 * 1496 * <p><code>null</code> returns <code>0</code>.</p> 1497 * 1498 * @param str the String to check 1499 * @param sub the substring to count 1500 * @return the number of occurrences, 0 if the String is <code>null</code> 1501 * @throws NullPointerException if sub is <code>null</code> 1502 */ 1503 public static int countMatches(@Nullable String str, @Nonnull String sub) { 1504 if (sub.equals("")) { 1505 return 0; 1506 } 1507 if (str == null) { 1508 return 0; 1509 } 1510 int count = 0; 1511 int idx = 0; 1512 while ((idx = str.indexOf(sub, idx)) != -1) { 1513 count++; 1514 idx += sub.length(); 1515 } 1516 return count; 1517 } 1518 1519 // Character Tests 1520 // -------------------------------------------------------------------------- 1521 1522 /** 1523 * <p>Checks if the String contains only Unicode letters.</p> 1524 * 1525 * <p><code>null</code> will return <code>false</code>. 1526 * An empty String will return <code>true</code>.</p> 1527 * 1528 * @param str the String to check 1529 * @return <code>true</code> if only contains letters, and is non-null 1530 */ 1531 public static boolean isAlpha(String str) { 1532 if (str == null) { 1533 return false; 1534 } 1535 int sz = str.length(); 1536 for (int i = 0; i < sz; i++) { 1537 if (!Character.isLetter(str.charAt(i))) { 1538 return false; 1539 } 1540 } 1541 return true; 1542 } 1543 1544 /** 1545 * <p>Checks if the String contains only whitespace.</p> 1546 * 1547 * <p><code>null</code> will return <code>false</code>. An 1548 * empty String will return <code>true</code>.</p> 1549 * 1550 * @param str the String to check 1551 * @return <code>true</code> if only contains whitespace, and is non-null 1552 */ 1553 public static boolean isWhitespace(String str) { 1554 if (str == null) { 1555 return false; 1556 } 1557 int sz = str.length(); 1558 for (int i = 0; i < sz; i++) { 1559 if ((!Character.isWhitespace(str.charAt(i)))) { 1560 return false; 1561 } 1562 } 1563 return true; 1564 } 1565 1566 /** 1567 * <p>Checks if the String contains only Unicode letters and 1568 * space (<code>' '</code>).</p> 1569 * 1570 * <p><code>null</code> will return <code>false</code>. An 1571 * empty String will return <code>true</code>.</p> 1572 * 1573 * @param str the String to check 1574 * @return <code>true</code> if only contains letters and space, 1575 * and is non-null 1576 */ 1577 public static boolean isAlphaSpace(String str) { 1578 if (str == null) { 1579 return false; 1580 } 1581 int sz = str.length(); 1582 for (int i = 0; i < sz; i++) { 1583 if ((!Character.isLetter(str.charAt(i))) && (str.charAt(i) != ' ')) { 1584 return false; 1585 } 1586 } 1587 return true; 1588 } 1589 1590 /** 1591 * <p>Checks if the String contains only Unicode letters or digits.</p> 1592 * 1593 * <p><code>null</code> will return <code>false</code>. An empty 1594 * String will return <code>true</code>.</p> 1595 * 1596 * @param str the String to check 1597 * @return <code>true</code> if only contains letters or digits, 1598 * and is non-null 1599 */ 1600 public static boolean isAlphanumeric(String str) { 1601 if (str == null) { 1602 return false; 1603 } 1604 int sz = str.length(); 1605 for (int i = 0; i < sz; i++) { 1606 if (!Character.isLetterOrDigit(str.charAt(i))) { 1607 return false; 1608 } 1609 } 1610 return true; 1611 } 1612 1613 /** 1614 * <p>Checks if the String contains only Unicode letters, digits 1615 * or space (<code>' '</code>).</p> 1616 * 1617 * <p><code>null</code> will return <code>false</code>. An empty 1618 * String will return <code>true</code>.</p> 1619 * 1620 * @param str the String to check 1621 * @return <code>true</code> if only contains letters, digits or space, 1622 * and is non-null 1623 */ 1624 public static boolean isAlphanumericSpace(String str) { 1625 if (str == null) { 1626 return false; 1627 } 1628 int sz = str.length(); 1629 for (int i = 0; i < sz; i++) { 1630 if ((!Character.isLetterOrDigit(str.charAt(i))) && (str.charAt(i) != ' ')) { 1631 return false; 1632 } 1633 } 1634 return true; 1635 } 1636 1637 /** 1638 * <p>Checks if the String contains only Unicode digits.</p> 1639 * 1640 * <p><code>null</code> will return <code>false</code>. 1641 * An empty String will return <code>true</code>.</p> 1642 * 1643 * @param str the String to check 1644 * @return <code>true</code> if only contains digits, and is non-null 1645 */ 1646 public static boolean isNumeric(String str) { 1647 if (str == null) { 1648 return false; 1649 } 1650 int sz = str.length(); 1651 for (int i = 0; i < sz; i++) { 1652 if (!Character.isDigit(str.charAt(i))) { 1653 return false; 1654 } 1655 } 1656 return true; 1657 } 1658 1659 // Defaults 1660 // -------------------------------------------------------------------------- 1661 1662 /** 1663 * <p>Returns either the passed in <code>Object</code> as a String, 1664 * or, if the <code>Object</code> is <code>null</code>, an empty 1665 * String.</p> 1666 * 1667 * @param obj the Object to check 1668 * @return the passed in Object's toString, or blank if it was 1669 * <code>null</code> 1670 * @deprecated use {@code java.lang.Objects.toString()} 1671 */ 1672 @Deprecated 1673 @Nonnull 1674 public static String defaultString(Object obj) { 1675 return defaultString(obj, ""); 1676 } 1677 1678 /** 1679 * <p>Returns either the passed in <code>Object</code> as a String, 1680 * or, if the <code>Object</code> is <code>null</code>, a passed 1681 * in default String.</p> 1682 * 1683 * @param obj the Object to check 1684 * @param defaultString the default String to return if str is 1685 * <code>null</code> 1686 * @return the passed in string, or the default if it was 1687 * <code>null</code> 1688 * @deprecated use {@code java.lang.Objects.toString()} 1689 */ 1690 @Deprecated 1691 @Nonnull 1692 public static String defaultString(Object obj, @Nonnull String defaultString) { 1693 return (obj == null) ? defaultString : obj.toString(); 1694 } 1695 1696 // Reversing 1697 // -------------------------------------------------------------------------- 1698 1699 /** 1700 * <p>Reverse a String.</p> 1701 * 1702 * <p><code>null</code> String returns <code>null</code>.</p> 1703 * 1704 * @param str the String to reverse 1705 * @return the reversed String 1706 */ 1707 public static String reverse(String str) { 1708 if (str == null) { 1709 return null; 1710 } 1711 return new StringBuffer(str).reverse().toString(); 1712 } 1713 1714 /** 1715 * <p>Reverses a String that is delimited by a specific character.</p> 1716 * 1717 * <p>The Strings between the delimiters are not reversed. 1718 * Thus java.lang.String becomes String.lang.java (if the delimiter 1719 * is <code>'.'</code>).</p> 1720 * 1721 * @param str the String to reverse 1722 * @param delimiter the delimiter to use 1723 * @return the reversed String 1724 */ 1725 @Nonnull 1726 public static String reverseDelimitedString(@Nonnull String str, String delimiter) { 1727 // could implement manually, but simple way is to reuse other, 1728 // probably slower, methods. 1729 String[] strs = split(str, delimiter); 1730 reverseArray(strs); 1731 return join(strs, delimiter); 1732 } 1733 1734 /** 1735 * <p>Reverses an array.</p> 1736 * 1737 * @param array the array to reverse 1738 */ 1739 private static void reverseArray(@Nonnull String... array) { 1740 int i = 0; 1741 int j = array.length - 1; 1742 String tmp; 1743 1744 while (j > i) { 1745 tmp = array[j]; 1746 array[j] = array[i]; 1747 array[i] = tmp; 1748 j--; 1749 i++; 1750 } 1751 } 1752 1753 // Abbreviating 1754 // -------------------------------------------------------------------------- 1755 1756 /** 1757 * <p>Turn "Now is the time for all good men" into "Now is the time for..."</p> 1758 * <p>Specifically:</p> 1759 * <p>If str is less than max characters long, return it. 1760 * Else abbreviate it to (substring(str, 0, max-3) + "..."). 1761 * If maxWidth is less than 3, throw an IllegalArgumentException. 1762 * In no case will it return a string of length greater than maxWidth.</p> 1763 * 1764 * @param s The string to be abbreviated. 1765 * @param maxWidth maximum length of result string 1766 * @return The abbreviated string. 1767 */ 1768 @Nonnull 1769 public static String abbreviate(@Nonnull String s, int maxWidth) { 1770 return abbreviate(s, 0, maxWidth); 1771 } 1772 1773 /** 1774 * Turn "Now is the time for all good men" into "...is the time for..." 1775 * <p> 1776 * Works like abbreviate(String, int), but allows you to specify a "left edge" 1777 * offset. Note that this left edge is not necessarily going to be the leftmost 1778 * character in the result, or the first 1779 * character following the ellipses, but it will appear somewhere in the result. 1780 * In no case will it return a string of length greater than maxWidth. 1781 * </p> 1782 * 1783 * @param s String to abbreviate. 1784 * @param offset left edge of source string 1785 * @param maxWidth maximum length of result string 1786 * @return The abbreviated string. 1787 */ 1788 @Nonnull 1789 public static String abbreviate(@Nonnull String s, int offset, int maxWidth) { 1790 if (maxWidth < 4) { 1791 throw new IllegalArgumentException("Minimum abbreviation width is 4"); 1792 } 1793 if (s.length() <= maxWidth) { 1794 return s; 1795 } 1796 if (offset > s.length()) { 1797 offset = s.length(); 1798 } 1799 if ((s.length() - offset) < (maxWidth - 3)) { 1800 offset = s.length() - (maxWidth - 3); 1801 } 1802 if (offset <= 4) { 1803 return s.substring(0, maxWidth - 3) + "..."; 1804 } 1805 if (maxWidth < 7) { 1806 throw new IllegalArgumentException("Minimum abbreviation width with offset is 7"); 1807 } 1808 if ((offset + (maxWidth - 3)) < s.length()) { 1809 return "..." + abbreviate(s.substring(offset), maxWidth - 3); 1810 } 1811 return "..." + s.substring(s.length() - (maxWidth - 3)); 1812 } 1813 1814 // Difference 1815 // -------------------------------------------------------------------------- 1816 1817 /** 1818 * Compare two strings, and return the portion where they differ. 1819 * (More precisely, return the remainder of the second string, 1820 * starting from where it's different from the first.) 1821 * <p> 1822 * E.g. strdiff("i am a machine", "i am a robot") → "robot" 1823 * </p> 1824 * 1825 * @param s1 The first string. 1826 * @param s2 The second string. 1827 * @return the portion of s2 where it differs from s1; returns the empty string ("") if they are equal 1828 */ 1829 public static String difference(@Nonnull String s1, @Nonnull String s2) { 1830 int at = differenceAt(s1, s2); 1831 if (at == -1) { 1832 return ""; 1833 } 1834 return s2.substring(at); 1835 } 1836 1837 /** 1838 * Compare two strings, and return the index at which the strings begin to differ. 1839 * <p> 1840 * E.g. strdiff("i am a machine", "i am a robot") → 7 1841 * </p> 1842 * 1843 * @param s1 The first string. 1844 * @param s2 The second string. 1845 * @return the index where s2 and s1 begin to differ; -1 if they are equal 1846 */ 1847 public static int differenceAt(@Nonnull String s1, @Nonnull String s2) { 1848 int i; 1849 for (i = 0; (i < s1.length()) && (i < s2.length()); ++i) { 1850 if (s1.charAt(i) != s2.charAt(i)) { 1851 break; 1852 } 1853 } 1854 if ((i < s2.length()) || (i < s1.length())) { 1855 return i; 1856 } 1857 return -1; 1858 } 1859 1860 /** 1861 * Fill all 'variables' in the given text with the values from the map. 1862 * Any text looking like '${key}' will get replaced by the value stored 1863 * in the namespace map under the 'key'. 1864 * 1865 * @param text The text where replacements will be searched for. 1866 * @param namespace The namespace which contains the replacements. 1867 * @return the interpolated text. 1868 */ 1869 public static String interpolate(String text, @Nonnull Map<?, ?> namespace) { 1870 for (Map.Entry<?, ?> entry : namespace.entrySet()) { 1871 String key = entry.getKey().toString(); 1872 1873 Object obj = entry.getValue(); 1874 1875 if (obj == null) { 1876 throw new NullPointerException("The value of the key '" + key + "' is null."); 1877 } 1878 1879 String value = obj.toString(); 1880 1881 text = replace(text, "${" + key + "}", value); 1882 1883 if (!key.contains(" ")) { 1884 text = replace(text, "$" + key, value); 1885 } 1886 } 1887 return text; 1888 } 1889 1890 /** 1891 * This is basically the inverse of {@link #addAndDeHump(String)}. 1892 * It will remove the 'replaceThis' parameter and uppercase the next 1893 * character afterwards. 1894 * <pre> 1895 * removeAndHump( "this-is-it", %quot;-" ); 1896 * </pre> 1897 * will become 'ThisIsIt'. 1898 * 1899 * @param data The data. 1900 * @param replaceThis The things which should be replaced. 1901 * @return humped String 1902 */ 1903 @Nonnull 1904 public static String removeAndHump(@Nonnull String data, @Nonnull String replaceThis) { 1905 String temp; 1906 1907 StringBuilder out = new StringBuilder(); 1908 1909 temp = data; 1910 1911 StringTokenizer st = new StringTokenizer(temp, replaceThis); 1912 1913 while (st.hasMoreTokens()) { 1914 String element = st.nextToken(); 1915 1916 out.append(capitalizeFirstLetter(element)); 1917 } 1918 1919 return out.toString(); 1920 } 1921 1922 /** 1923 * Converts the first character of the given String to uppercase. 1924 * This method does <i>not</i> trim spaces! 1925 * 1926 * @param data the String to get capitalized 1927 * @return data string with the first character transformed to uppercase 1928 * @throws NullPointerException if data is <code>null</code> 1929 * @throws IndexOutOfBoundsException if data is empty 1930 */ 1931 @Nonnull 1932 public static String capitalizeFirstLetter(@Nonnull String data) { 1933 char firstChar = data.charAt(0); 1934 char titleCase = Character.toTitleCase(firstChar); 1935 if (firstChar == titleCase) { 1936 return data; 1937 } 1938 StringBuilder result = new StringBuilder(data.length()); 1939 result.append(titleCase); 1940 result.append(data, 1, data.length()); 1941 return result.toString(); 1942 } 1943 1944 /** 1945 * Converts the first character of the given String to lowercase. 1946 * This method does <i>not</i> trim spaces! 1947 * 1948 * @param data the String to get it's first character lower-cased. 1949 * @return data string with the first character transformed to lowercase 1950 * @throws NullPointerException if data is <code>null</code> 1951 * @throws IndexOutOfBoundsException if data is empty 1952 */ 1953 @Nonnull 1954 public static String lowercaseFirstLetter(@Nonnull String data) { 1955 char firstLetter = Character.toLowerCase(data.substring(0, 1).charAt(0)); 1956 1957 String restLetters = data.substring(1); 1958 1959 return firstLetter + restLetters; 1960 } 1961 1962 /** 1963 * <p>Take the input string and un-camel-case it.</p> 1964 * <p>'ThisIsIt' will become 'this-is-it'.</p> 1965 * 1966 * @param view the view 1967 * @return deHumped String 1968 */ 1969 @Nonnull 1970 public static String addAndDeHump(@Nonnull String view) { 1971 StringBuilder sb = new StringBuilder(); 1972 1973 for (int i = 0; i < view.length(); i++) { 1974 if ((i != 0) && Character.isUpperCase(view.charAt(i))) { 1975 sb.append('-'); 1976 } 1977 1978 sb.append(view.charAt(i)); 1979 } 1980 1981 return sb.toString().trim().toLowerCase(Locale.ENGLISH); 1982 } 1983 1984 /** 1985 * <p>Quote and escape a String with the given character, handling <code>null</code>.</p> 1986 * 1987 * <pre> 1988 * StringUtils.quoteAndEscape(null, *) = null 1989 * StringUtils.quoteAndEscape("", *) = "" 1990 * StringUtils.quoteAndEscape("abc", '"') = abc 1991 * StringUtils.quoteAndEscape("a\"bc", '"') = "a\"bc" 1992 * StringUtils.quoteAndEscape("a\"bc", '\'') = 'a\"bc' 1993 * </pre> 1994 * 1995 * @param source The source. 1996 * @param quoteChar The quote character. 1997 * @return the String quoted and escaped 1998 * @see #quoteAndEscape(String, char, char[], char[], char, boolean) 1999 * @see #quoteAndEscape(String, char, char[], char[], char, boolean) 2000 * 2001 */ 2002 public static String quoteAndEscape(@Nullable String source, char quoteChar) { 2003 return quoteAndEscape(source, quoteChar, new char[] {quoteChar}, new char[] {' '}, '\\', false); 2004 } 2005 2006 /** 2007 * <p>Quote and escape a String with the given character, handling <code>null</code>.</p> 2008 * 2009 * @param source the source 2010 * @param quoteChar the quote character 2011 * @param quotingTriggers the quoting trigger 2012 * @return the String quoted and escaped 2013 * @see #quoteAndEscape(String, char, char[], char[], char, boolean) 2014 * 2015 */ 2016 public static String quoteAndEscape(@Nullable String source, char quoteChar, @Nonnull char[] quotingTriggers) { 2017 return quoteAndEscape(source, quoteChar, new char[] {quoteChar}, quotingTriggers, '\\', false); 2018 } 2019 2020 /** 2021 * @param source the source 2022 * @param quoteChar the quote character 2023 * @param escapedChars the escaped characters 2024 * @param escapeChar the escape character 2025 * @param force true/false 2026 * @return the String quoted and escaped 2027 * @see #quoteAndEscape(String, char, char[], char[], char, boolean) 2028 * 2029 */ 2030 public static String quoteAndEscape( 2031 @Nullable String source, 2032 char quoteChar, 2033 @Nonnull final char[] escapedChars, 2034 char escapeChar, 2035 boolean force) { 2036 return quoteAndEscape(source, quoteChar, escapedChars, new char[] {' '}, escapeChar, force); 2037 } 2038 2039 /** 2040 * @param source the source 2041 * @param quoteChar the quote character 2042 * @param escapedChars set of characters to escape 2043 * @param quotingTriggers the quoting trigger 2044 * @param escapeChar prefix for escaping a character 2045 * @param force true/false 2046 * @return the String quoted and escaped 2047 */ 2048 public static String quoteAndEscape( 2049 @Nullable String source, 2050 char quoteChar, 2051 @Nonnull final char[] escapedChars, 2052 @Nonnull final char[] quotingTriggers, 2053 char escapeChar, 2054 boolean force) { 2055 if (source == null) { 2056 return null; 2057 } 2058 2059 if (!force 2060 && source.startsWith(Character.toString(quoteChar)) 2061 && source.endsWith(Character.toString(quoteChar))) { 2062 return source; 2063 } 2064 2065 String escaped = escape(source, escapedChars, escapeChar); 2066 2067 boolean quote = false; 2068 if (force) { 2069 quote = true; 2070 } else if (!escaped.equals(source)) { 2071 quote = true; 2072 } else { 2073 for (char quotingTrigger : quotingTriggers) { 2074 if (escaped.indexOf(quotingTrigger) > -1) { 2075 quote = true; 2076 break; 2077 } 2078 } 2079 } 2080 2081 if (quote) { 2082 return quoteChar + escaped + quoteChar; 2083 } 2084 2085 return escaped; 2086 } 2087 2088 /** 2089 * @param source the source 2090 * @param escapedChars set of characters to escape 2091 * @param escapeChar prefix for escaping a character 2092 * @return the String escaped 2093 */ 2094 public static String escape(@Nullable String source, @Nonnull final char[] escapedChars, char escapeChar) { 2095 if (source == null) { 2096 return null; 2097 } 2098 2099 char[] eqc = new char[escapedChars.length]; 2100 System.arraycopy(escapedChars, 0, eqc, 0, escapedChars.length); 2101 Arrays.sort(eqc); 2102 2103 StringBuilder buffer = new StringBuilder(source.length()); 2104 2105 for (int i = 0; i < source.length(); i++) { 2106 final char c = source.charAt(i); 2107 int result = Arrays.binarySearch(eqc, c); 2108 2109 if (result > -1) { 2110 buffer.append(escapeChar); 2111 } 2112 buffer.append(c); 2113 } 2114 2115 return buffer.toString(); 2116 } 2117 2118 /** 2119 * Remove all duplicate whitespace characters and replace line terminators with a single space. 2120 * 2121 * @param s a not null String 2122 * @return a string with unique whitespace 2123 * 2124 */ 2125 @Nonnull 2126 public static String removeDuplicateWhitespace(@Nonnull String s) { 2127 StringBuilder result = new StringBuilder(); 2128 int length = s.length(); 2129 boolean isPreviousWhiteSpace = false; 2130 for (int i = 0; i < length; i++) { 2131 char c = s.charAt(i); 2132 boolean thisCharWhiteSpace = Character.isWhitespace(c); 2133 if (!(isPreviousWhiteSpace && thisCharWhiteSpace)) { 2134 result.append(c); 2135 } 2136 isPreviousWhiteSpace = thisCharWhiteSpace; 2137 } 2138 return result.toString(); 2139 } 2140 2141 /** 2142 * Parses the given String and replaces all occurrences of 2143 * '\n', '\r', and "\r\n" with the system line separator. 2144 * 2145 * @param s a not null String 2146 * @return a String that contains only System line separators 2147 * @see #unifyLineSeparators(String, String) 2148 * @deprecated this method produces platform dependent code and contributes to 2149 * non-reproducible builds. In the context of Maven, this is almost never what's needed. 2150 * Remove calls to this method and do not replace them. That is, change 2151 * {@code Stringutils.unifyLineSeparators(s)} to simply {@code s}. 2152 */ 2153 @Deprecated 2154 public static String unifyLineSeparators(@Nullable String s) { 2155 return unifyLineSeparators(s, System.getProperty("line.separator")); 2156 } 2157 2158 /** 2159 * Parses the given String and replaces all occurrences of 2160 * '\n', '\r' and '\r\n' with the system line separator. 2161 * 2162 * @param s a not null String 2163 * @param ls the wanted line separator ("\n" on UNIX), if null using the System line separator 2164 * @return a String that contains only System line separators 2165 * @throws IllegalArgumentException if ls is not '\n', '\r', or "\r\n" 2166 * 2167 */ 2168 public static String unifyLineSeparators(@Nullable String s, @Nullable String ls) { 2169 if (s == null) { 2170 return null; 2171 } 2172 2173 if (ls == null) { 2174 ls = System.getProperty("line.separator"); 2175 } 2176 2177 if (!(ls.equals("\n") || ls.equals("\r") || ls.equals("\r\n"))) { 2178 throw new IllegalArgumentException("Requested line separator is invalid."); 2179 } 2180 2181 int length = s.length(); 2182 2183 StringBuilder buffer = new StringBuilder(length); 2184 for (int i = 0; i < length; i++) { 2185 if (s.charAt(i) == '\r') { 2186 if ((i + 1) < length && s.charAt(i + 1) == '\n') { 2187 i++; 2188 } 2189 2190 buffer.append(ls); 2191 } else if (s.charAt(i) == '\n') { 2192 buffer.append(ls); 2193 } else { 2194 buffer.append(s.charAt(i)); 2195 } 2196 } 2197 2198 return buffer.toString(); 2199 } 2200 2201 /** 2202 * <p>Checks if String contains a search character, handling <code>null</code>. 2203 * This method uses {@link String#indexOf(int)}.</p> 2204 * 2205 * <p>A <code>null</code> or empty ("") String will return <code>false</code>.</p> 2206 * 2207 * <pre> 2208 * StringUtils.contains(null, *) = false 2209 * StringUtils.contains("", *) = false 2210 * StringUtils.contains("abc", 'a') = true 2211 * StringUtils.contains("abc", 'z') = false 2212 * </pre> 2213 * 2214 * @param str the String to check, may be null 2215 * @param searchChar the character to find 2216 * @return true if the String contains the search character, 2217 * false if not or <code>null</code> string input 2218 * 2219 */ 2220 public static boolean contains(@Nullable String str, char searchChar) { 2221 return !isEmpty(str) && str.indexOf(searchChar) >= 0; 2222 } 2223 2224 /** 2225 * <p>Checks if String contains a search String, handling <code>null</code>. 2226 * This method uses {@link String#indexOf(int)}.</p> 2227 * 2228 * <p>A <code>null</code> String will return <code>false</code>.</p> 2229 * 2230 * <pre> 2231 * StringUtils.contains(null, *) = false 2232 * StringUtils.contains(*, null) = false 2233 * StringUtils.contains("", "") = true 2234 * StringUtils.contains("abc", "") = true 2235 * StringUtils.contains("abc", "a") = true 2236 * StringUtils.contains("abc", "z") = false 2237 * </pre> 2238 * 2239 * @param str the String to check, may be null 2240 * @param searchStr the String to find, may be null 2241 * @return true if the String contains the search String, 2242 * false if not or <code>null</code> string input 2243 */ 2244 public static boolean contains(@Nullable String str, @Nullable String searchStr) { 2245 return !(str == null || searchStr == null) && str.contains(searchStr); 2246 } 2247 2248 /** 2249 * <p>Checks if String ends with a search String, handling <code>null</code>.</p> 2250 * <p>A <code>null</code> String will return <code>false</code>.</p> 2251 * 2252 * <pre> 2253 * StringUtils.endsWithIgnoreCase(null, *) = false 2254 * StringUtils.endsWithIgnoreCase(*, null) = false 2255 * StringUtils.endsWithIgnoreCase("", "") = true 2256 * StringUtils.endsWithIgnoreCase("abc", "") = true 2257 * StringUtils.endsWithIgnoreCase("abc", "C") = true 2258 * StringUtils.endsWithIgnoreCase("abc", "a") = false 2259 * </pre> 2260 * 2261 * @param str the String to check, may be null 2262 * @param searchStr the String to find at end, may be null 2263 * @return true if the String ends with the search String, 2264 * false if not or <code>null</code> string input 2265 * 2266 */ 2267 public static boolean endsWithIgnoreCase(@Nullable String str, @Nullable String searchStr) { 2268 if (str == null || searchStr == null) { 2269 // for consistency with contains 2270 return false; 2271 } 2272 2273 if (str.length() < searchStr.length()) { 2274 return false; 2275 } 2276 2277 return str.regionMatches(true, str.length() - searchStr.length(), searchStr, 0, searchStr.length()); 2278 } 2279 }