View Javadoc
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 &gt; 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 &lt; 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") &rarr; "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") &rarr; 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( &quot;this-is-it&quot;, %quot;-&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 }