3 // namespace: System.Text.RegularExpressions
\r
6 // author: Dan Lewis (dlewis@gmx.co.uk)
\r
11 using System.Collections;
\r
13 using Parser = System.Text.RegularExpressions.Syntax.Parser;
\r
15 namespace System.Text.RegularExpressions {
\r
17 class ReplacementEvaluator {
\r
18 public static string Evaluate (string replacement, Match match) {
\r
19 ReplacementEvaluator ev = new ReplacementEvaluator (match.Regex, replacement);
\r
20 return ev.Evaluate (match);
\r
23 public ReplacementEvaluator (Regex regex, string replacement) {
\r
25 terms = new ArrayList ();
\r
26 Compile (replacement);
\r
29 public string Evaluate (Match match) {
\r
30 StringBuilder result = new StringBuilder ();
\r
31 foreach (Term term in terms)
\r
32 result.Append (term.GetResult (match));
\r
34 return result.ToString ();
\r
39 private void Compile (string replacement) {
\r
40 replacement = Parser.Unescape (replacement);
\r
41 string literal = "";
\r
46 while (ptr < replacement.Length) {
\r
47 c = replacement[ptr ++];
\r
50 if (replacement[ptr] != '$')
\r
51 term = CompileTerm (replacement, ref ptr);
\r
57 term.Literal = literal;
\r
67 if (term == null && literal.Length > 0) {
\r
68 terms.Add (new Term (literal));
\r
72 private Term CompileTerm (string str, ref int ptr) {
\r
75 if (Char.IsDigit (c)) { // numbered group
\r
76 int n = Parser.ParseDecimal (str, ref ptr);
\r
77 if (n < 0 || n > regex.GroupCount)
\r
78 throw new ArgumentException ("Bad group number.");
\r
80 return new Term (TermOp.Match, n);
\r
86 case '{': { // named group
\r
87 string name = Parser.ParseName (str, ref ptr);
\r
88 if (str[ptr ++] != '}' || name == null)
\r
89 throw new ArgumentException ("Bad group name.");
\r
91 int n = regex.GroupNumberFromName (name);
\r
94 throw new ArgumentException ("Bad group name.");
\r
96 return new Term (TermOp.Match, n);
\r
99 case '&': // entire match
\r
100 return new Term (TermOp.Match, 0);
\r
102 case '`': // text before match
\r
103 return new Term (TermOp.PreMatch, 0);
\r
105 case '\'': // text after match
\r
106 return new Term (TermOp.PostMatch, 0);
\r
108 case '+': // last group
\r
109 return new Term (TermOp.Match, regex.GroupCount - 1);
\r
111 case '_': // entire text
\r
112 return new Term (TermOp.All, 0);
\r
115 throw new ArgumentException ("Bad replacement pattern.");
\r
119 private Regex regex;
\r
120 private ArrayList terms;
\r
122 private enum TermOp {
\r
124 Match, // input within group
\r
125 PreMatch, // input before group
\r
126 PostMatch, // input after group
\r
127 All // entire input
\r
130 private class Term {
\r
131 public Term (TermOp op, int arg) {
\r
137 public Term (string literal) {
\r
138 this.op = TermOp.None;
\r
140 this.literal = literal;
\r
143 public string Literal {
\r
144 set { literal = value; }
\r
147 public string GetResult (Match match) {
\r
148 Group group = match.Groups[arg];
\r
155 return literal + group.Value;
\r
157 case TermOp.PreMatch:
\r
158 return literal + group.Text.Substring (0, group.Index);
\r
160 case TermOp.PostMatch:
\r
161 return literal + group.Text.Substring (group.Index + group.Length);
\r
164 return literal + group.Text;
\r
170 public TermOp op; // term type
\r
171 public int arg; // group argument
\r
172 public string literal; // literal to prepend
\r
174 public override string ToString () {
\r
175 return op.ToString () + "(" + arg + ") " + literal;
\r