3 // namespace: System.Text.RegularExpressions
\r
6 // author: Dan Lewis (dlewis@gmx.co.uk)
\r
10 // Permission is hereby granted, free of charge, to any person obtaining
11 // a copy of this software and associated documentation files (the
12 // "Software"), to deal in the Software without restriction, including
13 // without limitation the rights to use, copy, modify, merge, publish,
14 // distribute, sublicense, and/or sell copies of the Software, and to
15 // permit persons to whom the Software is furnished to do so, subject to
16 // the following conditions:
18 // The above copyright notice and this permission notice shall be
19 // included in all copies or substantial portions of the Software.
21 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
22 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
23 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
24 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
25 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
26 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
27 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
32 using System.Collections;
\r
34 using Parser = System.Text.RegularExpressions.Syntax.Parser;
\r
36 namespace System.Text.RegularExpressions {
\r
38 class ReplacementEvaluator {
\r
39 public static string Evaluate (string replacement, Match match) {
\r
40 ReplacementEvaluator ev = new ReplacementEvaluator (match.Regex, replacement);
\r
41 return ev.Evaluate (match);
\r
44 public ReplacementEvaluator (Regex regex, string replacement) {
\r
46 terms = new ArrayList ();
\r
47 Compile (replacement);
\r
50 public string Evaluate (Match match) {
\r
51 StringBuilder result = new StringBuilder ();
\r
52 foreach (Term term in terms)
\r
53 result.Append (term.GetResult (match));
\r
55 return result.ToString ();
\r
60 private void Compile (string replacement) {
\r
61 replacement = Parser.Unescape (replacement);
\r
62 string literal = "";
\r
67 while (ptr < replacement.Length) {
\r
68 c = replacement[ptr ++];
\r
71 if (replacement[ptr] != '$')
\r
72 term = CompileTerm (replacement, ref ptr);
\r
78 term.Literal = literal;
\r
88 if (term == null && literal.Length > 0) {
\r
89 terms.Add (new Term (literal));
\r
93 private Term CompileTerm (string str, ref int ptr) {
\r
96 if (Char.IsDigit (c)) { // numbered group
\r
97 int n = Parser.ParseDecimal (str, ref ptr);
\r
98 if (n < 0 || n > regex.GroupCount)
\r
99 throw new ArgumentException ("Bad group number.");
\r
101 return new Term (TermOp.Match, n);
\r
107 case '{': { // named group
\r
108 string name = Parser.ParseName (str, ref ptr);
\r
109 if (str[ptr ++] != '}' || name == null)
\r
110 throw new ArgumentException ("Bad group name.");
\r
112 int n = regex.GroupNumberFromName (name);
\r
115 throw new ArgumentException ("Bad group name.");
\r
117 return new Term (TermOp.Match, n);
\r
120 case '&': // entire match
\r
121 return new Term (TermOp.Match, 0);
\r
123 case '`': // text before match
\r
124 return new Term (TermOp.PreMatch, 0);
\r
126 case '\'': // text after match
\r
127 return new Term (TermOp.PostMatch, 0);
\r
129 case '+': // last group
\r
130 return new Term (TermOp.Match, regex.GroupCount - 1);
\r
132 case '_': // entire text
\r
133 return new Term (TermOp.All, 0);
\r
136 throw new ArgumentException ("Bad replacement pattern.");
\r
140 private Regex regex;
\r
141 private ArrayList terms;
\r
143 private enum TermOp {
\r
145 Match, // input within group
\r
146 PreMatch, // input before group
\r
147 PostMatch, // input after group
\r
148 All // entire input
\r
151 private class Term {
\r
152 public Term (TermOp op, int arg) {
\r
158 public Term (string literal) {
\r
159 this.op = TermOp.None;
\r
161 this.literal = literal;
\r
164 public string Literal {
\r
165 set { literal = value; }
\r
168 public string GetResult (Match match) {
\r
169 Group group = match.Groups[arg];
\r
176 return literal + group.Value;
\r
178 case TermOp.PreMatch:
\r
179 return literal + group.Text.Substring (0, group.Index);
\r
181 case TermOp.PostMatch:
\r
182 return literal + group.Text.Substring (group.Index + group.Length);
\r
185 return literal + group.Text;
\r
191 public TermOp op; // term type
\r
192 public int arg; // group argument
\r
193 public string literal; // literal to prepend
\r
195 public override string ToString () {
\r
196 return op.ToString () + "(" + arg + ") " + literal;
\r