In ilasm/tests:
[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 //\r
10 // Permission is hereby granted, free of charge, to any person obtaining\r
11 // a copy of this software and associated documentation files (the\r
12 // "Software"), to deal in the Software without restriction, including\r
13 // without limitation the rights to use, copy, modify, merge, publish,\r
14 // distribute, sublicense, and/or sell copies of the Software, and to\r
15 // permit persons to whom the Software is furnished to do so, subject to\r
16 // the following conditions:\r
17 // \r
18 // The above copyright notice and this permission notice shall be\r
19 // included in all copies or substantial portions of the Software.\r
20 // \r
21 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,\r
22 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\r
23 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\r
24 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE\r
25 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION\r
26 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION\r
27 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\r
28 //\r
29 \r
30 using System;\r
31 using System.Text;\r
32 using System.Collections;\r
33 using System.Reflection;\r
34 using System.Reflection.Emit;\r
35 using System.Runtime.Serialization;\r
36 \r
37 using RegularExpression = System.Text.RegularExpressions.Syntax.RegularExpression;\r
38 using Parser = System.Text.RegularExpressions.Syntax.Parser;\r
39 \r
40 using System.Diagnostics;\r
41 \r
42 \r
43 namespace System.Text.RegularExpressions {\r
44         \r
45         public delegate string MatchEvaluator (Match match);\r
46 \r
47         delegate void MatchAppendEvaluator (Match match, StringBuilder sb);\r
48 \r
49         [Flags]\r
50         public enum RegexOptions {\r
51                 None                            = 0x000,\r
52                 IgnoreCase                      = 0x001,\r
53                 Multiline                       = 0x002,\r
54                 ExplicitCapture                 = 0x004,\r
55                 Compiled                        = 0x008,\r
56                 Singleline                      = 0x010,\r
57                 IgnorePatternWhitespace         = 0x020,\r
58                 RightToLeft                     = 0x040,\r
59                 ECMAScript                      = 0x100,\r
60                 CultureInvariant                = 0x200 \r
61         }\r
62         \r
63         [Serializable]\r
64         public class Regex : ISerializable {\r
65                 public static void CompileToAssembly\r
66                         (RegexCompilationInfo[] regexes, AssemblyName aname)\r
67                 {\r
68                                 Regex.CompileToAssembly(regexes, aname, new CustomAttributeBuilder[] {}, null);\r
69                 }\r
70 \r
71                 public static void CompileToAssembly\r
72                         (RegexCompilationInfo[] regexes, AssemblyName aname,\r
73                          CustomAttributeBuilder[] attribs)\r
74                 {\r
75                         Regex.CompileToAssembly(regexes, aname, attribs, null);\r
76                 }\r
77 \r
78                 [MonoTODO]\r
79                 public static void CompileToAssembly\r
80                         (RegexCompilationInfo[] regexes, AssemblyName aname,\r
81                          CustomAttributeBuilder[] attribs, string resourceFile)\r
82                 {\r
83                         throw new NotImplementedException ();\r
84                         // TODO : Make use of attribs and resourceFile parameters\r
85                         /*\r
86                         AssemblyBuilder asmBuilder = AppDomain.CurrentDomain.DefineDynamicAssembly (aname, AssemblyBuilderAccess.RunAndSave);\r
87                         ModuleBuilder modBuilder = asmBuilder.DefineDynamicModule("InnerRegexModule",aname.Name);\r
88                         Parser psr = new Parser ();     \r
89                         \r
90                         System.Console.WriteLine("CompileToAssembly");\r
91                                \r
92                         for(int i=0; i < regexes.Length; i++)\r
93                                 {\r
94                                         System.Console.WriteLine("Compiling expression :" + regexes[i].Pattern);\r
95                                         RegularExpression re = psr.ParseRegularExpression (regexes[i].Pattern, regexes[i].Options);\r
96                                         \r
97                                         // compile\r
98                                                                                 \r
99                                         CILCompiler cmp = new CILCompiler (modBuilder, i);\r
100                                         bool reverse = (regexes[i].Options & RegexOptions.RightToLeft) !=0;\r
101                                         re.Compile (cmp, reverse);\r
102                                         cmp.Close();\r
103                                         \r
104                                 }\r
105                        \r
106 \r
107                         // Define a runtime class with specified name and attributes.\r
108                         TypeBuilder builder = modBuilder.DefineType("ITest");\r
109                         builder.CreateType();\r
110                         asmBuilder.Save(aname.Name);\r
111                         */\r
112                 }\r
113                 \r
114                 public static string Escape (string str) {\r
115                         return Parser.Escape (str);\r
116                 }\r
117 \r
118                 public static string Unescape (string str) {\r
119                         return Parser.Unescape (str);\r
120                 }\r
121 \r
122                 public static bool IsMatch (string input, string pattern) {\r
123                         return IsMatch (input, pattern, RegexOptions.None);\r
124                 }\r
125 \r
126                 public static bool IsMatch (string input, string pattern, RegexOptions options) {\r
127                         Regex re = new Regex (pattern, options);\r
128                         return re.IsMatch (input);\r
129                 }\r
130 \r
131                 public static Match Match (string input, string pattern) {\r
132                         return Regex.Match (input, pattern, RegexOptions.None);\r
133                 }\r
134 \r
135                 public static Match Match (string input, string pattern, RegexOptions options) {\r
136                         Regex re = new Regex (pattern, options);\r
137                         return re.Match (input);\r
138                 }\r
139 \r
140                 public static MatchCollection Matches (string input, string pattern) {\r
141                         return Matches (input, pattern, RegexOptions.None);\r
142                 }\r
143 \r
144                 public static MatchCollection Matches (string input, string pattern, RegexOptions options) {\r
145                         Regex re = new Regex (pattern, options);\r
146                         return re.Matches (input);\r
147                 }\r
148 \r
149                 public static string Replace\r
150                         (string input, string pattern, MatchEvaluator evaluator)\r
151                 {\r
152                         return Regex.Replace (input, pattern, evaluator, RegexOptions.None);\r
153                 }\r
154 \r
155                 public static string Replace\r
156                         (string input, string pattern, MatchEvaluator evaluator,\r
157                          RegexOptions options)\r
158                 {\r
159                         Regex re = new Regex (pattern, options);\r
160                         return re.Replace (input, evaluator);\r
161                 }\r
162 \r
163                 public static string Replace\r
164                         (string input, string pattern, string replacement)\r
165                 {\r
166                         return Regex.Replace (input, pattern, replacement, RegexOptions.None);\r
167                 }\r
168 \r
169                 public static string Replace\r
170                         (string input, string pattern, string replacement,\r
171                          RegexOptions options)\r
172                 {\r
173                         Regex re = new Regex (pattern, options);\r
174                         return re.Replace (input, replacement);\r
175                 }\r
176 \r
177                 public static string[] Split (string input, string pattern) {\r
178                         return Regex.Split (input, pattern, RegexOptions.None);\r
179                 }\r
180 \r
181                 public static string[] Split (string input, string pattern, RegexOptions options) {\r
182                         Regex re = new Regex (pattern, options);\r
183                         return re.Split (input);\r
184                 }\r
185 \r
186                 // private\r
187 \r
188                 private static FactoryCache cache = new FactoryCache (200);     // TODO put some meaningful number here\r
189 \r
190                 // constructors\r
191 \r
192                 protected Regex () {\r
193                         // XXX what's this constructor for?\r
194                         // : Used to compile to assembly (Custum regex inherit from Regex and use this constructor)\r
195                 }\r
196 \r
197                 public Regex (string pattern) : this (pattern, RegexOptions.None) {\r
198                 }\r
199 \r
200                 public Regex (string pattern, RegexOptions options) {\r
201                         this.pattern = pattern;\r
202                         this.roptions = options;\r
203                 \r
204                         this.machineFactory = cache.Lookup (pattern, options);\r
205 \r
206                         if (this.machineFactory == null) {\r
207                                 // parse and install group mapping\r
208 \r
209                                 Parser psr = new Parser ();\r
210                                 RegularExpression re = psr.ParseRegularExpression (pattern, options);\r
211                                 this.group_count = re.GroupCount;\r
212                                 this.mapping = psr.GetMapping ();\r
213 \r
214                                 // compile\r
215                                 \r
216                                 ICompiler cmp;\r
217                                 //if ((options & RegexOptions.Compiled) != 0)\r
218                                 //      //throw new Exception ("Not implemented.");\r
219                                 //      cmp = new CILCompiler ();\r
220                                 //else\r
221                                         cmp = new PatternCompiler ();\r
222 \r
223                                 re.Compile (cmp, RightToLeft);\r
224 \r
225                                 // install machine factory and add to pattern cache\r
226 \r
227                                 this.machineFactory = cmp.GetMachineFactory ();\r
228                                 this.machineFactory.Mapping = mapping;\r
229                                 cache.Add (pattern, options, this.machineFactory);\r
230                         } else {\r
231                                 this.group_count = this.machineFactory.GroupCount;\r
232                                 this.mapping = this.machineFactory.Mapping;\r
233                         }\r
234                 }\r
235 \r
236                 private Regex (SerializationInfo info, StreamingContext context) :\r
237                         this (info.GetString ("pattern"), \r
238                               (RegexOptions) info.GetValue ("options", typeof (RegexOptions))) {\r
239                 }\r
240 \r
241                 // fixes public API signature\r
242                 ~Regex ()\r
243                 {\r
244                 }\r
245 \r
246                 // public instance properties\r
247                 \r
248                 public RegexOptions Options {\r
249                         get { return roptions; }\r
250                 }\r
251 \r
252                 public bool RightToLeft {\r
253                         get { return (roptions & RegexOptions.RightToLeft) != 0; }\r
254                 }\r
255 \r
256                 // public instance methods\r
257                 \r
258                 public string[] GetGroupNames () {\r
259                         string[] names = new string[mapping.Count];\r
260                         mapping.Keys.CopyTo (names, 0);\r
261 \r
262                         return names;\r
263                 }\r
264 \r
265                 public int[] GetGroupNumbers () {\r
266                         int[] numbers = new int[mapping.Count];\r
267                         mapping.Values.CopyTo (numbers, 0);\r
268 \r
269                         return numbers;\r
270                 }\r
271 \r
272                 public string GroupNameFromNumber (int i) {\r
273                         if (i > group_count)\r
274                                 return "";\r
275                 \r
276                         foreach (string name in mapping.Keys) {\r
277                                 if ((int)mapping[name] == i)\r
278                                         return name;\r
279                         }\r
280 \r
281                         return "";\r
282                 }\r
283 \r
284                 public int GroupNumberFromName (string name) {\r
285                         if (mapping.Contains (name))\r
286                                 return (int)mapping[name];\r
287 \r
288                         return -1;\r
289                 }\r
290 \r
291                 // match methods\r
292                 \r
293                 public bool IsMatch (string input) {\r
294                         if (RightToLeft)\r
295                                 return IsMatch (input, input.Length);\r
296                         else\r
297                                 return IsMatch (input, 0);\r
298                 }\r
299 \r
300                 public bool IsMatch (string input, int startat) {\r
301                         return Match (input, startat).Success;\r
302                 }\r
303 \r
304                 public Match Match (string input) {\r
305                         if (RightToLeft)\r
306                                 return Match (input, input.Length);\r
307                         else\r
308                                 return Match (input, 0);\r
309                 }\r
310 \r
311                 public Match Match (string input, int startat) {\r
312         \r
313                         return CreateMachine ().Scan (this, input, startat, input.Length);\r
314                 }\r
315 \r
316                 public Match Match (string input, int startat, int length) {\r
317         \r
318                         return CreateMachine ().Scan (this, input, startat, startat + length);\r
319                 }\r
320 \r
321                 public MatchCollection Matches (string input) {\r
322                         if (RightToLeft)\r
323                                 return Matches (input, input.Length);\r
324                         else\r
325                                 return Matches (input, 0);\r
326                 }\r
327 \r
328                 public MatchCollection Matches (string input, int startat) {\r
329                         Match m = Match (input, startat);\r
330                         return new MatchCollection (m);\r
331                 }\r
332 \r
333                 // replace methods\r
334 \r
335                 public string Replace (string input, MatchEvaluator evaluator) {\r
336                         if (RightToLeft)                        \r
337                                 return Replace (input, evaluator, Int32.MaxValue, input.Length);\r
338                         else\r
339                                 return Replace (input, evaluator, Int32.MaxValue, 0);\r
340                 }\r
341 \r
342                 public string Replace (string input, MatchEvaluator evaluator, int count) {\r
343                         if (RightToLeft)\r
344                                 return Replace (input, evaluator, count, input.Length);\r
345                         else\r
346                                 return Replace (input, evaluator, count, 0);\r
347                 }\r
348 \r
349                 class Adapter\r
350                 {\r
351                         MatchEvaluator ev;\r
352                         public Adapter (MatchEvaluator ev) { this.ev = ev; }\r
353                         public void Evaluate (Match m, StringBuilder sb) { sb.Append (ev (m)); }\r
354                 }\r
355 \r
356                 public string Replace (string input, MatchEvaluator evaluator, int count, int startat)\r
357                 {\r
358                         Adapter a = new Adapter (evaluator);\r
359                         return Replace (input, new MatchAppendEvaluator (a.Evaluate), count, startat);\r
360                 }\r
361 \r
362                 string Replace (string input, MatchAppendEvaluator evaluator, int count, int startat)\r
363                 {\r
364                         StringBuilder result = new StringBuilder ();\r
365                         int ptr = startat;\r
366                         int counter = count;\r
367 \r
368                         result.Append (input, 0, ptr);\r
369 \r
370                         Match m = Match (input, startat);\r
371                         while (m.Success) {\r
372                                 if (count != -1)\r
373                                         if(counter -- <= 0)\r
374                                                 break;\r
375                                 result.Append (input, ptr, m.Index - ptr);\r
376                                 evaluator (m, result);\r
377 \r
378                                 ptr = m.Index + m.Length;\r
379                                 m = m.NextMatch ();\r
380                         }\r
381                         \r
382                         if (ptr == 0)\r
383                                 return input;\r
384                         \r
385                         result.Append (input, ptr, input.Length - ptr);\r
386 \r
387                         return result.ToString ();\r
388                 }\r
389 \r
390                 public string Replace (string input, string replacement) {\r
391                         if (RightToLeft)\r
392                                 return Replace (input, replacement, Int32.MaxValue, input.Length);\r
393                         else\r
394                                 return Replace (input, replacement, Int32.MaxValue, 0);\r
395                 }\r
396 \r
397                 public string Replace (string input, string replacement, int count) {\r
398                         if (RightToLeft)                        \r
399                                 return Replace (input, replacement, count, input.Length);\r
400                         else    \r
401                                 return Replace (input, replacement, count, 0);\r
402                 }\r
403 \r
404                 public string Replace (string input, string replacement, int count, int startat) {\r
405                         ReplacementEvaluator ev = new ReplacementEvaluator (this, replacement);\r
406                         return Replace (input, new MatchAppendEvaluator (ev.EvaluateAppend), count, startat);\r
407                 }\r
408 \r
409                 // split methods\r
410 \r
411                 public string[] Split (string input) {\r
412                         if (RightToLeft)        \r
413                                 return Split (input, Int32.MaxValue, input.Length);\r
414                         else\r
415                                 return Split (input, Int32.MaxValue, 0);\r
416                 }\r
417 \r
418                 public string[] Split (string input, int count) {\r
419                         if (RightToLeft)                                \r
420                                 return Split (input, count, input.Length);\r
421                         else\r
422                                 return Split (input, count, 0);\r
423                 }\r
424 \r
425                 public string[] Split (string input, int count, int startat) {\r
426                         ArrayList splits = new ArrayList ();\r
427                         if (count == 0)\r
428                                 count = Int32.MaxValue;\r
429 \r
430                         int ptr = startat;\r
431                         Match m = null;\r
432                         while (--count > 0) {\r
433                                 if (m != null)\r
434                                         m = m.NextMatch ();\r
435                                 else\r
436                                         m = Match (input, ptr);\r
437 \r
438                                 if (!m.Success)\r
439                                         break;\r
440                         \r
441                                 if (RightToLeft)\r
442                                         splits.Add (input.Substring (m.Index + m.Length , ptr - m.Index - m.Length ));\r
443                                 else\r
444                                         splits.Add (input.Substring (ptr, m.Index - ptr));\r
445                                         \r
446                                 int gcount = m.Groups.Count;\r
447                                 for (int gindex = 1; gindex < gcount; gindex++) {\r
448                                         Group grp = m.Groups [gindex];\r
449                                         splits.Add (input.Substring (grp.Index, grp.Length));\r
450                                 }\r
451 \r
452                                 if (RightToLeft)\r
453                                         ptr = m.Index; \r
454                                 else\r
455                                         ptr = m.Index + m.Length;\r
456                                         \r
457                         }\r
458 \r
459                         if (RightToLeft) {\r
460                                 if ( ptr >= 0) {\r
461                                                 splits.Add (input.Substring(0, ptr));\r
462                                 }\r
463                         }                               \r
464                         else {\r
465                                 if (ptr <= input.Length) {\r
466                                                 splits.Add (input.Substring (ptr));\r
467                                 }\r
468                                 \r
469                         }\r
470 \r
471                         return (string []) splits.ToArray (typeof (string));\r
472                 }\r
473 \r
474                 // MS undocummented method\r
475                 [MonoTODO]\r
476                 protected void InitializeReferences() {\r
477                         throw new NotImplementedException ();\r
478                 }\r
479 \r
480                 [MonoTODO]\r
481                 protected bool UseOptionC(){\r
482                         throw new NotImplementedException ();\r
483                 }\r
484 \r
485                 [MonoTODO]\r
486                 protected bool UseOptionR(){\r
487                         throw new NotImplementedException ();\r
488                 }\r
489 \r
490                 // object methods\r
491                 \r
492                 public override string ToString () {\r
493                         return pattern;\r
494                 }\r
495 \r
496                 // ISerializable interface\r
497                 void ISerializable.GetObjectData (SerializationInfo info, StreamingContext context) {\r
498                         info.AddValue ("pattern", this.ToString (), typeof (string));\r
499                         info.AddValue ("options", this.Options, typeof (RegexOptions));\r
500                 }\r
501 \r
502                 // internal\r
503 \r
504                 internal int GroupCount {\r
505                         get { return group_count; }\r
506                 }\r
507 \r
508                 // private\r
509 \r
510                 private IMachine CreateMachine () {\r
511                         return machineFactory.NewInstance ();\r
512                 }\r
513 \r
514                 private IMachineFactory machineFactory;\r
515                 private IDictionary mapping;\r
516                 private int group_count;\r
517 \r
518                 \r
519                 // protected members\r
520 \r
521                 protected internal string pattern;\r
522                 protected internal RegexOptions roptions;\r
523                 \r
524                 // MS undocumented members\r
525                 [MonoTODO]\r
526                 protected internal System.Collections.Hashtable capnames;\r
527                 [MonoTODO]\r
528                 protected internal System.Collections.Hashtable caps;\r
529                 [MonoTODO]\r
530                 protected internal int capsize;\r
531                 [MonoTODO]\r
532                 protected internal string[] capslist;\r
533                 [MonoTODO]\r
534                 protected internal RegexRunnerFactory factory;\r
535         }\r
536 \r
537         [Serializable]\r
538         public class RegexCompilationInfo {\r
539                 public RegexCompilationInfo (string pattern, RegexOptions options, string name, string nspace, bool isPublic)\r
540                 {\r
541                         this.pattern = pattern;\r
542                         this.options = options;\r
543                         this.name = name;\r
544                         this.nspace = nspace;\r
545                         this.isPublic = isPublic;\r
546                 }\r
547 \r
548                 public bool IsPublic {\r
549                         get { return isPublic; }\r
550                         set { isPublic = value; }\r
551                 }\r
552 \r
553                 public string Name {\r
554                         get { return name; }\r
555                         set { name = value; }\r
556                 }\r
557 \r
558                 public string Namespace {\r
559                         get { return nspace; }\r
560                         set { nspace = value; }\r
561                 }\r
562 \r
563                 public RegexOptions Options {\r
564                         get { return options; }\r
565                         set { options = value; }\r
566                 }\r
567 \r
568                 public string Pattern {\r
569                         get { return pattern; }\r
570                         set { pattern = value; }\r
571                 }\r
572 \r
573                 // private\r
574 \r
575                 private string pattern, name, nspace;\r
576                 private RegexOptions options;\r
577                 private bool isPublic;\r
578         }\r
579 }\r