001: /*-------------------------------------------------------------------------
002: *
003: * Copyright (c) 2003-2005, PostgreSQL Global Development Group
004: *
005: * IDENTIFICATION
006: * $PostgreSQL: pgjdbc/org/postgresql/util/PGtokenizer.java,v 1.11 2005/01/11 08:25:49 jurka Exp $
007: *
008: *-------------------------------------------------------------------------
009: */
010: package org.postgresql.util;
011:
012: import java.util.Vector;
013:
014: /**
015: * This class is used to tokenize the text output of org.postgres.
016: * It's mainly used by the geometric classes, but is useful in parsing any
017: * output from custom data types output from org.postgresql.
018: *
019: * @see org.postgresql.geometric.PGbox
020: * @see org.postgresql.geometric.PGcircle
021: * @see org.postgresql.geometric.PGlseg
022: * @see org.postgresql.geometric.PGpath
023: * @see org.postgresql.geometric.PGpoint
024: * @see org.postgresql.geometric.PGpolygon
025: */
026: public class PGtokenizer {
027: // Our tokens
028: protected Vector tokens;
029:
030: /*
031: * Create a tokeniser.
032: *
033: * <p>We could have used StringTokenizer to do this, however, we needed to
034: * handle nesting of '(' ')' '[' ']' '<' and '>' as these are used
035: * by the geometric data types.
036: *
037: * @param string containing tokens
038: * @param delim single character to split the tokens
039: */
040: public PGtokenizer(String string, char delim) {
041: tokenize(string, delim);
042: }
043:
044: /*
045: * This resets this tokenizer with a new string and/or delimiter.
046: *
047: * @param string containing tokens
048: * @param delim single character to split the tokens
049: */
050: public int tokenize(String string, char delim) {
051: tokens = new Vector();
052:
053: // nest holds how many levels we are in the current token.
054: // if this is > 0 then we don't split a token when delim is matched.
055: //
056: // The Geometric datatypes use this, because often a type may have others
057: // (usualls PGpoint) imbedded within a token.
058: //
059: // Peter 1998 Jan 6 - Added < and > to the nesting rules
060: int nest = 0, p, s;
061:
062: for (p = 0, s = 0; p < string.length(); p++) {
063: char c = string.charAt(p);
064:
065: // increase nesting if an open character is found
066: if (c == '(' || c == '[' || c == '<')
067: nest++;
068:
069: // decrease nesting if a close character is found
070: if (c == ')' || c == ']' || c == '>')
071: nest--;
072:
073: if (nest == 0 && c == delim) {
074: tokens.addElement(string.substring(s, p));
075: s = p + 1; // +1 to skip the delimiter
076: }
077:
078: }
079:
080: // Don't forget the last token ;-)
081:
082: if (s < string.length())
083: tokens.addElement(string.substring(s));
084:
085: return tokens.size();
086: }
087:
088: /*
089: * @return the number of tokens available
090: */
091: public int getSize() {
092: return tokens.size();
093: }
094:
095: /*
096: * @param n Token number ( 0 ... getSize()-1 )
097: * @return The token value
098: */
099: public String getToken(int n) {
100: return (String) tokens.elementAt(n);
101: }
102:
103: /*
104: * This returns a new tokenizer based on one of our tokens.
105: *
106: * The geometric datatypes use this to process nested tokens (usually
107: * PGpoint).
108: *
109: * @param n Token number ( 0 ... getSize()-1 )
110: * @param delim The delimiter to use
111: * @return A new instance of PGtokenizer based on the token
112: */
113: public PGtokenizer tokenizeToken(int n, char delim) {
114: return new PGtokenizer(getToken(n), delim);
115: }
116:
117: /*
118: * This removes the lead/trailing strings from a string
119: * @param s Source string
120: * @param l Leading string to remove
121: * @param t Trailing string to remove
122: * @return String without the lead/trailing strings
123: */
124: public static String remove(String s, String l, String t) {
125: if (s.startsWith(l))
126: s = s.substring(l.length());
127: if (s.endsWith(t))
128: s = s.substring(0, s.length() - t.length());
129: return s;
130: }
131:
132: /*
133: * This removes the lead/trailing strings from all tokens
134: * @param l Leading string to remove
135: * @param t Trailing string to remove
136: */
137: public void remove(String l, String t) {
138: for (int i = 0; i < tokens.size(); i++) {
139: tokens.setElementAt(remove((String) tokens.elementAt(i), l,
140: t), i);
141: }
142: }
143:
144: /*
145: * Removes ( and ) from the beginning and end of a string
146: * @param s String to remove from
147: * @return String without the ( or )
148: */
149: public static String removePara(String s) {
150: return remove(s, "(", ")");
151: }
152:
153: /*
154: * Removes ( and ) from the beginning and end of all tokens
155: * @return String without the ( or )
156: */
157: public void removePara() {
158: remove("(", ")");
159: }
160:
161: /*
162: * Removes [ and ] from the beginning and end of a string
163: * @param s String to remove from
164: * @return String without the [ or ]
165: */
166: public static String removeBox(String s) {
167: return remove(s, "[", "]");
168: }
169:
170: /*
171: * Removes [ and ] from the beginning and end of all tokens
172: * @return String without the [ or ]
173: */
174: public void removeBox() {
175: remove("[", "]");
176: }
177:
178: /*
179: * Removes < and > from the beginning and end of a string
180: * @param s String to remove from
181: * @return String without the < or >
182: */
183: public static String removeAngle(String s) {
184: return remove(s, "<", ">");
185: }
186:
187: /*
188: * Removes < and > from the beginning and end of all tokens
189: * @return String without the < or >
190: */
191: public void removeAngle() {
192: remove("<", ">");
193: }
194: }
|