// // assembly: System // namespace: System.Text.RegularExpressions // file: replace.cs // // author: Dan Lewis (dlewis@gmx.co.uk) // (c) 2002 using System; using System.Text; using System.Collections; using Parser = System.Text.RegularExpressions.Syntax.Parser; namespace System.Text.RegularExpressions { class ReplacementEvaluator { public static string Evaluate (string replacement, Match match) { ReplacementEvaluator ev = new ReplacementEvaluator (match.Regex, replacement); return ev.Evaluate (match); } public ReplacementEvaluator (Regex regex, string replacement) { this.regex = regex; terms = new ArrayList (); Compile (replacement); } public string Evaluate (Match match) { StringBuilder result = new StringBuilder (); foreach (Term term in terms) result.Append (term.GetResult (match)); return result.ToString (); } // private private void Compile (string replacement) { replacement = Parser.Unescape (replacement); string literal = ""; int ptr = 0; char c; Term term = null; while (ptr < replacement.Length) { c = replacement[ptr ++]; if (c == '$') { if (replacement[ptr] != '$') term = CompileTerm (replacement, ref ptr); else ++ ptr; } if (term != null) { term.Literal = literal; terms.Add (term); term = null; literal = ""; } else literal += c; } if (term == null && literal.Length > 0) { terms.Add (new Term (literal)); } } private Term CompileTerm (string str, ref int ptr) { char c = str[ptr]; if (Char.IsDigit (c)) { // numbered group int n = Parser.ParseDecimal (str, ref ptr); if (n < 0 || n > regex.GroupCount) throw new ArgumentException ("Bad group number."); return new Term (TermOp.Match, n); } ++ ptr; switch (c) { case '{': { // named group string name = Parser.ParseName (str, ref ptr); if (str[ptr ++] != '}' || name == null) throw new ArgumentException ("Bad group name."); int n = regex.GroupNumberFromName (name); if (n < 0) throw new ArgumentException ("Bad group name."); return new Term (TermOp.Match, n); } case '&': // entire match return new Term (TermOp.Match, 0); case '`': // text before match return new Term (TermOp.PreMatch, 0); case '\'': // text after match return new Term (TermOp.PostMatch, 0); case '+': // last group return new Term (TermOp.Match, regex.GroupCount - 1); case '_': // entire text return new Term (TermOp.All, 0); default: throw new ArgumentException ("Bad replacement pattern."); } } private Regex regex; private ArrayList terms; private enum TermOp { None, // no action Match, // input within group PreMatch, // input before group PostMatch, // input after group All // entire input } private class Term { public Term (TermOp op, int arg) { this.op = op; this.arg = arg; this.literal = ""; } public Term (string literal) { this.op = TermOp.None; this.arg = 0; this.literal = literal; } public string Literal { set { literal = value; } } public string GetResult (Match match) { Group group = match.Groups[arg]; switch (op) { case TermOp.None: return literal; case TermOp.Match: return literal + group.Value; case TermOp.PreMatch: return literal + group.Text.Substring (0, group.Index); case TermOp.PostMatch: return literal + group.Text.Substring (group.Index + group.Length); case TermOp.All: return literal + group.Text; } return ""; } public TermOp op; // term type public int arg; // group argument public string literal; // literal to prepend public override string ToString () { return op.ToString () + "(" + arg + ") " + literal; } } } }