KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > oro > text > MatchActionProcessor


1 package org.apache.oro.text;
2
3 /* ====================================================================
4  * The Apache Software License, Version 1.1
5  *
6  * Copyright (c) 2000 The Apache Software Foundation. All rights
7  * reserved.
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted provided that the following conditions
11  * are met:
12  *
13  * 1. Redistributions of source code must retain the above copyright
14  * notice, this list of conditions and the following disclaimer.
15  *
16  * 2. Redistributions in binary form must reproduce the above copyright
17  * notice, this list of conditions and the following disclaimer in
18  * the documentation and/or other materials provided with the
19  * distribution.
20  *
21  * 3. The end-user documentation included with the redistribution,
22  * if any, must include the following acknowledgment:
23  * "This product includes software developed by the
24  * Apache Software Foundation (http://www.apache.org/)."
25  * Alternately, this acknowledgment may appear in the software itself,
26  * if and wherever such third-party acknowledgments normally appear.
27  *
28  * 4. The names "Apache" and "Apache Software Foundation", "Jakarta-Oro"
29  * must not be used to endorse or promote products derived from this
30  * software without prior written permission. For written
31  * permission, please contact apache@apache.org.
32  *
33  * 5. Products derived from this software may not be called "Apache"
34  * or "Jakarta-Oro", nor may "Apache" or "Jakarta-Oro" appear in their
35  * name, without prior written permission of the Apache Software Foundation.
36  *
37  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
38  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
39  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
40  * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
41  * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
42  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
43  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
44  * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
45  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
46  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
47  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
48  * SUCH DAMAGE.
49  * ====================================================================
50  *
51  * This software consists of voluntary contributions made by many
52  * individuals on behalf of the Apache Software Foundation. For more
53  * information on the Apache Software Foundation, please see
54  * <http://www.apache.org/>.
55  *
56  * Portions of this software are based upon software originally written
57  * by Daniel F. Savarese. We appreciate his contributions.
58  */

59  
60 import java.io.*;
61 import java.util.*;
62
63 import org.apache.oro.text.regex.*;
64
65 /**
66  * The MatchActionProcessor class provides AWK-like line by line filtering
67  * of a text stream, pattern action pair association, and field splitting
68  * based on a registered separator. However, the class can be used with
69  * any compatible PatternMatcher/PatternCompiler implementations and
70  * need not use the AWK matching classes in org.apache.oro.text.awk. In fact,
71  * the default matcher and compiler used by the class are Perl5Matcher and
72  * Perl5Compiler from org.apache.oro.text.regex.
73  * <p>
74  * To completely understand how to use MatchActionProcessor, you should first
75  * look at {@link MatchAction} and {@link MatchActionInfo}.
76  * A MatchActionProcessor is first initialized with
77  * the desired PatternCompiler and PatternMatcher instances to use to compile
78  * patterns and perform matches. Then, optionally, a field separator may
79  * be registered with {@link #setFieldSeparator setFieldSeparator()}
80  * Finally, as many pattern action pairs as desired are registerd with
81  * {@link #addAction addAction()} before processing the input
82  * with {@link #processMatches processMatches()}. Pattern action
83  * pairs are processed in the order they were registered.
84  * <p>
85  * The look of added actions can closely mirror that of AWK when anonymous
86  * classes are used. Here's an example of how you might use
87  * MatchActionProcessor to extract only the second column of a semicolon
88  * delimited file:
89  * <p>
90  * <pre>
91  * import java.io.*;
92  *
93  * import org.apache.oro.text.*;
94  * import org.apache.oro.text.regex.*;
95  *
96  * public final class semicolon {
97  *
98  * public static final void main(String[] args) {
99  * MatchActionProcessor processor = new MatchActionProcessor();
100  *
101  * try {
102  * processor.setFieldSeparator(";");
103  * // Using a null pattern means to perform the action for every line.
104  * processor.addAction(null, new MatchAction() {
105  * public void processMatch(MatchActionInfo info) {
106  * // We assume the second column exists
107  * info.output.println(info.fields.elementAt(1));
108  * }
109  * });
110  * } catch(MalformedPatternException e) {
111  * e.printStackTrace();
112  * System.exit(1);
113  * }
114  *
115  * try {
116  * processor.processMatches(System.in, System.out);
117  * } catch(IOException e) {
118  * e.printStackTrace();
119  * System.exit(1);
120  * }
121  * }
122  *}
123  * </pre>
124  * You can redirect the following sample input to stdin to test the code:
125  * <pre>
126  * 1;Trenton;New Jersey
127  * 2;Annapolis;Maryland
128  * 3;Austin;Texas
129  * 4;Richmond;Virginia
130  * 5;Harrisburg;Pennsylvania
131  * 6;Honolulu;Hawaii
132  * 7;Santa Fe;New Mexico
133  * </pre>
134
135  @author <a HREF="dfs@savarese.org">Daniel F. Savarese</a>
136  @version $Id: MatchActionProcessor.java,v 1.1.1.1 2000/07/23 23:08:49 jon Exp $
137
138  * @see MatchAction
139  * @see MatchActionInfo
140  */

