/* * StringUtil.java * * Copyright (C) 1996 Shaun Terry. All Rights Reserved. */ package spt.util; import java.util.StringTokenizer; import java.util.Hashtable; import java.lang.String; import java.lang.StringBuffer; import java.lang.Integer; import java.lang.NumberFormatException; import java.lang.System; import java.io.InputStream; import java.io.DataInput; import java.io.DataOutput; import java.io.IOException; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.awt.Color; /** * A variety of String related utility functions. * * @author Shaun Terry */ public class StringUtil { /** Convert a delimited String to an array of elements * using the specified delimiter set. * @see java.util.StringTokenizer */ static public String[] split(String s, String delimSet) { StringTokenizer tok = new StringTokenizer(s, delimSet); String s_array[] = new String[ tok.countTokens() ]; for (int i=0; tok.hasMoreTokens(); ++i) { s_array[i] = tok.nextToken(); } return s_array; } /** Convert a pipe delimited String to an array of elements. * @see java.util.StringTokenizer */ static public String[] split(String s) { return split(s, "|"); } /** Parse a String and return a Color. The following formats * are recognized: "#FFFFFF", "r,g,b" and one of a number * known case-independent strings (e.g. "red", "black", etc.). * @see java.awt.Color */ static public Color stringToColor(String s) { if (s.startsWith("#")) { // Formatted like #FFFFFF try { int i = Integer.parseInt(s.substring(1), 16); return new Color((i>>16) & 0xFF, (i>>8) & 0xFF, i & 0xFF); } catch (NumberFormatException e) { return null; } } else if (s.length() > 0 && s.charAt(0) >= '0' && s.charAt(0) <= '9') { // Formatted like rrr,ggg,bbb String rgb[] = StringUtil.split(s, ","); if (rgb.length != 3) return null; int c[] = new int[3]; for (int i=0; i < 3; ++i) { try { c[i] = Integer.parseInt(rgb[i].trim()); } catch (NumberFormatException e) { return null; } } return new Color(c[0], c[1], c[2]); } else if (s.equalsIgnoreCase("white")) return Color.white; else if (s.equalsIgnoreCase("lightGray")) return Color.lightGray; else if (s.equalsIgnoreCase("gray")) return Color.gray; else if (s.equalsIgnoreCase("darkGray")) return Color.darkGray; else if (s.equalsIgnoreCase("red")) return Color.red; else if (s.equalsIgnoreCase("pink")) return Color.pink; else if (s.equalsIgnoreCase("yellow")) return Color.yellow; else if (s.equalsIgnoreCase("green")) return Color.green; else if (s.equalsIgnoreCase("magenta")) return Color.magenta; else if (s.equalsIgnoreCase("cyan")) return Color.cyan; else if (s.equalsIgnoreCase("orange")) return Color.orange; else if (s.equalsIgnoreCase("black")) return Color.black; else if (s.equalsIgnoreCase("blue")) return Color.blue; return null; } /** Convert single string in CGI parameter format to an * array of 2 strings. The 0th element is the parameter name * and the 1st element is the parameter value. * @see #cgiParams */ static public String[] cgiParamToStrings(String s) { s = s.replace('+', ' '); String sn[] = split(s, "="); StringBuffer sb[] = new StringBuffer[2]; for (int i=0; i < 2; ++i) { sb[i] = new StringBuffer(""); int j=0, k; while ((k = sn[i].indexOf('%', j)) >= 0) { sb[i].append(sn[i].substring(j, k)); try sb[i].append( (char) Integer.parseInt(sn[i].substring(k+1, k+3), 16)); catch (NumberFormatException e) {} j = k + 3; } sb[i].append(sn[i].substring(j, sn[i].length())); } sn[0] = sb[0].toString(); sn[1] = sb[1].toString(); return sn; } /** Read System.in and convert CGI-format parameters to a * Hashtable of name/value pairs. The length of the data to * be read is determined by the property * CONTENT_LENGTH (preferably) or, if not * present, by the number of bytes available to read. * @see java.util.Hashtable * @see java.lang.System#getProperty */ static public Hashtable cgiParams() { String s = System.getProperty("CONTENT_LENGTH", "0"); int cl; try cl = Integer.parseInt(s); catch (NumberFormatException e) { cl = 0; } // if no content length, this *should* work if (cl == 0) { try cl = System.in.available(); catch (IOException e) {} } if (cl > 0) return cgiParams(cl); else return null; } /** Read System.in and convert CGI-format parameters to a * Hashtable of name/value pairs. The length of the data to * be read is determined by content_length. * @see java.util.Hashtable */ static public Hashtable cgiParams(int content_length) { Hashtable hash = new Hashtable(); char b[] = new char[content_length]; for (int i=0; i < content_length; ++i) { int c; try c = System.in.read(); catch (IOException e) { continue; } if (c < 0) { break; } b[i] = (char) c; } String p = new String(b); String params[] = split(p, "&"); String ss[] = new String[2]; for (int i=0; i < params.length; ++i) { ss = cgiParamToStrings(params[i]); hash.put(ss[0], ss[1]); } return hash; } /** Write a String to a DataOutput source. Strings are transmitted * as an int, the length, followed by the bytes of the String itself. * @see java.io.DataOutput */ static public void writeString(DataOutput d, String s) throws IOException { d.writeInt(s.length()); d.writeBytes(s); } /** Read a String from a DataInput source. The String must have * been sent by StringUtil.writeString. * @see java.io.DataInput */ static public String readString(DataInput d) throws IOException { int len = d.readInt(); if (len == 0) return ""; byte b[] = new byte[len]; d.readFully(b); return new String(b, 0); } /** Convert a fractional String to it's decimal * equivalent. e.g. "2 1/4". */ static public float fractionalToFloat(String s) throws NumberFormatException { StringTokenizer tok = new StringTokenizer(s, " "); float whole = 0; if (!tok.hasMoreTokens()) throw new NumberFormatException(); String p = tok.nextToken(); if (p.indexOf("/") < 0) { whole = Float.valueOf(p).floatValue(); if (!tok.hasMoreTokens()) return whole; p = tok.nextToken(); } StringTokenizer tok2 = new StringTokenizer(p, "/"); float frac = 0; if (tok2.countTokens() != 2) throw new NumberFormatException(); p = tok2.nextToken(); frac = Float.valueOf(p).floatValue(); p = tok2.nextToken(); frac /= Float.valueOf(p).floatValue(); if (whole < 0) return whole - frac; else return whole + frac; } /** Create a string initialized with the contents of a file. */ static public String stringFromFile(String file) throws IOException { File f = new File(file); int len = (int) f.length(); if (len == 0) return ""; byte b[] = new byte[len]; FileInputStream is = new FileInputStream(f); is.read(b); String s = new String(b, 0); is.close(); return s; } /** Store a String in its own file. */ static public void toFile(String s, String file) throws IOException { FileOutputStream os = new FileOutputStream(file); byte b[] = new byte[s.length()]; s.getBytes(0, s.length(), b, 0); os.write(b); os.close(); } /** Returns the index of the matching '{', '[' or '(' character * in the given String. The char to be matched must be in * position startAt in the string. */ static public int indexOfMatched(String s, int startAt) { int cnt=0; char matchChar, c = s.charAt(startAt); if (c == '{') matchChar = '}'; else if (c == '[') matchChar = ']'; else /*if (c == '(')*/ matchChar = ')'; for (int i=startAt+1; i < s.length(); ++i) { if (s.charAt(i) == matchChar) { if (cnt == 0) return i; else --cnt; } else if (s.charAt(i) == c) ++cnt; } return -1; } /** Converts a String to a Hashtable. The String must have been * produced by Hastable.toString(). This method converts both * the key and value to objects of type String. * Useful for writing out Hashtables to permanent storage and then * reading them back in.

* Warning: This will fail miserably if any of the keys or values have * '=' chars in them. * @see java.util.Hashtable#toString() */ static public Hashtable hashtableFromString(String s) { Hashtable h = new Hashtable(); // 5 is the minimum length of a correctly formatted string // (e.g. "{A=1}") if (s.length() < 5) return h; int a=1, b; while (true) { // Search for the next '=' b = s.indexOf('=', a); String key = s.substring(a, b); a = b+1; if (s.charAt(a) == '{') { // This is a sub-list, parse it out and recursively call // ourself b = indexOfMatched(s, a); h.put(key, hashtableFromString(s.substring(a, b+1))); if (s.charAt(b+1) == '}') break; a = b+3; continue; } // Search for the last ',' before the next '=' (this way // we can handle commas embedded in the string). b = s.indexOf('=', a); // If there is no next ',' then we're at the end of the list // so we just need to find the next '}' if (b < 0) b = s.indexOf('}', a); else b = s.lastIndexOf(',', b); String val = s.substring(a, b); h.put(key, val); if (s.charAt(b) == '}') break; a = b+2; } return h; } }