1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
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 }