001: /* ====================================================================
002: * The LateralNZ Software License, Version 1.0
003: *
004: * Copyright (c) 2003 LateralNZ. All rights reserved.
005: *
006: * Redistribution and use in source and binary forms, with or without
007: * modification, are permitted provided that the following conditions
008: * are met:
009: *
010: * 1. Redistributions of source code must retain the above copyright
011: * notice, this list of conditions and the following disclaimer.
012: *
013: * 2. Redistributions in binary form must reproduce the above copyright
014: * notice, this list of conditions and the following disclaimer in
015: * the documentation and/or other materials provided with the
016: * distribution.
017: *
018: * 3. The end-user documentation included with the redistribution,
019: * if any, must include the following acknowledgment:
020: * "This product includes software developed by
021: * LateralNZ (http://www.lateralnz.org/) and other third parties."
022: * Alternately, this acknowledgment may appear in the software itself,
023: * if and wherever such third-party acknowledgments normally appear.
024: *
025: * 4. The names "LateralNZ" must not be used to endorse or promote
026: * products derived from this software without prior written
027: * permission. For written permission, please
028: * contact oss@lateralnz.org.
029: *
030: * 5. Products derived from this software may not be called "Panther",
031: * or "Lateral" or "LateralNZ", nor may "PANTHER" or "LATERAL" or
032: * "LATERALNZ" appear in their name, without prior written
033: * permission of LateralNZ.
034: *
035: * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
036: * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
037: * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
038: * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
039: * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
040: * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
041: * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
042: * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
043: * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
044: * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
045: * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
046: * SUCH DAMAGE.
047: * ====================================================================
048: *
049: * This software consists of voluntary contributions made by many
050: * individuals on behalf of LateralNZ. For more
051: * information on Lateral, please see http://www.lateralnz.com/ or
052: * http://www.lateralnz.org
053: *
054: */
055: package org.lateralnz.common.util;
056:
057: import java.io.ByteArrayInputStream;
058: import java.io.ByteArrayOutputStream;
059: import java.io.BufferedReader;
060: import java.io.File;
061: import java.io.FileReader;
062: import java.io.IOException;
063: import java.io.Reader;
064: import java.security.MessageDigest;
065: import java.text.MessageFormat;
066: import java.util.ArrayList;
067: import java.util.HashMap;
068: import java.util.Iterator;
069: import java.util.List;
070: import java.util.Map;
071: import java.util.StringTokenizer;
072: import java.util.zip.GZIPInputStream;
073: import java.util.zip.GZIPOutputStream;
074:
075: import java.util.regex.Matcher;
076: import java.util.regex.Pattern;
077: import java.util.regex.PatternSyntaxException;
078:
079: /**
080: * common string utility functions
081: *
082: * @author J R Briggs
083: */
084: public final class StringUtils implements Constants {
085: private static MessageDigest md5 = null;
086: private static MessageDigest sha = null;
087:
088: private static HashMap patternCache = new HashMap();
089:
090: private static final String MD5 = "MD5";
091: private static final String SHA = "SHA";
092:
093: private static final char[] hexChars = new char[] { '0', '1', '2',
094: '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e',
095: 'f' };
096:
097: private static final String[][] HTML_PATTERNS = { { "&", "&" },
098: { "<", "<" }, { ">", ">" },
099: { "\\ \\; ", " " }, { "'", "'" },
100: { "\"", """ }, { "\n", "<br />" },
101: { "\n ", "<br /> " } };
102:
103: private static final String[][] ESCAPES = { { "\n", "\\n" },
104: { "\r", "\\r" }, { "\"", "\\\"" }, { "\t", "\\t" } };
105:
106: private static final String[][] REV_ESCAPES = { { "\\n", "\n" },
107: { "\\r", "\r" }, { "\\\"", "\"" }, { "\\t", "\t" },
108: { "\\'", "'" } };
109:
110: private static final String AMP_HASH = "&#";
111:
112: private static Pattern[] strpatterns = new Pattern[HTML_PATTERNS.length];
113:
114: static {
115: try {
116: for (int i = 0; i < HTML_PATTERNS.length; i++) {
117: strpatterns[i] = getPattern(HTML_PATTERNS[i][0]);
118: }
119:
120: } catch (PatternSyntaxException pse) {
121: pse.printStackTrace();
122: }
123: }
124:
125: /**
126: * count the occurrences of a character in a string
127: */
128: public static final int countOccurrences(String s, char c) {
129: int total = 0;
130: for (int i = 0; i < s.length(); i++) {
131: if (s.charAt(i) == c) {
132: total++;
133: }
134: }
135: return total;
136: }
137:
138: public static final int countOccurrences(StringBuffer sb, char c) {
139: int total = 0;
140: for (int i = 0; i < sb.length(); i++) {
141: if (sb.charAt(i) == c) {
142: total++;
143: }
144: }
145: return total;
146: }
147:
148: public static final String degzip(byte[] b) throws IOException {
149: GZIPInputStream gis = null;
150: try {
151: gis = new GZIPInputStream(new ByteArrayInputStream(b));
152:
153: int offset = 0;
154: int len = 1024;
155: int read;
156: int total = 0;
157: byte[] buf = new byte[len];
158: while ((read = gis.read(buf, offset, len)) != -1) {
159: total += read;
160: if (read < len) {
161: break;
162: } else {
163: byte[] tmp = new byte[buf.length + len];
164: System.arraycopy(buf, 0, tmp, 0, buf.length);
165: offset = buf.length;
166: buf = tmp;
167: }
168: }
169:
170: return new String(buf, 0, total);
171: } finally {
172: IOUtils.close(gis);
173: }
174: }
175:
176: /**
177: * escape a string
178: */
179: public static final String escape(String s) {
180: StringBuffer sb = new StringBuffer(s);
181: for (int i = 0; i < ESCAPES.length; i++) {
182: replace(sb, ESCAPES[i][0], ESCAPES[i][1]);
183: }
184:
185: return sb.toString();
186:
187: }
188:
189: /**
190: * return a list of regular expression groups given a string and a regex grouping pattern
191: */
192: public static final List findRegex(String s, String pattern) {
193: ArrayList rtn = new ArrayList();
194: Pattern p = getPattern(pattern);
195: Matcher matcher = p.matcher(s);
196: while (matcher.find()) {
197: int groups = matcher.groupCount();
198: for (int i = 1; i <= groups; i++) {
199: rtn.add(matcher.group(i));
200: }
201: }
202:
203: return rtn;
204: }
205:
206: /**
207: * a quick and dirty wrapper over MessageFormat.format, so we don't need
208: * to import it into JSPs as well as org.lateralnz.util.*
209: */
210: public static final String format(String pattern, Object[] arguments) {
211: if (isEmpty(pattern)) {
212: return EMPTY;
213: } else {
214: return MessageFormat.format(pattern, arguments);
215: }
216: }
217:
218: /**
219: * a wrapper for MessageFormat.format that takes a single argument
220: * rather than an array
221: */
222: public static final String format(String pattern, String argument) {
223: return format(pattern, new Object[] { argument });
224: }
225:
226: public static final String fromArray(String[] s, String delim) {
227: if (s == null || s.length < 1) {
228: return EMPTY;
229: } else {
230: return fromArray(s, delim, 0, s.length);
231: }
232: }
233:
234: /**
235: * turn an array of strings into a single delimited string
236: * @param s the array of strings to use
237: * @param delim the delimiter to use between each value
238: * @param start the start position of the array
239: * @param len the number of elements to use from the array
240: * @returns a delimited string
241: */
242: public static final String fromArray(String[] s, String delim,
243: int start, int len) {
244: StringBuffer sb = new StringBuffer();
245: if (s != null && start < s.length && len > 0) {
246: for (int i = 0, j = start; i < len && j < s.length; i++, j++) {
247: sb.append(s[j]);
248: if (j < s.length - 1 && i < len - 1) {
249: sb.append(delim);
250: }
251: }
252: }
253: return sb.toString();
254: }
255:
256: /**
257: * turn a list of strings into a single delimited string
258: */
259: public static final String fromList(List l, String delim) {
260: StringBuffer sb = new StringBuffer();
261: Iterator iter = l.iterator();
262: while (iter.hasNext()) {
263: sb.append(iter.next());
264: if (iter.hasNext()) {
265: sb.append(delim);
266: }
267: }
268: return sb.toString();
269: }
270:
271: /**
272: * create a string based upon the contents of a map. The string will be constructed
273: * as key=value[DELIM]key=value[DELIM]..., where [DELIM] is specified in the call to
274: * this method. For example:
275: * fromMap(m, ',')
276: * would return: key1=value1,key2=value2,key3=value3,etc
277: */
278: public static final String fromMap(Map map, char delim) {
279: StringBuffer sb = new StringBuffer();
280: Iterator iter = map.keySet().iterator();
281: while (iter.hasNext()) {
282: String key = (String) iter.next();
283: String value = (String) map.get(key);
284: if (sb.length() > 0) {
285: sb.append(delim);
286: }
287: sb.append(key).append(EQUALS).append(value);
288: }
289: return sb.toString();
290: }
291:
292: /**
293: * parse a delimited string returning the element at the specified index
294: * @param s the string to parse
295: * @param delim the delimiters
296: * @param index the index value to return
297: * @returns a string value
298: */
299: public static final String getFromDelimitedString(String s,
300: String delim, int index) {
301: String rtn = null;
302: StringTokenizer st = new StringTokenizer(s, delim);
303: int counter = 0;
304: while (st.hasMoreTokens() && counter <= index) {
305: if (counter == index) {
306: rtn = st.nextToken();
307: } else {
308: st.nextToken();
309: }
310: counter++;
311: }
312:
313: return rtn;
314: }
315:
316: public static final Pattern getPattern(String pattern)
317: throws PatternSyntaxException {
318: if (patternCache.containsKey(pattern)) {
319: return (Pattern) patternCache.get(pattern);
320: } else {
321: Pattern pat = Pattern.compile(pattern,
322: Pattern.CASE_INSENSITIVE | Pattern.MULTILINE
323: | Pattern.DOTALL);
324: patternCache.put(pattern, pat);
325: return pat;
326: }
327: }
328:
329: /**
330: * create a random string of a specified length
331: */
332: public static String getRandomString(int len) {
333: char[] stringchars = new char[len];
334: for (int i = 0; i < len; i++) {
335: int index = (int) ((Math.random() * 25 + 65) + 0.5);
336: if (Math.random() > 0.5) {
337: index += 32;
338: }
339: stringchars[i] = (char) index;
340: }
341: return new String(stringchars);
342: }
343:
344: /**
345: * given a string and the start and end of a tag return the contents of the tag.
346: * For example, given the string: "hello this <!-- is a test -->" and a tag start
347: * of "<!--" and a tag end of "-->", this method should return " is a test "
348: */
349: public static final String getTagValue(String s, String tagStart,
350: String tagEnd) {
351: if (isEmpty(s)) {
352: return EMPTY;
353: } else {
354: int start = s.indexOf(tagStart);
355: if (start < 0) {
356: return EMPTY;
357: } else {
358: start += tagStart.length();
359: }
360:
361: int end = -1;
362: if (!StringUtils.isEmpty(tagEnd)) {
363: end = s.indexOf(tagEnd, start);
364: }
365:
366: if (end >= 0) {
367: return s.substring(start, end);
368: } else {
369: return s.substring(start);
370: }
371: }
372: }
373:
374: public static final byte[] gzip(String s) throws IOException {
375: ByteArrayOutputStream baos;
376: GZIPOutputStream gos = null;
377: try {
378: baos = new ByteArrayOutputStream();
379: gos = new GZIPOutputStream(baos);
380: byte[] b = s.getBytes();
381: gos.write(b, 0, b.length);
382: gos.finish();
383: return baos.toByteArray();
384: } finally {
385: IOUtils.close(gos);
386: }
387: }
388:
389: /**
390: * return true if a string is null or empty (in other words equals(\"\"))
391: */
392: public static final boolean isEmpty(String s) {
393: if (s == null || s.equals(EMPTY)) {
394: return true;
395: } else {
396: return false;
397: }
398: }
399:
400: /**
401: * return true if an object is null, or it is a string and empty
402: */
403: public static final boolean isEmpty(Object o) {
404: if (o == null || (o instanceof String && o.equals(EMPTY))) {
405: return true;
406: } else {
407: return false;
408: }
409: }
410:
411: /**
412: * check for equality between two strings, taking nulls into account
413: */
414: public static final boolean isEqual(String s1, String s2) {
415: if ((isEmpty(s1) && !isEmpty(s2))
416: || (!isEmpty(s1) && isEmpty(s2))) {
417: return false;
418: } else if (isEmpty(s1) && isEmpty(s2)) {
419: return true;
420: } else {
421: return s1.equals(s2);
422: }
423: }
424:
425: /**
426: * Check if a string is numeric (digit chars only)
427: */
428: public static final boolean isNumeric(String s) {
429: if (isEmpty(s)) {
430: return false;
431: }
432:
433: for (int i = 0; i < s.length(); i++) {
434: if (!Character.isDigit(s.charAt(i))) {
435: return false;
436: }
437: }
438:
439: return true;
440: }
441:
442: /**
443: * if a string is null, then return the specified replacement
444: * @param s the string to check for null
445: * @param replacement the string to return if s is null
446: */
447: public static final String isNull(String s, String replacement) {
448: return (s == null ? replacement : s);
449: }
450:
451: /**
452: * left pad a string with a certain character so that it equals the specified
453: * length
454: */
455: public static final String lpad(String text, char pad, int length) {
456: return pad(text, pad, length, true);
457: }
458:
459: /**
460: * return true if a particular string matches the regular expression
461: * @param s the string to check
462: * @param pattern the regular expression to look for
463: */
464: public static final boolean matches(String s, String pattern)
465: throws PatternSyntaxException {
466: Pattern p = getPattern(pattern);
467:
468: Matcher matcher = p.matcher(s);
469:
470: return matcher.matches();
471: }
472:
473: /**
474: * actual padding method
475: */
476: private static final String pad(String text, char pad, int length,
477: boolean left) {
478: int textlen = text.length();
479: if (textlen > length) {
480: return text;
481: }
482:
483: StringBuffer sb;
484: if (left) {
485: sb = new StringBuffer();
486: } else {
487: sb = new StringBuffer(text);
488: }
489:
490: int len = length - textlen;
491: for (int i = 0; i < len; i++) {
492: sb.append(pad);
493: }
494:
495: if (left) {
496: sb.append(text);
497: }
498:
499: return sb.toString();
500: }
501:
502: /**
503: * read the contents of a file and return as a string
504: */
505: public static final String readFromFile(String filename) {
506: File f = new File(filename);
507:
508: if (f.exists() && f.canRead()) {
509: FileReader fr = null;
510: try {
511: fr = new FileReader(f);
512: return readFrom(fr);
513: } catch (Exception e) {
514: e.printStackTrace();
515: } finally {
516: IOUtils.close(fr);
517: }
518: } else {
519: System.err.println(filename
520: + " does not exist or is not readable");
521: }
522:
523: return EMPTY;
524: }
525:
526: /**
527: * read the contents of the specified reader
528: */
529: public static final String readFrom(Reader r) {
530: try {
531: StringBuffer sb = new StringBuffer();
532: BufferedReader in = new BufferedReader(r);
533: char[] array = new char[2048];
534: int num;
535: while ((num = in.read(array)) != -1) {
536: sb.append(array, 0, num);
537: }
538: in.close();
539:
540: return sb.toString();
541: } catch (Exception e) {
542: }
543:
544: return EMPTY;
545: }
546:
547: /**
548: * read the contents of the specified reader up to the specified size
549: */
550: public static final String readFrom(Reader r, int size) {
551: try {
552: StringBuffer sb = new StringBuffer();
553: BufferedReader in = new BufferedReader(r);
554: char[] array = new char[size];
555: in.read(array);
556: String rtn = new String(array);
557: return rtn;
558: } catch (Exception e) {
559: e.printStackTrace();
560: return EMPTY;
561: }
562: }
563:
564: /**
565: * remove all occurences of a list of characters from a string. for example:
566: * <pre>
567: * remove("This is a test", " ");
568: * </pre>
569: * should return "Thisisatest".
570: * @param s the string to remove characters from
571: * @param chars the list of characters to remove
572: * @returns a new string with chars removed
573: */
574: public static final String remove(String s, String chars) {
575: if (s == null) {
576: return EMPTY;
577: } else {
578: StringBuffer sb = new StringBuffer();
579: for (int i = 0; i < s.length(); i++) {
580: char c = s.charAt(i);
581: if (chars.indexOf(c) < 0) {
582: sb.append(c);
583: }
584: }
585: return sb.toString();
586: }
587: }
588:
589: /**
590: * replace all references of a string in a stringbuffer with the contents
591: * of a replacement string
592: */
593: public static final void replace(StringBuffer sb, String oldstr,
594: String newstr) {
595: if (sb.length() == 0 || isEmpty(oldstr)) {
596: return;
597: } else if (newstr == null) {
598: newstr = EMPTY;
599: }
600: int len = oldstr.length();
601: int nlen = newstr.length();
602: int start = 0;
603: int occ = 0;
604: while (occ != -1) {
605: occ = sb.indexOf(oldstr, start);
606: if (occ != -1) {
607: sb.replace(occ, occ + len, newstr);
608: start = occ + nlen;
609: }
610: }
611: }
612:
613: /**
614: * replace all occurrences of a string with the contents of another string
615: * @param s the string to search
616: * @param oldstr the string pattern to look for
617: * @param newstr the string pattern to replace with
618: */
619: public static final String replace(String s, String oldstr,
620: String newstr) {
621: if (isEmpty(s)) {
622: return s;
623: }
624: StringBuffer sb = new StringBuffer(s);
625:
626: replace(sb, oldstr, newstr);
627:
628: return sb.toString();
629: }
630:
631: public static final String replaceChars(String s, String chars,
632: char newChar) {
633: StringBuffer sb = new StringBuffer();
634: for (int i = 0; i < s.length(); i++) {
635: char c = s.charAt(i);
636: if (chars.indexOf(c) >= 0) {
637: sb.append(newChar);
638: } else {
639: sb.append(c);
640: }
641: }
642: return sb.toString();
643: }
644:
645: /**
646: * replace all references to a 'tag' within a string. A tag is a section of text
647: * defined with a start string and and end string.
648: * For example:
649: * <pre>
650: * replaceTag("this is a test <!-- this is a test --> blah blah", "<!--", "-->", "");
651: * </pre>
652: * Would be expected to return "this is a test blah blah"
653: */
654: public static final String replaceTag(String s, String tagStart,
655: String tagEnd, String replace) {
656: if (s.length() == 0 || isEmpty(tagStart) || isEmpty(tagEnd)) {
657: return EMPTY;
658: } else if (replace == null) {
659: replace = EMPTY;
660: }
661: StringBuffer sb = new StringBuffer(s);
662: int nlen = replace.length();
663: int elen = tagEnd.length();
664: int start = 0;
665: int occ = 0;
666: while (occ != -1) {
667: occ = sb.indexOf(tagStart, start);
668: if (occ != -1) {
669: int occend = sb.indexOf(tagEnd, occ) + elen;
670: sb.replace(occ, occend, replace);
671: start = occ + nlen;
672: }
673: }
674: return sb.toString();
675: }
676:
677: /**
678: * right pad a string with a character so that the length is the same as that
679: * specified by the length param
680: */
681: public static final String rpad(String text, char pad, int length) {
682: return pad(text, pad, length, false);
683: }
684:
685: /**
686: * split a string based upon a regular expression pattern
687: * For example: splitRegex("a,b,c,d,e", ",")
688: * would return a list containing a, b, c, d, and e as the elements
689: */
690: public static final List splitRegex(String s, String pattern)
691: throws PatternSyntaxException {
692: // Pattern p = getPattern(pattern);
693:
694: String[] tmp = s.split(pattern);
695: List l = java.util.Arrays.asList(tmp);
696:
697: return new ArrayList(l);
698: }
699:
700: /**
701: * strip all occurrences of characters in a string from a specified string
702: * @param s the string to search
703: * @param chars a string of characters to remove from s
704: */
705: public static final String strip(String s, String chars) {
706: StringBuffer sb = new StringBuffer();
707: for (int i = 0; i < s.length(); i++) {
708: char c = s.charAt(i);
709: if (chars.indexOf(c) < 0) {
710: sb.append(c);
711: }
712: }
713:
714: return sb.toString();
715: }
716:
717: /**
718: * strip leading a trailing spaces from a string based upon line delimiters
719: */
720: public static final String stripLTSpaces(String s) {
721: Pattern lpattern = getPattern("^\\s+");
722: Pattern rpattern = getPattern("\\s+$");
723:
724: Matcher matcher = lpattern.matcher(s);
725: s = matcher.replaceAll(EMPTY);
726: matcher = rpattern.matcher(s);
727: String rtn = matcher.replaceAll(EMPTY);
728: return rtn;
729: }
730:
731: /**
732: * turn a string into an array of strings (delimiters are not returned as part of the array)
733: * @param s the string to convert
734: * @param delim the delimiters to use in conversion
735: */
736: public static final String[] toArray(String s, String delim) {
737: return toArray(s, delim, false);
738: }
739:
740: /**
741: * turn a string into a string array based upon a delimiter
742: * @param s the string to convert
743: * @param delim the delimiters to use in conversion
744: * @param returnDelimiters if true, then delimiters are included in the array
745: */
746: public static final String[] toArray(String s, String delim,
747: boolean returnDelims) {
748: StringTokenizer st = new StringTokenizer(s, delim, returnDelims);
749: String[] rtn = new String[st.countTokens()];
750: for (int i = 0; i < rtn.length; i++) {
751: rtn[i] = st.nextToken();
752: }
753:
754: st = null;
755: return rtn;
756: }
757:
758: /**
759: * makes sure that a directory filename ends with the file separator.
760: * eg: /usr/local/lib becomes /usr/local/lib/
761: */
762: public static final String toDirectory(String filename) {
763: if (isEmpty(filename)) {
764: return EMPTY;
765: } else if (filename.endsWith(FILE_SEPARATOR)) {
766: return filename;
767: } else {
768: return filename + FILE_SEPARATOR;
769: }
770: }
771:
772: public static final String toHex(byte b) {
773: int i = b & 0xff;
774: int h0 = i & 0xf;
775: int h1 = (i >>> 4) & 0xf;
776:
777: char[] c = new char[2];
778: c[0] = hexChars[h1];
779: c[1] = hexChars[h0];
780:
781: return new String(c);
782: }
783:
784: public static final String toHex(byte[] b) {
785: StringBuffer sb = new StringBuffer();
786: for (int i = 0; i < b.length; i++) {
787: sb.append(toHex(b[i]));
788: }
789: return sb.toString();
790: }
791:
792: /**
793: * convert a string into an 'HTML-ready' string, handling special characters and newlines
794: */
795: public static final String toHTML(String s) {
796: return toHTML(s, true);
797: }
798:
799: /**
800: * convert a string into an 'HTML-ready' string, handling special characters.
801: * This will convert newlines to html breaks if specified
802: */
803: public static final String toHTML(String s, boolean includeBR) {
804: Matcher matcher;
805: int end = strpatterns.length - 2;
806: if (includeBR) {
807: end = strpatterns.length;
808: }
809:
810: for (int i = 0; i < end; i++) {
811: matcher = strpatterns[i].matcher(s);
812: s = matcher.replaceAll(HTML_PATTERNS[i][1]);
813: }
814:
815: return s;
816: }
817:
818: /**
819: * chop a string up into tokens based upon the delimiter and add
820: * the tokens to a list
821: */
822: public static final List toList(String s, String delim, List list) {
823: if (isEmpty(s)) {
824: s = EMPTY;
825: }
826: StringTokenizer st = new StringTokenizer(s, delim);
827: while (st.hasMoreTokens()) {
828: list.add(st.nextToken());
829: }
830:
831: st = null;
832: return list;
833: }
834:
835: /**
836: * turn a string into a list based upon a delimiter
837: */
838: public static final List toList(String s, String delim) {
839: ArrayList list = new ArrayList();
840: return toList(s, delim, list);
841: }
842:
843: /**
844: * turn a string into a map of param=value objects based upon a delimiter.
845: * The string should be something like: "a=100,b=hello,c=a203" where the delimiter
846: * is obviously ","
847: */
848: public static final Map toMap(String s, String delim) {
849: HashMap hm = new HashMap();
850:
851: toMap(hm, s, delim);
852:
853: return hm;
854: }
855:
856: /**
857: * turn a string into a map of param=value objects based upon a delimiter and
858: * using the specified map object for the result
859: */
860: public static final void toMap(Map m, String s, String delim) {
861: if (!isEmpty(s)) {
862: StringTokenizer st = new StringTokenizer(s, delim);
863: while (st.hasMoreTokens()) {
864: String token = st.nextToken();
865: int pos = token.indexOf(EQUALS);
866: if (pos >= 0) {
867: String key = token.substring(0, pos);
868: String val;
869: if (pos < token.length() - 1) {
870: val = token.substring(pos + 1);
871: } else {
872: val = EMPTY;
873: }
874: m.put(key, val);
875: } else {
876: m.put(s, EMPTY);
877: }
878: }
879: }
880: }
881:
882: /**
883: * take a string that contains escaped values \\n \\t \\r and returns it with
884: * the actual escape codes (\n, \t, \r)
885: */
886: public static final String unescape(String s) {
887: StringBuffer sb = new StringBuffer(s);
888: for (int i = 0; i < REV_ESCAPES.length; i++) {
889: replace(sb, REV_ESCAPES[i][0], REV_ESCAPES[i][1]);
890: }
891:
892: return sb.toString();
893:
894: }
895:
896: /**
897: * unencode a string containing html escape codes (in the form &#...;)
898: */
899: public static final String unencode(String s)
900: throws NumberFormatException {
901: StringBuffer sb = new StringBuffer(s);
902: int pos = 0;
903: int endpos;
904: String tmp;
905: while ((pos = sb.indexOf(AMP_HASH, pos)) >= 0) {
906: endpos = sb.indexOf(SEMICOLON, pos);
907: if (endpos >= 0) {
908: tmp = sb.substring(pos + 2, endpos);
909: int i = Integer.parseInt(tmp);
910: sb.replace(pos, endpos + 1, EMPTY + (char) i);
911: }
912: pos++;
913: }
914: return sb.toString();
915: }
916:
917: private static final String toDigest(String s, MessageDigest md)
918: throws Exception {
919: md.update(s.getBytes());
920:
921: StringBuffer sb = new StringBuffer();
922: byte[] b = md.digest();
923: for (int i = 0; i < b.length; i++) {
924: sb.append(toHex(b[i]));
925: }
926:
927: return sb.toString();
928: /*
929: StringReader sr = new StringReader(new String(md.digest()));
930: int c;
931: StringBuffer sb = new StringBuffer();
932: while ((c = sr.read()) != -1) {
933: String hexString = Integer.toHexString(c);
934: if ( hexString.length() == 1 ) {
935: sb.append(ZERO).append(hexString);
936: }
937: else {
938: sb.append(hexString);
939: }
940: }
941:
942: return sb.toString();*/
943: }
944:
945: /**
946: * return an MD5 digest of a specified string
947: */
948: public static final String toMD5Digest(String s) throws Exception {
949: if (md5 == null) {
950: synchronized (StringUtils.class) {
951: if (md5 == null) {
952: md5 = MessageDigest.getInstance(MD5);
953: }
954: }
955: }
956:
957: MessageDigest md5c = (MessageDigest) md5.clone();
958:
959: return toDigest(s, md5c);
960: }
961:
962: public static final String toSHADigest(String s) throws Exception {
963: if (sha == null) {
964: synchronized (StringUtils.class) {
965: if (sha == null) {
966: sha = MessageDigest.getInstance(SHA);
967: }
968: }
969: }
970:
971: MessageDigest shac = (MessageDigest) sha.clone();
972:
973: return toDigest(s, shac);
974:
975: }
976:
977: }
|