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