//------------------------------------------------------------------------------
// <copyright file="Regex.cs" company="Microsoft">
//
// Copyright (c) 2002 Microsoft Corporation. All rights reserved.
//
// The use and distribution terms for this software are contained in the file
// named license.txt, which can be found in the root of this distribution.
// By using this software in any fashion, you are agreeing to be bound by the
// terms of this license.
//
// You must not remove this notice, or any other, from this software.
//
// </copyright>
//------------------------------------------------------------------------------
// The Regex class represents a single compiled instance of a regular
// expression.
//
#define ECMA
namespace System.Text.RegularExpressions {
using System;
using System.Threading;
using System.Collections;
using System.Runtime.Serialization;
using System.Reflection;
using System.Reflection.Emit;
using System.Globalization;
/**//// <include file='doc\Regex.uex' path='docs/doc[@for="Regex"]/*' />
/// <devdoc>
/// <para>
/// Represents an immutable, compiled regular expression. Also
/// contains static methods that allow use of regular expressions without instantiating
/// a Regex explicitly.
/// </para>
/// </devdoc>
[ Serializable() ]
public class Regex : ISerializable {
// Fields used by precompiled regexes
/**//// <include file='doc\Regex.uex' path='docs/doc[@for="Regex.pattern"]/*' />
/// <devdoc>
/// <para>[To be supplied.]</para>
/// </devdoc>
protected internal string pattern;
/**//// <include file='doc\Regex.uex' path='docs/doc[@for="Regex.factory"]/*' />
/// <devdoc>
/// <para>[To be supplied.]</para>
/// </devdoc>
protected internal RegexRunnerFactory factory; // if compiled, this is the RegexRunner subclass
/**//// <include file='doc\Regex.uex' path='docs/doc[@for="Regex.roptions"]/*' />
/// <devdoc>
/// <para>[To be supplied.]</para>
/// </devdoc>
protected internal RegexOptions roptions; // the top-level options from the options string
/**//// <include file='doc\Regex.uex' path='docs/doc[@for="Regex.caps"]/*' />
/// <devdoc>
/// <para>[To be supplied.]</para>
/// </devdoc>
protected internal Hashtable caps; // if captures are sparse, this is the hashtable capnum->index
/**//// <include file='doc\Regex.uex' path='docs/doc[@for="Regex.capnames"]/*' />
/// <devdoc>
/// <para>[To be supplied.]</para>
/// </devdoc>
protected internal Hashtable capnames; // if named captures are used, this maps names->index
/**//// <include file='doc\Regex.uex' path='docs/doc[@for="Regex.capslist"]/*' />
/// <devdoc>
/// <para>[To be supplied.]</para>
/// </devdoc>
protected internal String[] capslist; // if captures are sparse or named captures are used, this is the sorted list of names
/**//// <include file='doc\Regex.uex' path='docs/doc[@for="Regex.capsize"]/*' />
/// <devdoc>
/// <para>[To be supplied.]</para>
/// </devdoc>
protected internal int capsize; // the size of the capture array
internal ExclusiveReference runnerref; // cached runner
internal SharedReference replref; // cached parsed replacement pattern
internal RegexCode code; // if interpreted, this is the code for RegexIntepreter
internal CachedCodeEntry cachedentry;
internal bool refsInitialized = false;
internal static Hashtable livecode = new Hashtable();// the cached of code and factories that are currently loaded
internal const int MaxOptionShift = 10;
/**//// <include file='doc\Regex.uex' path='docs/doc[@for="Regex.Regex2"]/*' />
protected Regex() {
}
// Compiles and returns a Regex object corresponding to the given pattern
/**//// <include file='doc\Regex.uex' path='docs/doc[@for="Regex.Regex"]/*' />
/// <devdoc>
/// <para>
/// Creates and compiles a regular expression object for the specified regular
/// expression.
/// </para>
/// </devdoc>
public Regex(String pattern) : this(pattern, RegexOptions.None) {
}
// Returns a Regex object corresponding to the given pattern, compiled with
// the specified options.
/**//// <include file='doc\Regex.uex' path='docs/doc[@for="Regex.Regex1"]/*' />
/// <devdoc>
/// <para>
/// Creates and compiles a regular expression object for the
/// specified regular expression
/// with options that modify the pattern.
/// </para>
/// </devdoc>
public Regex(String pattern, RegexOptions options) {
RegexTree tree;
CachedCodeEntry cached;
if (pattern == null)
throw new ArgumentNullException("pattern");
if (options < RegexOptions.None || ( ((int) options) >> MaxOptionShift) != 0)
throw new ArgumentOutOfRangeException("options");
if ((options & RegexOptions.ECMAScript) != 0
&& (options & ~(RegexOptions.ECMAScript | RegexOptions.IgnoreCase | RegexOptions.Multiline | RegexOptions.Compiled
#if DBG
| RegexOptions.Debug
#endif
)) != 0)
throw new ArgumentOutOfRangeException("options");
String key = ((int) options).ToString(NumberFormatInfo.InvariantInfo) + ":" + pattern;
cached = LookupCached(key);
this.pattern = pattern;
this.roptions = options;
if (cached == null) {
// Parse the input
tree = RegexParser.Parse(pattern, roptions);
// Extract the relevant information
capnames = tree._capnames;
capslist = tree._capslist;
code = RegexWriter.Write(tree);
caps = code._caps;
capsize = code._capsize;
InitializeReferences();
tree = null;
cachedentry= CacheCode(key);
}
else {
caps = cached._caps;
capnames = cached._capnames;
capslist = cached._capslist;
capsize = cached._capsize;
code = cached._code;
factory = cached._factory;
runnerref = cached._runnerref;
replref = cached._replref;
refsInitialized = true;
cachedentry = cached;
}
// if the compile option is set, then compile the code if it's not already
if (UseOptionC() && factory == null) {
factory = Compile(code, roptions);
cachedentry.AddCompiled(factory);
code = null;
}
}
// ISerializable constructor
private Regex(SerializationInfo info, StreamingContext context) : this(info.GetString("pattern"), (RegexOptions) info.GetInt32("options")) {
}
// ISerializable method
/**//// <include file='doc\Regex.uex' path='docs/doc[@for="Regex.ISerializable.GetObjectData"]/*' />
/// <internalonly/>
void ISerializable.GetObjectData(SerializationInfo si, StreamingContext context) {
si.AddValue("pattern", this.ToString());
si.AddValue("options", this.Options);
}
// This method is here for perf reasons: if the call to RegexCompiler is NOT in the
// Regex constructor, we don't load RegexCompiler and its reflection classes when
// instantiating a non-compiled regex
// This method is internal virtual so the jit does not inline it.
internal virtual RegexRunnerFactory Compile(RegexCode code, RegexOptions roptions) {
return RegexCompiler.Compile(code, roptions);
}
// No refs -> we can release our ref on the cached code
/**//// <include file='doc\Regex.uex' path='docs/doc[@for="Regex.Finalize"]/*' />
/// <devdoc>
/// <para>[To be supplied.]</para>
/// </devdoc>
~Regex() {
UncacheCode();
}
// Escape metacharacters within the string
// <copyright file="Regex.cs" company="Microsoft">
//
// Copyright (c) 2002 Microsoft Corporation. All rights reserved.
//
// The use and distribution terms for this software are contained in the file
// named license.txt, which can be found in the root of this distribution.
// By using this software in any fashion, you are agreeing to be bound by the
// terms of this license.
//
// You must not remove this notice, or any other, from this software.
//
// </copyright>
//------------------------------------------------------------------------------
// The Regex class represents a single compiled instance of a regular
// expression.
//
#define ECMA
namespace System.Text.RegularExpressions {
using System;
using System.Threading;
using System.Collections;
using System.Runtime.Serialization;
using System.Reflection;
using System.Reflection.Emit;
using System.Globalization;
/**//// <include file='doc\Regex.uex' path='docs/doc[@for="Regex"]/*' />
/// <devdoc>
/// <para>
/// Represents an immutable, compiled regular expression. Also
/// contains static methods that allow use of regular expressions without instantiating
/// a Regex explicitly.
/// </para>
/// </devdoc>
[ Serializable() ]
public class Regex : ISerializable {
// Fields used by precompiled regexes
/**//// <include file='doc\Regex.uex' path='docs/doc[@for="Regex.pattern"]/*' />
/// <devdoc>
/// <para>[To be supplied.]</para>
/// </devdoc>
protected internal string pattern;
/**//// <include file='doc\Regex.uex' path='docs/doc[@for="Regex.factory"]/*' />
/// <devdoc>
/// <para>[To be supplied.]</para>
/// </devdoc>
protected internal RegexRunnerFactory factory; // if compiled, this is the RegexRunner subclass
/**//// <include file='doc\Regex.uex' path='docs/doc[@for="Regex.roptions"]/*' />
/// <devdoc>
/// <para>[To be supplied.]</para>
/// </devdoc>
protected internal RegexOptions roptions; // the top-level options from the options string
/**//// <include file='doc\Regex.uex' path='docs/doc[@for="Regex.caps"]/*' />
/// <devdoc>
/// <para>[To be supplied.]</para>
/// </devdoc>
protected internal Hashtable caps; // if captures are sparse, this is the hashtable capnum->index
/**//// <include file='doc\Regex.uex' path='docs/doc[@for="Regex.capnames"]/*' />
/// <devdoc>
/// <para>[To be supplied.]</para>
/// </devdoc>
protected internal Hashtable capnames; // if named captures are used, this maps names->index
/**//// <include file='doc\Regex.uex' path='docs/doc[@for="Regex.capslist"]/*' />
/// <devdoc>
/// <para>[To be supplied.]</para>
/// </devdoc>
protected internal String[] capslist; // if captures are sparse or named captures are used, this is the sorted list of names
/**//// <include file='doc\Regex.uex' path='docs/doc[@for="Regex.capsize"]/*' />
/// <devdoc>
/// <para>[To be supplied.]</para>
/// </devdoc>
protected internal int capsize; // the size of the capture array
internal ExclusiveReference runnerref; // cached runner
internal SharedReference replref; // cached parsed replacement pattern
internal RegexCode code; // if interpreted, this is the code for RegexIntepreter
internal CachedCodeEntry cachedentry;
internal bool refsInitialized = false;
internal static Hashtable livecode = new Hashtable();// the cached of code and factories that are currently loaded
internal const int MaxOptionShift = 10;
/**//// <include file='doc\Regex.uex' path='docs/doc[@for="Regex.Regex2"]/*' />
protected Regex() {
}
// Compiles and returns a Regex object corresponding to the given pattern
/**//// <include file='doc\Regex.uex' path='docs/doc[@for="Regex.Regex"]/*' />
/// <devdoc>
/// <para>
/// Creates and compiles a regular expression object for the specified regular
/// expression.
/// </para>
/// </devdoc>
public Regex(String pattern) : this(pattern, RegexOptions.None) {
}
// Returns a Regex object corresponding to the given pattern, compiled with
// the specified options.
/**//// <include file='doc\Regex.uex' path='docs/doc[@for="Regex.Regex1"]/*' />
/// <devdoc>
/// <para>
/// Creates and compiles a regular expression object for the
/// specified regular expression
/// with options that modify the pattern.
/// </para>
/// </devdoc>
public Regex(String pattern, RegexOptions options) {
RegexTree tree;
CachedCodeEntry cached;
if (pattern == null)
throw new ArgumentNullException("pattern");
if (options < RegexOptions.None || ( ((int) options) >> MaxOptionShift) != 0)
throw new ArgumentOutOfRangeException("options");
if ((options & RegexOptions.ECMAScript) != 0
&& (options & ~(RegexOptions.ECMAScript | RegexOptions.IgnoreCase | RegexOptions.Multiline | RegexOptions.Compiled
#if DBG
| RegexOptions.Debug
#endif
)) != 0)
throw new ArgumentOutOfRangeException("options");
String key = ((int) options).ToString(NumberFormatInfo.InvariantInfo) + ":" + pattern;
cached = LookupCached(key);
this.pattern = pattern;
this.roptions = options;
if (cached == null) {
// Parse the input
tree = RegexParser.Parse(pattern, roptions);
// Extract the relevant information
capnames = tree._capnames;
capslist = tree._capslist;
code = RegexWriter.Write(tree);
caps = code._caps;
capsize = code._capsize;
InitializeReferences();
tree = null;
cachedentry= CacheCode(key);
}
else {
caps = cached._caps;
capnames = cached._capnames;
capslist = cached._capslist;
capsize = cached._capsize;
code = cached._code;
factory = cached._factory;
runnerref = cached._runnerref;
replref = cached._replref;
refsInitialized = true;
cachedentry = cached;
}
// if the compile option is set, then compile the code if it's not already
if (UseOptionC() && factory == null) {
factory = Compile(code, roptions);
cachedentry.AddCompiled(factory);
code = null;
}
}
// ISerializable constructor
private Regex(SerializationInfo info, StreamingContext context) : this(info.GetString("pattern"), (RegexOptions) info.GetInt32("options")) {
}
// ISerializable method
/**//// <include file='doc\Regex.uex' path='docs/doc[@for="Regex.ISerializable.GetObjectData"]/*' />
/// <internalonly/>
void ISerializable.GetObjectData(SerializationInfo si, StreamingContext context) {
si.AddValue("pattern", this.ToString());
si.AddValue("options", this.Options);
}
// This method is here for perf reasons: if the call to RegexCompiler is NOT in the
// Regex constructor, we don't load RegexCompiler and its reflection classes when
// instantiating a non-compiled regex
// This method is internal virtual so the jit does not inline it.
internal virtual RegexRunnerFactory Compile(RegexCode code, RegexOptions roptions) {
return RegexCompiler.Compile(code, roptions);
}
// No refs -> we can release our ref on the cached code
/**//// <include file='doc\Regex.uex' path='docs/doc[@for="Regex.Finalize"]/*' />
/// <devdoc>
/// <para>[To be supplied.]</para>
/// </devdoc>
~Regex() {
UncacheCode();
}
// Escape metacharacters within the string