Add MIT license to System.dll
[mono.git] / mcs / class / System / System.Text.RegularExpressions / replace.cs
1 //\r
2 // assembly:    System\r
3 // namespace:   System.Text.RegularExpressions\r
4 // file:        replace.cs\r
5 //\r
6 // author:      Dan Lewis (dlewis@gmx.co.uk)\r
7 //              (c) 2002\r
8
9 //
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:
17 // 
18 // The above copyright notice and this permission notice shall be
19 // included in all copies or substantial portions of the Software.
20 // 
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.
28 //
29 \r
30 using System;\r
31 using System.Text;\r
32 using System.Collections;\r
33 \r
34 using Parser = System.Text.RegularExpressions.Syntax.Parser;\r
35 \r
36 namespace System.Text.RegularExpressions {\r
37 \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
42                 }\r
43 \r
44                 public ReplacementEvaluator (Regex regex, string replacement) {\r
45                         this.regex = regex;\r
46                         terms = new ArrayList ();\r
47                         Compile (replacement);\r
48                 }\r
49 \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
54 \r
55                         return result.ToString ();\r
56                 }\r
57 \r
58                 // private\r
59 \r
60                 private void Compile (string replacement) {\r
61                         replacement = Parser.Unescape (replacement);\r
62                         string literal = "";\r
63 \r
64                         int ptr = 0;\r
65                         char c;\r
66                         Term term = null;\r
67                         while (ptr < replacement.Length) {\r
68                                 c = replacement[ptr ++];\r
69 \r
70                                 if (c == '$') {\r
71                                         if (replacement[ptr] != '$') \r
72                                                 term = CompileTerm (replacement, ref ptr);\r
73                                         else\r
74                                                 ++ ptr;\r
75                                 }\r
76 \r
77                                 if (term != null) {\r
78                                         term.Literal = literal;\r
79                                         terms.Add (term);\r
80 \r
81                                         term = null;\r
82                                         literal = "";\r
83                                 }\r
84                                 else\r
85                                         literal += c;\r
86                         }\r
87 \r
88                         if (term == null && literal.Length > 0) {\r
89                                 terms.Add (new Term (literal));\r
90                         }\r
91                 }\r
92 \r
93                 private Term CompileTerm (string str, ref int ptr) {\r
94                         char c = str[ptr];\r
95 \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
100                                 \r
101                                 return new Term (TermOp.Match, n);\r
102                         }\r
103                         \r
104                         ++ ptr;\r
105 \r
106                         switch (c) {\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
111                                 \r
112                                 int n = regex.GroupNumberFromName (name);\r
113                                 \r
114                                 if (n < 0)\r
115                                         throw new ArgumentException ("Bad group name.");\r
116 \r
117                                 return new Term (TermOp.Match, n);\r
118                         }\r
119 \r
120                         case '&':                       // entire match\r
121                                 return new Term (TermOp.Match, 0);\r
122 \r
123                         case '`':                       // text before match\r
124                                 return new Term (TermOp.PreMatch, 0);\r
125 \r
126                         case '\'':                      // text after match\r
127                                 return new Term (TermOp.PostMatch, 0);\r
128 \r
129                         case '+':                       // last group\r
130                                 return new Term (TermOp.Match, regex.GroupCount - 1);\r
131 \r
132                         case '_':                       // entire text\r
133                                 return new Term (TermOp.All, 0);\r
134 \r
135                         default:\r
136                                 throw new ArgumentException ("Bad replacement pattern.");\r
137                         }\r
138                 }\r
139 \r
140                 private Regex regex;\r
141                 private ArrayList terms;\r
142 \r
143                 private enum TermOp {\r
144                         None,                           // no action\r
145                         Match,                          // input within group\r
146                         PreMatch,                       // input before group\r
147                         PostMatch,                      // input after group\r
148                         All                             // entire input\r
149                 }\r
150 \r
151                 private class Term {\r
152                         public Term (TermOp op, int arg) {\r
153                                 this.op = op;\r
154                                 this.arg = arg;\r
155                                 this.literal = "";\r
156                         }\r
157 \r
158                         public Term (string literal) {\r
159                                 this.op = TermOp.None;\r
160                                 this.arg = 0;\r
161                                 this.literal = literal;\r
162                         }\r
163 \r
164                         public string Literal {\r
165                                 set { literal = value; }\r
166                         }\r
167 \r
168                         public string GetResult (Match match) {\r
169                                 Group group = match.Groups[arg];\r
170                         \r
171                                 switch (op) {\r
172                                 case TermOp.None:\r
173                                         return literal;\r
174 \r
175                                 case TermOp.Match:\r
176                                         return literal + group.Value;\r
177 \r
178                                 case TermOp.PreMatch:\r
179                                         return literal + group.Text.Substring (0, group.Index);\r
180 \r
181                                 case TermOp.PostMatch:\r
182                                         return literal + group.Text.Substring (group.Index + group.Length);\r
183 \r
184                                 case TermOp.All:\r
185                                         return literal + group.Text;\r
186                                 }\r
187 \r
188                                 return "";\r
189                         }\r
190                 \r
191                         public TermOp op;               // term type\r
192                         public int arg;                 // group argument\r
193                         public string literal;          // literal to prepend\r
194 \r
195                         public override string ToString () {\r
196                                 return op.ToString () + "(" + arg + ") " + literal;\r
197                         }\r
198                 }\r
199         }\r
200 }\r