1 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 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 patternString, String flagString) throws TemplateModelException { 75 int flags = 0; 76 String 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 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 166 static class RegexMatchModel 167 implements TemplateBooleanModel, TemplateCollectionModel, TemplateSequenceModel { 168 Matcher matcher; 169 String input, matchedString; 170 final boolean matches; 171 TemplateSequenceModel groups; 172 private ArrayList data; 173 174 RegexMatchModel(Matcher matcher, String 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 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 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 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 getAsString() { 257 return match; 258 } 259 } 260 } 261 262 static class MatcherBuilder implements TemplateMethodModel { 263 264 String matchString; 265 266 MatcherBuilder(TemplateScalarModel match) throws TemplateModelException { 267 this.matchString = match.getAsString(); 268 } 269 270 public Object 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 patternString = (String ) args.get(0); 279 String flagString = (numArgs >1) ? (String ) 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 s; 288 289 ReplaceMethod(String s) { 290 this.s = s; 291 } 292 293 public Object 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 first = (String ) args.get(0); 300 String second = (String ) args.get(1); 301 String flags = numArgs >2 ? (String ) 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 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 s; 319 320 SplitMethod(String s) { 321 this.s = s; 322 } 323 324 public Object 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 splitString = (String ) args.get(0); 331 String flags = numArgs >1 ? (String ) args.get(1) : ""; 332 boolean caseInsensitive = flags.indexOf('i') >=0; 333 boolean useRegexp = flags.indexOf('r') >=0; 334 String [] 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 |