3 // namespace: System.Text.RegularExpressions
6 // author: Dan Lewis (dlewis@gmx.co.uk)
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;
33 using System.Reflection;
34 using System.Reflection.Emit;
35 using System.Runtime.Serialization;
37 using RegularExpression = System.Text.RegularExpressions.Syntax.RegularExpression;
38 using Parser = System.Text.RegularExpressions.Syntax.Parser;
40 using System.Diagnostics;
43 namespace System.Text.RegularExpressions {
46 public class Regex : ISerializable {
49 private static int cache_size = 15;
53 public static void CompileToAssembly (RegexCompilationInfo [] regexes, AssemblyName aname)
55 Regex.CompileToAssembly(regexes, aname, new CustomAttributeBuilder [] {}, null);
59 public static void CompileToAssembly (RegexCompilationInfo [] regexes, AssemblyName aname,
60 CustomAttributeBuilder [] attribs)
62 Regex.CompileToAssembly(regexes, aname, attribs, null);
66 public static void CompileToAssembly (RegexCompilationInfo [] regexes, AssemblyName aname,
67 CustomAttributeBuilder [] attribs, string resourceFile)
69 throw new NotImplementedException ();
70 // TODO : Make use of attribs and resourceFile parameters
72 AssemblyBuilder asmBuilder = AppDomain.CurrentDomain.DefineDynamicAssembly (aname, AssemblyBuilderAccess.RunAndSave);
73 ModuleBuilder modBuilder = asmBuilder.DefineDynamicModule("InnerRegexModule",aname.Name);
74 Parser psr = new Parser ();
76 System.Console.WriteLine("CompileToAssembly");
78 for(int i=0; i < regexes.Length; i++)
80 System.Console.WriteLine("Compiling expression :" + regexes[i].Pattern);
81 RegularExpression re = psr.ParseRegularExpression (regexes[i].Pattern, regexes[i].Options);
85 CILCompiler cmp = new CILCompiler (modBuilder, i);
86 bool reverse = (regexes[i].Options & RegexOptions.RightToLeft) !=0;
87 re.Compile (cmp, reverse);
93 // Define a runtime class with specified name and attributes.
94 TypeBuilder builder = modBuilder.DefineType("ITest");
96 asmBuilder.Save(aname.Name);
100 public static string Escape (string str)
102 return Parser.Escape (str);
105 public static string Unescape (string str)
107 return Parser.Unescape (str);
110 public static bool IsMatch (string input, string pattern)
112 return IsMatch (input, pattern, RegexOptions.None);
115 public static bool IsMatch (string input, string pattern, RegexOptions options)
117 Regex re = new Regex (pattern, options);
118 return re.IsMatch (input);
121 public static Match Match (string input, string pattern)
123 return Regex.Match (input, pattern, RegexOptions.None);
126 public static Match Match (string input, string pattern, RegexOptions options)
128 Regex re = new Regex (pattern, options);
129 return re.Match (input);
132 public static MatchCollection Matches (string input, string pattern)
134 return Matches (input, pattern, RegexOptions.None);
137 public static MatchCollection Matches (string input, string pattern, RegexOptions options)
139 Regex re = new Regex (pattern, options);
140 return re.Matches (input);
143 public static string Replace (string input, string pattern, MatchEvaluator evaluator)
145 return Regex.Replace (input, pattern, evaluator, RegexOptions.None);
148 public static string Replace (string input, string pattern, MatchEvaluator evaluator,
149 RegexOptions options)
151 Regex re = new Regex (pattern, options);
152 return re.Replace (input, evaluator);
155 public static string Replace (string input, string pattern, string replacement)
157 return Regex.Replace (input, pattern, replacement, RegexOptions.None);
160 public static string Replace (string input, string pattern, string replacement,
161 RegexOptions options)
163 Regex re = new Regex (pattern, options);
164 return re.Replace (input, replacement);
167 public static string [] Split (string input, string pattern)
169 return Regex.Split (input, pattern, RegexOptions.None);
172 public static string [] Split (string input, string pattern, RegexOptions options)
174 Regex re = new Regex (pattern, options);
175 return re.Split (input);
179 [MonoTODO ("should be used somewhere ? FactoryCache ?")]
180 public static int CacheSize {
181 get { return cache_size; }
184 throw new ArgumentOutOfRangeException ("CacheSize");
192 private static FactoryCache cache = new FactoryCache (200); // TODO put some meaningful number here
196 // This constructor is used by compiled regular expressions that are
197 // classes derived from Regex class. No initialization required.
202 public Regex (string pattern) : this (pattern, RegexOptions.None)
206 public Regex (string pattern, RegexOptions options)
208 this.pattern = pattern;
209 this.roptions = options;
215 this.machineFactory = cache.Lookup (this.pattern, this.roptions);
217 if (this.machineFactory == null) {
218 // parse and install group mapping
220 Parser psr = new Parser ();
221 RegularExpression re = psr.ParseRegularExpression (this.pattern, this.roptions);
222 this.group_count = re.GroupCount;
223 this.mapping = psr.GetMapping ();
228 //if ((this.roptions & RegexOptions.Compiled) != 0)
229 // //throw new Exception ("Not implemented.");
230 // cmp = new CILCompiler ();
232 cmp = new PatternCompiler ();
234 re.Compile (cmp, RightToLeft);
236 // install machine factory and add to pattern cache
238 this.machineFactory = cmp.GetMachineFactory ();
239 this.machineFactory.Mapping = mapping;
240 cache.Add (this.pattern, this.roptions, this.machineFactory);
242 this.group_count = this.machineFactory.GroupCount;
243 this.mapping = this.machineFactory.Mapping;
252 Regex (SerializationInfo info, StreamingContext context) :
253 this (info.GetString ("pattern"),
254 (RegexOptions) info.GetValue ("options", typeof (RegexOptions)))
258 #if NET_1_1 && !TARGET_JVM
259 // fixes public API signature
264 // public instance properties
266 public RegexOptions Options {
267 get { return roptions; }
270 public bool RightToLeft {
271 get { return (roptions & RegexOptions.RightToLeft) != 0; }
274 // public instance methods
276 public string [] GetGroupNames ()
278 string [] names = new string [mapping.Count];
279 mapping.Keys.CopyTo (names, 0);
284 public int[] GetGroupNumbers ()
286 int[] numbers = new int [mapping.Count];
287 mapping.Values.CopyTo (numbers, 0);
292 public string GroupNameFromNumber (int i)
297 foreach (string name in mapping.Keys) {
298 if ((int) mapping [name] == i)
305 public int GroupNumberFromName (string name)
307 if (mapping.Contains (name))
308 return (int) mapping [name];
315 public bool IsMatch (string input)
317 return IsMatch (input, RightToLeft ? input.Length : 0);
320 public bool IsMatch (string input, int startat)
322 return Match (input, startat).Success;
325 public Match Match (string input)
327 return Match (input, RightToLeft ? input.Length : 0);
330 public Match Match (string input, int startat)
332 return CreateMachine ().Scan (this, input, startat, input.Length);
335 public Match Match (string input, int startat, int length)
337 return CreateMachine ().Scan (this, input, startat, startat + length);
340 public MatchCollection Matches (string input)
342 return Matches (input, RightToLeft ? input.Length : 0);
345 public MatchCollection Matches (string input, int startat)
347 Match m = Match (input, startat);
348 return new MatchCollection (m);
353 public string Replace (string input, MatchEvaluator evaluator)
355 return Replace (input, evaluator, Int32.MaxValue, RightToLeft ? input.Length : 0);
358 public string Replace (string input, MatchEvaluator evaluator, int count)
360 return Replace (input, evaluator, count, RightToLeft ? input.Length : 0);
365 public Adapter (MatchEvaluator ev) { this.ev = ev; }
366 public void Evaluate (Match m, StringBuilder sb) { sb.Append (ev (m)); }
369 delegate void MatchAppendEvaluator (Match match, StringBuilder sb);
371 public string Replace (string input, MatchEvaluator evaluator, int count, int startat)
373 Adapter a = new Adapter (evaluator);
374 return Replace (input, new MatchAppendEvaluator (a.Evaluate), count, startat);
377 string Replace (string input, MatchAppendEvaluator evaluator, int count, int startat)
379 StringBuilder result = new StringBuilder ();
383 result.Append (input, 0, ptr);
385 Match m = Match (input, startat);
391 throw new SystemException ("how");
392 result.Append (input, ptr, m.Index - ptr);
393 evaluator (m, result);
395 ptr = m.Index + m.Length;
402 result.Append (input, ptr, input.Length - ptr);
404 return result.ToString ();
407 public string Replace (string input, string replacement)
409 return Replace (input, replacement, Int32.MaxValue, RightToLeft ? input.Length : 0);
412 public string Replace (string input, string replacement, int count)
414 return Replace (input, replacement, count, RightToLeft ? input.Length : 0);
417 public string Replace (string input, string replacement, int count, int startat)
419 ReplacementEvaluator ev = new ReplacementEvaluator (this, replacement);
420 return Replace (input, new MatchAppendEvaluator (ev.EvaluateAppend), count, startat);
425 public string [] Split (string input)
427 return Split (input, Int32.MaxValue, RightToLeft ? input.Length : 0);
430 public string [] Split (string input, int count)
432 return Split (input, count, RightToLeft ? input.Length : 0);
435 public string [] Split (string input, int count, int startat)
437 ArrayList splits = new ArrayList ();
439 count = Int32.MaxValue;
443 while (--count > 0) {
447 m = Match (input, ptr);
453 splits.Add (input.Substring (m.Index + m.Length, ptr - m.Index - m.Length));
455 splits.Add (input.Substring (ptr, m.Index - ptr));
457 int gcount = m.Groups.Count;
458 for (int gindex = 1; gindex < gcount; gindex++) {
459 Group grp = m.Groups [gindex];
460 splits.Add (input.Substring (grp.Index, grp.Length));
466 ptr = m.Index + m.Length;
470 if (RightToLeft && ptr >= 0)
471 splits.Add (input.Substring (0, ptr));
472 if (!RightToLeft && ptr <= input.Length)
473 splits.Add (input.Substring (ptr));
475 return (string []) splits.ToArray (typeof (string));
478 // This method is called at the end of the constructor of compiled
479 // regular expression classes to do internal initialization.
480 protected void InitializeReferences ()
483 throw new NotSupportedException ("This operation is only allowed once per object.");
485 refsInitialized = true;
487 // Compile pattern that results in performance loss as existing
488 // CIL code is ignored but provides support for regular
489 // expressions compiled to assemblies.
493 protected bool UseOptionC ()
495 return ((roptions & RegexOptions.Compiled) != 0);
498 protected bool UseOptionR ()
500 return ((roptions & RegexOptions.RightToLeft) != 0);
505 public override string ToString ()
510 // ISerializable interface
511 void ISerializable.GetObjectData (SerializationInfo info, StreamingContext context)
513 info.AddValue ("pattern", this.ToString (), typeof (string));
514 info.AddValue ("options", this.Options, typeof (RegexOptions));
519 internal int GroupCount {
520 get { return group_count; }
525 private IMachine CreateMachine ()
527 return machineFactory.NewInstance ();
530 private IMachineFactory machineFactory;
531 private IDictionary mapping;
532 private int group_count;
533 private bool refsInitialized;
538 protected internal string pattern;
539 protected internal RegexOptions roptions;
541 // MS undocumented members
543 protected internal System.Collections.Hashtable capnames;
545 protected internal System.Collections.Hashtable caps;
547 protected internal int capsize;
549 protected internal string [] capslist;
551 protected internal RegexRunnerFactory factory;