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
\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
18 // The above copyright notice and this permission notice shall be
\r
19 // included in all copies or substantial portions of the Software.
\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
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
47 delegate void MatchAppendEvaluator (Match match, StringBuilder sb);
\r
50 public enum RegexOptions {
\r
54 ExplicitCapture = 0x004,
\r
57 IgnorePatternWhitespace = 0x020,
\r
58 RightToLeft = 0x040,
\r
60 CultureInvariant = 0x200
\r
64 public class Regex : ISerializable {
\r
65 public static void CompileToAssembly
\r
66 (RegexCompilationInfo[] regexes, AssemblyName aname)
\r
68 Regex.CompileToAssembly(regexes, aname, new CustomAttributeBuilder[] {}, null);
\r
71 public static void CompileToAssembly
\r
72 (RegexCompilationInfo[] regexes, AssemblyName aname,
\r
73 CustomAttributeBuilder[] attribs)
\r
75 Regex.CompileToAssembly(regexes, aname, attribs, null);
\r
79 public static void CompileToAssembly
\r
80 (RegexCompilationInfo[] regexes, AssemblyName aname,
\r
81 CustomAttributeBuilder[] attribs, string resourceFile)
\r
83 throw new NotImplementedException ();
\r
84 // TODO : Make use of attribs and resourceFile parameters
\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
90 System.Console.WriteLine("CompileToAssembly");
\r
92 for(int i=0; i < regexes.Length; i++)
\r
94 System.Console.WriteLine("Compiling expression :" + regexes[i].Pattern);
\r
95 RegularExpression re = psr.ParseRegularExpression (regexes[i].Pattern, regexes[i].Options);
\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
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
114 public static string Escape (string str) {
\r
115 return Parser.Escape (str);
\r
118 public static string Unescape (string str) {
\r
119 return Parser.Unescape (str);
\r
122 public static bool IsMatch (string input, string pattern) {
\r
123 return IsMatch (input, pattern, RegexOptions.None);
\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
131 public static Match Match (string input, string pattern) {
\r
132 return Regex.Match (input, pattern, RegexOptions.None);
\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
140 public static MatchCollection Matches (string input, string pattern) {
\r
141 return Matches (input, pattern, RegexOptions.None);
\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
149 public static string Replace
\r
150 (string input, string pattern, MatchEvaluator evaluator)
\r
152 return Regex.Replace (input, pattern, evaluator, RegexOptions.None);
\r
155 public static string Replace
\r
156 (string input, string pattern, MatchEvaluator evaluator,
\r
157 RegexOptions options)
\r
159 Regex re = new Regex (pattern, options);
\r
160 return re.Replace (input, evaluator);
\r
163 public static string Replace
\r
164 (string input, string pattern, string replacement)
\r
166 return Regex.Replace (input, pattern, replacement, RegexOptions.None);
\r
169 public static string Replace
\r
170 (string input, string pattern, string replacement,
\r
171 RegexOptions options)
\r
173 Regex re = new Regex (pattern, options);
\r
174 return re.Replace (input, replacement);
\r
177 public static string[] Split (string input, string pattern) {
\r
178 return Regex.Split (input, pattern, RegexOptions.None);
\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
188 private static FactoryCache cache = new FactoryCache (200); // TODO put some meaningful number here
\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
197 public Regex (string pattern) : this (pattern, RegexOptions.None) {
\r
200 public Regex (string pattern, RegexOptions options) {
\r
201 this.pattern = pattern;
\r
202 this.roptions = options;
\r
204 this.machineFactory = cache.Lookup (pattern, options);
\r
206 if (this.machineFactory == null) {
\r
207 // parse and install group mapping
\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
217 //if ((options & RegexOptions.Compiled) != 0)
\r
218 // //throw new Exception ("Not implemented.");
\r
219 // cmp = new CILCompiler ();
\r
221 cmp = new PatternCompiler ();
\r
223 re.Compile (cmp, RightToLeft);
\r
225 // install machine factory and add to pattern cache
\r
227 this.machineFactory = cmp.GetMachineFactory ();
\r
228 this.machineFactory.Mapping = mapping;
\r
229 cache.Add (pattern, options, this.machineFactory);
\r
231 this.group_count = this.machineFactory.GroupCount;
\r
232 this.mapping = this.machineFactory.Mapping;
\r
236 private Regex (SerializationInfo info, StreamingContext context) :
\r
237 this (info.GetString ("pattern"),
\r
238 (RegexOptions) info.GetValue ("options", typeof (RegexOptions))) {
\r
241 // fixes public API signature
\r
246 // public instance properties
\r
248 public RegexOptions Options {
\r
249 get { return roptions; }
\r
252 public bool RightToLeft {
\r
253 get { return (roptions & RegexOptions.RightToLeft) != 0; }
\r
256 // public instance methods
\r
258 public string[] GetGroupNames () {
\r
259 string[] names = new string[mapping.Count];
\r
260 mapping.Keys.CopyTo (names, 0);
\r
265 public int[] GetGroupNumbers () {
\r
266 int[] numbers = new int[mapping.Count];
\r
267 mapping.Values.CopyTo (numbers, 0);
\r
272 public string GroupNameFromNumber (int i) {
\r
273 if (i > group_count)
\r
276 foreach (string name in mapping.Keys) {
\r
277 if ((int)mapping[name] == i)
\r
284 public int GroupNumberFromName (string name) {
\r
285 if (mapping.Contains (name))
\r
286 return (int)mapping[name];
\r
293 public bool IsMatch (string input) {
\r
295 return IsMatch (input, input.Length);
\r
297 return IsMatch (input, 0);
\r
300 public bool IsMatch (string input, int startat) {
\r
301 return Match (input, startat).Success;
\r
304 public Match Match (string input) {
\r
306 return Match (input, input.Length);
\r
308 return Match (input, 0);
\r
311 public Match Match (string input, int startat) {
\r
313 return CreateMachine ().Scan (this, input, startat, input.Length);
\r
316 public Match Match (string input, int startat, int length) {
\r
318 return CreateMachine ().Scan (this, input, startat, startat + length);
\r
321 public MatchCollection Matches (string input) {
\r
323 return Matches (input, input.Length);
\r
325 return Matches (input, 0);
\r
328 public MatchCollection Matches (string input, int startat) {
\r
329 Match m = Match (input, startat);
\r
330 return new MatchCollection (m);
\r
335 public string Replace (string input, MatchEvaluator evaluator) {
\r
337 return Replace (input, evaluator, Int32.MaxValue, input.Length);
\r
339 return Replace (input, evaluator, Int32.MaxValue, 0);
\r
342 public string Replace (string input, MatchEvaluator evaluator, int count) {
\r
344 return Replace (input, evaluator, count, input.Length);
\r
346 return Replace (input, evaluator, count, 0);
\r
352 public Adapter (MatchEvaluator ev) { this.ev = ev; }
\r
353 public void Evaluate (Match m, StringBuilder sb) { sb.Append (ev (m)); }
\r
356 public string Replace (string input, MatchEvaluator evaluator, int count, int startat)
\r
358 Adapter a = new Adapter (evaluator);
\r
359 return Replace (input, new MatchAppendEvaluator (a.Evaluate), count, startat);
\r
362 string Replace (string input, MatchAppendEvaluator evaluator, int count, int startat)
\r
364 StringBuilder result = new StringBuilder ();
\r
366 int counter = count;
\r
368 result.Append (input, 0, ptr);
\r
370 Match m = Match (input, startat);
\r
371 while (m.Success) {
\r
373 if(counter -- <= 0)
\r
375 result.Append (input, ptr, m.Index - ptr);
\r
376 evaluator (m, result);
\r
378 ptr = m.Index + m.Length;
\r
379 m = m.NextMatch ();
\r
385 result.Append (input, ptr, input.Length - ptr);
\r
387 return result.ToString ();
\r
390 public string Replace (string input, string replacement) {
\r
392 return Replace (input, replacement, Int32.MaxValue, input.Length);
\r
394 return Replace (input, replacement, Int32.MaxValue, 0);
\r
397 public string Replace (string input, string replacement, int count) {
\r
399 return Replace (input, replacement, count, input.Length);
\r
401 return Replace (input, replacement, count, 0);
\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
411 public string[] Split (string input) {
\r
413 return Split (input, Int32.MaxValue, input.Length);
\r
415 return Split (input, Int32.MaxValue, 0);
\r
418 public string[] Split (string input, int count) {
\r
420 return Split (input, count, input.Length);
\r
422 return Split (input, count, 0);
\r
425 public string[] Split (string input, int count, int startat) {
\r
426 ArrayList splits = new ArrayList ();
\r
428 count = Int32.MaxValue;
\r
432 while (--count > 0) {
\r
434 m = m.NextMatch ();
\r
436 m = Match (input, ptr);
\r
442 splits.Add (input.Substring (m.Index + m.Length , ptr - m.Index - m.Length ));
\r
444 splits.Add (input.Substring (ptr, m.Index - ptr));
\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
455 ptr = m.Index + m.Length;
\r
461 splits.Add (input.Substring(0, ptr));
\r
465 if (ptr <= input.Length) {
\r
466 splits.Add (input.Substring (ptr));
\r
471 return (string []) splits.ToArray (typeof (string));
\r
474 // MS undocummented method
\r
476 protected void InitializeReferences() {
\r
477 throw new NotImplementedException ();
\r
481 protected bool UseOptionC(){
\r
482 throw new NotImplementedException ();
\r
486 protected bool UseOptionR(){
\r
487 throw new NotImplementedException ();
\r
492 public override string ToString () {
\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
504 internal int GroupCount {
\r
505 get { return group_count; }
\r
510 private IMachine CreateMachine () {
\r
511 return machineFactory.NewInstance ();
\r
514 private IMachineFactory machineFactory;
\r
515 private IDictionary mapping;
\r
516 private int group_count;
\r
519 // protected members
\r
521 protected internal string pattern;
\r
522 protected internal RegexOptions roptions;
\r
524 // MS undocumented members
\r
526 protected internal System.Collections.Hashtable capnames;
\r
528 protected internal System.Collections.Hashtable caps;
\r
530 protected internal int capsize;
\r
532 protected internal string[] capslist;
\r
534 protected internal RegexRunnerFactory factory;
\r
538 public class RegexCompilationInfo {
\r
539 public RegexCompilationInfo (string pattern, RegexOptions options, string name, string nspace, bool isPublic)
\r
541 this.pattern = pattern;
\r
542 this.options = options;
\r
544 this.nspace = nspace;
\r
545 this.isPublic = isPublic;
\r
548 public bool IsPublic {
\r
549 get { return isPublic; }
\r
550 set { isPublic = value; }
\r
553 public string Name {
\r
554 get { return name; }
\r
555 set { name = value; }
\r
558 public string Namespace {
\r
559 get { return nspace; }
\r
560 set { nspace = value; }
\r
563 public RegexOptions Options {
\r
564 get { return options; }
\r
565 set { options = value; }
\r
568 public string Pattern {
\r
569 get { return pattern; }
\r
570 set { pattern = value; }
\r
575 private string pattern, name, nspace;
\r
576 private RegexOptions options;
\r
577 private bool isPublic;
\r