141 public final class MatchActionProcessor {
142   private Pattern __fieldSeparator = null;
143   private PatternCompiler __compiler;
144   private PatternMatcher __matcher;
145   // If a pattern is null, it means to do it for every line.
146
private Vector __patterns = new Vector();
147   private Vector __actions = new Vector();
148
149   private MatchAction __defaultAction = new DefaultMatchAction();
150
151   /**
152    * Creates a new MatchActionProcessor instance initialized with the specified
153    * pattern compiler and matcher. The field separator is set to null by
154    * default, which means that matched lines will not be split into separate
155    * fields unless the field separator is set with
156    * {@link #setFieldSeparator setFieldSeparator()}.
157    * <p>
158    * @param compiler The PatternCompiler to use to compile registered
159    * patterns.
160    * @param matcher The PatternMatcher to use when searching for matches.
161    */

162   public MatchActionProcessor(PatternCompiler compiler, PatternMatcher matcher)
163   {
164     __compiler = compiler;
165     __matcher = matcher;
166   }
167
168   /**
169    * Default constructor for MatchActionProcessor. Same as calling
170    * <blockquote><code>
171    * MatchActionProcessor(new Perl5Compiler(), new Perl5Matcher());
172    * </code></blockquote>
173    */

174   public MatchActionProcessor() {
175     this(new Perl5Compiler(), new Perl5Matcher());
176   }
177
178
179   /**
180    * Registers a pattern action pair, providing options to be used to
181    * compile the pattern. If a pattern is null, the action
182    * is performed for every line of input.
183    * <p>
184    * @param pattern The pattern to bind to an action.
185    * @param options The compilation options to use for the pattern.
186    * @param action The action to associate with the pattern.
187    * @exception MalformedPatternException If the pattern cannot be compiled.
188    */

189   public void addAction(String JavaDoc pattern, int options, MatchAction action)
190        throws MalformedPatternException
191   {
192     if(pattern != null)
193       __patterns.addElement(__compiler.compile(pattern, options));
194     else
195       __patterns.addElement(null);
196     __actions.addElement(action);
197   }
198
199   /**
200    * Binds a patten to the default action, providing options to be
201    * used to compile the pattern. The default action is to simply print
202    * the matched line to the output. If a pattern is null, the action
203    * is performed for every line of input.
204    * <p>
205    * @param pattern The pattern to bind to an action.
206    * @param options The compilation options to use for the pattern.
207    * @exception MalformedPatternException If the pattern cannot be compiled.
208    */

209   public void addAction(String JavaDoc pattern, int options)
210        throws MalformedPatternException
211   {
212     addAction(pattern, options, __defaultAction);
213   }
214
215   /**
216    * Binds a patten to the default action. The default action is to simply
217    * print the matched line to the output. If a pattern is null, the action
218    * is performed for every line of input.
219    * <p>
220    * @param pattern The pattern to bind to an action.
221    * @exception MalformedPatternException If the pattern cannot be compiled.
222    */

223   public void addAction(String JavaDoc pattern) throws MalformedPatternException {
224     addAction(pattern, 0);
225   }
226
227
228   /**
229    * Registers a pattern action pair. If a pattern is null, the action
230    * is performed for every line of input.
231    * <p>
232    * @param pattern The pattern to bind to an action.
233    * @param action The action to associate with the pattern.
234    * @exception MalformedPatternException If the pattern cannot be compiled.
235    */

236   public void addAction(String JavaDoc pattern, MatchAction action)
237        throws MalformedPatternException
238   {
239     addAction(pattern, 0, action);
240   }
241
242   /**
243    * Sets the field separator to use when splitting a line into fields.
244    * If the field separator is never set, or set to null, matched input
245    * lines are not split into fields.
246    * <p>
247    * @param separator A regular expression defining the field separator.
248    * @param options The options to use when compiling the separator.
249    * @exception MalformedPatternException If the separator cannot be compiled.
250    */

251   public void setFieldSeparator(String JavaDoc separator, int options)
252        throws MalformedPatternException
253   {
254     if(separator == null) {
255       __fieldSeparator = null;
256       return;
257     }
258     __fieldSeparator = __compiler.compile(separator, options);
259   }
260
261
262   /**
263    * Sets the field separator to use when splitting a line into fields.
264    * If the field separator is never set, or set to null, matched input
265    * lines are not split into fields.
266    * <p>
267    * @param separator A regular expression defining the field separator.
268    * @exception MalformedPatternException If the separator cannot be compiled.
269    */

270   public void setFieldSeparator(String JavaDoc separator)
271        throws MalformedPatternException
272   {
273     setFieldSeparator(separator, 0);
274   }
275
276
277   /**
278    * This method reads the provided input one line at a time and for
279    * every registered pattern that is contained in the line it executes
280    * the associated MatchAction's processMatch() method. If a field
281    * separator has been defined with
282    * {@link #setFieldSeparator setFieldSeparator()}, the
283    * fields member of the MatchActionInfo instance passed to the
284    * processMatch() method is set to a Vector of Strings containing
285    * the split fields of the line. Otherwise the fields member is set
286    * to null. If no match was performed to invoke the action (i.e.,
287    * a null pattern was registered), then the match member is set
288    * to null. Otherwise, the match member will contain the result of
289    * the match.
290    * <p>
291    * The input stream, having been exhausted, is closed right before the
292    * method terminates and the output stream is flushed.
293    * <p>
294    * @see MatchActionInfo
295    * @param input The input stream from which to read lines.
296    * @param output Where to send output.
297    * @exception IOException If an error occurs while reading input
298    * or writing output.
299    */

300   public void processMatches(InputStream input, OutputStream output)
301        throws IOException
302   {
303     int patternCount, current;
304     LineNumberReader reader =
305       new LineNumberReader(new InputStreamReader(input));
306     PrintWriter writer = new PrintWriter(output);
307     MatchActionInfo info = new MatchActionInfo();
308     Object JavaDoc obj;
309     Pattern pattern;
310     MatchAction action;
311
312     // Set those things that will not change.
313
info.matcher = __matcher;
314     info.fieldSeparator = __fieldSeparator;
315     info.input = reader;
316     info.output = writer;
317     info.fields = null;
318     patternCount = __patterns.size();
319
320     info.lineNumber = 0;
321
322     while((info.line = reader.readLine()) != null) {
323       info.charLine = info.line.toCharArray();
324       for(current=0; current < patternCount; current++) {
325     obj = __patterns.elementAt(current);
326     // If a pattern is null, it means to do it for every line.
327
if(obj != null) {
328       pattern = (Pattern)__patterns.elementAt(current);
329       if(__matcher.contains(info.charLine, pattern)) {
330         info.match = __matcher.getMatch();
331         info.lineNumber = reader.getLineNumber();
332         if(__fieldSeparator != null)
333           info.fields = Util.split(__matcher, __fieldSeparator, info.line);
334         action = (MatchAction)__actions.elementAt(current);
335         action.processMatch(info);
336       }
337     } else {
338       info.match = null;
339       info.lineNumber = reader.getLineNumber();
340       if(__fieldSeparator != null)
341         info.fields = Util.split(__matcher, __fieldSeparator, info.line);
342       action = (MatchAction)__actions.elementAt(current);
343       action.processMatch(info);
344     }
345       }
346     }
347
348     // Flush output but don't close, close input since we reached end.
349
writer.flush();
350     reader.close();
351   }
352
353
354 }
355
Popular Tags