3 // namespace: System.Text.RegularExpressions
\r
6 // author: Dan Lewis (dlewis@gmx.co.uk)
\r
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;
\r
33 using System.Reflection;
\r
34 using System.Reflection.Emit;
\r
35 using System.Runtime.Serialization;
\r
37 using RegularExpression = System.Text.RegularExpressions.Syntax.RegularExpression;
\r
38 using Parser = System.Text.RegularExpressions.Syntax.Parser;
\r
40 using System.Diagnostics;
\r
43 namespace System.Text.RegularExpressions {
\r
45 public delegate string MatchEvaluator (Match match);
\r
48 public enum RegexOptions {
\r
52 ExplicitCapture = 0x004,
\r
55 IgnorePatternWhitespace = 0x020,
\r
56 RightToLeft = 0x040,
\r
58 CultureInvariant = 0x200
\r
62 public class Regex : ISerializable {
\r
63 public static void CompileToAssembly
\r
64 (RegexCompilationInfo[] regexes, AssemblyName aname)
\r
66 Regex.CompileToAssembly(regexes, aname, new CustomAttributeBuilder[] {}, null);
\r
69 public static void CompileToAssembly
\r
70 (RegexCompilationInfo[] regexes, AssemblyName aname,
\r
71 CustomAttributeBuilder[] attribs)
\r
73 Regex.CompileToAssembly(regexes, aname, attribs, null);
\r
77 public static void CompileToAssembly
\r
78 (RegexCompilationInfo[] regexes, AssemblyName aname,
\r
79 CustomAttributeBuilder[] attribs, string resourceFile)
\r
81 throw new NotImplementedException ();
\r
82 // TODO : Make use of attribs and resourceFile parameters
\r
84 AssemblyBuilder asmBuilder = AppDomain.CurrentDomain.DefineDynamicAssembly (aname, AssemblyBuilderAccess.RunAndSave);
\r
85 ModuleBuilder modBuilder = asmBuilder.DefineDynamicModule("InnerRegexModule",aname.Name);
\r
86 Parser psr = new Parser ();
\r
88 System.Console.WriteLine("CompileToAssembly");
\r
90 for(int i=0; i < regexes.Length; i++)
\r
92 System.Console.WriteLine("Compiling expression :" + regexes[i].Pattern);
\r
93 RegularExpression re = psr.ParseRegularExpression (regexes[i].Pattern, regexes[i].Options);
\r
97 CILCompiler cmp = new CILCompiler (modBuilder, i);
\r
98 bool reverse = (regexes[i].Options & RegexOptions.RightToLeft) !=0;
\r
99 re.Compile (cmp, reverse);
\r
105 // Define a runtime class with specified name and attributes.
\r
106 TypeBuilder builder = modBuilder.DefineType("ITest");
\r
107 builder.CreateType();
\r
108 asmBuilder.Save(aname.Name);
\r
112 public static string Escape (string str) {
\r
113 return Parser.Escape (str);
\r
116 public static string Unescape (string str) {
\r
117 return Parser.Unescape (str);
\r
120 public static bool IsMatch (string input, string pattern) {
\r
121 return IsMatch (input, pattern, RegexOptions.None);
\r
124 public static bool IsMatch (string input, string pattern, RegexOptions options) {
\r
125 Regex re = new Regex (pattern, options);
\r
126 return re.IsMatch (input);
\r
129 public static Match Match (string input, string pattern) {
\r
130 return Regex.Match (input, pattern, RegexOptions.None);
\r
133 public static Match Match (string input, string pattern, RegexOptions options) {
\r
134 Regex re = new Regex (pattern, options);
\r
135 return re.Match (input);
\r
138 public static MatchCollection Matches (string input, string pattern) {
\r
139 return Matches (input, pattern, RegexOptions.None);
\r
142 public static MatchCollection Matches (string input, string pattern, RegexOptions options) {
\r
143 Regex re = new Regex (pattern, options);
\r
144 return re.Matches (input);
\r
147 public static string Replace
\r
148 (string input, string pattern, MatchEvaluator evaluator)
\r
150 return Regex.Replace (input, pattern, evaluator, RegexOptions.None);
\r
153 public static string Replace
\r
154 (string input, string pattern, MatchEvaluator evaluator,
\r
155 RegexOptions options)
\r
157 Regex re = new Regex (pattern, options);
\r
158 return re.Replace (input, evaluator);
\r
161 public static string Replace
\r
162 (string input, string pattern, string replacement)
\r
164 return Regex.Replace (input, pattern, replacement, RegexOptions.None);
\r
167 public static string Replace
\r
168 (string input, string pattern, string replacement,
\r
169 RegexOptions options)
\r
171 Regex re = new Regex (pattern, options);
\r
172 return re.Replace (input, replacement);
\r
175 public static string[] Split (string input, string pattern) {
\r
176 return Regex.Split (input, pattern, RegexOptions.None);
\r
179 public static string[] Split (string input, string pattern, RegexOptions options) {
\r
180 Regex re = new Regex (pattern, options);
\r
181 return re.Split (input);
\r
186 private static FactoryCache cache = new FactoryCache (200); // TODO put some meaningful number here
\r
190 protected Regex () {
\r
191 // XXX what's this constructor for?
\r
192 // : Used to compile to assembly (Custum regex inherit from Regex and use this constructor)
\r
195 public Regex (string pattern) : this (pattern, RegexOptions.None) {
\r
198 public Regex (string pattern, RegexOptions options) {
\r
199 this.pattern = pattern;
\r
200 this.roptions = options;
\r
202 this.machineFactory = cache.Lookup (pattern, options);
\r
204 if (this.machineFactory == null) {
\r
205 // parse and install group mapping
\r
207 Parser psr = new Parser ();
\r
208 RegularExpression re = psr.ParseRegularExpression (pattern, options);
\r
209 this.group_count = re.GroupCount;
\r
210 this.mapping = psr.GetMapping ();
\r
215 //if ((options & RegexOptions.Compiled) != 0)
\r
216 // //throw new Exception ("Not implemented.");
\r
217 // cmp = new CILCompiler ();
\r
219 cmp = new PatternCompiler ();
\r
221 re.Compile (cmp, RightToLeft);
\r
223 // install machine factory and add to pattern cache
\r
225 this.machineFactory = cmp.GetMachineFactory ();
\r
226 this.machineFactory.Mapping = mapping;
\r
227 cache.Add (pattern, options, this.machineFactory);
\r
229 this.group_count = this.machineFactory.GroupCount;
\r
230 this.mapping = this.machineFactory.Mapping;
\r
234 private Regex (SerializationInfo info, StreamingContext context) :
\r
235 this (info.GetString ("pattern"),
\r
236 (RegexOptions) info.GetValue ("options", typeof (RegexOptions))) {
\r
239 // fixes public API signature
\r
244 // public instance properties
\r
246 public RegexOptions Options {
\r
247 get { return roptions; }
\r
250 public bool RightToLeft {
\r
251 get { return (roptions & RegexOptions.RightToLeft) != 0; }
\r
254 // public instance methods
\r
256 public string[] GetGroupNames () {
\r
257 string[] names = new string[mapping.Count];
\r
258 mapping.Keys.CopyTo (names, 0);
\r
263 public int[] GetGroupNumbers () {
\r
264 int[] numbers = new int[mapping.Count];
\r
265 mapping.Values.CopyTo (numbers, 0);
\r
270 public string GroupNameFromNumber (int i) {
\r
271 if (i > group_count)
\r
274 foreach (string name in mapping.Keys) {
\r
275 if ((int)mapping[name] == i)
\r
282 public int GroupNumberFromName (string name) {
\r
283 if (mapping.Contains (name))
\r
284 return (int)mapping[name];
\r
291 public bool IsMatch (string input) {
\r
293 return IsMatch (input, input.Length);
\r
295 return IsMatch (input, 0);
\r
298 public bool IsMatch (string input, int startat) {
\r
299 return Match (input, startat).Success;
\r
302 public Match Match (string input) {
\r
304 return Match (input, input.Length);
\r
306 return Match (input, 0);
\r
309 public Match Match (string input, int startat) {
\r
311 return CreateMachine ().Scan (this, input, startat, input.Length);
\r
314 public Match Match (string input, int startat, int length) {
\r
316 return CreateMachine ().Scan (this, input, startat, startat + length);
\r
319 public MatchCollection Matches (string input) {
\r
321 return Matches (input, input.Length);
\r
323 return Matches (input, 0);
\r
326 public MatchCollection Matches (string input, int startat) {
\r
327 MatchCollection ms = new MatchCollection ();
\r
328 Match m = Match (input, startat);
\r
329 while (m.Success) {
\r
331 m = m.NextMatch ();
\r
339 public string Replace (string input, MatchEvaluator evaluator) {
\r
341 return Replace (input, evaluator, Int32.MaxValue, input.Length);
\r
343 return Replace (input, evaluator, Int32.MaxValue, 0);
\r
346 public string Replace (string input, MatchEvaluator evaluator, int count) {
\r
348 return Replace (input, evaluator, count, input.Length);
\r
350 return Replace (input, evaluator, count, 0);
\r
353 public string Replace (string input, MatchEvaluator evaluator, int count, int startat)
\r
355 StringBuilder result = new StringBuilder ();
\r
358 Match m = Match (input, startat);
\r
359 while (m.Success && count -- > 0) {
\r
360 result.Append (input.Substring (ptr, m.Index - ptr));
\r
361 result.Append (evaluator (m));
\r
363 ptr = m.Index + m.Length;
\r
364 m = m.NextMatch ();
\r
366 result.Append (input.Substring (ptr));
\r
368 return result.ToString ();
\r
371 public string Replace (string input, string replacement) {
\r
373 return Replace (input, replacement, Int32.MaxValue, input.Length);
\r
375 return Replace (input, replacement, Int32.MaxValue, 0);
\r
378 public string Replace (string input, string replacement, int count) {
\r
380 return Replace (input, replacement, count, input.Length);
\r
382 return Replace (input, replacement, count, 0);
\r
385 public string Replace (string input, string replacement, int count, int startat) {
\r
386 ReplacementEvaluator ev = new ReplacementEvaluator (this, replacement);
\r
387 return Replace (input, new MatchEvaluator (ev.Evaluate), count, startat);
\r
392 public string[] Split (string input) {
\r
394 return Split (input, Int32.MaxValue, input.Length);
\r
396 return Split (input, Int32.MaxValue, 0);
\r
399 public string[] Split (string input, int count) {
\r
401 return Split (input, count, input.Length);
\r
403 return Split (input, count, 0);
\r
406 public string[] Split (string input, int count, int startat) {
\r
407 ArrayList splits = new ArrayList ();
\r
409 count = Int32.MaxValue;
\r
412 while (--count > 0) {
\r
413 Match m = Match (input, ptr);
\r
418 splits.Add (input.Substring (m.Index + m.Length , ptr - m.Index - m.Length ));
\r
420 splits.Add (input.Substring (ptr, m.Index - ptr));
\r
422 int gcount = m.Groups.Count;
\r
423 for (int gindex = 1; gindex < gcount; gindex++) {
\r
424 Group grp = m.Groups [gindex];
\r
425 splits.Add (input.Substring (grp.Index, grp.Length));
\r
431 ptr = m.Index + m.Length;
\r
437 splits.Add (input.Substring(0, ptr));
\r
441 if (ptr <= input.Length) {
\r
442 splits.Add (input.Substring (ptr));
\r
447 return (string []) splits.ToArray (typeof (string));
\r
450 // MS undocummented method
\r
452 protected void InitializeReferences() {
\r
453 throw new NotImplementedException ();
\r
457 protected bool UseOptionC(){
\r
458 throw new NotImplementedException ();
\r
462 protected bool UseOptionR(){
\r
463 throw new NotImplementedException ();
\r
468 public override string ToString () {
\r
472 // ISerializable interface
\r
473 void ISerializable.GetObjectData (SerializationInfo info, StreamingContext context) {
\r
474 info.AddValue ("pattern", this.ToString (), typeof (string));
\r
475 info.AddValue ("options", this.Options, typeof (RegexOptions));
\r
480 internal int GroupCount {
\r
481 get { return group_count; }
\r
486 private IMachine CreateMachine () {
\r
487 return machineFactory.NewInstance ();
\r
490 private IMachineFactory machineFactory;
\r
491 private IDictionary mapping;
\r
492 private int group_count;
\r
495 // protected members
\r
497 protected internal string pattern;
\r
498 protected internal RegexOptions roptions;
\r
500 // MS undocumented members
\r
502 protected internal System.Collections.Hashtable capnames;
\r
504 protected internal System.Collections.Hashtable caps;
\r
506 protected internal int capsize;
\r
508 protected internal string[] capslist;
\r
510 protected internal RegexRunnerFactory factory;
\r
514 public class RegexCompilationInfo {
\r
515 public RegexCompilationInfo (string pattern, RegexOptions options, string name, string nspace, bool isPublic)
\r
517 this.pattern = pattern;
\r
518 this.options = options;
\r
520 this.nspace = nspace;
\r
521 this.isPublic = isPublic;
\r
524 public bool IsPublic {
\r
525 get { return isPublic; }
\r
526 set { isPublic = value; }
\r
529 public string Name {
\r
530 get { return name; }
\r
531 set { name = value; }
\r
534 public string Namespace {
\r
535 get { return nspace; }
\r
536 set { nspace = value; }
\r
539 public RegexOptions Options {
\r
540 get { return options; }
\r
541 set { options = value; }
\r
544 public string Pattern {
\r
545 get { return pattern; }
\r
546 set { pattern = value; }
\r
551 private string pattern, name, nspace;
\r
552 private RegexOptions options;
\r
553 private bool isPublic;
\r