View Javadoc

1   /*
2    *  XNap Commons
3    *
4    *  Copyright (C) 2005  Felix Berger
5    *  Copyright (C) 2005  Steffen Pingel
6    *
7    *  This library is free software; you can redistribute it and/or
8    *  modify it under the terms of the GNU Lesser General Public
9    *  License as published by the Free Software Foundation; either
10   *  version 2.1 of the License, or (at your option) any later version.
11   *
12   *  This library is distributed in the hope that it will be useful,
13   *  but WITHOUT ANY WARRANTY; without even the implied warranty of
14   *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15   *  Lesser General Public License for more details.
16   *
17   *  You should have received a copy of the GNU Lesser General Public
18   *  License along with this library; if not, write to the Free Software
19   *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
20   */
21  package org.xnap.commons.util;
22  
23  import java.io.UnsupportedEncodingException;
24  import java.util.Collection;
25  import java.util.Iterator;
26  import java.util.LinkedList;
27  import java.util.List;
28  import java.util.StringTokenizer;
29  
30  /***
31   * Provides a set of static methods that help with string parsing and modifying.
32   */
33  public class StringHelper {
34  
35      public static final String[] SIZES = { "B", "KB", "MB", "GB", "TB" };
36  	
37      public static final String ALPHABET_LOWER = "abcdefghijklmnopqrstuvwxyz";
38      public static final String ALPHABET_UPPER = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
39      public static final String NUMBERS_INT = "0123456789";
40      public static final String NUMBERS_DECIMAL = NUMBERS_INT + ".";
41      public static final String MONEY_USD = "$" + NUMBERS_DECIMAL;
42      public static final String ALPHA_NUM 
43  		= ALPHABET_LOWER + ALPHABET_UPPER + NUMBERS_INT;
44      public static final String EMAIL = ALPHA_NUM + ".@_-";
45      public static final String HOST = ALPHA_NUM + ".";
46      public static final String REGULAR_STRING 
47  		= EMAIL + "[]?$%///(){}?????+-*,;.<>|_^?~#";
48      public static final String ANYTHING = null;
49  
50      /***
51       * Splits <code>text</code> at the first occurence of <code>separator</code>
52       * and returns the left part, excluding the separator. 
53       *
54       * @param text the haystack
55       * @param separator the needle
56       * @return the empty string, if no occurence can be found
57       */
58      public static String firstToken(String text, String separator) 
59      {
60      	if (separator == null) {
61      		throw new IllegalArgumentException("Separator must not be null");
62      	}
63      	if (separator.length() == 0) {
64      		throw new IllegalArgumentException("Separator must not be empty");
65      	}
66      	
67  		int i = text.indexOf(separator);
68  		return (i == -1) ? text : text.substring(0, i);
69      }
70  
71      /***
72       * Returns the index of the first digit in <code>s</code>.
73       *
74       * @return -1, if <code>s</code> does not contain digits; the index of
75       *         the first digit, otherwise
76       * @see java.lang.String#indexOf(String)
77       */
78      public static int indexOfDigit(String s)
79      {
80  		for (int i = 0; i < s.length(); i++) {
81  			if (Character.isDigit(s.charAt(i))) {
82  				return i;
83  			}
84  		}
85  	    
86  		return -1;
87      }
88  
89      /***
90       * Splits <code>text</code> at the last occurence of <code>separator</code>
91       * and returns the left part, excluding the separator.
92       *
93       * @param text the haystack
94       * @param separator the needle
95       * @return the empty string, if no occurence can be found
96       */
97      public static String lastPrefix(String text, String separator) 
98      {
99      	if (separator == null) {
100     		throw new IllegalArgumentException("Separator must not be null");
101     	}
102     	if (separator.length() == 0) {
103     		throw new IllegalArgumentException("Separator must not be empty");
104     	}
105 
106     	int i = text.lastIndexOf(separator);
107 		return (i == -1) ? text : text.substring(0, i);
108     }
109 
110     /***
111      * Splits <code>text</code> at the last occurence of <code>separator</code>
112      * and returns the right part, excluding the separator. 
113      *
114      * @param text the haystack
115      * @param separator the needle
116      * @return the empty string, if no occurence can be found
117      */
118     public static String lastToken(String text, String separator) 
119     {
120     	if (separator == null) {
121     		throw new IllegalArgumentException("Separator must not be null");
122     	}
123     	if (separator.length() == 0) {
124     		throw new IllegalArgumentException("Separator must not be empty");
125     	}
126     	
127 		int i = text.lastIndexOf(separator);
128 		if (i < 0 || i == text.length() - 1) {
129 			return "";
130 		}
131 		else {
132 			return text.substring(i + separator.length(), text.length());
133 		}
134     }
135 
136     /***
137      * Returns a random lower case letter-only string with <code>length</code>
138      * characters.
139      */
140     public static String randomString(int length) 
141     {
142         StringBuilder sb = new StringBuilder();
143         for (int i = 0; i < length; i++) {
144             sb.append((char)Math.round(Math.random() * 25 + 97));
145         }
146 
147         return sb.toString();
148     }
149 
150     /***
151      * Replaces all occurences of <code>oldChars</code> in <code>s</code> by
152      * <code>newChars</code>.
153      *
154      * @return the modified instance of <code>s</code>
155      */
156     public static String replaceAll(String s, String oldChars, String newChars)
157     {
158 		StringBuilder sb = new StringBuilder();
159 		int i = 0;
160 		while (true) {
161 			int j = s.indexOf(oldChars, i);
162 			if (j != -1) {
163 				sb.append(s.substring(i, j));
164 				sb.append(newChars);
165 				i = j + oldChars.length();
166 			}
167 			else {
168 				sb.append(s.substring(i));
169 				break;
170 			}
171 		}
172 		return sb.toString();
173     }
174 
175     /***
176      * Removes all characters from <code>s</code> that are not letters. 
177      * Returns a new String which can be for instance used as search text.
178      *
179      * @return a stripped instance of s
180      */
181     public static String stripExtra(String s)
182     {
183 		StringBuilder sb = new StringBuilder();
184 		boolean newWord = false;
185 		char[] chars = s.toCharArray();
186 		for (int i = 0; i < chars.length; i++) {
187 			if (Character.isLetter(chars[i])) {
188 				if (newWord) {
189 					sb.append(" ");
190 					newWord = false;
191 				}
192 				sb.append(chars[i]);
193 			}
194 			else {
195 				newWord = true;
196 			}
197 		}
198 
199 		return sb.toString();
200     }
201 
202     /***
203      * Uses a <code>StringTokenizer</code> to split <code>value</code>.
204      * @see java.util.StringTokenizer
205      * @param value the String to split
206      * @param separators the separators
207      * @return the tokens
208      */
209     public static String[] toArray(String value, String separators)
210     {
211 		StringTokenizer st = new StringTokenizer(value, separators);
212 		String[] array = new String[st.countTokens()];
213 		for (int i = 0; i < array.length; i++) {
214 			array[i] = st.nextToken();
215 		}
216 		return array;
217     }
218 
219     /***
220      * Returns a new <code>String</code> that has the first letter of value
221      * set to upper case.
222      */
223     public static String toFirstUpper(String value)
224     {
225 		if (value.length() > 1) {
226 			return Character.toUpperCase(value.charAt(0)) + value.substring(1);
227 		}
228 		else {
229 			return value.toUpperCase();
230 		}
231     }
232 
233     public static int[] toIntArray(String value, String separators)
234     {
235 		StringTokenizer st = new StringTokenizer(value, separators);
236 		int[] array = new int[st.countTokens()];
237 		for (int i = 0; i < array.length; i++) {
238 			try {
239 				array[i] = Integer.parseInt(st.nextToken());
240 			}
241 			catch (NumberFormatException e) {
242 			}
243 		}
244 		return array;
245     }
246 
247     public static List<String> toList(String value, String separators)
248     {
249 		StringTokenizer st = new StringTokenizer(value, separators);
250 		LinkedList<String> list = new LinkedList<String>();
251 	
252 		while (st.hasMoreTokens()) {
253 			list.add(st.nextToken());
254 		}
255 		return list;
256     }
257 
258 	/***
259 	 * Tries to autodect encoding.
260 	 */
261 	public static String toString(byte[] data)
262 	{
263 		try {
264 			return new String(data, "UTF-8");
265 		}
266 		catch (UnsupportedEncodingException e) {
267 			e.printStackTrace(System.err);
268 		}
269 
270 		try {
271 			return new String(data, "ISO-8859-1");
272 		}
273 		catch (UnsupportedEncodingException e) {
274 			e.printStackTrace(System.err);
275 		}
276 
277 		return new String(data);
278 	}
279 
280     public static String toString(Collection c, String separator)
281     {
282 		StringBuilder sb = new StringBuilder();
283 		for (Iterator i = c.iterator(); i.hasNext();) {
284 			sb.append(i.next().toString());
285 			sb.append(separator);
286 		}
287 		return sb.toString();
288     }
289 
290     public static String toString(int[] array, String separator)
291     {
292 		StringBuilder sb = new StringBuilder();
293 		for (int i = 0; i < array.length; i++) {
294 			sb.append(array[i]);
295 			sb.append(separator);
296 		}
297 		return sb.toString();
298     }
299 
300     public static String toString(String[] array, String separator)
301     {
302 		StringBuilder sb = new StringBuilder();
303 		for (int i = 0; i < array.length; i++) {
304 			sb.append(array[i]);
305 			sb.append(separator);
306 		}
307 		return sb.toString();
308     }
309 
310     /***
311      * Returns <code>value</code> (byte) formatted as a file size.
312      * For example value=2048 returns "2 kb".
313      * 
314      * @param size filesize to be formatted
315      * @return formatted number as string
316      */
317     public static String formatSize(long size)
318     {
319 		int i = 0;
320 		for (; i < SIZES.length - 1 && size >= 1024; i++) {
321 			size /= 1024;
322 		}
323 
324 		return String.format("%,d %s", size, SIZES[i]);
325     }
326 
327     /***
328      * Formats number of seconds in appropriate time unit
329      *
330      * @param i number of seconds
331      * @return formatted duration as string
332      */
333     public static String formatLength(long i)
334     {
335 		StringBuilder sb = new StringBuilder();
336 	
337 		long x = (i / 3600);
338 		if (x > 0) {
339 			sb.append(x);
340 			sb.append(":");
341 		}
342 		x = (i % 3600) / 60;
343 		if (x < 10) {
344 			sb.append("0");
345 		}
346 		sb.append(x);
347 		sb.append(":");
348 		x = (i % 60);
349 		if (x < 10) {
350 			sb.append("0");
351 		}
352 		sb.append(x);
353 
354 		return sb.toString();
355     }
356 
357 	/***
358 	 * Prepends and appends <code>padding</code> whitespaces to text and 
359 	 * returns the result.
360 	 * @param text the text
361 	 * @param padding the number of spaces to prepend and append
362 	 * @return the padded text, lenght will be text.length() + 2 * padding
363 	 * @throws IllegalArgumentException if <code>padding</code> < 0
364 	 */
365 	public static final String pad(String text, int padding)
366 	{
367 		if (padding < 0) {
368 			throw new IllegalArgumentException();
369 		}
370 		if (padding == 0) {
371 			return text;
372 		}
373 		StringBuilder sb = new StringBuilder(text.length() + padding * 2);
374 		append(sb, " ", padding);
375 		sb.append(text);
376 		append(sb, " ", padding);
377 		return sb.toString();
378 	}
379 
380 	/***
381 	 * Prepends <code>lpadding</code> and appends <code>rpadding</code> 
382 	 * whitespaces to text and returns the result.
383 	 * 
384 	 * @return the padded text, lenght will be text.length() + lpadding + rpadding
385 	 * @param text the text
386 	 * @param lpadding the number of spaces to prepend
387 	 * @param rpadding the number of spaces to append
388 	 * @throws IllegalArgumentException if <code>lpadding</code> < 0 or
389 	 * <code>rpadding</code> < 0
390 	 */
391 	public static final String pad(String text, int lpadding, int rpadding)
392 	{
393 		if (lpadding < 0) {
394 			throw new IllegalArgumentException();
395 		}
396 		if (rpadding < 0) {
397 			throw new IllegalArgumentException();
398 		}
399 		if (lpadding == 0 && rpadding == 0) {
400 			return text;
401 		}
402 		StringBuilder sb = new StringBuilder(text.length() + lpadding + rpadding);
403 		append(sb, " ", lpadding);
404 		sb.append(text);
405 		append(sb, " ", rpadding);
406 		return sb.toString();
407 	}
408 	
409 	/***
410 	 * Appends <code>text</text> to <code>sb</code> <code>count</code> times.
411 	 * @param sb the buffer the text is appended to
412 	 * @param text the text
413 	 * @param count the number of times text is appenden to buffer
414 	 */
415 	private static final void append(StringBuilder sb, String text, int count)
416     {
417 		for (int i = 0; i < count; i++) {
418 			sb.append(text);
419 		}
420     }
421 	
422 	/***
423 	 * Appends <code>text</text> to <code>sb</code> <code>count</code> times.
424 	 * @param sb the buffer the text is appended to
425 	 * @param text the text
426 	 * @param count the number of times text is appenden to buffer
427 	 */
428 	public static final void append(StringBuffer sb, String text, int count)
429     {
430 		for (int i = 0; i < count; i++) {
431 			sb.append(text);
432 		}
433     }
434 
435 }