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  
20  package org.apache.myfaces.tobago.internal.util;
21  
22  import java.util.ArrayList;
23  import java.util.List;
24  import java.util.Locale;
25  import java.util.StringTokenizer;
26  
27  public final class StringUtils {
28  
29    private StringUtils() {
30      // to prevent instantiation
31    }
32  
33    public static List<Integer> parseIntegerList(final String integerList) throws NumberFormatException {
34      return parseIntegerList(integerList, ", ");
35    }
36  
37    public static List<Integer> parseIntegerList(final String integerList, final String delimiters)
38        throws NumberFormatException {
39      final List<Integer> list = new ArrayList<>();
40  
41      final StringTokenizer tokenizer = new StringTokenizer(integerList, delimiters);
42      while (tokenizer.hasMoreElements()) {
43        final String token = tokenizer.nextToken().trim();
44        if (token.length() > 0) {
45          list.add(new Integer(token));
46        }
47      }
48  
49      return list;
50    }
51  
52    public static <T> String joinWithSurroundingSeparator(final List<T> list) {
53      final StringBuilder buffer = new StringBuilder(",");
54      if (list != null) {
55        for (final T t : list) {
56          buffer.append(t);
57          buffer.append(",");
58        }
59      }
60      return buffer.toString();
61    }
62  
63    public static int[] getIndices(final String list) {
64      if (list == null) {
65        return new int[0];
66      }
67      final List<String> indexList = new ArrayList<>();
68      final StringTokenizer st = new StringTokenizer(list.trim(), ",");
69      while (st.hasMoreTokens()) {
70        final String token = st.nextToken().trim();
71        final int idx = token.indexOf('-');
72        if (idx == -1) {
73          indexList.add(token);
74        } else {
75          final int start = Integer.parseInt(token.substring(0, idx).trim());
76          final int end = Integer.parseInt(token.substring(idx + 1).trim());
77          if (start < end) {
78            for (int i = start; i < end + 1; i++) {
79              indexList.add(Integer.toString(i));
80            }
81          } else {
82            for (int i = start; i > end - 1; i--) {
83              indexList.add(Integer.toString(i));
84            }
85          }
86        }
87      }
88  
89      final int[] indices = new int[indexList.size()];
90      for (int i = 0; i < indices.length; i++) {
91        indices[i] = Integer.parseInt(indexList.get(i));
92      }
93      return indices;
94    }
95  
96    public static String constantToLowerCamelCase(final String constant) {
97      final StringBuilder builder = new StringBuilder(constantToUpperCamelCase(constant));
98      if (builder.length() > 0) {
99        builder.setCharAt(0, Character.toLowerCase(builder.charAt(0)));
100     }
101     return builder.toString();
102   }
103 
104   public static String constantToUpperCamelCase(final String constant) {
105     final StringBuilder builder = new StringBuilder(constant.length());
106     final char[] chars = constant.toCharArray();
107     for (int i = 0; i < chars.length; i++) {
108       if (i == 0) {
109         builder.append(chars[i]);
110       } else if (chars[i] == '_') {
111         builder.append(chars[++i]);
112       } else {
113         builder.append(((Character) chars[i]).toString().toLowerCase(Locale.ENGLISH));
114       }
115     }
116     return builder.toString();
117   }
118 
119   public static String firstToUpperCase(final String string) {
120     return string.substring(0, 1).toUpperCase(Locale.ENGLISH) + string.substring(1);
121   }
122 
123   /**
124    * Is the same string, by ignoring differences that are only whitespaces.
125    * (null and "" are not equal)
126    */
127   @SuppressWarnings("StringEquality")
128   public static boolean equalsIgnoreCaseAndWhitespace(final String type1, final String type2) {
129 
130     // StringEquality
131     if (type1 == type2) {
132       return true;
133     }
134 
135     if (type1 == null || type2 == null) {
136       return false;
137     }
138 
139     final char[] chars1 = type1.toCharArray();
140     final char[] chars2 = type2.toCharArray();
141     final int length1 = chars1.length;
142     final int length = chars2.length;
143 
144     int i = 0;
145     int j = 0;
146 
147     while (i < length1 && j < length) {
148       if (chars1[i] == chars2[j] || Character.toUpperCase(chars1[i]) == Character.toUpperCase(chars2[j])) {
149         i++;
150         j++;
151         // okay
152       } else if (Character.isWhitespace(chars1[i])) {
153         i++;
154         // okay, ignore space
155       } else if (Character.isWhitespace(chars2[j])) {
156         j++;
157         // try again
158       } else {
159         return false;
160       }
161     }
162 
163     while (i < length1) {
164       if (Character.isWhitespace(chars1[i])) {
165         i++;
166         // okay, ignore space
167       } else {
168         return false;
169       }
170     }
171 
172     while (j < length) {
173       if (Character.isWhitespace(chars2[j])) {
174         j++;
175         // okay, ignore space
176       } else {
177         return false;
178       }
179     }
180 
181     return true;
182   }
183 
184   /**
185    * Basically taken from commons-lang
186    */
187   public static boolean endsWith(final String string, final String suffix) {
188     if (string == null || suffix == null) {
189       return string == null && suffix == null;
190     }
191     if (suffix.length() > string.length()) {
192       return false;
193     }
194     final int strOffset = string.length() - suffix.length();
195     return string.regionMatches(false, strOffset, suffix, 0, suffix.length());
196   }
197 
198   /**
199    * Basically taken from commons-lang
200    */
201   public static String[] split(final String string, final char separator) {
202     // Performance tuned for 2.0 (JDK1.4)
203 
204     if (string == null) {
205       return null;
206     }
207     final int len = string.length();
208     if (len == 0) {
209       return ArrayUtils.EMPTY_STRING_ARRAY;
210     }
211     final List<String> list = new ArrayList<>();
212     int i = 0;
213     int start = 0;
214     boolean match = false;
215     while (i < len) {
216       if (string.charAt(i) == separator) {
217         if (match) {
218           list.add(string.substring(start, i));
219           match = false;
220         }
221         start = ++i;
222         continue;
223       }
224       match = true;
225       i++;
226     }
227     if (match) {
228       list.add(string.substring(start, i));
229     }
230     return list.toArray(new String[list.size()]);
231   }
232 
233   /**
234    * Basically taken from commons-lang
235    */
236   public static String[] split(final String string, final String separator) {
237     final int max = -1;
238     // Performance tuned for 2.0 (JDK1.4)
239     // Direct code is quicker than StringTokenizer.
240     // Also, StringTokenizer uses isSpace() not isWhitespace()
241 
242     if (string == null) {
243       return null;
244     }
245     final int len = string.length();
246     if (len == 0) {
247       return ArrayUtils.EMPTY_STRING_ARRAY;
248     }
249     final List<String> list = new ArrayList<>();
250     int sizePlus1 = 1;
251     int i = 0;
252     int start = 0;
253     boolean match = false;
254     if (separator == null) {
255       // Null separator means use whitespace
256       while (i < len) {
257         if (Character.isWhitespace(string.charAt(i))) {
258           if (match) {
259             if (sizePlus1++ == max) {
260               i = len;
261             }
262             list.add(string.substring(start, i));
263             match = false;
264           }
265           start = ++i;
266           continue;
267         }
268         match = true;
269         i++;
270       }
271     } else if (separator.length() == 1) {
272       // Optimise 1 character case
273       final char sep = separator.charAt(0);
274       while (i < len) {
275         if (string.charAt(i) == sep) {
276           if (match) {
277             if (sizePlus1++ == max) {
278               i = len;
279             }
280             list.add(string.substring(start, i));
281             match = false;
282           }
283           start = ++i;
284           continue;
285         }
286         match = true;
287         i++;
288       }
289     } else {
290       // standard case
291       while (i < len) {
292         if (separator.indexOf(string.charAt(i)) >= 0) {
293           if (match) {
294             if (sizePlus1++ == max) {
295               i = len;
296             }
297             list.add(string.substring(start, i));
298             match = false;
299           }
300           start = ++i;
301           continue;
302         }
303         match = true;
304         i++;
305       }
306     }
307     if (match) {
308       list.add(string.substring(start, i));
309     }
310     return list.toArray(new String[list.size()]);
311   }
312 
313   /**
314    * Basically taken from commons-lang
315    */
316   public static boolean isAlpha(final String string) {
317     if (string == null) {
318       return false;
319     }
320     final int sz = string.length();
321     for (int i = 0; i < sz; i++) {
322       if (!Character.isLetter(string.charAt(i))) {
323         return false;
324       }
325     }
326     return true;
327   }
328 
329   /**
330    * Basically taken from commons-lang
331    */
332   public static boolean isEmpty(final String value) {
333     return value == null || value.length() == 0;
334   }
335 
336   /**
337    * Basically taken from commons-lang
338    */
339   public static boolean isNotEmpty(final String value) {
340     return !isEmpty(value);
341   }
342 
343   /**
344    * Basically taken from commons-lang
345    */
346   public static boolean isBlank(final String string) {
347     if (string == null) {
348       return true;
349     }
350     final int strLen = string.length();
351     if (strLen == 0) {
352       return true;
353     }
354     for (int i = 0; i < strLen; i++) {
355       if (!Character.isWhitespace(string.charAt(i))) {
356         return false;
357       }
358     }
359     return true;
360   }
361 
362   /**
363    * Basically taken from commons-lang
364    */
365   public static boolean isNotBlank(final String str) {
366     return !isBlank(str);
367   }
368 
369   /**
370    * Basically taken from commons-lang
371    */
372   public static String replace(final String text, final String searchString, final String replacement) {
373     if (isEmpty(text) || isEmpty(searchString) || replacement == null) {
374       return text;
375     }
376     int start = 0;
377     int end = text.indexOf(searchString, start);
378     if (end == -1) {
379       return text;
380     }
381     final int replLength = searchString.length();
382     int increase = replacement.length() - replLength;
383     increase = increase < 0 ? 0 : increase * 16;
384     final StringBuilder buf = new StringBuilder(text.length() + increase);
385     while (end != -1) {
386       buf.append(text.substring(start, end)).append(replacement);
387       start = end + replLength;
388       end = text.indexOf(searchString, start);
389     }
390     buf.append(text.substring(start));
391     return buf.toString();
392   }
393 
394   /**
395    * Basically taken from commons-lang
396    */
397   public static String repeat(final String str, final int repeat) {
398     final int outputLength = str.length() * repeat;
399     final StringBuilder buf = new StringBuilder(outputLength);
400     for (int i = 0; i < repeat; i++) {
401       buf.append(str);
402     }
403     return buf.toString();
404   }
405 
406   /**
407    * Returns a string of the same length to hide confidential passwords from log files etc.
408    */
409   public static String toConfidentialString(final String string, final boolean confidential) {
410     if (string == null) {
411       return "<null>";
412     } else if (confidential) {
413       return repeat("*", string.length()) + " (confidential)";
414     } else {
415       return string;
416     }
417   }
418 
419   /**
420    * Basically taken from commons-lang
421    */
422   public static String uncapitalize(final String str) {
423     return String.valueOf(Character.toLowerCase(str.charAt(0))) + str.substring(1);
424   }
425 
426   /**
427    * Basically taken from commons-lang
428    */
429   public static boolean isAlphanumeric(final String str) {
430     final int sz = str.length();
431     for (int i = 0; i < sz; i++) {
432       if (!Character.isLetterOrDigit(str.charAt(i))) {
433         return false;
434       }
435     }
436     return true;
437   }
438 
439   /**
440    * Basically taken from commons-lang
441    */
442   public static String join(final List<String> list, final char separator) {
443     final int size = list.size();
444     if (size <= 0) {
445       return "";
446     }
447 
448     final int bufSize = size * list.get(0).length() + 1;
449     final StringBuilder builder = new StringBuilder(bufSize);
450 
451     for (int i = 0; i < size; i++) {
452       if (i > 0) {
453         builder.append(separator);
454       }
455       final String string = list.get(i);
456       if (string != null) {
457         builder.append(string);
458       }
459     }
460     return builder.toString();
461   }
462 
463   /**
464    * Basically taken from commons-lang
465    */
466   public static String defaultString(final String string) {
467     return string == null ? "" : string;
468   }
469 
470   /**
471    * Basically taken from commons-lang
472    */
473   public static boolean notEquals(final String a, final String b) {
474     return a == null ? b != null : !a.equals(b);
475   }
476 
477   /**
478    * Checks if the String starts like a url, e.g. http: or xyz:
479    */
480   public static boolean isUrl(final String link) {
481     if (link == null) {
482       return false;
483     }
484     final int colon = link.indexOf(':');
485     if (colon < 1) {
486       return false;
487     }
488     for (int i = 0; i < colon; i++) {
489       if (!Character.isLetter(link.charAt(i))) {
490         return false;
491       }
492     }
493     return true;
494   }
495 
496   public static boolean startsWith(final String string, final String prefix) {
497     if (string == null || prefix == null) {
498       return string == null && prefix == null;
499     }
500     return prefix.length() <= string.length() && string.regionMatches(0, prefix, 0, prefix.length());
501   }
502 
503   /**
504    * <p>
505    * Checks if the String contains any character in the given set of characters.
506    * </p>
507    *
508    * <p>
509    * A <code>null</code> String will return <code>false</code>. A <code>null</code> search string will return
510    * <code>false</code>.
511    * </p>
512    *
513    * <pre>
514    * StringUtils.containsAny(null, *)            = false
515    * StringUtils.containsAny("", *)              = false
516    * StringUtils.containsAny(*, null)            = false
517    * StringUtils.containsAny(*, "")              = false
518    * StringUtils.containsAny("zzabyycdxx", "za") = true
519    * StringUtils.containsAny("zzabyycdxx", "by") = true
520    * StringUtils.containsAny("aba","z")          = false
521    * </pre>
522    *
523    * @param str the String to check, may be null
524    * @param searchChars the chars to search for, may be null
525    * @return the <code>true</code> if any of the chars are found, <code>false</code> if no match or null input
526    *
527    * Basically taken from commons-lang
528    */
529   public static boolean containsAny(final String str, final String searchChars) {
530     if (searchChars == null) {
531       return false;
532     }
533     final char[] searchChars1 = searchChars.toCharArray();
534     if (isEmpty(str) || searchChars1.length == 0) {
535       return false;
536     }
537     final int csLength = str.length();
538     final int searchLength = searchChars1.length;
539     final int csLast = csLength - 1;
540     final int searchLast = searchLength - 1;
541     for (int i = 0; i < csLength; i++) {
542       final char ch = str.charAt(i);
543       for (int j = 0; j < searchLength; j++) {
544         if (searchChars1[j] == ch) {
545           if (isHighSurrogate(ch)) {
546             if (j == searchLast) {
547               // missing low surrogate, fine, like String.indexOf(String)
548               return true;
549             }
550             if (i < csLast && searchChars1[j + 1] == str.charAt(i + 1)) {
551               return true;
552             }
553           } else {
554             // ch is in the Basic Multilingual Plane
555             return true;
556           }
557         }
558       }
559     }
560     return false;
561   }
562 
563   /**
564    * Indicates whether {@code ch} is a high- (or leading-) surrogate code unit
565    * that is used for representing supplementary characters in UTF-16
566    * encoding.
567    *
568    * @param ch the character to test.
569    * @return {@code true} if {@code ch} is a high-surrogate code unit;
570    *         {@code false} otherwise.
571    */
572   private static boolean isHighSurrogate(final char ch) {
573     return '\uD800' <= ch && '\uDBFF' >= ch;
574   }
575 
576 }