KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > oro > text > regex > Perl5Substitution


1 package org.apache.oro.text.regex;
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.util.Vector JavaDoc;
61
62 /**
63  * Perl5Substitution implements a Substitution consisting of a
64  * literal string, but allowing Perl5 variable interpolation referencing
65  * saved groups in a match. This class is intended for use with
66  * {@link Util#substitute Util.substitute}.
67  * <p>
68  * The substitution string may contain variable interpolations referring
69  * to the saved parenthesized groups of the search pattern.
70  * A variable interpolation is denoted by <b>$1</b>, or <b>$2</b>,
71  * or <b>$3</b>, etc. If you don want such expressions to be
72  * interpreted literally, you should set the <b> numInterpolations </b>
73  * parameter to <b> INTERPOLATE_NONE </b>. It is easiest to explain
74  * what an interpolated variable does by giving an example:
75  * <ul>
76  * Suppose you have the pattern <b>b\d+:</b> and you want to substitute
77  * the <b>b</b>'s for <b>a</b>'s and the colon for a dash in parts of
78  * your input matching the pattern. You can do this by changing the
79  * pattern to <b>b(\d+):</b> and using the substitution expression
80  * <b>a$1-</b>. When a substitution is made, the <b>$1</b> means
81  * "Substitute whatever was matched by the first saved group of the
82  * matching pattern." An input of <b>b123:</b> after substitution
83  * would yield a result of <b>a123-</b>. But there's a little more
84  * to be aware of. If you set the <b>numInterpolations</b> parameter to
85  * <b>INTERPOLATE_ALL</b>, then every time a match is found, the
86  * interpolation variables are computed relative to that match.
87  * But if <b>numInterpolations</b> is set to some positive integer, then
88  * only the interpolation variables for the first <b>numInterpolations</b>
89  * matches are computed relative to the most recent match. After that,
90  * the remaining substitutions have their variable interpolations performed
91  * relative to the <b> numInterpolations </b>'th match. So using the
92  * previously mentioned pattern and substitution expression, if you have
93  * an input of <pre><b>Tank b123: 85 Tank b256: 32 Tank b78: 22</b></pre>
94  * and use a <b> numInterpolations </b> value of <b>INTERPOLATE_ALL</b> and
95  * <b> numSubs </b> value (see
96  * {@link Util#substitute Util.substitute})
97  * of <b> SUBSTITUTE_ALL</b>, then your result will be:
98  * <pre><b>Tank a123- 85 Tank a256- 32 Tank a78- 22</b></pre>
99  * But if you set <b> numInterpolations </b> to 2 and keep
100  * <b> numSubs </b> with a value of <b>SUBSTITUTE_ALL</b>, your result is:
101  * <pre><b>Tank a123- 85 Tank a256- 32 Tank a256- 22</b></pre>
102  * Notice how the last substitution uses the same value for <b>$1</b>
103  * as the second substitution.
104  * </ul>
105  * <p>
106  * A final thing to keep in mind is that if you use an interpolation variable
107  * that corresponds to a group not contained in the match, then it is
108  * interpreted literally. So given the regular expression from the
109  * example, and a substitution expression of <b>a$2-</b>, the result
110  * of the last sample input would be:
111  * <pre><b>Tank a$2- 85 Tank a$2- 32 Tank a$2- 22</b></pre>
112  * Also, <b>$0</b> is always interpreted literally.
113
114  @author <a HREF="dfs@savarese.org">Daniel F. Savarese</a>
115  @version $Id: Perl5Substitution.java,v 1.1.1.1 2000/07/23 23:08:54 jon Exp $
116
117  * @see Substitution
118  * @see Util
119  * @see Util#substitute
120  * @see Substitution
121  * @see StringSubstitution
122  */

