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 }