2 // This software is now distributed according to
\r
3 // the Lesser Gnu Public License. Please see
\r
4 // http://www.gnu.org/copyleft/lesser.txt for
\r
6 // -- Happy Computing!
\r
8 package com.stevesoft.pat;
\r
11 * This class provides a method for parsing the "s/.../.../" constructs of
\r
14 * @see Regex#perlCode
\r
18 final static char close(char c)
\r
20 // This switch statement does not behave
\r
21 // properly when compiled with jdk1.1.5
\r
24 * switch(c) { case '[': return ']'; case '(': return ')'; case '{': return
\r
46 final public static String codify(String s, boolean keepbs)
\r
48 return codify(s, 0, s.length(), keepbs);
\r
51 final public static String codify(String s, int i0, int iN, boolean keepbs)
\r
53 javajs.util.SB sb = new javajs.util.SB();
\r
54 boolean ucmode = false, lcmode = false, litmode = false;
\r
55 boolean uc1 = false, lc1 = false;
\r
56 boolean modified = false;
\r
57 for (int i = i0; i < iN; i++)
\r
59 char c = s.charAt(i);
\r
60 boolean mf = true, app = true;
\r
67 char c2 = s.charAt(i);
\r
86 uc1 = lc1 = ucmode = lcmode = litmode = false;
\r
124 if (litmode && needbs(c))
\r
131 return modified ? sb.toString() : s;
\r
134 final static char uc(char c)
\r
136 return CaseMgr.toUpperCase(c);
\r
139 final static char lc(char c)
\r
141 return CaseMgr.toLowerCase(c);
\r
144 final static boolean needbs(char c)
\r
146 if (c >= 'a' && c <= 'z')
\r
150 if (c >= 'A' && c <= 'Z')
\r
154 if (c >= '0' && c <= '9')
\r
165 final static Regex parse(String s)
\r
167 boolean igncase = false, optim = false, gFlag = false;
\r
168 boolean sFlag = false, mFlag = false, xFlag = false;
\r
170 javajs.util.SB s1 = new javajs.util.SB();
\r
171 javajs.util.SB s2 = new javajs.util.SB();
\r
172 int i = 0, count = 0;
\r
173 char mode, delim = '/', cdelim = '/';
\r
174 if (s.length() >= 3 && s.charAt(0) == 's')
\r
177 delim = s.charAt(1);
\r
178 cdelim = close(delim);
\r
181 else if (s.length() >= 2 && s.charAt(0) == 'm')
\r
184 delim = s.charAt(1);
\r
185 cdelim = close(delim);
\r
188 else if (s.length() >= 1 && s.charAt(0) == '/')
\r
197 RegSyntaxError.endItAll("Regex.perlCode should be of the "
\r
198 + "form s/// or m// or //");
\r
199 } catch (RegSyntax rs)
\r
204 for (; i < s.length(); i++)
\r
206 if (s.charAt(i) == '\\')
\r
211 else if (s.charAt(i) == cdelim && count == 0)
\r
216 else if (s.charAt(i) == delim && cdelim != delim)
\r
220 else if (s.charAt(i) == cdelim && cdelim != delim)
\r
224 s1.appendC(s.charAt(i));
\r
226 if (mode == 's' && cdelim != delim)
\r
228 while (i < s.length() && Prop.isWhite(s.charAt(i)))
\r
232 if (i >= s.length())
\r
236 RegSyntaxError.endItAll("" + mode + delim + " needs " + cdelim);
\r
237 } catch (RegSyntax rs)
\r
242 cdelim = close(delim = s.charAt(i));
\r
248 for (; i < s.length(); i++)
\r
250 if (s.charAt(i) == '\\')
\r
255 else if (s.charAt(i) == cdelim && count == 0)
\r
260 else if (s.charAt(i) == delim && cdelim != delim)
\r
264 else if (s.charAt(i) == cdelim && cdelim != delim)
\r
268 s2.appendC(s.charAt(i));
\r
271 for (; i < s.length(); i++)
\r
273 char c = s.charAt(i);
\r
299 RegSyntaxError.endItAll("Illegal flag to pattern: " + c);
\r
300 } catch (RegSyntax rs)
\r
306 Regex r = new Regex();
\r
309 String pat = s1.toString(), reprul = s2.toString();
\r
313 reprul = strip(reprul);
\r
316 r.ignoreCase |= igncase;
\r
326 r.setReplaceRule(new StringRule(reprul));
\r
330 r.setReplaceRule(parsePerl.perlCode(reprul));
\r
332 } catch (RegSyntax rs)
\r
339 static String strip(String s)
\r
341 javajs.util.SB sb = new javajs.util.SB();
\r
342 for (int i = 0; i < s.length(); i++)
\r
344 char c = s.charAt(i);
\r
345 if (Prop.isWhite(c))
\r
352 while (i < s.length())
\r
354 if (s.charAt(i) == '\n')
\r
361 else if (c == '\\')
\r
364 sb.appendC(s.charAt(++i));
\r
371 return sb.toString();
\r
375 * Compile a ReplaceRule using the text that would go between the second and
\r
376 * third /'s in a typical substitution pattern in Perl: s/ ... / <i>The
\r
377 * argument to ReplaceRule.perlCode</i> /.
\r
379 public static ReplaceRule perlCode(String s)
\r
381 // String sav_backGs = Regex.backGs;
\r
382 // int sav_backGto = Regex.backGto;
\r
385 int mf = 0, mt = 0;
\r
386 Regex gv = ReplaceRule.getv();
\r
387 ReplaceRule head = null;
\r
389 while (gv.searchFrom(s, mt))
\r
391 int off = Regex.BackRefOffset - 1;
\r
392 mf = gv.matchedFrom();
\r
395 head = ReplaceRule.add(head, new StringRule(s.substring(mt, mf)));
\r
398 if ((var = gv.stringMatched(1 + off)) != null
\r
399 || (var = gv.stringMatched(2 + off)) != null
\r
400 || (var = gv.stringMatched(5 + off)) != null)
\r
403 for (int i = 0; i < var.length(); i++)
\r
405 d = 8 * d + (var.charAt(i) - '0');
\r
407 if (var.length() == 1)
\r
409 head = ReplaceRule.add(head, new BackRefRule(d));
\r
413 head = new StringRule("" + (char) d);
\r
416 else if ((var = gv.stringMatched(10 + off)) != null)
\r
418 if ("QELlUu".indexOf(var) >= 0)
\r
420 head = ReplaceRule.add(head, new CodeRule(var.charAt(0)));
\r
424 head = ReplaceRule.add(head, new StringRule(var));
\r
427 else if ((var = gv.stringMatched(3 + off)) != null
\r
428 || (var = gv.stringMatched(4 + off)) != null
\r
429 || (var = gv.stringMatched(6 + off)) != null)
\r
433 if ((pc = var.indexOf(':')) > 0)
\r
435 arg = var.substring(pc + 1);
\r
436 var = var.substring(0, pc);
\r
438 if (var.equals("&") || var.equals("MATCH"))
\r
440 head = ReplaceRule.add(head, new AmpersandRule());
\r
442 else if (var.equals("`") || var.equals("PREMATCH"))
\r
444 head = ReplaceRule.add(head, new LeftRule());
\r
446 else if (var.equals("'") || var.equals("POSTMATCH"))
\r
448 head = ReplaceRule.add(head, new RightRule());
\r
450 else if (var.equals("WANT_MORE_TEXT"))
\r
452 head = ReplaceRule.add(head, new WantMoreTextReplaceRule());
\r
454 else if (var.equals("POP"))
\r
456 head = ReplaceRule.add(head, new PopRule());
\r
458 else if (var.startsWith("+")
\r
459 && (tmp = ReplaceRule.defs.get(var.substring(1))) != null)
\r
461 if (tmp instanceof Regex)
\r
463 head = ReplaceRule.add(head, new PushRule(var.substring(1), (Regex) tmp));
\r
465 else if (tmp instanceof Transformer)
\r
467 head = ReplaceRule.add(head, new PushRule(var.substring(1),
\r
468 (Transformer) tmp));
\r
472 head = ReplaceRule.add(head, new StringRule("${" + var + "}"));
\r
475 else if (var.startsWith("=")
\r
476 && (tmp = ReplaceRule.defs.get(var.substring(1))) != null)
\r
478 if (tmp instanceof Regex)
\r
480 head = ReplaceRule.add(head,
\r
481 new ChangeRule(var.substring(1), (Regex) tmp));
\r
483 else if (tmp instanceof Transformer)
\r
485 head = ReplaceRule.add(head, new ChangeRule(var.substring(1),
\r
486 (Transformer) tmp));
\r
490 head = ReplaceRule.add(head, new StringRule("${" + var + "}"));
\r
493 else if ((tmp = ReplaceRule.defs.get(var)) != null)
\r
495 if (tmp instanceof ReplaceRule)
\r
497 ReplaceRule alt = ((ReplaceRule) tmp).arg(arg);
\r
500 alt = ((ReplaceRule) tmp);
\r
502 head = ReplaceRule.add(head, (ReplaceRule) (alt.clone()));
\r
506 // can't figure out how to transform this thing...
\r
508 head = ReplaceRule.add(head, new StringRule("${" + var + "}"));
\r
511 else if ((var = gv.stringMatched(7 + off)) != null)
\r
513 char c = var.charAt(0);
\r
516 head = ReplaceRule.add(head, new StringRule("\n"));
\r
520 head = ReplaceRule.add(head, new StringRule("\t"));
\r
524 head = ReplaceRule.add(head, new StringRule("\r"));
\r
528 head = ReplaceRule.add(head, new StringRule("\r"));
\r
532 head = ReplaceRule.add(head, new StringRule("" + (char) 7));
\r
536 head = ReplaceRule.add(head, new StringRule("" + (char) 27));
\r
540 head = ReplaceRule.add(head, new StringRule("" + (char) 12));
\r
543 else if ((var = gv.stringMatched(8 + off)) != null)
\r
545 char c = var.charAt(0);
\r
546 if (c < Ctrl.cmap.length)
\r
550 head = ReplaceRule.add(head, new StringRule("" + c));
\r
552 else if ((var = gv.stringMatched(9 + off)) != null)
\r
554 int d = 16 * ReplaceRule.getHexDigit(var.charAt(0))
\r
555 + ReplaceRule.getHexDigit(var.charAt(1));
\r
556 head = ReplaceRule.add(head, new StringRule("" + (char) d));
\r
558 mt = gv.matchedTo();
\r
560 if (mt <= s.length())
\r
562 head = ReplaceRule.add(head, new StringRule(s.substring(mt)));
\r
567 // Regex.backGs = sav_backGs;
\r
568 // Regex.backGto = sav_backGto;
\r