2004-03-17 Francois Beauchemin <beauche@softhome.net>
[mono.git] / mcs / class / System / System.Text.RegularExpressions / regex.cs
1 //\r
2 // assembly:    System\r
3 // namespace:   System.Text.RegularExpressions\r
4 // file:        regex.cs\r
5 //\r
6 // author:      Dan Lewis (dlewis@gmx.co.uk)\r
7 //              (c) 2002\r
8 \r
9 using System;\r
10 using System.Text;\r
11 using System.Collections;\r
12 using System.Reflection;\r
13 using System.Reflection.Emit;\r
14 using System.Runtime.Serialization;\r
15 \r
16 using RegularExpression = System.Text.RegularExpressions.Syntax.RegularExpression;\r
17 using Parser = System.Text.RegularExpressions.Syntax.Parser;\r
18 \r
19 using System.Diagnostics;\r
20 \r
21 \r
22 namespace System.Text.RegularExpressions {\r
23         \r
24         public delegate string MatchEvaluator (Match match);\r
25 \r
26         [Flags]\r
27         public enum RegexOptions {\r
28                 None                            = 0x000,\r
29                 IgnoreCase                      = 0x001,\r
30                 Multiline                       = 0x002,\r
31                 ExplicitCapture                 = 0x004,\r
32                 Compiled                        = 0x008,\r
33                 Singleline                      = 0x010,\r
34                 IgnorePatternWhitespace         = 0x020,\r
35                 RightToLeft                     = 0x040,\r
36                 ECMAScript                      = 0x100,\r
37                 CultureInvariant                = 0x200 \r
38         }\r
39         \r
40         [Serializable]\r
41         public class Regex : ISerializable {\r
42                 public static void CompileToAssembly\r
43                         (RegexCompilationInfo[] regexes, AssemblyName aname)\r
44                 {\r
45                                 Regex.CompileToAssembly(regexes, aname, new CustomAttributeBuilder[] {}, null);\r
46                 }\r
47 \r
48                 public static void CompileToAssembly\r
49                         (RegexCompilationInfo[] regexes, AssemblyName aname,\r
50                          CustomAttributeBuilder[] attribs)\r
51                 {\r
52                         Regex.CompileToAssembly(regexes, aname, attribs, null);                \r
53                 }\r
54 \r
55                 public static void CompileToAssembly\r
56                         (RegexCompilationInfo[] regexes, AssemblyName aname,\r
57                          CustomAttributeBuilder[] attribs, string resourceFile)\r
58                 {\r
59                         throw new Exception ("Not fully implemented.");\r
60                         // TODO : Make use of attribs and resourceFile parameters\r
61                         /*\r
62                         AssemblyBuilder asmBuilder = AppDomain.CurrentDomain.DefineDynamicAssembly (aname, AssemblyBuilderAccess.RunAndSave);\r
63                         ModuleBuilder modBuilder = asmBuilder.DefineDynamicModule("InnerRegexModule",aname.Name);\r
64                         Parser psr = new Parser ();     \r
65                         \r
66                         System.Console.WriteLine("CompileToAssembly");\r
67                                \r
68                         for(int i=0; i < regexes.Length; i++)\r
69                                 {\r
70                                         System.Console.WriteLine("Compiling expression :" + regexes[i].Pattern);\r
71                                         RegularExpression re = psr.ParseRegularExpression (regexes[i].Pattern, regexes[i].Options);\r
72                                         \r
73                                         // compile\r
74                                                                                 \r
75                                         CILCompiler cmp = new CILCompiler (modBuilder, i);\r
76                                         bool reverse = (regexes[i].Options & RegexOptions.RightToLeft) !=0;\r
77                                         re.Compile (cmp, reverse);\r
78                                         cmp.Close();\r
79                                         \r
80                                 }\r
81                        \r
82 \r
83                         // Define a runtime class with specified name and attributes.\r
84                         TypeBuilder builder = modBuilder.DefineType("ITest");\r
85                         builder.CreateType();\r
86                         asmBuilder.Save(aname.Name);\r
87                         */\r
88                 }\r
89                 \r
90                 public static string Escape (string str) {\r
91                         return Parser.Escape (str);\r
92                 }\r
93 \r
94                 public static string Unescape (string str) {\r
95                         return Parser.Unescape (str);\r
96                 }\r
97 \r
98                 public static bool IsMatch (string input, string pattern) {\r
99                         return IsMatch (input, pattern, RegexOptions.None);\r
100                 }\r
101 \r
102                 public static bool IsMatch (string input, string pattern, RegexOptions options) {\r
103                         Regex re = new Regex (pattern, options);\r
104                         return re.IsMatch (input);\r
105                 }\r
106 \r
107                 public static Match Match (string input, string pattern) {\r
108                         return Regex.Match (input, pattern, RegexOptions.None);\r
109                 }\r
110 \r
111                 public static Match Match (string input, string pattern, RegexOptions options) {\r
112                         Regex re = new Regex (pattern, options);\r
113                         return re.Match (input);\r
114                 }\r
115 \r
116                 public static MatchCollection Matches (string input, string pattern) {\r
117                         return Matches (input, pattern, RegexOptions.None);\r
118                 }\r
119 \r
120                 public static MatchCollection Matches (string input, string pattern, RegexOptions options) {\r
121                         Regex re = new Regex (pattern, options);\r
122                         return re.Matches (input);\r
123                 }\r
124 \r
125                 public static string Replace\r
126                         (string input, string pattern, MatchEvaluator evaluator)\r
127                 {\r
128                         return Regex.Replace (input, pattern, evaluator, RegexOptions.None);\r
129                 }\r
130 \r
131                 public static string Replace\r
132                         (string input, string pattern, MatchEvaluator evaluator,\r
133                          RegexOptions options)\r
134                 {\r
135                         Regex re = new Regex (pattern, options);\r
136                         return re.Replace (input, evaluator);\r
137                 }\r
138 \r
139                 public static string Replace\r
140                         (string input, string pattern, string replacement)\r
141                 {\r
142                         return Regex.Replace (input, pattern, replacement, RegexOptions.None);\r
143                 }\r
144 \r
145                 public static string Replace\r
146                         (string input, string pattern, string replacement,\r
147                          RegexOptions options)\r
148                 {\r
149                         Regex re = new Regex (pattern, options);\r
150                         return re.Replace (input, replacement);\r
151                 }\r
152 \r
153                 public static string[] Split (string input, string pattern) {\r
154                         return Regex.Split (input, pattern, RegexOptions.None);\r
155                 }\r
156 \r
157                 public static string[] Split (string input, string pattern, RegexOptions options) {\r
158                         Regex re = new Regex (pattern, options);\r
159                         return re.Split (input);\r
160                 }\r
161 \r
162                 // private\r
163 \r
164                 private static FactoryCache cache = new FactoryCache (200);     // TODO put some meaningful number here\r
165 \r
166                 // constructors\r
167 \r
168                 protected Regex () {\r
169                         // XXX what's this constructor for?\r
170                         // : Used to compile to assembly (Custum regex inherit from Regex and use this constructor)\r
171                 }\r
172 \r
173                 public Regex (string pattern) : this (pattern, RegexOptions.None) {\r
174                 }\r
175 \r
176                 public Regex (string pattern, RegexOptions options) {\r
177                         this.pattern = pattern;\r
178                         this.roptions = options;\r
179                 \r
180                         this.machineFactory = cache.Lookup (pattern, options);\r
181 \r
182                         if (this.machineFactory == null) {\r
183                                 // parse and install group mapping\r
184 \r
185                                 Parser psr = new Parser ();\r
186                                 RegularExpression re = psr.ParseRegularExpression (pattern, options);\r
187                                 this.group_count = re.GroupCount;\r
188                                 this.mapping = psr.GetMapping ();\r
189 \r
190                                 // compile\r
191                                 \r
192                                 ICompiler cmp;\r
193                                 //if ((options & RegexOptions.Compiled) != 0)\r
194                                 //      //throw new Exception ("Not implemented.");\r
195                                 //      cmp = new CILCompiler ();\r
196                                 //else\r
197                                         cmp = new PatternCompiler ();\r
198 \r
199                                 re.Compile (cmp, RightToLeft);\r
200 \r
201                                 // install machine factory and add to pattern cache\r
202 \r
203                                 this.machineFactory = cmp.GetMachineFactory ();\r
204                                 this.machineFactory.Mapping = mapping;\r
205                                 cache.Add (pattern, options, this.machineFactory);\r
206                         } else {\r
207                                 this.group_count = this.machineFactory.GroupCount;\r
208                                 this.mapping = this.machineFactory.Mapping;\r
209                         }\r
210                 }\r
211 \r
212                 protected Regex (SerializationInfo info, StreamingContext context) :\r
213                         this (info.GetString ("pattern"), \r
214                               (RegexOptions) info.GetValue ("roptions", typeof (RegexOptions))) {                       \r
215                 }\r
216 \r
217 \r
218                 // public instance properties\r
219                 \r
220                 public RegexOptions Options {\r
221                         get { return roptions; }\r
222                 }\r
223 \r
224                 public bool RightToLeft {\r
225                         get { return (roptions & RegexOptions.RightToLeft) != 0; }\r
226                 }\r
227 \r
228                 // public instance methods\r
229                 \r
230                 public string[] GetGroupNames () {\r
231                         string[] names = new string[mapping.Count];\r
232                         mapping.Keys.CopyTo (names, 0);\r
233 \r
234                         return names;\r
235                 }\r
236 \r
237                 public int[] GetGroupNumbers () {\r
238                         int[] numbers = new int[mapping.Count];\r
239                         mapping.Values.CopyTo (numbers, 0);\r
240 \r
241                         return numbers;\r
242                 }\r
243 \r
244                 public string GroupNameFromNumber (int i) {\r
245                         if (i >= group_count)\r
246                                 return "";\r
247                 \r
248                         foreach (string name in mapping.Keys) {\r
249                                 if ((int)mapping[name] == i)\r
250                                         return name;\r
251                         }\r
252 \r
253                         return "";\r
254                 }\r
255 \r
256                 public int GroupNumberFromName (string name) {\r
257                         if (mapping.Contains (name))\r
258                                 return (int)mapping[name];\r
259 \r
260                         return -1;\r
261                 }\r
262 \r
263                 // match methods\r
264                 \r
265                 public bool IsMatch (string input) {\r
266                         if (RightToLeft)\r
267                                 return IsMatch (input, input.Length);\r
268                         else\r
269                                 return IsMatch (input, 0);\r
270                 }\r
271 \r
272                 public bool IsMatch (string input, int startat) {\r
273                         return Match (input, startat).Success;\r
274                 }\r
275 \r
276                 public Match Match (string input) {\r
277                         if (RightToLeft)\r
278                                 return Match (input, input.Length);\r
279                         else\r
280                                 return Match (input, 0);\r
281                 }\r
282 \r
283                 public Match Match (string input, int startat) {\r
284         \r
285                         return CreateMachine ().Scan (this, input, startat, input.Length);\r
286                 }\r
287 \r
288                 public Match Match (string input, int startat, int length) {\r
289         \r
290                         return CreateMachine ().Scan (this, input, startat, startat + length);\r
291                 }\r
292 \r
293                 public MatchCollection Matches (string input) {\r
294                         if (RightToLeft)\r
295                                 return Matches (input, input.Length);\r
296                         else\r
297                                 return Matches (input, 0);\r
298                 }\r
299 \r
300                 public MatchCollection Matches (string input, int startat) {\r
301                         MatchCollection ms = new MatchCollection ();\r
302                         Match m = Match (input, startat);\r
303                         while (m.Success) {\r
304                                 ms.Add (m);\r
305                                 m = m.NextMatch ();\r
306                         }\r
307 \r
308                         return ms;\r
309                 }\r
310 \r
311                 // replace methods\r
312 \r
313                 public string Replace (string input, MatchEvaluator evaluator) {\r
314                         if (RightToLeft)                        \r
315                                 return Replace (input, evaluator, Int32.MaxValue, input.Length);\r
316                         else\r
317                                 return Replace (input, evaluator, Int32.MaxValue, 0);\r
318                 }\r
319 \r
320                 public string Replace (string input, MatchEvaluator evaluator, int count) {\r
321                         if (RightToLeft)\r
322                                 return Replace (input, evaluator, count, input.Length);\r
323                         else\r
324                                 return Replace (input, evaluator, count, 0);\r
325                 }\r
326 \r
327                 public string Replace (string input, MatchEvaluator evaluator, int count, int startat)\r
328                 {\r
329                         StringBuilder result = new StringBuilder ();\r
330                         int ptr = startat;\r
331 \r
332                         Match m = Match (input, startat);\r
333                         while (m.Success && count -- > 0) {\r
334                                 result.Append (input.Substring (ptr, m.Index - ptr));\r
335                                 result.Append (evaluator (m));\r
336 \r
337                                 ptr = m.Index + m.Length;\r
338                                 m = m.NextMatch ();\r
339                         }\r
340                         result.Append (input.Substring (ptr));\r
341 \r
342                         return result.ToString ();\r
343                 }\r
344 \r
345                 public string Replace (string input, string replacement) {\r
346                         if (RightToLeft)\r
347                                 return Replace (input, replacement, Int32.MaxValue, input.Length);\r
348                         else\r
349                                 return Replace (input, replacement, Int32.MaxValue, 0);\r
350                 }\r
351 \r
352                 public string Replace (string input, string replacement, int count) {\r
353                         if (RightToLeft)                        \r
354                                 return Replace (input, replacement, count, input.Length);\r
355                         else    \r
356                                 return Replace (input, replacement, count, 0);\r
357                 }\r
358 \r
359                 public string Replace (string input, string replacement, int count, int startat) {\r
360                         ReplacementEvaluator ev = new ReplacementEvaluator (this, replacement);\r
361                         return Replace (input, new MatchEvaluator (ev.Evaluate), count, startat);\r
362                 }\r
363 \r
364                 // split methods\r
365 \r
366                 public string[] Split (string input) {\r
367                         if (RightToLeft)        \r
368                                 return Split (input, Int32.MaxValue, input.Length);\r
369                         else\r
370                                 return Split (input, Int32.MaxValue, 0);\r
371                 }\r
372 \r
373                 public string[] Split (string input, int count) {\r
374                         if (RightToLeft)                                \r
375                                 return Split (input, count, input.Length);\r
376                         else\r
377                                 return Split (input, count, 0);\r
378                 }\r
379 \r
380                 public string[] Split (string input, int count, int startat) {\r
381                         ArrayList splits = new ArrayList ();\r
382                         if (count == 0)\r
383                                 count = Int32.MaxValue;\r
384 \r
385                         int ptr = startat;\r
386                         while (--count > 0) {\r
387                                 Match m = Match (input, ptr);\r
388                                 if (!m.Success)\r
389                                         break;\r
390                         \r
391                                 if (RightToLeft)\r
392                                         splits.Add (input.Substring (m.Index + m.Length , ptr - m.Index - m.Length ));\r
393                                 else\r
394                                         splits.Add (input.Substring (ptr, m.Index - ptr));\r
395                                         \r
396                                 int gcount = m.Groups.Count;\r
397                                 for (int gindex = 1; gindex < gcount; gindex++) {\r
398                                         Group grp = m.Groups [gindex];\r
399                                         splits.Add (input.Substring (grp.Index, grp.Length));\r
400                                 }\r
401 \r
402                                 if (RightToLeft)\r
403                                         ptr = m.Index; \r
404                                 else\r
405                                         ptr = m.Index + m.Length;\r
406                                         \r
407                         }\r
408 \r
409                         if (RightToLeft) {\r
410                                 if ( ptr >= 0) {\r
411                                                 splits.Add (input.Substring(0, ptr));\r
412                                 }\r
413                         }                               \r
414                         else {\r
415                                 if (ptr <= input.Length) {\r
416                                                 splits.Add (input.Substring (ptr));\r
417                                 }\r
418                                 \r
419                         }\r
420 \r
421                         return (string []) splits.ToArray (typeof (string));\r
422                 }\r
423 \r
424                 // MS undocummented method\r
425                                \r
426                 protected void InitializeReferences() {\r
427                         throw new Exception ("Not implemented.");\r
428                 }\r
429                 \r
430                 protected bool UseOptionC(){\r
431                         throw new Exception ("Not implemented.");\r
432                 }\r
433 \r
434                 protected bool UseOptionR(){\r
435                         throw new Exception ("Not implemented.");\r
436                 }\r
437 \r
438                 // object methods\r
439                 \r
440                 public override string ToString () {\r
441                         return pattern;\r
442                 }\r
443 \r
444                 // ISerializable interface\r
445                 public virtual void GetObjectData (SerializationInfo info, StreamingContext context) {\r
446                         info.AddValue ("pattern", this.ToString (), typeof (string));\r
447                         info.AddValue ("roptions", this.Options, typeof (RegexOptions));\r
448                 }\r
449 \r
450                 // internal\r
451 \r
452                 internal int GroupCount {\r
453                         get { return group_count; }\r
454                 }\r
455 \r
456                 // private\r
457 \r
458                 private IMachine CreateMachine () {\r
459                         return machineFactory.NewInstance ();\r
460                 }\r
461 \r
462                 private IMachineFactory machineFactory;\r
463                 private IDictionary mapping;\r
464                 private int group_count;\r
465 \r
466                 \r
467                 // protected members\r
468 \r
469                 protected internal string pattern;\r
470                 protected internal RegexOptions roptions;\r
471                 \r
472                 // MS undocumented members\r
473                 protected internal System.Collections.Hashtable capnames;\r
474                 protected internal System.Collections.Hashtable cap;\r
475                 protected internal int capsize;\r
476                 protected internal string[] caplist;\r
477                 protected internal RegexRunnerFactory factory;\r
478         }\r
479 \r
480         [Serializable]\r
481         public class RegexCompilationInfo {\r
482                 public RegexCompilationInfo (string pattern, RegexOptions options, string name, string full_namespace, bool is_public) {\r
483                         this.pattern = pattern;\r
484                         this.options = options;\r
485                         this.name = name;\r
486                         this.full_namespace = full_namespace;\r
487                         this.is_public = is_public;\r
488                 }\r
489 \r
490                 public bool IsPublic {\r
491                         get { return is_public; }\r
492                         set { is_public = value; }\r
493                 }\r
494 \r
495                 public string Name {\r
496                         get { return name; }\r
497                         set { name = value; }\r
498                 }\r
499 \r
500                 public string Namespace {\r
501                         get { return full_namespace; }\r
502                         set { full_namespace = value; }\r
503                 }\r
504 \r
505                 public RegexOptions Options {\r
506                         get { return options; }\r
507                         set { options = value; }\r
508                 }\r
509 \r
510                 public string Pattern {\r
511                         get { return pattern; }\r
512                         set { pattern = value; }\r
513                 }\r
514 \r
515                 // private\r
516 \r
517                 private string pattern, name, full_namespace;\r
518                 private RegexOptions options;\r
519                 private bool is_public;\r
520         }\r
521 }\r