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
{
50 public static void CompileToAssembly (RegexCompilationInfo
[] regexes
, AssemblyName aname
)
52 Regex
.CompileToAssembly(regexes
, aname
, new CustomAttributeBuilder
[] {}, null);
56 public static void CompileToAssembly (RegexCompilationInfo
[] regexes
, AssemblyName aname
,
57 CustomAttributeBuilder
[] attribs
)
59 Regex
.CompileToAssembly(regexes
, aname
, attribs
, null);
63 public static void CompileToAssembly (RegexCompilationInfo
[] regexes
, AssemblyName aname
,
64 CustomAttributeBuilder
[] attribs
, string resourceFile
)
66 throw new NotImplementedException ();
67 // TODO : Make use of attribs and resourceFile parameters
69 AssemblyBuilder asmBuilder = AppDomain.CurrentDomain.DefineDynamicAssembly (aname, AssemblyBuilderAccess.RunAndSave);
70 ModuleBuilder modBuilder = asmBuilder.DefineDynamicModule("InnerRegexModule",aname.Name);
71 Parser psr = new Parser ();
73 System.Console.WriteLine("CompileToAssembly");
75 for(int i=0; i < regexes.Length; i++)
77 System.Console.WriteLine("Compiling expression :" + regexes[i].Pattern);
78 RegularExpression re = psr.ParseRegularExpression (regexes[i].Pattern, regexes[i].Options);
82 CILCompiler cmp = new CILCompiler (modBuilder, i);
83 bool reverse = (regexes[i].Options & RegexOptions.RightToLeft) !=0;
84 re.Compile (cmp, reverse);
90 // Define a runtime class with specified name and attributes.
91 TypeBuilder builder = modBuilder.DefineType("ITest");
93 asmBuilder.Save(aname.Name);
98 public static string Escape (string str
)
100 return Parser
.Escape (str
);
103 public static string Unescape (string str
)
105 return Parser
.Unescape (str
);
108 public static bool IsMatch (string input
, string pattern
)
110 return IsMatch (input
, pattern
, RegexOptions
.None
);
113 public static bool IsMatch (string input
, string pattern
, RegexOptions options
)
115 Regex re
= new Regex (pattern
, options
);
116 return re
.IsMatch (input
);
119 public static Match
Match (string input
, string pattern
)
121 return Regex
.Match (input
, pattern
, RegexOptions
.None
);
124 public static Match
Match (string input
, string pattern
, RegexOptions options
)
126 Regex re
= new Regex (pattern
, options
);
127 return re
.Match (input
);
130 public static MatchCollection
Matches (string input
, string pattern
)
132 return Matches (input
, pattern
, RegexOptions
.None
);
135 public static MatchCollection
Matches (string input
, string pattern
, RegexOptions options
)
137 Regex re
= new Regex (pattern
, options
);
138 return re
.Matches (input
);
141 public static string Replace (string input
, string pattern
, MatchEvaluator evaluator
)
143 return Regex
.Replace (input
, pattern
, evaluator
, RegexOptions
.None
);
146 public static string Replace (string input
, string pattern
, MatchEvaluator evaluator
,
147 RegexOptions options
)
149 Regex re
= new Regex (pattern
, options
);
150 return re
.Replace (input
, evaluator
);
153 public static string Replace (string input
, string pattern
, string replacement
)
155 return Regex
.Replace (input
, pattern
, replacement
, RegexOptions
.None
);
158 public static string Replace (string input
, string pattern
, string replacement
,
159 RegexOptions options
)
161 Regex re
= new Regex (pattern
, options
);
162 return re
.Replace (input
, replacement
);
165 public static string [] Split (string input
, string pattern
)
167 return Regex
.Split (input
, pattern
, RegexOptions
.None
);
170 public static string [] Split (string input
, string pattern
, RegexOptions options
)
172 Regex re
= new Regex (pattern
, options
);
173 return re
.Split (input
);
177 static FactoryCache cache
= new FactoryCache (15);
178 public static int CacheSize
{
179 get { return cache.Capacity; }
182 throw new ArgumentOutOfRangeException ("CacheSize");
184 cache
.Capacity
= value;
188 static FactoryCache cache
= new FactoryCache (200);
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) {
220 this.group_count
= this.machineFactory
.GroupCount
;
221 this.mapping
= this.machineFactory
.Mapping
;
222 this._groupNumberToNameMap
= this.machineFactory
.NamesMapping
;
227 private void InitNewRegex ()
229 this.machineFactory
= CreateMachineFactory (this.pattern
, this.roptions
);
230 cache
.Add (this.pattern
, this.roptions
, this.machineFactory
);
231 this.group_count
= machineFactory
.GroupCount
;
232 this.mapping
= machineFactory
.Mapping
;
233 this._groupNumberToNameMap
= this.machineFactory
.NamesMapping
;
236 // The new rx engine has blocking bugs like
237 // https://bugzilla.novell.com/show_bug.cgi?id=470827
238 static readonly bool old_rx
=
240 Environment
.GetEnvironmentVariable ("MONO_NEW_RX") == null;
245 private static IMachineFactory
CreateMachineFactory (string pattern
, RegexOptions options
)
247 Parser psr
= new Parser ();
248 RegularExpression re
= psr
.ParseRegularExpression (pattern
, options
);
252 if ((options
& RegexOptions
.Compiled
) != 0)
253 cmp
= new CILCompiler ();
255 cmp
= new RxCompiler ();
257 cmp
= new PatternCompiler ();
260 re
.Compile (cmp
, (options
& RegexOptions
.RightToLeft
) != 0);
262 IMachineFactory machineFactory
= cmp
.GetMachineFactory ();
263 machineFactory
.Mapping
= psr
.GetMapping ();
264 machineFactory
.NamesMapping
= GetGroupNamesArray (machineFactory
.GroupCount
, machineFactory
.Mapping
);
266 return machineFactory
;
274 Regex (SerializationInfo info
, StreamingContext context
) :
275 this (info
.GetString ("pattern"),
276 (RegexOptions
) info
.GetValue ("options", typeof (RegexOptions
)))
280 #if ONLY_1_1 && !TARGET_JVM
281 // fixes public API signature
286 // public instance properties
288 public RegexOptions Options
{
289 get { return roptions; }
292 public bool RightToLeft
{
293 get { return (roptions & RegexOptions.RightToLeft) != 0; }
296 // public instance methods
298 public string [] GetGroupNames ()
300 string [] names
= new string [mapping
.Count
];
301 mapping
.Keys
.CopyTo (names
, 0);
306 public int[] GetGroupNumbers ()
308 int[] numbers
= new int [mapping
.Count
];
309 mapping
.Values
.CopyTo (numbers
, 0);
314 public string GroupNameFromNumber (int i
)
316 if (i
< 0 || i
> group_count
)
319 return _groupNumberToNameMap
[i
];
322 public int GroupNumberFromName (string name
)
324 if (mapping
.Contains (name
))
325 return (int) mapping
[name
];
332 public bool IsMatch (string input
)
334 return IsMatch (input
, RightToLeft
? input
.Length
: 0);
337 public bool IsMatch (string input
, int startat
)
339 return Match (input
, startat
).Success
;
342 public Match
Match (string input
)
344 return Match (input
, RightToLeft
? input
.Length
: 0);
347 public Match
Match (string input
, int startat
)
349 return CreateMachine ().Scan (this, input
, startat
, input
.Length
);
352 public Match
Match (string input
, int startat
, int length
)
354 return CreateMachine ().Scan (this, input
, startat
, startat
+ length
);
357 public MatchCollection
Matches (string input
)
359 return Matches (input
, RightToLeft
? input
.Length
: 0);
362 public MatchCollection
Matches (string input
, int startat
)
364 Match m
= Match (input
, startat
);
365 return new MatchCollection (m
);
370 public string Replace (string input
, MatchEvaluator evaluator
)
372 return Replace (input
, evaluator
, Int32
.MaxValue
, RightToLeft
? input
.Length
: 0);
375 public string Replace (string input
, MatchEvaluator evaluator
, int count
)
377 return Replace (input
, evaluator
, count
, RightToLeft
? input
.Length
: 0);
382 public Adapter (MatchEvaluator ev
) { this.ev = ev; }
383 public void Evaluate (Match m
, StringBuilder sb
) { sb.Append (ev (m)); }
386 public string Replace (string input
, MatchEvaluator evaluator
, int count
, int startat
)
389 throw new ArgumentNullException ("null");
390 if (evaluator
== null)
391 throw new ArgumentNullException ("evaluator");
393 BaseMachine m
= (BaseMachine
)CreateMachine ();
396 return m
.RTLReplace (this, input
, evaluator
, count
, startat
);
398 // NOTE: If this is a cause of a lot of allocations, we can convert it to
399 // use a ThreadStatic allocation mitigator
400 Adapter a
= new Adapter (evaluator
);
402 return m
.LTRReplace (this, input
, new BaseMachine
.MatchAppendEvaluator (a
.Evaluate
),
406 public string Replace (string input
, string replacement
)
408 return Replace (input
, replacement
, Int32
.MaxValue
, RightToLeft
? input
.Length
: 0);
411 public string Replace (string input
, string replacement
, int count
)
413 return Replace (input
, replacement
, count
, RightToLeft
? input
.Length
: 0);
416 public string Replace (string input
, string replacement
, int count
, int startat
)
418 return CreateMachine ().Replace (this, input
, replacement
, count
, startat
);
423 public string [] Split (string input
)
425 return Split (input
, Int32
.MaxValue
, RightToLeft
? input
.Length
: 0);
428 public string [] Split (string input
, int count
)
430 return Split (input
, count
, RightToLeft
? input
.Length
: 0);
433 public string [] Split (string input
, int count
, int startat
)
435 return CreateMachine ().Split (this, input
, count
, startat
);
438 // This method is called at the end of the constructor of compiled
439 // regular expression classes to do internal initialization.
440 protected void InitializeReferences ()
443 throw new NotSupportedException ("This operation is only allowed once per object.");
445 refsInitialized
= true;
447 // Compile pattern that results in performance loss as existing
448 // CIL code is ignored but provides support for regular
449 // expressions compiled to assemblies.
453 protected bool UseOptionC ()
455 return ((roptions
& RegexOptions
.Compiled
) != 0);
458 protected bool UseOptionR ()
460 return ((roptions
& RegexOptions
.RightToLeft
) != 0);
465 public override string ToString ()
470 // ISerializable interface
471 void ISerializable
.GetObjectData (SerializationInfo info
, StreamingContext context
)
473 info
.AddValue ("pattern", this.ToString (), typeof (string));
474 info
.AddValue ("options", this.Options
, typeof (RegexOptions
));
479 internal int GroupCount
{
480 get { return group_count; }
485 private IMachine
CreateMachine ()
487 return machineFactory
.NewInstance ();
490 private static string [] GetGroupNamesArray (int groupCount
, IDictionary mapping
)
492 string [] groupNumberToNameMap
= new string [groupCount
+ 1];
493 foreach (string name
in mapping
.Keys
) {
494 groupNumberToNameMap
[(int) mapping
[name
]] = name
;
496 return groupNumberToNameMap
;
499 private IMachineFactory machineFactory
;
500 private IDictionary mapping
;
501 private int group_count
;
502 private bool refsInitialized
;
503 private string [] _groupNumberToNameMap
;
508 protected internal string pattern
;
509 protected internal RegexOptions roptions
;
511 // MS undocumented members
514 protected internal System
.Collections
.Generic
.Dictionary
<string, int> capnames
;
516 protected internal System
.Collections
.Generic
.Dictionary
<int, int> caps
;
519 protected internal System
.Collections
.Hashtable capnames
;
521 protected internal System
.Collections
.Hashtable caps
;
524 protected internal int capsize
;
526 protected internal string [] capslist
;
528 protected internal RegexRunnerFactory factory
;