View Javadoc

1   package org.apache.velocity.util;
2   
3   /*
4    * Licensed to the Apache Software Foundation (ASF) under one
5    * or more contributor license agreements.  See the NOTICE file
6    * distributed with this work for additional information
7    * regarding copyright ownership.  The ASF licenses this file
8    * to you under the Apache License, Version 2.0 (the
9    * "License"); you may not use this file except in compliance
10   * with the License.  You may obtain a copy of the License at
11   *
12   *   http://www.apache.org/licenses/LICENSE-2.0
13   *
14   * Unless required by applicable law or agreed to in writing,
15   * software distributed under the License is distributed on an
16   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17   * KIND, either express or implied.  See the License for the
18   * specific language governing permissions and limitations
19   * under the License.    
20   */
21  
22  import java.io.ByteArrayOutputStream;
23  import java.io.File;
24  import java.io.FileReader;
25  import java.io.PrintWriter;
26  import java.util.ArrayList;
27  import java.util.Hashtable;
28  import java.util.List;
29  import java.util.Map;
30  import java.util.StringTokenizer;
31  
32  
33  /**
34   * This class provides some methods for dynamically
35   * invoking methods in objects, and some string
36   * manipulation methods used by torque. The string
37   * methods will soon be moved into the turbine
38   * string utilities class.
39   *
40   *  @author <a href="mailto:jvanzyl@apache.org">Jason van Zyl</a>
41   *  @author <a href="mailto:dlr@finemaltcoding.com">Daniel Rall</a>
42   *  @version $Id: StringUtils.java 685685 2008-08-13 21:43:27Z nbubna $
43   */
44  public class StringUtils
45  {
46      /**
47       * Line separator for the OS we are operating on.
48       */
49      private static final String EOL = System.getProperty("line.separator");
50  
51      /**
52       * Concatenates a list of objects as a String.
53       *
54       * @param list The list of objects to concatenate.
55       * @return     A text representation of the concatenated objects.
56       */
57      public String concat(List list)
58      {
59          StringBuffer sb = new StringBuffer();
60          int size = list.size();
61  
62          for (int i = 0; i < size; i++)
63          {
64              sb.append(list.get(i).toString());
65          }
66          return sb.toString();
67      }
68  
69      /**
70       * Return a package name as a relative path name
71       *
72       * @param pckge package name to convert to a directory.
73       * @return String directory path.
74       */
75      static public String getPackageAsPath(String pckge)
76      {
77          return pckge.replace( '.', File.separator.charAt(0) ) + File.separator;
78      }
79  
80      /**
81       * <p>
82       * Remove underscores from a string and replaces first
83       * letters with capitals.  Other letters are changed to lower case.
84       * </p>
85       *
86       * <p>
87       * For example <code>foo_bar</code> becomes <code>FooBar</code>
88       * but <code>foo_barBar</code> becomes <code>FooBarbar</code>.
89       * </p>
90       *
91       * @param data string to remove underscores from.
92       * @return String
93       * @deprecated Use the org.apache.commons.util.StringUtils class
94       * instead.  Using its firstLetterCaps() method in conjunction
95       * with a StringTokenizer will achieve the same result.
96       */
97      static public String removeUnderScores (String data)
98      {
99          String temp = null;
100         StringBuffer out = new StringBuffer();
101         temp = data;
102 
103         StringTokenizer st = new StringTokenizer(temp, "_");
104 
105         while (st.hasMoreTokens())
106         {
107             String element = (String) st.nextElement();
108             out.append ( firstLetterCaps(element));
109         }
110 
111         return out.toString();
112     }
113 
114     /**
115      * <p>
116      *  'Camels Hump' replacement of underscores.
117      * </p>
118      *
119      * <p>
120      * Remove underscores from a string but leave the capitalization of the
121      * other letters unchanged.
122      * </p>
123      *
124      * <p>
125      * For example <code>foo_barBar</code> becomes <code>FooBarBar</code>.
126      * </p>
127      *
128      * @param data string to hump
129      * @return String
130      */
131     static public String removeAndHump (String data)
132     {
133         return removeAndHump(data,"_");
134     }
135 
136     /**
137      * <p>
138      * 'Camels Hump' replacement.
139      * </p>
140      *
141      * <p>
142      * Remove one string from another string but leave the capitalization of the
143      * other letters unchanged.
144      * </p>
145      *
146      * <p>
147      * For example, removing "_" from <code>foo_barBar</code> becomes <code>FooBarBar</code>.
148      * </p>
149      *
150      * @param data string to hump
151      * @param replaceThis string to be replaced
152      * @return String
153      */
154     static public String removeAndHump (String data,String replaceThis)
155     {
156         String temp = null;
157         StringBuffer out = new StringBuffer();
158         temp = data;
159 
160         StringTokenizer st = new StringTokenizer(temp, replaceThis);
161 
162         while (st.hasMoreTokens())
163         {
164             String element = (String) st.nextElement();
165             out.append ( capitalizeFirstLetter(element));
166         }//while
167 
168         return out.toString();
169     }
170 
171     /**
172      * <p>
173      *  Makes the first letter caps and the rest lowercase.
174      * </p>
175      *
176      * <p>
177      *  For example <code>fooBar</code> becomes <code>Foobar</code>.
178      * </p>
179      *
180      * @param data capitalize this
181      * @return String
182      */
183     static public String firstLetterCaps ( String data )
184     {
185         String firstLetter = data.substring(0,1).toUpperCase();
186         String restLetters = data.substring(1).toLowerCase();
187         return firstLetter + restLetters;
188     }
189 
190     /**
191      * <p>
192      * Capitalize the first letter but leave the rest as they are.
193      * </p>
194      *
195      * <p>
196      *  For example <code>fooBar</code> becomes <code>FooBar</code>.
197      * </p>
198      *
199      * @param data capitalize this
200      * @return String
201      */
202     static public String capitalizeFirstLetter ( String data )
203     {
204         String firstLetter = data.substring(0,1).toUpperCase();
205         String restLetters = data.substring(1);
206         return firstLetter + restLetters;
207     }
208 
209     /**
210      * Create a string array from a string separated by delim
211      *
212      * @param line the line to split
213      * @param delim the delimter to split by
214      * @return a string array of the split fields
215      */
216     public static String [] split(String line, String delim)
217     {
218         List list = new ArrayList();
219         StringTokenizer t = new StringTokenizer(line, delim);
220         while (t.hasMoreTokens())
221         {
222             list.add(t.nextToken());
223         }
224         return (String []) list.toArray(new String[list.size()]);
225     }
226 
227     /**
228      * Chop i characters off the end of a string.
229      * This method assumes that any EOL characters in String s
230      * and the platform EOL will be the same.
231      * A 2 character EOL will count as 1 character.
232      *
233      * @param s String to chop.
234      * @param i Number of characters to chop.
235      * @return String with processed answer.
236      */
237     public static String chop(String s, int i)
238     {
239         return chop(s, i, EOL);
240     }
241 
242     /**
243      * Chop i characters off the end of a string.
244      * A 2 character EOL will count as 1 character.
245      *
246      * @param s String to chop.
247      * @param i Number of characters to chop.
248      * @param eol A String representing the EOL (end of line).
249      * @return String with processed answer.
250      */
251     public static String chop(String s, int i, String eol)
252     {
253         if ( i == 0 || s == null || eol == null )
254         {
255            return s;
256         }
257 
258         int length = s.length();
259 
260         /*
261          * if it is a 2 char EOL and the string ends with
262          * it, nip it off.  The EOL in this case is treated like 1 character
263          */
264         if ( eol.length() == 2 && s.endsWith(eol ))
265         {
266             length -= 2;
267             i -= 1;
268         }
269 
270         if ( i > 0)
271         {
272             length -= i;
273         }
274 
275         if ( length < 0)
276         {
277             length = 0;
278         }
279 
280         return s.substring( 0, length);
281     }
282 
283     /**
284      * @param argStr
285      * @param vars
286      * @return Substituted String.
287      */
288     public static StringBuffer stringSubstitution( String argStr,
289                                                    Hashtable vars )
290     {
291         return stringSubstitution( argStr, (Map) vars );
292     }
293 
294     /**
295      * Perform a series of substitutions. The substitions
296      * are performed by replacing $variable in the target
297      * string with the value of provided by the key "variable"
298      * in the provided hashtable.
299      *
300      * @param argStr target string
301      * @param vars name/value pairs used for substitution
302      * @return String target string with replacements.
303      */
304     public static StringBuffer stringSubstitution(String argStr,
305             Map vars)
306     {
307         StringBuffer argBuf = new StringBuffer();
308 
309         for (int cIdx = 0 ; cIdx < argStr.length();)
310         {
311             char ch = argStr.charAt(cIdx);
312 
313             switch (ch)
314             {
315                 case '$':
316                     StringBuffer nameBuf = new StringBuffer();
317                     for (++cIdx ; cIdx < argStr.length(); ++cIdx)
318                     {
319                         ch = argStr.charAt(cIdx);
320                         if (ch == '_' || Character.isLetterOrDigit(ch))
321                             nameBuf.append(ch);
322                         else
323                             break;
324                     }
325 
326                     if (nameBuf.length() > 0)
327                     {
328                         String value =
329                                 (String) vars.get(nameBuf.toString());
330 
331                         if (value != null)
332                         {
333                             argBuf.append(value);
334                         }
335                     }
336                     break;
337 
338                 default:
339                     argBuf.append(ch);
340                     ++cIdx;
341                     break;
342             }
343         }
344 
345         return argBuf;
346     }
347 
348     /**
349      * Read the contents of a file and place them in
350      * a string object.
351      *
352      * @param file path to file.
353      * @return String contents of the file.
354      */
355     public static String fileContentsToString(String file)
356     {
357         String contents = "";
358 
359         File f = null;
360         try
361         {
362             f = new File(file);
363 
364             if (f.exists())
365             {
366                 FileReader fr = null;
367                 try
368                 {
369                     fr = new FileReader(f);
370                     char[] template = new char[(int) f.length()];
371                     fr.read(template);
372                     contents = new String(template);
373                 }
374                 catch (Exception e)
375                 {
376                     e.printStackTrace();
377                 }
378                 finally
379                 {
380                     if (fr != null)
381                     {
382                         fr.close();
383                     }
384                 }
385             }
386         }
387         catch (Exception e)
388         {
389             e.printStackTrace();
390         }
391         return contents;
392     }
393 
394     /**
395      * Remove/collapse multiple newline characters.
396      *
397      * @param argStr string to collapse newlines in.
398      * @return String
399      */
400     public static String collapseNewlines(String argStr)
401     {
402         char last = argStr.charAt(0);
403         StringBuffer argBuf = new StringBuffer();
404 
405         for (int cIdx = 0 ; cIdx < argStr.length(); cIdx++)
406         {
407             char ch = argStr.charAt(cIdx);
408             if (ch != '\n' || last != '\n')
409             {
410                 argBuf.append(ch);
411                 last = ch;
412             }
413         }
414 
415         return argBuf.toString();
416     }
417 
418     /**
419      * Remove/collapse multiple spaces.
420      *
421      * @param argStr string to remove multiple spaces from.
422      * @return String
423      */
424     public static String collapseSpaces(String argStr)
425     {
426         char last = argStr.charAt(0);
427         StringBuffer argBuf = new StringBuffer();
428 
429         for (int cIdx = 0 ; cIdx < argStr.length(); cIdx++)
430         {
431             char ch = argStr.charAt(cIdx);
432             if (ch != ' ' || last != ' ')
433             {
434                 argBuf.append(ch);
435                 last = ch;
436             }
437         }
438 
439         return argBuf.toString();
440     }
441 
442     /**
443       * Replaces all instances of oldString with newString in line.
444       * Taken from the Jive forum package.
445       *
446       * @param line original string.
447       * @param oldString string in line to replace.
448       * @param newString replace oldString with this.
449       * @return String string with replacements.
450       */
451     public static final String sub(String line, String oldString,
452             String newString)
453     {
454         int i = 0;
455         if ((i = line.indexOf(oldString, i)) >= 0)
456         {
457             char [] line2 = line.toCharArray();
458             char [] newString2 = newString.toCharArray();
459             int oLength = oldString.length();
460             StringBuffer buf = new StringBuffer(line2.length);
461             buf.append(line2, 0, i).append(newString2);
462             i += oLength;
463             int j = i;
464             while ((i = line.indexOf(oldString, i)) > 0)
465             {
466                 buf.append(line2, j, i - j).append(newString2);
467                 i += oLength;
468                 j = i;
469             }
470             buf.append(line2, j, line2.length - j);
471             return buf.toString();
472         }
473         return line;
474     }
475 
476     /**
477      * Returns the output of printStackTrace as a String.
478      *
479      * @param e A Throwable.
480      * @return A String.
481      */
482     public static final String stackTrace(Throwable e)
483     {
484         String foo = null;
485         try
486         {
487             // And show the Error Screen.
488             ByteArrayOutputStream ostr = new ByteArrayOutputStream();
489             e.printStackTrace( new PrintWriter(ostr,true) );
490             foo = ostr.toString();
491         }
492         catch (Exception f)
493         {
494             // Do nothing.
495         }
496         return foo;
497     }
498 
499     /**
500      * Return a context-relative path, beginning with a "/", that represents
501      * the canonical version of the specified path after ".." and "." elements
502      * are resolved out.  If the specified path attempts to go outside the
503      * boundaries of the current context (i.e. too many ".." path elements
504      * are present), return <code>null</code> instead.
505      *
506      * @param path Path to be normalized
507      * @return String normalized path
508      */
509     public static final String normalizePath(String path)
510     {
511         // Normalize the slashes and add leading slash if necessary
512         String normalized = path;
513         if (normalized.indexOf('\\') >= 0)
514         {
515             normalized = normalized.replace('\\', '/');
516         }
517 
518         if (!normalized.startsWith("/"))
519         {
520             normalized = "/" + normalized;
521         }
522 
523         // Resolve occurrences of "//" in the normalized path
524         while (true)
525         {
526             int index = normalized.indexOf("//");
527             if (index < 0)
528                 break;
529             normalized = normalized.substring(0, index) +
530             normalized.substring(index + 1);
531         }
532 
533         // Resolve occurrences of "%20" in the normalized path
534         while (true)
535         {
536             int index = normalized.indexOf("%20");
537             if (index < 0)
538                 break;
539             normalized = normalized.substring(0, index) + " " +
540             normalized.substring(index + 3);
541         }
542 
543         // Resolve occurrences of "/./" in the normalized path
544         while (true)
545         {
546             int index = normalized.indexOf("/./");
547             if (index < 0)
548                 break;
549             normalized = normalized.substring(0, index) +
550             normalized.substring(index + 2);
551         }
552 
553         // Resolve occurrences of "/../" in the normalized path
554         while (true)
555         {
556             int index = normalized.indexOf("/../");
557             if (index < 0)
558                 break;
559             if (index == 0)
560                 return (null);  // Trying to go outside our context
561             int index2 = normalized.lastIndexOf('/', index - 1);
562             normalized = normalized.substring(0, index2) +
563             normalized.substring(index + 3);
564         }
565 
566         // Return the normalized path that we have completed
567         return (normalized);
568     }
569 
570     /**
571      * If state is true then return the trueString, else
572      * return the falseString.
573      *
574      * @param state
575      * @param trueString
576      * @param falseString
577      * @return Selected result.
578      */
579     public String select(boolean state, String trueString, String falseString)
580     {
581         if (state)
582         {
583             return trueString;
584         }
585         else
586         {
587             return falseString;
588         }
589     }
590 
591     /**
592      * Check to see if all the string objects passed
593      * in are empty.
594      *
595      * @param list A list of {@link java.lang.String} objects.
596      * @return     Whether all strings are empty.
597      */
598     public boolean allEmpty(List list)
599     {
600         int size = list.size();
601 
602         for (int i = 0; i < size; i++)
603         {
604             if (list.get(i) != null && list.get(i).toString().length() > 0)
605             {
606                 return false;
607             }
608         }
609         return true;
610     }
611 
612     /**
613      * Trim all strings in a List.  Changes the strings in the existing list.
614      * @param list
615      * @return List of trimmed strings.
616      * @since 1.5
617      */
618     public static List trimStrings(List list)
619     {
620         if (list == null)
621             return null;
622 
623         int sz = list.size();
624         for (int i = 0; i < sz; i++)
625             list.set(i,nullTrim((String) list.get(i)));
626         return list;
627     }
628 
629     /**
630      * Trim the string, but pass a null through.
631      * @param s
632      * @return List of trimmed Strings.
633      * @since 1.5
634      */
635     public static String nullTrim(String s)
636     {
637         if (s == null)
638         {
639             return null;
640         }
641         else
642         {
643             return s.trim();
644         }
645     }
646 }