KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > freemarker > core > RegexBuiltins


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

52
53 package freemarker.core;
54
55 import java.util.*;
56 import java.util.regex.*;
57 import freemarker.template.*;
58 import freemarker.template.utility.StringUtil;
59
60
61 /**
62  * This is a first-pass implementation of regular expression support.
63  * It is subject to change based on community feedback.
64  * In that sense, use it at your own risk.
65  * @version $Id: RegexBuiltins.java,v 1.14 2005/06/01 22:39:07 ddekany Exp $
66  * @author Jonathan Revusky
67  */

68 abstract class RegexBuiltins {
69     
70     static HashMap patternLookup = new HashMap();
71     static LinkedList patterns = new LinkedList();
72     static final int PATTERN_CACHE_SIZE=100;
73     
74     static Pattern getPattern(String JavaDoc patternString, String JavaDoc flagString) throws TemplateModelException {
75         int flags = 0;
76         String JavaDoc patternKey = patternString + (char) 0 + flagString;
77         Pattern result = (Pattern) patternLookup.get(patternKey);
78         if (result != null) {
79             return result;
80         }
81         if (flagString == null || flagString.length() == 0) {
82             try {
83                 result = Pattern.compile(patternString);
84             } catch (PatternSyntaxException e) {
85                 throw new TemplateModelException(e);
86             }
87         }
88         else {
89             if (flagString.indexOf('i') >=0) {
90                 flags = flags | Pattern.CASE_INSENSITIVE;
91             }
92             if (flagString.indexOf('m') >=0) {
93                 flags = flags | Pattern.MULTILINE;
94             }
95             if (flagString.indexOf('c') >=0) {
96                 flags = flags | Pattern.COMMENTS;
97             }
98             if (flagString.indexOf('s') >=0) {
99                 flags = flags | Pattern.DOTALL;
100             }
101             try {
102                 result = Pattern.compile(patternString, flags);
103             } catch (PatternSyntaxException e) {
104                 throw new TemplateModelException(e);
105             }
106         }
107         patterns.add(patternKey);
108         patternLookup.put(patternKey, result);
109         if (patterns.size() > PATTERN_CACHE_SIZE) {
110             Object JavaDoc first = patterns.removeFirst();
111             patterns.remove(first);
112         }
113         return result;
114     }
115     
116     static class matchesBI extends BuiltIn {
117         TemplateModel _getAsTemplateModel(Environment env) throws TemplateException {
118             TemplateModel targetModel = target.getAsTemplateModel(env);
119             assertNonNull(targetModel, this, env);
120             if (!(targetModel instanceof TemplateScalarModel)) {
121                 throw invalidTypeException(targetModel, target, env, "string");
122             }
123             return new MatcherBuilder((TemplateScalarModel) targetModel);
124         }
125     }
126     
127     static class groupsBI extends BuiltIn {
128         TemplateModel _getAsTemplateModel(Environment env) throws TemplateException {
129             TemplateModel targetModel = target.getAsTemplateModel(env);
130             assertNonNull(targetModel, this, env);
131             if (targetModel instanceof RegexMatchModel) {
132                 return ((RegexMatchModel) targetModel).getGroups();
133             }
134             if (targetModel instanceof RegexMatchModel.Match) {
135                 return ((RegexMatchModel.Match) targetModel).subs;
136             }
137             throw invalidTypeException(targetModel, target, env, "a regular expression matcher");
138         }
139     }
140     
141     
142     static class replace_reBI extends BuiltIn {
143         TemplateModel _getAsTemplateModel(Environment env)
144                 throws TemplateException {
145             TemplateModel model = target.getAsTemplateModel(env);
146             if (model instanceof TemplateScalarModel) {
147                 return new ReplaceMethod(((TemplateScalarModel) model).getAsString());
148             }
149             throw invalidTypeException(model, target, env, "string");
150         }
151     }
152     
153     static class split_reBI extends BuiltIn {
154         TemplateModel _getAsTemplateModel(Environment env)
155                 throws TemplateException {
156             TemplateModel model = target.getAsTemplateModel(env);
157             if (model instanceof TemplateScalarModel) {
158                 return new SplitMethod(((TemplateScalarModel) model).getAsString());
159             }
160             throw invalidTypeException(model, target, env, "string");
161         }
162     }
163     
164     // Represents the match
165

166     static class RegexMatchModel
167     implements TemplateBooleanModel, TemplateCollectionModel, TemplateSequenceModel {
168         Matcher matcher;
169         String JavaDoc input, matchedString;
170         final boolean matches;
171         TemplateSequenceModel groups;
172         private ArrayList data;
173         
174         RegexMatchModel(Matcher matcher, String JavaDoc input) {
175             this.matcher = matcher;
176             this.input = input;
177             this.matches = matcher.matches();
178             if (matches) {
179                 matchedString = input.substring(matcher.start(), matcher.end());
180             }
181         }
182         
183         public boolean getAsBoolean() {
184             return matches;
185         }
186         
187         public TemplateModel get(int i) throws TemplateModelException {
188             if (data == null) initSequence();
189             return (TemplateModel) data.get(i);
190         }
191         
192         public int size() throws TemplateModelException {
193             if (data == null) initSequence();
194             return data.size();
195         }
196         
197         private void initSequence() throws TemplateModelException {
198             data = new ArrayList();
199             TemplateModelIterator it = iterator();
200             while (it.hasNext()) {
201                 data.add(it.next());
202             }
203         }
204         
205         public TemplateModel getGroups() {
206            if (groups == null) {
207                 groups = new TemplateSequenceModel() {
208                     public int size() throws TemplateModelException {
209                         try {
210                             return matcher.groupCount() + 1;
211                         }
212                         catch (Exception JavaDoc e) {
213                             throw new TemplateModelException(e);
214                         }
215                     }
216                     public TemplateModel get(int i) throws TemplateModelException {
217                         try {
218                             return new SimpleScalar(matcher.group(i));
219                         }
220                         catch (Exception JavaDoc e) {
221                             throw new TemplateModelException(e);
222                         }
223                     }
224                 };
225             }
226             return groups;
227         }
228         
229         public TemplateModelIterator iterator() {
230             matcher.reset();
231             return new TemplateModelIterator() {
232                 boolean hasFindInfo = matcher.find();
233                 
234                 public boolean hasNext() {
235                     return hasFindInfo;
236                 }
237                 
238                 public TemplateModel next() throws TemplateModelException {
239                     if (!hasNext()) throw new TemplateModelException("No more matches");
240                     Match result = new Match();
241                     hasFindInfo = matcher.find();
242                     return result;
243                 }
244             };
245         }
246         
247         class Match implements TemplateScalarModel {
248             String JavaDoc match;
249             SimpleSequence subs = new SimpleSequence();
250             Match() {
251                 match = input.substring(matcher.start(), matcher.end());
252                 for (int i=0; i< matcher.groupCount() + 1; i++) {
253                     subs.add(matcher.group(i));
254                 }
255             }
256             public String JavaDoc getAsString() {
257                 return match;
258             }
259         }
260     }
261     
262     static class MatcherBuilder implements TemplateMethodModel {
263         
264         String JavaDoc matchString;
265         
266         MatcherBuilder(TemplateScalarModel match) throws TemplateModelException {
267             this.matchString = match.getAsString();
268         }
269         
270         public Object JavaDoc exec(List args) throws TemplateModelException {
271             int numArgs = args.size();
272             if (numArgs == 0) {
273                 throw new TemplateModelException("Expecting at least one argument");
274             }
275             if (numArgs > 2) {
276                 throw new TemplateModelException("Expecting at most two argumnets");
277             }
278             String JavaDoc patternString = (String JavaDoc) args.get(0);
279             String JavaDoc flagString = (numArgs >1) ? (String JavaDoc) args.get(1) : "";
280             Pattern pattern = getPattern(patternString, flagString);
281             Matcher matcher = pattern.matcher(matchString);
282             return new RegexMatchModel(matcher, matchString);
283         }
284     }
285     
286     static class ReplaceMethod implements TemplateMethodModel {
287         private String JavaDoc s;
288
289         ReplaceMethod(String JavaDoc s) {
290             this.s = s;
291         }
292
293         public Object JavaDoc exec(List args) throws TemplateModelException {
294             int numArgs = args.size();
295             if (numArgs < 2 || numArgs >3 ) {
296                 throw new TemplateModelException(
297                         "?replace(...) needs 2 or 3 arguments.");
298             }
299             String JavaDoc first = (String JavaDoc) args.get(0);
300             String JavaDoc second = (String JavaDoc) args.get(1);
301             String JavaDoc flags = numArgs >2 ? (String JavaDoc) args.get(2) : "";
302             boolean caseInsensitive = flags.indexOf('i') >=0;
303             boolean useRegexp = flags.indexOf('r') >=0;
304             boolean firstOnly = flags.indexOf('f') >=0;
305             String JavaDoc result = null;
306             if (!useRegexp) {
307                 result = StringUtil.replace(s, first, second, caseInsensitive, firstOnly);
308             } else {
309                 Pattern pattern = getPattern(first, flags);
310                 Matcher matcher = pattern.matcher(s);
311                 result = firstOnly ? matcher.replaceFirst(second) : matcher.replaceAll(second);
312             }
313             return new SimpleScalar(result);
314         }
315     }
316     
317     static class SplitMethod implements TemplateMethodModel {
318         private String JavaDoc s;
319
320         SplitMethod(String JavaDoc s) {
321             this.s = s;
322         }
323
324         public Object JavaDoc exec(List args) throws TemplateModelException {
325             int numArgs = args.size();
326             if (numArgs < 1 || numArgs >2 ) {
327                 throw new TemplateModelException(
328                         "?replace(...) needs 1 or 2 arguments.");
329             }
330             String JavaDoc splitString = (String JavaDoc) args.get(0);
331             String JavaDoc flags = numArgs >1 ? (String JavaDoc) args.get(1) : "";
332             boolean caseInsensitive = flags.indexOf('i') >=0;
333             boolean useRegexp = flags.indexOf('r') >=0;
334             String JavaDoc[] result = null;
335             if (!useRegexp) {
336                 result = StringUtil.split(s, splitString, caseInsensitive);
337             } else {
338                 Pattern pattern = getPattern(splitString, flags);
339                 result = pattern.split(s);
340             }
341             return ObjectWrapper.DEFAULT_WRAPPER.wrap(result);
342         }
343     }
344 }
345
Popular Tags