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 partial 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);
101 public static string Escape (string str)
103 return Parser.Escape (str);
106 public static string Unescape (string str)
108 return Parser.Unescape (str);
111 public static bool IsMatch (string input, string pattern)
113 return IsMatch (input, pattern, RegexOptions.None);
116 public static bool IsMatch (string input, string pattern, RegexOptions options)
118 Regex re = new Regex (pattern, options);
119 return re.IsMatch (input);
122 public static Match Match (string input, string pattern)
124 return Regex.Match (input, pattern, RegexOptions.None);
127 public static Match Match (string input, string pattern, RegexOptions options)
129 Regex re = new Regex (pattern, options);
130 return re.Match (input);
133 public static MatchCollection Matches (string input, string pattern)
135 return Matches (input, pattern, RegexOptions.None);
138 public static MatchCollection Matches (string input, string pattern, RegexOptions options)
140 Regex re = new Regex (pattern, options);
141 return re.Matches (input);
144 public static string Replace (string input, string pattern, MatchEvaluator evaluator)
146 return Regex.Replace (input, pattern, evaluator, RegexOptions.None);
149 public static string Replace (string input, string pattern, MatchEvaluator evaluator,
150 RegexOptions options)
152 Regex re = new Regex (pattern, options);
153 return re.Replace (input, evaluator);
156 public static string Replace (string input, string pattern, string replacement)
158 return Regex.Replace (input, pattern, replacement, RegexOptions.None);
161 public static string Replace (string input, string pattern, string replacement,
162 RegexOptions options)
164 Regex re = new Regex (pattern, options);
165 return re.Replace (input, replacement);
168 public static string [] Split (string input, string pattern)
170 return Regex.Split (input, pattern, RegexOptions.None);
173 public static string [] Split (string input, string pattern, RegexOptions options)
175 Regex re = new Regex (pattern, options);
176 return re.Split (input);
180 static FactoryCache cache = new FactoryCache (15);
181 public static int CacheSize {
182 get { return cache.Capacity; }
185 throw new ArgumentOutOfRangeException ("CacheSize");
187 cache.Capacity = value;
191 static FactoryCache cache = new FactoryCache (200);
199 // This constructor is used by compiled regular expressions that are
200 // classes derived from Regex class. No initialization required.
205 public Regex (string pattern) : this (pattern, RegexOptions.None)
209 public Regex (string pattern, RegexOptions options)
211 this.pattern = pattern;
212 this.roptions = options;
218 this.machineFactory = cache.Lookup (this.pattern, this.roptions);
220 if (this.machineFactory == null) {
223 this.group_count = this.machineFactory.GroupCount;
224 this.mapping = this.machineFactory.Mapping;
225 this._groupNumberToNameMap = this.machineFactory.NamesMapping;
230 private void InitNewRegex ()
232 this.machineFactory = CreateMachineFactory (this.pattern, this.roptions);
233 cache.Add (this.pattern, this.roptions, this.machineFactory);
234 this.group_count = machineFactory.GroupCount;
235 this.mapping = machineFactory.Mapping;
236 this._groupNumberToNameMap = this.machineFactory.NamesMapping;
239 static readonly bool old_rx = Environment.GetEnvironmentVariable ("MONO_OLD_RX") != null;
241 private static IMachineFactory CreateMachineFactory (string pattern, RegexOptions options)
243 Parser psr = new Parser ();
244 RegularExpression re = psr.ParseRegularExpression (pattern, options);
248 if ((options & RegexOptions.Compiled) != 0)
249 cmp = new CILCompiler ();
251 cmp = new RxCompiler ();
253 cmp = new PatternCompiler ();
256 re.Compile (cmp, (options & RegexOptions.RightToLeft) != 0);
258 IMachineFactory machineFactory = cmp.GetMachineFactory ();
259 machineFactory.Mapping = psr.GetMapping ();
260 machineFactory.NamesMapping = GetGroupNamesArray (machineFactory.GroupCount, machineFactory.Mapping);
262 return machineFactory;
270 Regex (SerializationInfo info, StreamingContext context) :
271 this (info.GetString ("pattern"),
272 (RegexOptions) info.GetValue ("options", typeof (RegexOptions)))
276 #if ONLY_1_1 && !TARGET_JVM
277 // fixes public API signature
282 // public instance properties
284 public RegexOptions Options {
285 get { return roptions; }
288 public bool RightToLeft {
289 get { return (roptions & RegexOptions.RightToLeft) != 0; }
292 // public instance methods
294 public string [] GetGroupNames ()
296 string [] names = new string [mapping.Count];
297 mapping.Keys.CopyTo (names, 0);
302 public int[] GetGroupNumbers ()
304 int[] numbers = new int [mapping.Count];
305 mapping.Values.CopyTo (numbers, 0);
310 public string GroupNameFromNumber (int i)
312 if (i < 0 || i > group_count)
315 return _groupNumberToNameMap [i];
318 public int GroupNumberFromName (string name)
320 if (mapping.Contains (name))
321 return (int) mapping [name];
328 public bool IsMatch (string input)
330 return IsMatch (input, RightToLeft ? input.Length : 0);
333 public bool IsMatch (string input, int startat)
335 return Match (input, startat).Success;
338 public Match Match (string input)
340 return Match (input, RightToLeft ? input.Length : 0);
343 public Match Match (string input, int startat)
345 return CreateMachine ().Scan (this, input, startat, input.Length);
348 public Match Match (string input, int startat, int length)
350 return CreateMachine ().Scan (this, input, startat, startat + length);
353 public MatchCollection Matches (string input)
355 return Matches (input, RightToLeft ? input.Length : 0);
358 public MatchCollection Matches (string input, int startat)
360 Match m = Match (input, startat);
361 return new MatchCollection (m);
366 public string Replace (string input, MatchEvaluator evaluator)
368 return Replace (input, evaluator, Int32.MaxValue, RightToLeft ? input.Length : 0);
371 public string Replace (string input, MatchEvaluator evaluator, int count)
373 return Replace (input, evaluator, count, RightToLeft ? input.Length : 0);
378 public Adapter (MatchEvaluator ev) { this.ev = ev; }
379 public void Evaluate (Match m, StringBuilder sb) { sb.Append (ev (m)); }
382 public string Replace (string input, MatchEvaluator evaluator, int count, int startat)
384 BaseMachine m = (BaseMachine)CreateMachine ();
387 return m.RTLReplace (this, input, evaluator, count, startat);
389 // NOTE: If this is a cause of a lot of allocations, we can convert it to
390 // use a ThreadStatic allocation mitigator
391 Adapter a = new Adapter (evaluator);
393 return m.LTRReplace (this, input, new BaseMachine.MatchAppendEvaluator (a.Evaluate),
397 public string Replace (string input, string replacement)
399 return Replace (input, replacement, Int32.MaxValue, RightToLeft ? input.Length : 0);
402 public string Replace (string input, string replacement, int count)
404 return Replace (input, replacement, count, RightToLeft ? input.Length : 0);
407 public string Replace (string input, string replacement, int count, int startat)
409 return CreateMachine ().Replace (this, input, replacement, count, startat);
414 public string [] Split (string input)
416 return Split (input, Int32.MaxValue, RightToLeft ? input.Length : 0);
419 public string [] Split (string input, int count)
421 return Split (input, count, RightToLeft ? input.Length : 0);
424 public string [] Split (string input, int count, int startat)
426 return CreateMachine ().Split (this, input, count, startat);
429 // This method is called at the end of the constructor of compiled
430 // regular expression classes to do internal initialization.
431 protected void InitializeReferences ()
434 throw new NotSupportedException ("This operation is only allowed once per object.");
436 refsInitialized = true;
438 // Compile pattern that results in performance loss as existing
439 // CIL code is ignored but provides support for regular
440 // expressions compiled to assemblies.
444 protected bool UseOptionC ()
446 return ((roptions & RegexOptions.Compiled) != 0);
449 protected bool UseOptionR ()
451 return ((roptions & RegexOptions.RightToLeft) != 0);
456 public override string ToString ()
461 // ISerializable interface
462 void ISerializable.GetObjectData (SerializationInfo info, StreamingContext context)
464 info.AddValue ("pattern", this.ToString (), typeof (string));
465 info.AddValue ("options", this.Options, typeof (RegexOptions));
470 internal int GroupCount {
471 get { return group_count; }
476 private IMachine CreateMachine ()
478 return machineFactory.NewInstance ();
481 private static string [] GetGroupNamesArray (int groupCount, IDictionary mapping)
483 string [] groupNumberToNameMap = new string [groupCount + 1];
484 foreach (string name in mapping.Keys) {
485 groupNumberToNameMap [(int) mapping [name]] = name;
487 return groupNumberToNameMap;
490 private IMachineFactory machineFactory;
491 private IDictionary mapping;
492 private int group_count;
493 private bool refsInitialized;
494 private string [] _groupNumberToNameMap;
499 protected internal string pattern;
500 protected internal RegexOptions roptions;
502 // MS undocumented members
505 protected internal System.Collections.Generic.Dictionary<string, int> capnames;
507 protected internal System.Collections.Generic.Dictionary<int, int> caps;
510 protected internal System.Collections.Hashtable capnames;
512 protected internal System.Collections.Hashtable caps;
515 protected internal int capsize;
517 protected internal string [] capslist;
519 protected internal RegexRunnerFactory factory;