/*
* 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; } }