KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > mckoi > util > GeneralParser


1 /**
2  * com.mckoi.util.GeneralParser 30 Oct 1998
3  *
4  * Mckoi SQL Database ( http://www.mckoi.com/database )
5  * Copyright (C) 2000, 2001, 2002 Diehl and Associates, Inc.
6  *
7  * This program is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License
9  * Version 2 as published by the Free Software Foundation.
10  *
11  * This program 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 Version 2 for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * Version 2 along with this program; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
19  *
20  * Change Log:
21  *
22  *
23  */

24
25 package com.mckoi.util;
26
27 import java.text.CharacterIterator JavaDoc;
28 import java.text.ParseException JavaDoc;
29 import java.math.BigDecimal JavaDoc;
30
31 /**
32  * This class provides several static convenience functions for parsing
33  * various types of character sequences. In most cases, we use a
34  * CharacterIterator to represent the sequence of characters being parsed.
35  * <p>
36  * @author Tobias Downer
37  */

38
39 public class GeneralParser {
40
41   /**
42    * These statics represent some information about how many milliseconds are
43    * in various measures of time.
44    */

45   private static final BigDecimal JavaDoc MILLIS_IN_WEEK =
46                                       new BigDecimal JavaDoc(7 * 24 * 60 * 60 * 1000);
47   private static final BigDecimal JavaDoc MILLIS_IN_DAY =
48                                       new BigDecimal JavaDoc(24 * 60 * 60 * 1000);
49   private static final BigDecimal JavaDoc MILLIS_IN_HOUR =
50                                       new BigDecimal JavaDoc(60 * 60 * 1000);
51   private static final BigDecimal JavaDoc MILLIS_IN_MINUTE =
52                                       new BigDecimal JavaDoc(60 * 1000);
53   private static final BigDecimal JavaDoc MILLIS_IN_SECOND =
54                                       new BigDecimal JavaDoc(1000);
55
56   /**
57    * Parses a string of 0 or more digits and appends the digits into the string
58    * buffer.
59    */

60   public static void parseDigitString(CharacterIterator JavaDoc i, StringBuffer JavaDoc digit_str) {
61     char c = i.current();
62     while (Character.isDigit(c)) {
63       digit_str.append(c);
64       c = i.next();
65     }
66   }
67
68   /**
69    * Parses a string of 0 or more words and appends the characters into the
70    * string buffer.
71    */

72   public static void parseWordString(CharacterIterator JavaDoc i,
73                                      StringBuffer JavaDoc word_buffer) {
74     char c = i.current();
75     while (Character.isLetter(c)) {
76       word_buffer.append(c);
77       c = i.next();
78     }
79   }
80
81   /**
82    * Moves the iterator past any white space. White space is ' ', '\t', '\n'
83    * and '\r'.
84    */

85   public static void skipWhiteSpace(CharacterIterator JavaDoc i) {
86     char c = i.current();
87     while (c == ' ' || c == '\t' || c == '\n' || c == '\r') {
88       c = i.next();
89     }
90   }
91
92   /**
93    * This assumes there is a decimal number waiting on the iterator. It
94    * parses the decimal and returns the BigDecimal representation. It throws
95    * a GeneralParseException if we are unable to parse the decimal.
96    */

97   public static BigDecimal JavaDoc parseBigDecimal(CharacterIterator JavaDoc i)
98                                                       throws ParseException JavaDoc {
99     boolean done_decimal = false;
100     StringBuffer JavaDoc str_val = new StringBuffer JavaDoc();
101
102     // We can start with a '-'
103
char c = i.current();
104     if (c == '-') {
105       str_val.append(c);
106       c = i.next();
107     }
108     // We can start or follow with a '.'
109
if (c == '.') {
110       done_decimal = true;
111       str_val.append(c);
112       c = i.next();
113     }
114     // We must be able to parse a digit
115
if (!Character.isDigit(c)) {
116       throw new ParseException JavaDoc("Parsing BigDecimal", i.getIndex());
117     }
118     // Parse the digit string
119
parseDigitString(i, str_val);
120     // Is there a decimal part?
121
c = i.current();
122     if (!done_decimal && c == '.') {
123       str_val.append(c);
124       c = i.next();
125       parseDigitString(i, str_val);
126     }
127
128     return new BigDecimal JavaDoc(new String JavaDoc(str_val));
129   }
130
131   /**
132    * Parses a time grammer waiting on the character iterator. The grammer is
133    * quite simple. It allows for us to specify quite precisely some unit of
134    * time measure and convert it to a Java understandable form. It returns the
135    * number of milliseconds that the unit of time represents.
136    * For example, the string '2.5 hours' would return:
137    * 2.5 hours * 60 minutes * 60 seconds * 1000 milliseconds = 9000000
138    * <p>
139    * To construct a valid time measure, you must supply a sequence of time
140    * measurements. The valid time measurements are 'week(s)', 'day(s)',
141    * 'hour(s)', 'minute(s)', 'second(s)', 'millisecond(s)'. To construct a
142    * time, we simply concatinate the measurements together. For example,
143    * '3 days 22 hours 9.5 minutes'
144    * <p>
145    * It accepts any number of time measurements, but not duplicates of the
146    * same.
147    * <p>
148    * The time measures are case insensitive. It is a little lazy how it reads
149    * the grammer. We could for example enter '1 hours 40 second' or even
150    * more extreme, '1 houraboutit 90 secondilianit' both of which are
151    * acceptable!
152    * <p>
153    * This method will keep on parsing the string until the end of the iterator
154    * is reached or a non-numeric time measure is found. It throws a
155    * ParseException if an invalid time measure is found or a number is invalid
156    * (eg. -3 days).
157    * <p>
158    * LOCALE ISSUE: This will likely be a difficult method to localise.
159    */

160   public static BigDecimal JavaDoc parseTimeMeasure(CharacterIterator JavaDoc i)
161                                                         throws ParseException JavaDoc {
162     boolean time_measured = false;
163     BigDecimal JavaDoc time_measure = new BigDecimal JavaDoc(0);
164     boolean[] time_parsed = new boolean[6];
165     StringBuffer JavaDoc word_buffer = new StringBuffer JavaDoc();
166     BigDecimal JavaDoc num;
167
168     while (true) {
169       // Parse the number
170
skipWhiteSpace(i);
171       try {
172         num = parseBigDecimal(i);
173       }
174       catch (ParseException JavaDoc e) {
175         // If we can't parse a number, then return with the current time if
176
// any time has been parsed.
177
if (time_measured) {
178           return time_measure;
179         }
180         else {
181           throw new ParseException JavaDoc("No time value found", i.getIndex());
182         }
183       }
184       if (num.signum() < 0) {
185         throw new ParseException JavaDoc("Invalid time value: " + num, i.getIndex());
186       }
187
188       skipWhiteSpace(i);
189
190       // Parse the time measure
191
word_buffer.setLength(0);
192       parseWordString(i, word_buffer);
193
194       String JavaDoc str = new String JavaDoc(word_buffer).toLowerCase();
195       if ((str.startsWith("week") ||
196            str.equals("w")) &&
197           !time_parsed[0]) {
198         time_measure = time_measure.add(num.multiply(MILLIS_IN_WEEK));
199         time_parsed[0] = true;
200       }
201       else if ((str.startsWith("day") ||
202                 str.equals("d")) &&
203                !time_parsed[1]) {
204         time_measure = time_measure.add(num.multiply(MILLIS_IN_DAY));
205         time_parsed[1] = true;
206       }
207       else if ((str.startsWith("hour") ||
208                 str.startsWith("hr") ||
209                 str.equals("h")) &&
210                !time_parsed[2]) {
211         time_measure = time_measure.add(num.multiply(MILLIS_IN_HOUR));
212         time_parsed[2] = true;
213       }
214       else if ((str.startsWith("minute") ||
215                 str.startsWith("min") ||
216                 str.equals("m")) &&
217                !time_parsed[3]) {
218         time_measure = time_measure.add(num.multiply(MILLIS_IN_MINUTE));
219         time_parsed[3] = true;
220       }
221       else if ((str.startsWith("second") ||
222                 str.startsWith("sec") ||
223                 str.equals("s")) &&
224                !time_parsed[4]) {
225         time_measure = time_measure.add(num.multiply(MILLIS_IN_SECOND));
226         time_parsed[4] = true;
227       }
228       else if ((str.startsWith("millisecond") ||
229                 str.equals("ms")) &&
230                !time_parsed[5]) {
231         time_measure = time_measure.add(num);
232         time_parsed[5] = true;
233       }
234       else {
235         throw new ParseException JavaDoc("Unknown time measure: " + str, i.getIndex());
236       }
237       time_measured = true;
238
239     }
240
241   }
242
243 }
244
Popular Tags