3 // namespace: System.Text.RegularExpressions
\r
6 // author: Dan Lewis (dlewis@gmx.co.uk)
\r
11 using System.Collections;
\r
12 using System.Reflection;
\r
13 using System.Reflection.Emit;
\r
14 using System.Runtime.Serialization;
\r
16 using RegularExpression = System.Text.RegularExpressions.Syntax.RegularExpression;
\r
17 using Parser = System.Text.RegularExpressions.Syntax.Parser;
\r
19 using System.Diagnostics;
\r
22 namespace System.Text.RegularExpressions {
\r
24 public delegate string MatchEvaluator (Match match);
\r
27 public enum RegexOptions {
\r
31 ExplicitCapture = 0x004,
\r
34 IgnorePatternWhitespace = 0x020,
\r
35 RightToLeft = 0x040,
\r
37 CultureInvariant = 0x200
\r
41 public class Regex : ISerializable {
\r
42 public static void CompileToAssembly
\r
43 (RegexCompilationInfo[] regexes, AssemblyName aname)
\r
45 Regex.CompileToAssembly(regexes, aname, new CustomAttributeBuilder[] {}, null);
\r
48 public static void CompileToAssembly
\r
49 (RegexCompilationInfo[] regexes, AssemblyName aname,
\r
50 CustomAttributeBuilder[] attribs)
\r
52 Regex.CompileToAssembly(regexes, aname, attribs, null);
\r
55 public static void CompileToAssembly
\r
56 (RegexCompilationInfo[] regexes, AssemblyName aname,
\r
57 CustomAttributeBuilder[] attribs, string resourceFile)
\r
59 throw new Exception ("Not fully implemented.");
\r
60 // TODO : Make use of attribs and resourceFile parameters
\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
66 System.Console.WriteLine("CompileToAssembly");
\r
68 for(int i=0; i < regexes.Length; i++)
\r
70 System.Console.WriteLine("Compiling expression :" + regexes[i].Pattern);
\r
71 RegularExpression re = psr.ParseRegularExpression (regexes[i].Pattern, regexes[i].Options);
\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
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
90 public static string Escape (string str) {
\r
91 return Parser.Escape (str);
\r
94 public static string Unescape (string str) {
\r
95 return Parser.Unescape (str);
\r
98 public static bool IsMatch (string input, string pattern) {
\r
99 return IsMatch (input, pattern, RegexOptions.None);
\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
107 public static Match Match (string input, string pattern) {
\r
108 return Regex.Match (input, pattern, RegexOptions.None);
\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
116 public static MatchCollection Matches (string input, string pattern) {
\r
117 return Matches (input, pattern, RegexOptions.None);
\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
125 public static string Replace
\r
126 (string input, string pattern, MatchEvaluator evaluator)
\r
128 return Regex.Replace (input, pattern, evaluator, RegexOptions.None);
\r
131 public static string Replace
\r
132 (string input, string pattern, MatchEvaluator evaluator,
\r
133 RegexOptions options)
\r
135 Regex re = new Regex (pattern, options);
\r
136 return re.Replace (input, evaluator);
\r
139 public static string Replace
\r
140 (string input, string pattern, string replacement)
\r
142 return Regex.Replace (input, pattern, replacement, RegexOptions.None);
\r
145 public static string Replace
\r
146 (string input, string pattern, string replacement,
\r
147 RegexOptions options)
\r
149 Regex re = new Regex (pattern, options);
\r
150 return re.Replace (input, replacement);
\r
153 public static string[] Split (string input, string pattern) {
\r
154 return Regex.Split (input, pattern, RegexOptions.None);
\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
164 private static FactoryCache cache = new FactoryCache (200); // TODO put some meaningful number here
\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
173 public Regex (string pattern) : this (pattern, RegexOptions.None) {
\r
176 public Regex (string pattern, RegexOptions options) {
\r
177 this.pattern = pattern;
\r
178 this.roptions = options;
\r
180 this.machineFactory = cache.Lookup (pattern, options);
\r
182 if (this.machineFactory == null) {
\r
183 // parse and install group mapping
\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
193 //if ((options & RegexOptions.Compiled) != 0)
\r
194 // //throw new Exception ("Not implemented.");
\r
195 // cmp = new CILCompiler ();
\r
197 cmp = new PatternCompiler ();
\r
199 re.Compile (cmp, RightToLeft);
\r
201 // install machine factory and add to pattern cache
\r
203 this.machineFactory = cmp.GetMachineFactory ();
\r
204 this.machineFactory.Mapping = mapping;
\r
205 cache.Add (pattern, options, this.machineFactory);
\r
207 this.group_count = this.machineFactory.GroupCount;
\r
208 this.mapping = this.machineFactory.Mapping;
\r
212 protected Regex (SerializationInfo info, StreamingContext context) :
\r
213 this (info.GetString ("pattern"),
\r
214 (RegexOptions) info.GetValue ("roptions", typeof (RegexOptions))) {
\r
218 // public instance properties
\r
220 public RegexOptions Options {
\r
221 get { return roptions; }
\r
224 public bool RightToLeft {
\r
225 get { return (roptions & RegexOptions.RightToLeft) != 0; }
\r
228 // public instance methods
\r
230 public string[] GetGroupNames () {
\r
231 string[] names = new string[mapping.Count];
\r
232 mapping.Keys.CopyTo (names, 0);
\r
237 public int[] GetGroupNumbers () {
\r
238 int[] numbers = new int[mapping.Count];
\r
239 mapping.Values.CopyTo (numbers, 0);
\r
244 public string GroupNameFromNumber (int i) {
\r
245 if (i > group_count)
\r
248 foreach (string name in mapping.Keys) {
\r
249 if ((int)mapping[name] == i)
\r
256 public int GroupNumberFromName (string name) {
\r
257 if (mapping.Contains (name))
\r
258 return (int)mapping[name];
\r
265 public bool IsMatch (string input) {
\r
267 return IsMatch (input, input.Length);
\r
269 return IsMatch (input, 0);
\r
272 public bool IsMatch (string input, int startat) {
\r
273 return Match (input, startat).Success;
\r
276 public Match Match (string input) {
\r
278 return Match (input, input.Length);
\r
280 return Match (input, 0);
\r
283 public Match Match (string input, int startat) {
\r
285 return CreateMachine ().Scan (this, input, startat, input.Length);
\r
288 public Match Match (string input, int startat, int length) {
\r
290 return CreateMachine ().Scan (this, input, startat, startat + length);
\r
293 public MatchCollection Matches (string input) {
\r
295 return Matches (input, input.Length);
\r
297 return Matches (input, 0);
\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
305 m = m.NextMatch ();
\r
313 public string Replace (string input, MatchEvaluator evaluator) {
\r
315 return Replace (input, evaluator, Int32.MaxValue, input.Length);
\r
317 return Replace (input, evaluator, Int32.MaxValue, 0);
\r
320 public string Replace (string input, MatchEvaluator evaluator, int count) {
\r
322 return Replace (input, evaluator, count, input.Length);
\r
324 return Replace (input, evaluator, count, 0);
\r
327 public string Replace (string input, MatchEvaluator evaluator, int count, int startat)
\r
329 StringBuilder result = new StringBuilder ();
\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
337 ptr = m.Index + m.Length;
\r
338 m = m.NextMatch ();
\r
340 result.Append (input.Substring (ptr));
\r
342 return result.ToString ();
\r
345 public string Replace (string input, string replacement) {
\r
347 return Replace (input, replacement, Int32.MaxValue, input.Length);
\r
349 return Replace (input, replacement, Int32.MaxValue, 0);
\r
352 public string Replace (string input, string replacement, int count) {
\r
354 return Replace (input, replacement, count, input.Length);
\r
356 return Replace (input, replacement, count, 0);
\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
366 public string[] Split (string input) {
\r
368 return Split (input, Int32.MaxValue, input.Length);
\r
370 return Split (input, Int32.MaxValue, 0);
\r
373 public string[] Split (string input, int count) {
\r
375 return Split (input, count, input.Length);
\r
377 return Split (input, count, 0);
\r
380 public string[] Split (string input, int count, int startat) {
\r
381 ArrayList splits = new ArrayList ();
\r
383 count = Int32.MaxValue;
\r
386 while (--count > 0) {
\r
387 Match m = Match (input, ptr);
\r
392 splits.Add (input.Substring (m.Index + m.Length , ptr - m.Index - m.Length ));
\r
394 splits.Add (input.Substring (ptr, m.Index - ptr));
\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
405 ptr = m.Index + m.Length;
\r
411 splits.Add (input.Substring(0, ptr));
\r
415 if (ptr <= input.Length) {
\r
416 splits.Add (input.Substring (ptr));
\r
421 return (string []) splits.ToArray (typeof (string));
\r
424 // MS undocummented method
\r
426 protected void InitializeReferences() {
\r
427 throw new Exception ("Not implemented.");
\r
430 protected bool UseOptionC(){
\r
431 throw new Exception ("Not implemented.");
\r
434 protected bool UseOptionR(){
\r
435 throw new Exception ("Not implemented.");
\r
440 public override string ToString () {
\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
452 internal int GroupCount {
\r
453 get { return group_count; }
\r
458 private IMachine CreateMachine () {
\r
459 return machineFactory.NewInstance ();
\r
462 private IMachineFactory machineFactory;
\r
463 private IDictionary mapping;
\r
464 private int group_count;
\r
467 // protected members
\r
469 protected internal string pattern;
\r
470 protected internal RegexOptions roptions;
\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
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
486 this.full_namespace = full_namespace;
\r
487 this.is_public = is_public;
\r
490 public bool IsPublic {
\r
491 get { return is_public; }
\r
492 set { is_public = value; }
\r
495 public string Name {
\r
496 get { return name; }
\r
497 set { name = value; }
\r
500 public string Namespace {
\r
501 get { return full_namespace; }
\r
502 set { full_namespace = value; }
\r
505 public RegexOptions Options {
\r
506 get { return options; }
\r
507 set { options = value; }
\r
510 public string Pattern {
\r
511 get { return pattern; }
\r
512 set { pattern = value; }
\r
517 private string pattern, name, full_namespace;
\r
518 private RegexOptions options;
\r
519 private bool is_public;
\r