123 public class Perl5Substitution extends StringSubstitution {
124   /**
125    * A constant used when creating a Perl5Substitution indicating that
126    * interpolation variables should be computed relative to the most
127    * recent pattern match.
128    */

129   public static final int INTERPOLATE_ALL = 0;
130
131   /**
132    * A constant used when creating a Perl5Substitution indicating that
133    * interpolation variables should be interpreted literally, effectively
134    * disabling interpolation.
135    */

136   public static final int INTERPOLATE_NONE = -1;
137
138   int _numInterpolations;
139   Vector JavaDoc _substitutions;
140   transient String JavaDoc _lastInterpolation;
141
142   static Vector JavaDoc _parseSubs(String JavaDoc sub) {
143     boolean saveDigits, storedInterpolation;
144     int current;
145     char[] str;
146     Vector JavaDoc subs;
147     StringBuffer JavaDoc numBuffer, strBuffer;
148
149     subs = new Vector JavaDoc(5);
150     numBuffer = new StringBuffer JavaDoc(5);
151     strBuffer = new StringBuffer JavaDoc(10);
152
153     str = sub.toCharArray();
154     current = 0;
155     saveDigits = false;
156     storedInterpolation = false;
157
158     while(current < str.length) {
159       if(saveDigits && Character.isDigit(str[current])) {
160     numBuffer.append(str[current]);
161
162     if(strBuffer.length() > 0) {
163       subs.addElement(strBuffer.toString());
164       strBuffer.setLength(0);
165     }
166       } else {
167     if(saveDigits) {
168       try {
169         subs.addElement(new Integer JavaDoc(numBuffer.toString()));
170         storedInterpolation = true;
171       } catch(NumberFormatException JavaDoc e) {
172         subs.addElement(numBuffer.toString());
173       }
174
175       numBuffer.setLength(0);
176       saveDigits = false;
177     }
178
179     if(str[current] == '$' &&
180        current + 1 < str.length && str[current + 1] != '0' &&
181        Character.isDigit(str[current + 1]))
182       saveDigits = true;
183     else
184       strBuffer.append(str[current]);
185       }
186
187       ++current;
188     } // end while
189

190
191     if(saveDigits) {
192       try {
193     subs.addElement(new Integer JavaDoc(numBuffer.toString()));
194     storedInterpolation = true;
195       } catch(NumberFormatException JavaDoc e) {
196     subs.addElement(numBuffer.toString());
197       }
198     } else if(strBuffer.length() > 0)
199       subs.addElement(strBuffer.toString());
200
201     return (storedInterpolation ? subs : null);
202   }
203
204
205   String JavaDoc _finalInterpolatedSub(MatchResult result) {
206     StringBuffer JavaDoc buffer = new StringBuffer JavaDoc(10);
207     _calcSub(buffer, result);
208     return buffer.toString();
209   }
210
211   void _calcSub(StringBuffer JavaDoc buffer, MatchResult result) {
212     int size, element, value;
213     Object JavaDoc obj;
214     Integer JavaDoc integer;
215     String JavaDoc group;
216
217     size = _substitutions.size();
218
219     for(element=0; element < size; element++) {
220       obj = _substitutions.elementAt(element);
221
222       if(obj instanceof String JavaDoc)
223     buffer.append(obj);
224       else {
225     integer = (Integer JavaDoc)obj;
226     value = integer.intValue();
227
228     if(value > 0 && value < result.groups()) {
229       group = result.group(value);
230
231       if(group != null)
232         buffer.append(group);
233     } else {
234       buffer.append('$');
235       buffer.append(value);
236     }
237       }
238     }
239   }
240
241
242   /**
243    * Default constructor initializing substitution to a zero length
244    * String and the number of interpolations to
245    * {@link #INTERPOLATE_ALL}.
246    */

247   public Perl5Substitution() {
248     this("", INTERPOLATE_ALL);
249   }
250
251   /**
252    * Creates a Perl5Substitution using the specified substitution
253    * and setting the number of interpolations to
254    * {@link #INTERPOLATE_ALL}.
255    * <p>
256    * @param substitution The string to use as a substitution.
257    */

258   public Perl5Substitution(String JavaDoc substitution) {
259     this(substitution, INTERPOLATE_ALL);
260   }
261
262   /**
263    * Creates a Perl5Substitution using the specified substitution
264    * and setting the number of interpolations to the specified value.
265    * <p>
266    * @param substitution The string to use as a substitution.
267    * @param numInterpolations
268    * If set to <b>INTERPOLATE_NONE</b>, interpolation variables are
269    * interpreted literally and not as references to the saved
270    * parenthesized groups of a pattern match. If set to
271    * <b> INTERPOLATE_ALL </b>, all variable interpolations
272    * are computed relative to the pattern match responsible for
273    * the current substitution. If set to a positive integer,
274    * the first <b> numInterpolations </b> substitutions have
275    * their variable interpolation performed relative to the
276    * most recent match, but the remaining substitutions have
277    * their variable interpolations performed relative to the
278    * <b> numInterpolations </b>'th match.
279    */

280   public Perl5Substitution(String JavaDoc substitution, int numInterpolations) {
281     setSubstitution(substitution, numInterpolations);
282   }
283
284
285   /**
286    * Sets the substitution represented by this Perl5Substitution, also
287    * setting the number of interpolations to
288    * {@link #INTERPOLATE_ALL}.
289    * You should use this method in order to avoid repeatedly allocating new
290    * Perl5Substitutions. It is recommended that you allocate a single
291    * Perl5Substitution and reuse it by using this method when appropriate.
292    * <p>
293    * @param substitution The string to use as a substitution.
294    */

295   public void setSubstitution(String JavaDoc substitution) {
296     setSubstitution(substitution, INTERPOLATE_ALL);
297   }
298
299
300   /**
301    * Sets the substitution represented by this Perl5Substitution, also
302    * setting the number of interpolations to the specified value.
303    * You should use this method in order to avoid repeatedly allocating new
304    * Perl5Substitutions. It is recommended that you allocate a single
305    * Perl5Substitution and reuse it by using this method when appropriate.
306    * <p>
307    * @param substitution The string to use as a substitution.
308    * @param numInterpolations
309    * If set to <b>INTERPOLATE_NONE</b>, interpolation variables are
310    * interpreted literally and not as references to the saved
311    * parenthesized groups of a pattern match. If set to
312    * <b> INTERPOLATE_ALL </b>, all variable interpolations
313    * are computed relative to the pattern match responsible for
314    * the current substitution. If set to a positive integer,
315    * the first <b> numInterpolations </b> substitutions have
316    * their variable interpolation performed relative to the
317    * most recent match, but the remaining substitutions have
318    * their variable interpolations performed relative to the
319    * <b> numInterpolations </b>'th match.
320    */

321   public void setSubstitution(String JavaDoc substitution, int numInterpolations) {
322     super.setSubstitution(substitution);
323     _numInterpolations = numInterpolations;
324
325     if(numInterpolations != INTERPOLATE_NONE &&
326        substitution.indexOf('$') != -1)
327       _substitutions = _parseSubs(substitution);
328     else
329       _substitutions = null;
330     _lastInterpolation = null;
331   }
332
333
334   /**
335    * Appends the substitution to a buffer containing the original input
336    * with substitutions applied for the pattern matches found so far.
337    * See
338    * {@link Substitution#appendSubstitution Substitution.appendSubstition()}
339    * for more details regarding the expected behavior of this method.
340    * <p>
341    * @param appendBuffer The buffer containing the new string resulting
342    * from performing substitutions on the original input.
343    * @param match The current match causing a substitution to be made.
344    * @param substitutionCount The number of substitutions that have been
345    * performed so far by Util.substitute.
346    * @param originalInput The original input upon which the substitutions are
347    * being performed.
348    * @param matcher The PatternMatcher used to find the current match.
349    * @param pattern The Pattern used to find the current match.
350    */

351   public void appendSubstitution(StringBuffer JavaDoc appendBuffer, MatchResult match,
352                  int substitutionCount, String JavaDoc originalInput,
353                  PatternMatcher matcher, Pattern pattern)
354   {
355     if(_substitutions == null) {
356       super.appendSubstitution(appendBuffer, match, substitutionCount,
357                    originalInput, matcher, pattern);
358       return;
359     }
360
361     if(_numInterpolations < 1 || substitutionCount < _numInterpolations)
362       _calcSub(appendBuffer, match);
363     else {
364       if(substitutionCount == _numInterpolations)
365     _lastInterpolation = _finalInterpolatedSub(match);
366       appendBuffer.append(_lastInterpolation);
367     }
368   }
369
370 }
371
Popular Tags