View Javadoc
1   /*
2    * $Source$
3    * $Revision$
4    *
5    * Copyright (C) 2000 William Chesters
6    *
7    * Part of Melati (http://melati.org), a framework for the rapid
8    * development of clean, maintainable web applications.
9    *
10   * Melati is free software; Permission is granted to copy, distribute
11   * and/or modify this software under the terms either:
12   *
13   * a) the GNU General Public License as published by the Free Software
14   *    Foundation; either version 2 of the License, or (at your option)
15   *    any later version,
16   *
17   *    or
18   *
19   * b) any version of the Melati Software License, as published
20   *    at http://melati.org
21   *
22   * You should have received a copy of the GNU General Public License and
23   * the Melati Software License along with this program;
24   * if not, write to the Free Software Foundation, Inc.,
25   * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA to obtain the
26   * GNU General Public License and visit http://melati.org to obtain the
27   * Melati Software License.
28   *
29   * Feel free to contact the Developers of Melati (http://melati.org),
30   * if you would like to work out a different arrangement than the options
31   * outlined here.  It is our intention to allow Melati to be used by as
32   * wide an audience as possible.
33   *
34   * This program is distributed in the hope that it will be useful,
35   * but WITHOUT ANY WARRANTY; without even the implied warranty of
36   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
37   * GNU General Public License for more details.
38   *
39   * Contact details for copyright holder:
40   *
41   *     William Chesters <williamc At paneris.org>
42   *     http://paneris.org/~williamc
43   *     Obrechtstraat 114, 2517VX Den Haag, The Netherlands
44   */
45  
46  package org.melati.poem.util;
47  
48  /**
49   * An assortment of useful operations on <code>String</code>s.
50   */
51  public final class StringUtils {
52  
53  
54    /**
55     * As Perl, create an Array from a String by using a 
56     * character as the Array delimiter. 
57     * 
58     * @param s the String to split
59     * @param c the Array delimiter
60     * @return an Array
61     */
62    public static String[] split(String s, char c) {
63      int n = 0;
64      for (int i = s.indexOf(c); i >= 0; i = s.indexOf(c, i + 1))
65        ++n;
66  
67      String[] them = new String[n + 1];
68  
69      for (int i = 0, m = 0;; ++m) {
70        int j = s.indexOf(c, i);
71        if (j == -1) {
72          them[m] = s.substring(i);
73          break;
74        } else {
75          them[m] = s.substring(i, j);
76          i = j + 1;
77        }
78      }
79  
80      return them;
81    }
82  
83    /**
84     * @param b the buffer to append to 
85     * @param s the String to append
86     * @param character the character to escape
87     */
88    public static void appendEscaped(StringBuffer b, String s, char character) {
89      appendEscaped(b, s, character, '\\');
90    }
91    /**
92     * Append a String to a StringBuffer, and escaping any occurances 
93     * of the char in the String.
94     * 
95     * @param b the buffer to append to 
96     * @param s the String to append
97     * @param character the character to escape
98     * @param escapeChar the character to escape with
99     */
100   public static void appendEscaped(StringBuffer b, 
101           String s, char character, char escapeChar) {
102     int l = s.length();
103     for (int i = 0; i < l; ++i) {
104       char c = s.charAt(i);
105       if (c == escapeChar || c == character) {
106         // damn, found one; catch up to here ...
107 
108         for (int j = 0; j < i; ++j)
109           b.append(s.charAt(j));
110         b.append(escapeChar);
111         b.append(c);
112 
113         // ... and continue
114 
115         for (++i; i < l; ++i) {
116           c = s.charAt(i);
117           if (c == escapeChar || c == character)
118             b.append(escapeChar);
119           b.append(c);
120         }
121         return;
122       }
123     }
124 
125     b.append(s);
126   }
127 
128   /**
129    * Append a String to a StringBuffer, first quoting it with a quote 
130    * character and escaping any occurrences of the quote char in the String.
131    * 
132    * @param b the buffer to append to 
133    * @param s the String to append
134    * @param q the quote character
135    */
136   public static void appendQuoted(StringBuffer b, String s, char q) {
137     b.append(q);
138     appendEscaped(b, s, q);
139     b.append(q);
140   }
141 
142   /**
143    * Surround a string in quotes.
144    * 
145    * @param i the string to quote
146    * @param q The quote character to use
147    * @return the quoted string
148    */
149   public static String quoted(String i, char q) {
150     StringBuffer b = new StringBuffer();
151     appendQuoted(b, i, q);
152     return b.toString();
153   }
154 
155 
156   /**
157    * Capitalise the first character of the input string.
158    * 
159    * @param name String to capitalise
160    * @return the capitalised string
161    */
162   public static String capitalised(String name) {
163     char suffix[] = name.toCharArray();
164     suffix[0] = Character.toUpperCase(suffix[0]);
165     return new String(suffix);
166   }
167 
168   /**
169    * Uncaptialise the first character of the input string.
170    * 
171    * @param name String to uncapitalise
172    * @return the uncapitalised string
173    */
174   public static String uncapitalised(String name) {
175     char suffix[] = name.toCharArray();
176     suffix[0] = Character.toLowerCase(suffix[0]);
177     return new String(suffix);
178   }
179 
180  /**
181   * As Perl <code>tr</code>; swap any occurrences of any characters in the 
182   * <code>from</code> string in the input string with the 
183   * corresponding character from the <code>to</code> string.
184   * 
185   * <code>
186   *  tr("melati", "ait", "osn").equals("melons")
187   * </code>
188    * @param s String to act upon
189    * @param from String containing characters to swap from 
190    * @param to String containing characters to swap to
191    * @return the transformed input String
192    */
193   public static String tr(String s, String from, String to) {
194     StringBuffer sNew = null;
195 
196     for (int i = 0; i < s.length(); ++i) {
197       int t = from.indexOf(s.charAt(i));
198       if (t != -1) {
199         if (sNew == null)
200           sNew = new StringBuffer(s);
201         sNew.setCharAt(i, to.charAt(t));
202       }
203     }
204 
205     return sNew == null ? s : sNew.toString();
206   }
207 
208  /**
209   * As Perl <code>tr</code>; swap any occurances of the 
210   * <code>from</code> character in the input string with the 
211   * corresponding the <code>to</code> character.
212   * 
213   * <code>
214   *  tr("melati", 'i', 'o').equals("melato")
215   * </code>
216   * @param s String to act upon
217   * @param from character to swap from 
218   * @param to character to swap to
219   * @return the transformed input String
220   * @deprecated now use string.replace(old,new)
221   */
222   public static String tr(String s, char from, char to) {
223     StringBuffer sNew = null;
224 
225     for (int i = 0; i < s.length(); ++i) {
226       if (s.charAt(i) == from) {
227         if (sNew == null)
228           sNew = new StringBuffer(s);
229         sNew.setCharAt(i, to);
230       }
231     }
232 
233     return sNew == null ? s : sNew.toString();
234   }
235 
236   /**
237    * Concatenate an array of Strings with a separator. 
238    * 
239    * @param sep The separator String to use, may be null.
240    * @param xs An array of Strings to concatenate.
241    * @return the concatenated String.
242    */
243   public static String concatenated(String sep, String[] xs) {
244     if (sep == null) sep = "";
245     if (xs.length == 0)
246       return "";
247     else {
248       int l = sep.length() * (xs.length - 1) + xs[0].length();
249       for (int i = 1; i < xs.length; ++i)
250         l += xs[i].length();
251 
252       StringBuffer c = new StringBuffer(l);
253 
254       c.append(xs[0]);
255       for (int i = 1; i < xs.length; ++i) {
256         c.append(sep);
257         c.append(xs[i]);
258       }
259 
260       return c.toString();
261     }
262   }
263 
264   private static String allowableChars =
265     "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyz0123456789";
266 
267   /**
268    * Generate a random String.
269    * 
270    * @param length the required length of the String returned
271    * @return a random String of upper and lowercase letters and digits
272    */
273   public static String randomString(int length) {
274     String result = "";
275     int j = allowableChars.length();
276     for (int a = 0; a < length; a++) {
277       int index = new Double(Math.random() * j).intValue();
278       result += allowableChars.charAt(index);
279     }
280     return result;
281   }
282 
283   /**
284    * Turn an empty String into a null.
285    * 
286    * @param s input String, possibly of zero length or null
287    * @return null if input is empty, input otherwise
288    */
289   public static String nulled(String s) {
290     if (s != null && s.equals(""))
291       return null;
292     return s;
293   }
294 
295   /**
296    *  Turn a null into an empty String.
297    * @param in input String, possibly null
298    * @return empty String if input is null, input otherwise
299    */
300   public static String unNulled(String in) {
301     if (in == null)
302       return "";
303     return in;
304   }
305 
306   private static final char[] hexDigits =
307     { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 
308       'A', 'B', 'C', 'D', 'E', 'F' };
309 
310   /**
311    * Hex encode an Array of bytes.
312    * @param bytes the byte Array
313    * @return the hex representation
314    */
315   public static String hexEncoding(byte[] bytes) {
316     StringBuffer it = new StringBuffer(bytes.length * 2);
317 
318     for (int i = 0; i < bytes.length; ++i) {
319       int b = bytes[i];
320       it.append(hexDigits[b >> 4 & 0xF]);
321       it.append(hexDigits[b & 0xF]);
322     }
323 
324     return it.toString();
325   }
326 
327   /**
328    * Decode a hex char to a byte.
329    * 
330    * @param c the char
331    * @return a byte
332    */
333   public static byte hexDecoding(char c) {
334     if ('0' <= c && c <= '9')
335       return (byte) (c - '0');
336     else if ('A' <= c && c <= 'F')
337       return (byte) (0xA + c - 'A');
338     else if ('a' <= c && c <= 'f')
339       return (byte) (0xa + c - 'a');
340     else
341       throw new IllegalArgumentException("Invalid hex digit in string");
342   }
343 
344   /**
345    * Decode a hex String into a byte Array.
346    * @param digits the hex String
347    * @return a byte Array
348    */
349   public static byte[] hexDecoding(String digits) {
350 
351     int l = digits.length() / 2;
352     if (l * 2 != digits.length())
353       throw new IllegalArgumentException(
354                                     "Hex string has odd number of digits");
355 
356     byte[] it = new byte[l];
357 
358     for (int i = 0; i < l; ++i)
359       it[i] =
360         (byte) (hexDecoding(digits.charAt(i * 2)) << 4 | 
361                 hexDecoding(digits.charAt(i * 2 + 1)));
362 
363     return it;
364   }
365 
366   /**
367    * Determine whether a String is quoted, with either quoting character.
368    * @param in String to examine
369    * @return whether String is quoted
370    */
371   public static boolean isQuoted(String in) {
372     if (in == null)
373       return false;
374     if (in.length() < 2)
375       return false;
376     if ((in.startsWith("'") || in.startsWith("\"")) 
377         && 
378         (in.endsWith("'") || in.endsWith("\""))) {
379       return true;
380     }
381     return false;
382   }
383 }