1 package org.molwind.util;
2
3 /*
4 * This file is part of Molwind.
5 *
6 * Molwind is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, either version 3 of the License, or
9 * (at your option) any later version.
10 *
11 * Molwind is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with Molwind. If not, see <http://www.gnu.org/licenses/>.
18 */
19
20 import java.awt.Color;
21 import java.io.BufferedReader;
22 import java.io.IOException;
23 import java.io.StringReader;
24 import java.math.BigDecimal;
25 import java.text.DateFormat;
26 import java.text.ParseException;
27 import java.text.ParsePosition;
28 import java.text.SimpleDateFormat;
29 import java.util.ArrayList;
30 import java.util.Collection;
31 import java.util.Date;
32 import java.util.Hashtable;
33 import java.util.Iterator;
34 import java.util.Properties;
35 import java.util.StringTokenizer;
36 import java.util.zip.CRC32;
37
38 /**
39 * The Stringx class provides a collection of static methods for extended
40 * string processing.
41 *
42 * @author <a href="mailto:oliver.karch@molwind.org">Oliver Karch</a>
43 * @version 1.0
44 */
45 public final class Stringx {
46
47 /**
48 * A list of typical color names.
49 */
50 private static Hashtable < String, Color > colorNames;
51
52 static {
53 colorNames = new Hashtable();
54 colorNames.put("black", Color.black);
55 colorNames.put("blue", Color.blue);
56 colorNames.put("cyan", Color.cyan);
57 colorNames.put("darkGray", Color.darkGray);
58 colorNames.put("dark-gray", Color.darkGray);
59 colorNames.put("dark_gray", Color.darkGray);
60 colorNames.put("darkgray", Color.darkGray);
61 colorNames.put("gray", Color.gray);
62 colorNames.put("green", Color.green);
63 colorNames.put("lightGray", Color.lightGray);
64 colorNames.put("light-gray", Color.lightGray);
65 colorNames.put("light_gray", Color.lightGray);
66 colorNames.put("lightgray", Color.lightGray);
67 colorNames.put("magenta", Color.magenta);
68 colorNames.put("orange", Color.orange);
69 colorNames.put("pink", Color.pink);
70 colorNames.put("red", Color.red);
71 colorNames.put("white", Color.white);
72 colorNames.put("yellow", Color.yellow);
73 }
74
75 /**
76 * Empty constructor to prevent the creation of instances.
77 */
78 private Stringx() { }
79
80 /**
81 * Formats the current date according to the given format string. For
82 * example a valid format string could be <code>dd.MM.YYYY</code>.
83 * <p>
84 * See {@link java.text.SimpleDateFormat} for formatting options.
85 *
86 * @param format
87 * the format string
88 * @return
89 * the formated date string
90 */
91 public static String currentDateString(final String format) {
92 SimpleDateFormat formatter = new SimpleDateFormat(format);
93 return formatter.format(new Date());
94 }
95
96 /**
97 * Formats a given date according to the format string. For example a valid
98 * format string could be <code>dd.MM.YYYY</code>.
99 * <p>
100 * See {@link java.text.SimpleDateFormat} for formatting options.
101 *
102 * @param format
103 * the format string
104 * @param date
105 * the date
106 * @return
107 * the formated date string
108 */
109 public static String getDateString(final String format, final Date date) {
110 SimpleDateFormat formatter = new SimpleDateFormat(format);
111 return formatter.format(date);
112 }
113
114 /**
115 * Formats the current date according to local formating conventions.
116 *
117 * @return
118 * the formated date string
119 */
120 public static String localDate() {
121 DateFormat formatter = DateFormat.getDateInstance(DateFormat.SHORT);
122 return formatter.format(new Date());
123 }
124
125 /**
126 * Formats the current time according to local formating conventions.
127 *
128 * @return
129 * the formated time string
130 */
131 public static String localTime() {
132 DateFormat formatter = DateFormat.getTimeInstance(DateFormat.SHORT);
133 return formatter.format(new Date());
134 }
135
136 /**
137 * Formats the current date according to local formating conventions.
138 *
139 * @param date
140 * milliseconds since era
141 * @return
142 * the formated date string
143 */
144 public static String localDate(final long date) {
145 DateFormat formatter = DateFormat.getDateInstance(DateFormat.SHORT);
146 return formatter.format(new Date(date));
147 }
148
149 /**
150 * Formats the current date according to local formating conventions to
151 * display medium format length.
152 *
153 * @param date
154 * milliseconds since era
155 * @return
156 * the formated date string
157 */
158 public static String localMediumDate(final long date) {
159 DateFormat formatter = DateFormat.getDateInstance(DateFormat.MEDIUM);
160 return formatter.format(new Date(date));
161 }
162
163 /**
164 * Parses a date string according to local formating conventions.
165 *
166 * @param dateString
167 * a date string
168 * @return
169 * a long representing the date or <code>-1</code> if an error
170 * occurred
171 */
172 public static long parseDate(final String dateString) {
173 DateFormat formatter = DateFormat.getDateInstance();
174 long longDate;
175
176 try {
177 Date date = formatter.parse(dateString);
178 longDate = date.getTime();
179 } catch (ParseException pe) {
180 longDate = -1L;
181 }
182
183 return longDate;
184 }
185
186 /**
187 * Parses a date string conforming to a given date format pattern.
188 *
189 * @param dateString
190 * a date string
191 * @param pattern
192 * a date pattern
193 * @return
194 * a long representing the date or <code>-1</code> if an error
195 * occurred
196 */
197 public static long parseDate(final String dateString,
198 final String pattern) {
199 SimpleDateFormat formatter = new SimpleDateFormat(pattern);
200 ParsePosition pp = new ParsePosition(0);
201 Date date = formatter.parse(dateString, pp);
202
203 if (pp.getErrorIndex() >= 0) {
204 return -1L;
205 }
206
207 return date.getTime();
208 }
209
210 /**
211 * Formats the current time according to local formating conventions.
212 *
213 * @param date
214 * milliseconds since era
215 * @return
216 * the formated date string
217 */
218 public static String localTime(final long date) {
219 DateFormat formatter = DateFormat.getTimeInstance(DateFormat.SHORT);
220 return formatter.format(new Date(date));
221 }
222
223 /**
224 * Parses a time string according to local formating conventions.
225 *
226 * @param timeString
227 * a time string
228 * @return
229 * a long representing the time or <code>-1</code> if an error
230 * occurred
231 */
232 public static long parseTime(final String timeString) {
233 DateFormat formatter = DateFormat.getTimeInstance();
234 long longDate;
235
236 try {
237 Date date = formatter.parse(timeString);
238 longDate = date.getTime();
239 } catch (ParseException pe) {
240 longDate = -1L;
241 }
242
243 return longDate;
244 }
245
246 /**
247 * Cuts a substring out of a source string ending at a given delimiter
248 * string.
249 *
250 * @param source
251 * the source string
252 * @param delimiter
253 * a delimiter string
254 * @return
255 * the subtoken
256 */
257 public static String before(final String source, final String delimiter) {
258 int k = source.indexOf(delimiter);
259 if (k > 0) {
260 return source.substring(0, k);
261 }
262 return "";
263 }
264
265 /**
266 * Tailors a source string to the string beginning after a given delimiter
267 * string.
268 *
269 * @param source
270 * the source string
271 * @param delimiter
272 * a delimiter string
273 * @return
274 * the subtoken
275 */
276 public static String after(final String source, final String delimiter) {
277 int k = source.indexOf(delimiter);
278 if (k >= 0) {
279 return source.substring(k + delimiter.length());
280 }
281 return "";
282 }
283
284 /**
285 * Determines the string's portion after the last occurrence of the
286 * delimiter.
287 *
288 * @param source
289 * the source string
290 * @param delimiter
291 * a delimiter string
292 * @return
293 * the subtoken
294 */
295 public static String afterLast(final String source,
296 final String delimiter) {
297 int k = source.lastIndexOf(delimiter);
298 if ((k >= 0) && (k + delimiter.length() < source.length())) {
299 return source.substring(k + delimiter.length());
300 }
301 return "";
302 }
303
304 /**
305 * Discards all characters of a source string after a delimiter string.
306 *
307 * @param source
308 * the source string
309 * @param delimiter
310 * a delimiter string
311 * @return
312 * the shortened string
313 */
314 public static String strcut(final String source, final String delimiter) {
315 int k = source.indexOf(delimiter);
316 if (k > 0) {
317 return source.substring(0, k);
318 }
319 if (k == 0) {
320 return "";
321 }
322 return source;
323 }
324
325 /**
326 * Determines all tokens of a source string that are delimited by
327 * characters of a delimiter string.
328 *
329 * @param source
330 * the source string
331 * @param delimiter
332 * a delimiter string
333 * @return
334 * the tokens
335 */
336 public static String[] strtok(final String source, final String delimiter) {
337 return strtok(source, delimiter, false);
338 }
339
340 /**
341 * Creates a string consisting of the array's items separated by the given
342 * delimiter.
343 *
344 * @param items
345 * the string items
346 * @param delimiter
347 * a delimiter string
348 * @return
349 * the concatenated string
350 */
351 public static String toStringList(final Object[] items,
352 final String delimiter) {
353 StringBuffer buffer = new StringBuffer();
354 boolean first = true;
355
356 if (items != null) {
357 for (int i = 0; i < items.length; i++) {
358 if (items[i] == null) {
359 continue;
360 }
361 if (!first) {
362 buffer.append(delimiter);
363 }
364
365 buffer.append(items[i]);
366 first = false;
367 }
368 }
369 return buffer.toString();
370 }
371
372 /**
373 * Creates a string consisting of the array's items separated by the given
374 * delimiter.
375 *
376 * @param items
377 * the string items
378 * @param delimiter
379 * a delimiter string
380 * @return
381 * the concatenated string
382 */
383 public static String toStringList(final Collection items,
384 final String delimiter) {
385 StringBuffer buffer = new StringBuffer();
386
387 if (items != null) {
388 Iterator it = items.iterator();
389 boolean first = true;
390
391 while (it.hasNext()) {
392 Object object = it.next();
393 if (object == null) {
394 continue;
395 }
396 if (!first) {
397 buffer.append(delimiter);
398 }
399
400 buffer.append(object);
401 first = false;
402 }
403 }
404 return buffer.toString();
405 }
406
407 /**
408 * Determines all tokens of a source string that are delimited by
409 * characters of a delimiter string, optionally trims the tokens.
410 *
411 * @param source
412 * the source string
413 * @param delimiter
414 * a delimiter string
415 * @param trim
416 * true if tokens shall be trimmed
417 * @return
418 * the tokens
419 */
420 public static String[] strtok(final String source, final String delimiter,
421 final boolean trim) {
422 StringTokenizer tokenizer = new StringTokenizer(source, delimiter);
423 String[] tokens = new String[tokenizer.countTokens()];
424 for (int i = 0; tokenizer.hasMoreTokens(); i++) {
425 if (trim) {
426 tokens[i] = tokenizer.nextToken().trim();
427 } else {
428 tokens[i] = tokenizer.nextToken();
429 }
430 }
431 return tokens;
432 }
433
434 /**
435 * Determines all tokens of a source string that are delimited by
436 * whitespaces.
437 *
438 * @param source
439 * the source string
440 * @return
441 * the tokens
442 */
443 public static String[] strtok(final String source) {
444 StringTokenizer tokenizer = new StringTokenizer(source);
445 String[] tokens = new String[tokenizer.countTokens()];
446 for (int i = 0; tokenizer.hasMoreTokens(); i++) {
447 tokens[i] = tokenizer.nextToken();
448 }
449 return tokens;
450 }
451
452 /**
453 * Replaces one occurrence of a string to be substituted in a source
454 * string by a replacing string.
455 *
456 * @param source
457 * the source string
458 * @param substitute
459 * the string to be substituted
460 * @param replacement
461 * the replacing string
462 * @return
463 * entire string with replaced occurrence
464 */
465 public static String substitute(final String source,
466 final String substitute, final String replacement) {
467 return before(source, substitute) + replacement
468 + after(source, substitute);
469 }
470
471 /**
472 * Replaces all occurrences of a string to be substituted in a source
473 * string by a replacing string.
474 *
475 * @param source
476 * the source string
477 * @param substitute
478 * the string to be substituted
479 * @param replacement
480 * the replacing string
481 * @return
482 * entire string with replaced occurrences
483 */
484 public static String substituteAll(final String source,
485 final String substitute, final String replacement) {
486 String src = source;
487 while (src.indexOf(substitute) >= 0) {
488 src = before(src, substitute) + replacement
489 + after(src, substitute);
490 }
491 return src;
492 }
493
494 /**
495 * Extracts a substring from a source string between a left and a right
496 * delimiter string.
497 *
498 * @param source
499 * the source string
500 * @param leftMark
501 * left delimiter string
502 * @param rightMark
503 * right delimiter string
504 * @return
505 * the subtoken
506 */
507 public static String extract(final String source, final String leftMark,
508 final String rightMark) {
509 String st = after(source, leftMark);
510 return before(st, rightMark);
511 }
512
513 /**
514 * Extracts a substring from a source string between a left and a right
515 * delimiter string.
516 *
517 * @param source
518 * the source string
519 * @param leftMark
520 * the left delimiter string
521 * @param rightMark
522 * the right delimiter string
523 * @return
524 * the subtoken
525 */
526 public static String[] extractAll(final String source,
527 final String leftMark, final String rightMark) {
528 int l = 0;
529 int k = 0;
530 ArrayList hits = new ArrayList();
531
532 while ((k < source.length())
533 && ((l = source.indexOf(leftMark, k)) > k)) {
534 l += leftMark.length();
535 if ((k = source.indexOf(rightMark, l)) >= l) {
536 if (l == k) {
537 hits.add("");
538 } else {
539 hits.add(source.substring(l, k));
540 }
541 }
542 k = l + 1;
543 }
544 String[] extracts = new String[hits.size()];
545 return (String[]) hits.toArray(extracts);
546 }
547
548 /**
549 * Concatenates a paragraph of text into a single line by removing line
550 * ends and unnecessary blanks (i.e. blanks at the end and the beginning
551 * of each line).
552 *
553 * @param source
554 * the source string
555 * @return
556 * the concatenated paragraph
557 */
558 public static String concat(final String source) {
559 BufferedReader reader = new BufferedReader(new StringReader(source));
560 StringBuffer buffer = new StringBuffer();
561 String line = null;
562 boolean first = true;
563
564 try {
565 do {
566 line = reader.readLine();
567 if (line != null) {
568 line = line.trim();
569 if (line.length() > 0) {
570 if (!first) {
571 buffer.append(" ");
572 }
573 first = false;
574 buffer.append(line);
575 }
576 }
577 } while (line != null);
578 reader.close();
579 } catch (IOException ioe) {
580 ioe.printStackTrace();
581 }
582 return buffer.toString();
583 }
584
585 /**
586 * Deletes all occurrences of a substring from a source string.
587 *
588 * @param source
589 * the source string.
590 * @param delete
591 * string to be deleted
592 * @return
593 * the cleaned up string
594 */
595 public static String deleteAll(final String source, final String delete) {
596 int k = -1;
597 String newString = source;
598
599 while ((k = newString.indexOf(delete)) >= 0) {
600 String befSt = "";
601 if (k > 0) {
602 befSt = newString.substring(0, k);
603 }
604 newString = befSt + newString.substring(k + delete.length());
605 }
606 return newString;
607 }
608
609 /**
610 * Counts the digits of the fraction of a number's string representation of
611 * a source string.
612 *
613 * @param num
614 * string representation of a number
615 * @return
616 * the fractional count
617 */
618 public static int fractionDigits(final String num) {
619 int k = num.indexOf(".");
620 if (k >= 0) {
621 if (k == 0) {
622 return num.length() - 1;
623 }
624 return (num.length() - 1) - k;
625 }
626 return 0;
627 }
628
629 /**
630 * Deletes all occurrences of a substring between a left delimiter and a
631 * right delimiter string. The delimiter strings will be removed also.
632 *
633 * @param source
634 * the source string
635 * @param leftMark
636 * the left delimiter string
637 * @param rightMark
638 * the right delimiter string
639 * @return
640 * the cleaned up string
641 */
642 public static String deleteBetweenAll(final String source,
643 final String leftMark, final String rightMark) {
644 int k = -1;
645 String newString = source;
646
647 while ((k = newString.indexOf(leftMark)) >= 0) {
648 int l = newString.substring(k).indexOf(rightMark);
649 if (l > 0) {
650 String befSt = "";
651 if (k > 0) {
652 befSt = newString.substring(0, k);
653 }
654 if (l + k + rightMark.length() < newString.length()) {
655 newString = befSt + newString.substring(l + k
656 + rightMark.length());
657 } else {
658 newString = befSt + "";
659 }
660 }
661 }
662 return newString;
663 }
664
665 /**
666 * Extracts a substring from a source string beginning at a specified
667 * position and ending with a specific delimiter.
668 *
669 * @param source
670 * the source string
671 * @param index
672 * the index to start with
673 * @param delimiter
674 * delimiting string of the subtoken
675 * @return
676 * the subtoken
677 */
678 public static String subtoken(final String source, final int index,
679 final String delimiter) {
680 String hSt = source.substring(index);
681 int k = hSt.indexOf(delimiter);
682 if (k >= 0) {
683 return source.substring(index, index + k);
684 } else {
685 return "";
686 }
687 }
688
689 /**
690 * Truncates a string if it exceeds a certain length.
691 *
692 * @param source
693 * the source string
694 * @param length
695 * the maximum length
696 * @return
697 * the truncated string
698 */
699 public static String strtrunc(final String source, final int length) {
700 if (length < source.length()) {
701 return source.substring(0, length);
702 }
703 return source;
704 }
705
706 /**
707 * Truncates a string if it exceeds a certain length and appends a given
708 * continuation string instead.
709 *
710 * @param source
711 * the source string
712 * @param length
713 * the maximum length
714 * @param cont
715 * the continuation to be appended
716 * @return
717 * the truncated string
718 */
719 public static String strtrunc(final String source, final int length,
720 final String cont) {
721 if (length < source.length()) {
722 return source.substring(0, length - cont.length()) + cont;
723 }
724 return source;
725 }
726
727 /**
728 * Removes all leading non-digits and zeros from a string.
729 *
730 * @param source
731 * the source string
732 * @return
733 * the trimmed string
734 */
735 public static String trimZero(final String source) {
736 int i = 0;
737 for (i = 0; i < source.length(); i++) {
738 if ((source.charAt(i) != '1')
739 && (source.charAt(i) != '2')
740 && (source.charAt(i) != '3')
741 && (source.charAt(i) != '4')
742 && (source.charAt(i) != '5')
743 && (source.charAt(i) != '6')
744 && (source.charAt(i) != '7')
745 && (source.charAt(i) != '8')
746 && (source.charAt(i) != '9')
747 && (source.charAt(i) != '.')) {
748 break;
749 }
750 }
751 if (i < source.length()) {
752 return source.substring(i);
753 }
754 return "";
755 }
756
757 /**
758 * Constructs a string with the specified length that only consists of the
759 * given character.
760 *
761 * @param character
762 * the character
763 * @param length
764 * number of characters
765 * @return
766 * the constructed string
767 */
768 public static String fill(final char character, final int length) {
769 StringBuffer buffer = new StringBuffer();
770 for (int i = 0; i < length; i++) {
771 buffer.append(character);
772 }
773 return buffer.toString();
774 }
775
776
777 /**
778 * Breaks up a string into smaller pieces of specified length appended by
779 * the given string.
780 *
781 * @param source
782 * the source string
783 * @param insert
784 * the string to insert
785 * @param length
786 * the maximum line length
787 * @return
788 * a new string containing newlines
789 */
790 public static String strbreak(final String source, final String insert,
791 final int length) {
792 StringBuffer buffer = new StringBuffer();
793 int i = 0;
794 while (i < source.length()) {
795 int len = Math.min(length, source.length() - i);
796 buffer.append(source.substring(i, len));
797 buffer.append(insert);
798 i += len;
799 }
800 return buffer.toString();
801 }
802
803 /**
804 * Breaks up a string into smaller pieces of specified length appended by a
805 * newline.
806 *
807 * @param source
808 * the source string
809 * @param length
810 * maximum line length
811 * @return
812 * a new string containing newlines
813 */
814 public static String strnewline(final String source, final int length) {
815 StringBuffer buffer = new StringBuffer();
816 int i = 0;
817 while (i < source.length()) {
818 int len = Math.min(length, source.length() - i);
819 buffer.append(source.substring(i, len));
820 buffer.append('\n');
821 i += len;
822 }
823 return buffer.toString();
824 }
825
826 /**
827 * Replaces in the given string all meta character sequences such as
828 * <code>\n</code>, <code>\t</code> etc. by its corresponding character.
829 *
830 * @param string
831 * string containing meta character sequences
832 * @return
833 * the processed string
834 */
835 public static String escapeChar(final String string) {
836 StringBuffer buffer = new StringBuffer();
837
838 for (int i = 0; i < string.length(); i++) {
839 if ((string.charAt(i) == '\\') && (i + 1 < string.length())) {
840 switch (string.charAt(i + 1)) {
841 case 'b':
842 buffer.append('\b');
843 break;
844 case 'f':
845 buffer.append('\f');
846 break;
847 case 'n':
848 buffer.append('\n');
849 break;
850 case 'r':
851 buffer.append('\r');
852 break;
853 case 't':
854 buffer.append('\t');
855 break;
856 case '"':
857 buffer.append('"');
858 break;
859 case '\'':
860 buffer.append('\'');
861 break;
862 }
863 } else {
864 buffer.append(string.charAt(i));
865 }
866 }
867 return buffer.toString();
868 }
869
870 /**
871 * Converts a String to a boolean value. The given default is returned in
872 * case of a an invalid boolean representation.
873 *
874 * @param string
875 * the number string
876 * @param def
877 * the default value
878 * @return
879 * a boolean value converted from the string
880 */
881 public static boolean toBoolean(final String string, final boolean def) {
882 if (string == null) {
883 return def;
884 }
885
886 if (string.equalsIgnoreCase("true")
887 || string.equalsIgnoreCase("on")
888 || string.equalsIgnoreCase("yes")
889 || string.equalsIgnoreCase("t")
890 || string.equalsIgnoreCase("y")
891 || string.equals("1")) {
892 return true;
893 }
894 if (string.equalsIgnoreCase("false")
895 || string.equalsIgnoreCase("off")
896 || string.equalsIgnoreCase("no")
897 || string.equalsIgnoreCase("f")
898 || string.equalsIgnoreCase("n")
899 || string.equals("0")) {
900 return false;
901 }
902
903 return def;
904 }
905
906 /**
907 * Converts a String to an int value. The given default is returned in case
908 * of a <code>NumberFormatException</code>.
909 *
910 * @param string
911 * the number string
912 * @param def
913 * the default value
914 * @return
915 * an int value converted from the string
916 */
917 public static int toInt(final String string, final int def) {
918 if (string == null) {
919 return def;
920 }
921
922 int val;
923
924 try {
925 val = Integer.parseInt(string.trim());
926 } catch (NumberFormatException nfe) {
927 val = def;
928 }
929 return val;
930 }
931
932 /**
933 * Converts a String to a float value. The given default is returned in case
934 * of a <code>NumberFormatException</code>.
935 *
936 * @param string
937 * the number string
938 * @param def
939 * the default value
940 * @return
941 * a float value converted from the string
942 */
943 public static float toFloat(final String string, final float def) {
944 if (string == null) {
945 return def;
946 }
947
948 float val;
949
950 try {
951 val = Float.parseFloat(string.trim());
952 } catch (NumberFormatException nfe) {
953 val = def;
954 }
955
956 return val;
957 }
958
959 /**
960 * Converts a String to a long value. The given default is returned in case
961 * of a <code>NumberFormatException</code>.
962 *
963 * @param string
964 * the number string
965 * @param def
966 * the default value
967 * @return
968 * a long value converted from the string
969 */
970 public static long toLong(final String string, final long def) {
971 if (string == null) {
972 return def;
973 }
974
975 long val;
976
977 try {
978 val = Long.parseLong(string.trim());
979 } catch (NumberFormatException nfe) {
980 val = def;
981 }
982 return val;
983 }
984
985 /**
986 * Converts a String to a double value. The given default is returned in
987 * case of a <code>NumberFormatException</code>.
988 *
989 * @param string
990 * the number string
991 * @param def
992 * the default value
993 * @return
994 * a double value converted from the string
995 */
996 public static double toDouble(final String string, final double def) {
997 if (string == null) {
998 return def;
999 }
1000
1001 double val;
1002
1003 try {
1004 val = Double.parseDouble(string.trim());
1005 } catch (NumberFormatException nfe) {
1006 val = def;
1007 }
1008
1009 return val;
1010 }
1011
1012 /**
1013 * If the given string is null the default value provided is returned.
1014 *
1015 * @param string
1016 * the number string
1017 * @param def
1018 * the default value
1019 * @return
1020 * a string
1021 */
1022 public static String getDefault(final String string, final String def) {
1023 if (string != null) {
1024 return string;
1025 } else {
1026 return def;
1027 }
1028 }
1029
1030 /**
1031 * Converts a color name or description like <code>#FFCC00</code> into a
1032 * color object.
1033 *
1034 * @param colorName
1035 * the color name
1036 * @return
1037 * a color object, which is black by default or error
1038 */
1039 public static Color toColor(final String colorName) {
1040 Color color = (Color) colorNames.get(colorName.toLowerCase());
1041
1042 if (color != null) {
1043 return color;
1044 }
1045 if (colorName.startsWith("#")) {
1046 try {
1047 int rgb = Integer.parseInt(
1048 colorName.substring(1).toUpperCase(), 16);
1049 return new Color(rgb);
1050 } catch (NumberFormatException nfe) {
1051 // TODO Empty catch block
1052 }
1053 } else if ((colorName.startsWith("(") && colorName.endsWith(")"))
1054 || (colorName.startsWith("{") && colorName.endsWith("}"))) {
1055 String cleanedColorName = colorName.substring(1,
1056 colorName.length() - 1).trim();
1057 String[] colToks = cleanedColorName.split("\\p{Punct}");
1058 float[] rgb = new float[3];
1059
1060 for (int i = 0; (i < colToks.length) && (i < rgb.length); i++) {
1061 try {
1062 BigDecimal num = new BigDecimal(colToks[0]);
1063 rgb[i] = num.floatValue();
1064 } catch (NumberFormatException nfe) {
1065 rgb[i] = 0f;
1066 }
1067 }
1068 if ((rgb[0] > 1f) || (rgb[1] > 1f) || (rgb[2] > 1f)) {
1069 return new Color((int) rgb[0], (int) rgb[1], (int) rgb[2]);
1070 } else {
1071 return new Color(rgb[0], rgb[1], rgb[2]);
1072 }
1073 } else {
1074 try {
1075 BigDecimal num = new BigDecimal(colorName);
1076 int rgb = num.intValue();
1077 return new Color(rgb);
1078 } catch (NumberFormatException nfe) {
1079 int num = (colorName.hashCode() & Integer.MAX_VALUE);
1080 if (num > 0) {
1081 return new Color(num);
1082 }
1083 }
1084 }
1085 return Color.black;
1086 }
1087
1088 /**
1089 * Creates a crc checksum from a String.
1090 *
1091 * @param string
1092 * the string
1093 * @return
1094 * long value representing the checksum
1095 */
1096 public static long toCRC(final String string) {
1097 if (string != null) {
1098 CRC32 crc = new CRC32();
1099 crc.update(string.getBytes());
1100 return crc.getValue();
1101 }
1102 return 0;
1103 }
1104
1105 /**
1106 * Extracts the base class name (i.e. class name w/o package prefix) of
1107 * the given class.
1108 *
1109 * @param clazz
1110 * the class
1111 * @return
1112 * the base class name with package prefix stripped
1113 */
1114 public static String getClassName(final Class clazz) {
1115 int k = clazz.getName().lastIndexOf(".");
1116 String rn = null;
1117 if (k > 0) {
1118 rn = clazz.getName().substring(k + 1);
1119 } else {
1120 rn = clazz.getName();
1121 }
1122 return rn;
1123 }
1124
1125 /**
1126 * Checks whether a given string follows the rules for identifiers or not.
1127 *
1128 * @param token
1129 * the token to be analyzed
1130 * @return
1131 * true if the given token complies to identifier rules otherwise
1132 * false
1133 */
1134 public static boolean isIdentifier(final String token) {
1135 if (!Character.isJavaIdentifierStart(token.charAt(0))) {
1136 return false;
1137 }
1138
1139 for (int i = 1; i < token.length(); i++) {
1140 if (!Character.isJavaIdentifierPart(token.charAt(i))) {
1141 return false;
1142 }
1143 }
1144 return true;
1145 }
1146
1147 /**
1148 * Checks whether a given char can be part of a hex string.
1149 *
1150 * @param character
1151 * the character to be analyzed
1152 * @return
1153 * true if the given char can be part of a hex string false otherwise
1154 */
1155 public static boolean isHexDigit(final char character) {
1156 return (Character.isDigit(character)
1157 || (Character.toUpperCase(character) == 'A')
1158 || (Character.toUpperCase(character) == 'B')
1159 || (Character.toUpperCase(character) == 'C')
1160 || (Character.toUpperCase(character) == 'D')
1161 || (Character.toUpperCase(character) == 'E')
1162 || (Character.toUpperCase(character) == 'F'));
1163 }
1164
1165 /**
1166 * Append a string to the source string if it has not been appended
1167 * already.
1168 *
1169 * @param source
1170 * the source string
1171 * @param append
1172 * string to be appended
1173 * @return
1174 * the concatenated string
1175 */
1176 public static String strapp(final String source, final String append) {
1177 if (source.endsWith(append)) {
1178 return source;
1179 } else {
1180 return (source + append);
1181 }
1182 }
1183
1184 /**
1185 * Creates a Properties object from a key-value pair string which looks
1186 * something like <code>item1 = value1; item2 = value2; ...</code>
1187 *
1188 * @param itemString
1189 * a string containing key-value pairs
1190 * @param delimiter
1191 * delimiter string
1192 * @return
1193 * the initialized Properties object
1194 */
1195 public static Properties toProperties(final String itemString,
1196 final String delimiter) {
1197 String[] items = itemString.split(delimiter);
1198 Properties props = new Properties();
1199
1200 for (int i = 0; i < items.length; i++) {
1201 int k = -1;
1202 if (((k = items[i].indexOf("=")) > 0)
1203 || ((k = items[i].indexOf(":")) > 0)) {
1204 String pn = items[i].substring(0, k).trim();
1205 String pv = items[i].substring(k + 1);
1206 props.put(pn, pv);
1207 }
1208 }
1209 return props;
1210 }
1211
1212 /**
1213 * Escapes all xml meta-characters in the given string by the corresponding
1214 * entity char sequences. The resulting string can be safely used as an
1215 * attribute value of an xml tag.
1216 *
1217 * @param value
1218 * the value string
1219 * @return
1220 * a string where meta-characters have been replaced / escaped
1221 */
1222 public static String escapeXmlAttributeValue(final String value) {
1223 StringBuffer buffer = new StringBuffer();
1224 char[] charArray = value.toCharArray();
1225
1226 for (int i = 0; i < charArray.length; i++) {
1227 if (charArray[i] == '<') {
1228 buffer.append("<");
1229 } else if (charArray[i] == '>') {
1230 buffer.append(">");
1231 } else if (charArray[i] == '&') {
1232 buffer.append("&");
1233 } else if (charArray[i] == '\"') {
1234 buffer.append(""");
1235 } else if ((charArray[i] == '\n')
1236 || (charArray[i] == '\r')
1237 || (charArray[i] == '\t')
1238 || (charArray[i] == '\b')
1239 || (charArray[i] == '\f')) {
1240 buffer.append("&#");
1241 buffer.append(String.valueOf((int) charArray[i]));
1242 buffer.append(";");
1243 } else {
1244 buffer.append(charArray[i]);
1245 }
1246 }
1247 return buffer.toString();
1248 }
1249
1250 }