Regex.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ Net / Net / 3.5.50727.3053 / DEVDIV / depot / DevDiv / releases / whidbey / netfxsp / ndp / fx / src / Regex / System / Text / RegularExpressions / Regex.cs / 1 / Regex.cs

                            //------------------------------------------------------------------------------ 
// 
//     Copyright (c) Microsoft Corporation.  All rights reserved.
// 
//----------------------------------------------------------------------------- 

// The Regex class represents a single compiled instance of a regular 
// expression. 

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;
    using System.Security.Policy; 
    using System.Security.Permissions;
    using System.Runtime.CompilerServices;
    using System.Collections.Generic;
    using System.Runtime.Versioning; 

    ///  
    ///     
    ///       Represents an immutable, compiled regular expression. Also
    ///       contains static methods that allow use of regular expressions without instantiating 
    ///       a Regex explicitly.
    ///    
    /// 
    [ Serializable() ] 
    public class Regex : ISerializable {
 
        // Fields used by precompiled regexes 
        protected internal string pattern;
        protected internal RegexRunnerFactory factory;       // if compiled, this is the RegexRunner subclass 
        protected internal RegexOptions roptions;            // the top-level options from the options string
        protected internal Hashtable caps;                   // if captures are sparse, this is the hashtable capnum->index
        protected internal Hashtable capnames;               // if named captures are used, this maps names->index
        protected internal String[]  capslist;               // if captures are sparse or named captures are used, this is the sorted list of names 
        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  bool refsInitialized = false;

        internal static LinkedList livecode = new LinkedList();// the cached of code and factories that are currently loaded
        internal static int cacheSize = 15; 

        internal const int MaxOptionShift = 10; 
 
        protected Regex() {
        } 

        /*
         * Compiles and returns a Regex object corresponding to the given pattern
         */ 
        /// 
        ///     
        ///       Creates and compiles a regular expression object for the specified regular 
        ///       expression.
        ///     
        /// 
        public Regex(String pattern) : this(pattern, RegexOptions.None, false) {
        }
 
        /*
         * Returns a Regex object corresponding to the given pattern, compiled with 
         * the specified options. 
         */
        ///  
        ///    
        ///       Creates and compiles a regular expression object for the
        ///       specified regular expression
        ///       with options that modify the pattern. 
        ///    
        ///  
        public Regex(String pattern, RegexOptions options) : this(pattern, options, false){ 
        }
 
        private Regex(String pattern, RegexOptions options, bool useCache) {
            RegexTree tree;
            CachedCodeEntry cached = null;
            string cultureKey = null; 

            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 |
                             RegexOptions.CultureInvariant 
#if DBG 
                           | RegexOptions.Debug
#endif 
                                               )) != 0)
                throw new ArgumentOutOfRangeException("options");

            // Try to look up this regex in the cache.  We do this regardless of whether useCache is true since there's 
            // really no reason not to.
            if ((options & RegexOptions.CultureInvariant) != 0) 
                cultureKey = CultureInfo.InvariantCulture.ThreeLetterWindowsLanguageName; 
            else
                cultureKey = CultureInfo.CurrentCulture.ThreeLetterWindowsLanguageName; 

            String key = ((int) options).ToString(NumberFormatInfo.InvariantInfo) + ":" + cultureKey + ":" + pattern;
            cached = LookupCachedAndUpdate(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;
                if (useCache) 
                    cached = 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; 
            }
 
            // if the compile option is set, then compile the code if it's not already
            if (UseOptionC() && factory == null) {
                factory = Compile(code, roptions);
 
                if (useCache && cached != null)
                    cached.AddCompiled(factory); 
                code = null; 
            }
        } 

        /*
         *  ISerializable constructor
         */ 
        protected Regex(SerializationInfo info, StreamingContext context) : this(info.GetString("pattern"), (RegexOptions) info.GetInt32("options")) {
        } 
 
        /*
         *  ISerializable method 
         */
        /// 
        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.
        */ 
        [
            HostProtection(MayLeakOnAbort=true), 
            MethodImplAttribute(MethodImplOptions.NoInlining) 
        ]
        internal RegexRunnerFactory Compile(RegexCode code, RegexOptions roptions) { 
            return RegexCompiler.Compile(code, roptions);
        }

        /* 
         * Escape metacharacters within the string
         */ 
        ///  
        ///    
        ///       Escapes 
        ///          a minimal set of metacharacters (\, *, +, ?, |, {, [, (, ), ^, $, ., #, and
        ///          whitespace) by replacing them with their \ codes. This converts a string so that
        ///          it can be used as a constant within a regular expression safely. (Note that the
        ///          reason # and whitespace must be escaped is so the string can be used safely 
        ///          within an expression parsed with x mode. If future Regex features add
        ///          additional metacharacters, developers should depend on Escape to escape those 
        ///          characters as well.) 
        ///       
        ///     
        public static String Escape(String str) {
            if (str==null)
                throw new ArgumentNullException("str");
 
            return RegexParser.Escape(str);
        } 
 
        /*
         * Unescape character codes within the string 
         */
        /// 
        ///    
        ///       Unescapes any escaped characters in the input string. 
        ///    
        ///  
        public static String Unescape(String str) { 
            if (str==null)
                throw new ArgumentNullException("str"); 

            return RegexParser.Unescape(str);
        }
 
        public static int CacheSize {
            get { 
                return cacheSize; 
            }
            set { 
                if (value < 0)
                    throw new ArgumentOutOfRangeException("value");

                cacheSize = value; 
                if (livecode.Count > cacheSize) {
                    lock (livecode) { 
                        while (livecode.Count > cacheSize) 
                            livecode.RemoveLast();
                    } 
                }
            }
        }
 
        /// 
        ///     
        ///       Returns the options passed into the constructor 
        ///    
        ///  
        public RegexOptions Options {
            get { return roptions;}
        }
 
        /*
         * True if the regex is leftward 
         */ 
        /// 
        ///     
        ///       Indicates whether the regular expression matches from right to
        ///       left.
        ///    
        ///  
        public bool RightToLeft {
            get { 
                return UseOptionR(); 
            }
        } 

        /// 
        ///    
        ///       Returns the regular expression pattern passed into the constructor 
        ///    
        ///  
        public override string ToString() { 
            return pattern;
        } 

        /*
         * Returns an array of the group names that are used to capture groups
         * in the regular expression. Only needed if the regex is not known until 
         * runtime, and one wants to extract captured groups. (Probably unusual,
         * but supplied for completeness.) 
         */ 
        /// 
        ///    Returns 
        ///       the GroupNameCollection for the regular expression. This collection contains the
        ///       set of strings used to name capturing groups in the expression.
        ///    
        public String[] GetGroupNames() { 
            String[] result;
 
            if (capslist == null) { 
                int max = capsize;
                result = new String[max]; 

                for (int i = 0; i < max; i++) {
                    result[i] = Convert.ToString(i, CultureInfo.InvariantCulture);
                } 
            }
            else { 
                result = new String[capslist.Length]; 

                System.Array.Copy(capslist, 0, result, 0, capslist.Length); 
            }

            return result;
        } 

        /* 
         * Returns an array of the group numbers that are used to capture groups 
         * in the regular expression. Only needed if the regex is not known until
         * runtime, and one wants to extract captured groups. (Probably unusual, 
         * but supplied for completeness.)
         */
        /// 
        ///    returns 
        ///       the integer group number corresponding to a group name.
        ///     
        public int[] GetGroupNumbers() { 
            int[] result;
 
            if (caps == null) {
                int max = capsize;
                result = new int[max];
 
                for (int i = 0; i < max; i++) {
                    result[i] = i; 
                } 
            }
            else { 
                result = new int[caps.Count];

                IDictionaryEnumerator de = caps.GetEnumerator();
                while (de.MoveNext()) { 
                    result[(int)de.Value] = (int)de.Key;
                } 
            } 

            return result; 
        }

        /*
         * Given a group number, maps it to a group name. Note that nubmered 
         * groups automatically get a group name that is the decimal string
         * equivalent of its number. 
         * 
         * Returns null if the number is not a recognized group number.
         */ 
        /// 
        ///    
        ///       Retrieves a group name that corresponds to a group number.
        ///     
        /// 
        public String GroupNameFromNumber(int i) { 
            if (capslist == null) { 
                if (i >= 0 && i < capsize)
                    return i.ToString(CultureInfo.InvariantCulture); 

                return String.Empty;
            }
            else { 
                if (caps != null) {
                    Object obj = caps[i]; 
                    if (obj == null) 
                        return String.Empty;
 
                    i = (int)obj;
                }

                if (i >= 0 && i < capslist.Length) 
                    return capslist[i];
 
                return String.Empty; 
            }
        } 

        /*
         * Given a group name, maps it to a group number. Note that nubmered
         * groups automatically get a group name that is the decimal string 
         * equivalent of its number.
         * 
         * Returns -1 if the name is not a recognized group name. 
         */
        ///  
        ///    
        ///       Returns a group number that corresponds to a group name.
        ///    
        ///  
        public int GroupNumberFromName(String name) {
            int result = -1; 
 
            if (name == null)
                throw new ArgumentNullException("name"); 

            // look up name if we have a hashtable of names
            if (capnames != null) {
                Object ret = capnames[name]; 

                if (ret == null) 
                    return -1; 

                return(int)ret; 
            }

            // convert to an int if it looks like a number
            result = 0; 
            for (int i = 0; i < name.Length; i++) {
                char ch = name[i]; 
 
                if (ch > '9' || ch < '0')
                    return -1; 

                result *= 10;
                result += (ch - '0');
            } 

            // return int if it's in range 
            if (result >= 0 && result < capsize) 
                return result;
 
            return -1;
        }

        /* 
         * Static version of simple IsMatch call
         */ 
        ///     
        ///       
        ///          Searches the input 
        ///             string for one or more occurrences of the text supplied in the pattern
        ///             parameter.
        ///       
        ///     
        public static bool IsMatch(String input, String pattern) {
            return new Regex(pattern, RegexOptions.None, true).IsMatch(input); 
        } 

        /* 
         * Static version of simple IsMatch call
         */
        /// 
        ///     
        ///       Searches the input string for one or more occurrences of the text
        ///          supplied in the pattern parameter with matching options supplied in the options 
        ///          parameter. 
        ///       
        ///     
        public static bool IsMatch(String input, String pattern, RegexOptions options) {
            return new Regex(pattern, options, true).IsMatch(input);
        }
 
        /*
         * Returns true if the regex finds a match within the specified string 
         */ 
        /// 
        ///     
        ///       Searches the input string for one or
        ///          more matches using the previous pattern, options, and starting
        ///          position.
        ///        
        ///    
        public bool IsMatch(String input) { 
            if (input == null) 
                throw new ArgumentNullException("input");
 
            return(null == Run(true, -1, input, 0, input.Length, UseOptionR() ? input.Length : 0));
        }

        /* 
         * Returns true if the regex finds a match after the specified position
         * (proceeding leftward if the regex is leftward and rightward otherwise) 
         */ 
        /// 
        ///     
        ///       Searches the input
        ///          string for one or more matches using the previous pattern and options, with
        ///          a new starting position.
        ///     
        /// 
        public bool IsMatch(String input, int startat) { 
            if (input == null) 
                throw new ArgumentNullException("input");
 
            return(null == Run(true, -1, input, 0, input.Length, startat));
        }

        /* 
         * Static version of simple Match call
         */ 
        ///     
        ///       
        ///          Searches the input string for one or more occurrences of the text 
        ///             supplied in the pattern parameter.
        ///       
        ///    
        public static Match Match(String input, String pattern) { 
            return new Regex(pattern, RegexOptions.None, true).Match(input);
        } 
 
        /*
         * Static version of simple Match call 
         */
        /// 
        ///    
        ///       Searches the input string for one or more occurrences of the text 
        ///          supplied in the pattern parameter. Matching is modified with an option
        ///          string. 
        ///        
        ///    
        public static Match Match(String input, String pattern, RegexOptions options) { 
            return new Regex(pattern, options, true).Match(input);
        }

        /* 
         * Finds the first match for the regular expression starting at the beginning
         * of the string (or at the end of the string if the regex is leftward) 
         */ 
        /// 
        ///     
        ///       Matches a regular expression with a string and returns
        ///       the precise result as a RegexMatch object.
        ///    
        ///  
        public Match Match(String input) {
            if (input == null) 
                throw new ArgumentNullException("input"); 

            return Run(false, -1, input, 0, input.Length, UseOptionR() ? input.Length : 0); 
        }

        /*
         * Finds the first match, starting at the specified position 
         */
        ///  
        ///    Matches a regular expression with a string and returns 
        ///    the precise result as a RegexMatch object.
        ///  
        public Match Match(String input, int startat) {
            if (input == null)
                throw new ArgumentNullException("input");
 
            return Run(false, -1, input, 0, input.Length, startat);
        } 
 
        /*
         * Finds the first match, restricting the search to the specified interval of 
         * the char array.
         */
        /// 
        ///     
        ///       Matches a
        ///       regular expression with a string and returns the precise result as a 
        ///       RegexMatch object. 
        ///    
        ///  
        public Match Match(String input, int beginning, int length) {
            if (input == null)
                throw new ArgumentNullException("input");
 
            return Run(false, -1, input, beginning, length, UseOptionR() ? beginning + length : beginning);
        } 
 
        /*
         * Static version of simple Matches call 
         */
        ///    
        ///       
        ///          Returns all the successful matches as if Match were 
        ///          called iteratively numerous times.
        ///        
        ///     
        public static MatchCollection Matches(String input, String pattern) {
            return new Regex(pattern, RegexOptions.None, true).Matches(input); 
        }

        /*
         * Static version of simple Matches call 
         */
        ///  
        ///     
        ///       Returns all the successful matches as if Match were called iteratively
        ///       numerous times. 
        ///    
        /// 
        public static MatchCollection Matches(String input, String pattern, RegexOptions options) {
            return new Regex(pattern, options, true).Matches(input); 
        }
 
        /* 
         * Finds the first match for the regular expression starting at the beginning
         * of the string Enumerator(or at the end of the string if the regex is leftward) 
         */
        /// 
        ///    
        ///       Returns 
        ///       all the successful matches as if Match was called iteratively numerous
        ///       times. 
        ///     
        /// 
        public MatchCollection Matches(String input) { 
            if (input == null)
                throw new ArgumentNullException("input");

            return new MatchCollection(this, input, 0, input.Length, UseOptionR() ? input.Length : 0); 
        }
 
        /* 
         * Finds the first match, starting at the specified position
         */ 
        /// 
        ///    
        ///       Returns
        ///       all the successful matches as if Match was called iteratively numerous 
        ///       times.
        ///     
        ///  
        public MatchCollection Matches(String input, int startat) {
            if (input == null) 
                throw new ArgumentNullException("input");

            return new MatchCollection(this, input, 0, input.Length, startat);
        } 

        /* 
         * Static version of simple Replace call 
         */
        ///  
        ///    
        ///       Replaces
        ///          all occurrences of the pattern with the  pattern, starting at
        ///          the first character in the input string. 
        ///       
        ///     
        public static String Replace(String input, String pattern, String replacement) { 
            return new Regex(pattern, RegexOptions.None, true).Replace(input, replacement);
        } 

        /*
         * Static version of simple Replace call
         */ 
        /// 
        ///     
        ///       Replaces all occurrences of 
        ///          the with the 
        ///          pattern, starting at the first character in the input string. 
        ///       
        ///    
        public static String Replace(String input, String pattern, String replacement, RegexOptions options) {
            return new Regex(pattern, options, true).Replace(input, replacement); 
        }
 
        /* 
         * Does the replacement
         */ 
        /// 
        ///    
        ///       Replaces all occurrences of
        ///          the  with the  pattern, starting at the 
        ///          first character in the input string, using the previous patten.
        ///        
        ///     
        public String Replace(String input, String replacement) {
            if (input == null) 
                throw new ArgumentNullException("input");

            return Replace(input, replacement, -1, UseOptionR() ? input.Length : 0);
        } 

        /* 
         * Does the replacement 
         */
        ///  
        ///    
        ///    Replaces all occurrences of the (previously defined) with the
        ///     pattern, starting at the first character in the input string.
        ///  
        /// 
        public String Replace(String input, String replacement, int count) { 
            if (input == null) 
                throw new ArgumentNullException("input");
 
            return Replace(input, replacement, count, UseOptionR() ? input.Length : 0);
        }

        /* 
         * Does the replacement
         */ 
        ///  
        ///    
        ///    Replaces all occurrences of the with the recent 
        ///     pattern, starting at the character position
        ///    
        /// 
        ///  
        public String Replace(String input, String replacement, int count, int startat) {
            RegexReplacement repl; 
 
            if (input == null)
                throw new ArgumentNullException("input"); 
            if (replacement == null)
                throw new ArgumentNullException("replacement");

            // a little code to grab a cached parsed replacement object 
            repl = (RegexReplacement)replref.Get();
 
            if (repl == null || !repl.Pattern.Equals(replacement)) { 
                repl = RegexParser.ParseReplacement(replacement, caps, capsize, capnames, this.roptions);
                replref.Cache(repl); 
            }

            return repl.Replace(this, input, count, startat);
        } 

        /* 
         * Static version of simple Replace call 
         */
        ///  
        ///    
        ///    Replaces all occurrences of the with the
        ///     pattern
        ///     
        /// 
        ///  
        public static String Replace(String input, String pattern, MatchEvaluator evaluator) { 
            return new Regex(pattern, RegexOptions.None, true).Replace(input, evaluator);
        } 

        /*
         * Static version of simple Replace call
         */ 
        /// 
        ///     
        ///    Replaces all occurrences of the with the recent 
        ///     pattern, starting at the first character
        ///  
        /// 
        public static String Replace(String input, String pattern, MatchEvaluator evaluator, RegexOptions options) {
            return new Regex(pattern, options, true).Replace(input, evaluator);
        } 

        /* 
         * Does the replacement 
         */
        ///  
        ///    
        ///    Replaces all occurrences of the with the recent
        ///     pattern, starting at the first character
        ///    position 
        /// 
        ///  
        public String Replace(String input, MatchEvaluator evaluator) { 
            if (input==null)
                throw new ArgumentNullException("input"); 

            return Replace(input, evaluator, -1, UseOptionR() ? input.Length : 0);
        }
 
        /*
         * Does the replacement 
         */ 
        /// 
        ///     
        ///    Replaces all occurrences of the with the recent
        ///     pattern, starting at the first character
        ///    position
        ///  
        /// 
        public String Replace(String input, MatchEvaluator evaluator, int count) { 
            if (input==null) 
                throw new ArgumentNullException("input");
 
            return Replace(input, evaluator, count, UseOptionR() ? input.Length : 0);
        }

        /* 
         * Does the replacement
         */ 
        ///  
        ///    
        ///    Replaces all occurrences of the (previouly defined) with 
        ///       the recent  pattern, starting at the character
        ///    position
        /// 
        ///  
        public String Replace(String input, MatchEvaluator evaluator, int count, int startat) {
            if (input==null) 
                throw new ArgumentNullException("input"); 

            return RegexReplacement.Replace(evaluator, this, input, count, startat); 
        }

        /*
         * Static version of simple Split call 
         */
        ///     
        ///        
        ///          Splits the string at the position defined
        ///          by . 
        ///       
        ///    
        public static String[] Split(String input, String pattern) {
            return new Regex(pattern, RegexOptions.None, true).Split(input); 
        }
 
        /* 
         * Static version of simple Split call
         */ 
        /// 
        ///    
        ///       Splits the string at the position defined by .
        ///     
        /// 
        public static String[] Split(String input, String pattern, RegexOptions options) { 
            return new Regex(pattern, options, true).Split(input); 
        }
 
        /*
         * Does a split
         */
        ///  
        ///    
        ///       Splits the string at the position defined by 
        ///       a previous  
        ///       .
        ///     
        /// 
        public String[] Split(String input) {
            if (input==null)
                throw new ArgumentNullException("input"); 

            return Split(input, 0, UseOptionR() ? input.Length : 0); 
        } 

        /* 
         * Does a split
         */
        /// 
        ///     
        ///       Splits the string at the position defined by a previous
        ///     . 
        ///     
        /// 
        public String[] Split(String input, int count) { 
            if (input==null)
                throw new ArgumentNullException("input");

            return RegexReplacement.Split(this, input, count, UseOptionR() ? input.Length : 0); 
        }
 
        /* 
         * Does a split
         */ 
        /// 
        ///    
        ///       Splits the string at the position defined by a previous
        ///     . 
        ///    
        ///  
        public String[] Split(String input, int count, int startat) { 
            if (input==null)
                throw new ArgumentNullException("input"); 

            return RegexReplacement.Split(this, input, count, startat);
        }
 
        /// 
        ///  
        [HostProtection(MayLeakOnAbort=true)] 
        [ResourceExposure(ResourceScope.Machine)] // The AssemblyName is interesting.
        [ResourceConsumption(ResourceScope.Machine)] 
        public static void CompileToAssembly(RegexCompilationInfo[] regexinfos, AssemblyName assemblyname) {

            CompileToAssemblyInternal(regexinfos, assemblyname, null, null, Assembly.GetCallingAssembly().Evidence);
        } 

        ///  
        ///  
        [HostProtection(MayLeakOnAbort=true)]
        [ResourceExposure(ResourceScope.Machine)] // The AssemblyName is interesting. 
        [ResourceConsumption(ResourceScope.Machine)]
        public static void CompileToAssembly(RegexCompilationInfo[] regexinfos, AssemblyName assemblyname, CustomAttributeBuilder[] attributes) {
            CompileToAssemblyInternal(regexinfos, assemblyname, attributes, null, Assembly.GetCallingAssembly().Evidence);
        } 

        [HostProtection(MayLeakOnAbort=true)] 
        [ResourceExposure(ResourceScope.Machine)] 
        [ResourceConsumption(ResourceScope.Machine)]
        public static void CompileToAssembly(RegexCompilationInfo[] regexinfos, AssemblyName assemblyname, CustomAttributeBuilder[] attributes, String resourceFile) { 
            CompileToAssemblyInternal(regexinfos, assemblyname, attributes, resourceFile, Assembly.GetCallingAssembly().Evidence);
        }

        [ResourceExposure(ResourceScope.Machine)]  // AssemblyName & resourceFile 
        [ResourceConsumption(ResourceScope.Machine)]
        private static void CompileToAssemblyInternal (RegexCompilationInfo[] regexinfos, AssemblyName assemblyname, CustomAttributeBuilder[] attributes, String resourceFile, Evidence evidence) { 
            if (assemblyname == null) 
                throw new ArgumentNullException("assemblyname");
 
            if (regexinfos == null)
                throw new ArgumentNullException("regexinfos");

            RegexCompiler.CompileToAssembly(regexinfos, assemblyname, attributes, resourceFile, evidence); 
        }
 
        ///  
        /// 
        protected void InitializeReferences() { 
            if (refsInitialized)
                throw new NotSupportedException(SR.GetString(SR.OnlyAllowedOnce));

            refsInitialized = true; 
            runnerref  = new ExclusiveReference();
            replref    = new SharedReference(); 
        } 

        /* 
         * Internal worker called by all the public APIs
         */
        internal Match Run(bool quick, int prevlen, String input, int beginning, int length, int startat) {
            Match match; 
            RegexRunner runner = null;
 
            if (startat < 0 || startat > input.Length) 
                throw new ArgumentOutOfRangeException("start", SR.GetString(SR.BeginIndexNotNegative));
 
            if (length < 0 || length > input.Length)
                throw new ArgumentOutOfRangeException("length", SR.GetString(SR.LengthNotNegative));

            // There may be a cached runner; grab ownership of it if we can. 

            runner = (RegexRunner)runnerref.Get(); 
 
            // Create a RegexRunner instance if we need to
 
            if (runner == null) {
                // Use the compiled RegexRunner factory if the code was compiled to MSIL

                if (factory != null) 
                    runner = factory.CreateInstance();
                else 
                    runner = new RegexInterpreter(code, UseOptionInvariant() ? CultureInfo.InvariantCulture : CultureInfo.CurrentCulture); 
            }
 
            // Do the scan starting at the requested position

            match = runner.Scan(this, input, beginning, beginning + length, startat, prevlen, quick);
 
            // Release or fill the cache slot
 
            runnerref.Release(runner); 

#if DBG 
            if (Debug && match != null)
                match.Dump();
#endif
            return match; 
        }
 
        /* 
         * Find code cache based on options+pattern
         */ 
        private static CachedCodeEntry LookupCachedAndUpdate(String key) {
            lock (livecode) {
                for (LinkedListNode current = livecode.First; current != null; current = current.Next) {
                    if (current.Value._key == key) { 
                        // If we find an entry in the cache, move it to the head at the same time.
                        livecode.Remove(current); 
                        livecode.AddFirst(current); 
                        return current.Value;
                    } 
                }
            }

            return null; 
        }
 
        /* 
         * Add current code to the cache
         */ 
        private CachedCodeEntry CacheCode(String key) {
            CachedCodeEntry newcached = null;

            lock (livecode) { 
                // first look for it in the cache and move it to the head
                for (LinkedListNode current = livecode.First; current != null; current = current.Next) { 
                    if (current.Value._key == key) { 
                        livecode.Remove(current);
                        livecode.AddFirst(current); 
                        return current.Value;
                    }
                }
 
                // it wasn't in the cache, so we'll add a new one.  Shortcut out for the case where cacheSize is zero.
                if (cacheSize != 0) { 
                    newcached = new CachedCodeEntry(key, capnames, capslist, code, caps, capsize, runnerref, replref); 
                    livecode.AddFirst(newcached);
                    if (livecode.Count > cacheSize) 
                        livecode.RemoveLast();
                }
            }
 
            return newcached;
        } 
 
        /*
         * True if the O option was set 
         */
        /// 
        /// 
        ///  
        protected bool UseOptionC() {
            return(roptions & RegexOptions.Compiled) != 0; 
        } 

        /* 
         * True if the L option was set
         */
        /// 
        ///  
        /// 
        protected bool UseOptionR() { 
            return(roptions & RegexOptions.RightToLeft) != 0; 
        }
 
        internal bool UseOptionInvariant() {
            return(roptions & RegexOptions.CultureInvariant) != 0;
        }
 

#if DBG 
        /* 
         * True if the regex has debugging enabled
         */ 
        /// 
        /// 
        /// 
        internal bool Debug { 
            get {
                return(roptions & RegexOptions.Debug) != 0; 
            } 
        }
 
#endif
    }

 
    /*
     * Callback class 
     */ 
    /// 
    ///  
    [ Serializable() ]
    public delegate String MatchEvaluator(Match match);

 
    /*
     * Used to cache byte codes or compiled factories 
     */ 
    internal sealed class CachedCodeEntry {
        internal string _key; 
        internal RegexCode _code;
        internal Hashtable _caps;
        internal Hashtable _capnames;
        internal String[]  _capslist; 
        internal int       _capsize;
        internal RegexRunnerFactory _factory; 
        internal ExclusiveReference _runnerref; 
        internal SharedReference _replref;
 
        internal CachedCodeEntry(string key, Hashtable capnames, String[] capslist, RegexCode code, Hashtable caps, int capsize, ExclusiveReference runner, SharedReference repl) {

            _key        = key;
            _capnames   = capnames; 
            _capslist   = capslist;
 
            _code       = code; 
            _caps       = caps;
            _capsize    = capsize; 

            _runnerref     = runner;
            _replref       = repl;
        } 

        internal void AddCompiled(RegexRunnerFactory factory) { 
            _factory = factory; 
            _code = null;
        } 
    }

    /*
     * Used to cache one exclusive runner reference 
     */
    internal sealed class ExclusiveReference { 
        RegexRunner _ref; 
        Object _obj;
        int _locked; 

        /*
         * Return an object and grab an exclusive lock.
         * 
         * If the exclusive lock can't be obtained, null is returned;
         * if the object can't be returned, the lock is released. 
         * 
         */
        internal Object Get() { 
            // try to obtain the lock

            if (0 == Interlocked.Exchange(ref _locked, 1)) {
                // grab reference 

 
                Object obj = _ref; 

                // release the lock and return null if no reference 

                if (obj == null) {
                    _locked = 0;
                    return null; 
                }
 
                // remember the reference and keep the lock 

                _obj = obj; 
                return obj;
            }

            return null; 
        }
 
        /* 
         * Release an object back to the cache
         * 
         * If the object is the one that's under lock, the lock
         * is released.
         *
         * If there is no cached object, then the lock is obtained 
         * and the object is placed in the cache.
         * 
         */ 
        internal void Release(Object obj) {
            if (obj == null) 
                throw new ArgumentNullException("obj");

            // if this reference owns the lock, release it
 
            if (_obj == obj) {
                _obj = null; 
                _locked = 0; 
                return;
            } 

            // if no reference owns the lock, try to cache this reference

            if (_obj == null) { 
                // try to obtain the lock
 
                if (0 == Interlocked.Exchange(ref _locked, 1)) { 
                    // if there's really no reference, cache this reference
 
                    if (_ref == null)
                        _ref = (RegexRunner) obj;

                    // release the lock 

                    _locked = 0; 
                    return; 
                }
            } 
        }
    }

    /* 
     * Used to cache a weak reference in a threadsafe way
     */ 
    internal sealed class SharedReference { 
        WeakReference _ref = new WeakReference(null);
        int _locked; 

        /*
         * Return an object from a weakref, protected by a lock.
         * 
         * If the exclusive lock can't be obtained, null is returned;
         * 
         * Note that _ref.Target is referenced only under the protection 
         * of the lock. (Is this necessary?)
         */ 
        internal  Object Get() {
            if (0 == Interlocked.Exchange(ref _locked, 1)) {
                Object obj = _ref.Target;
                _locked = 0; 
                return obj;
            } 
 
            return null;
        } 

        /*
         * Suggest an object into a weakref, protected by a lock.
         * 
         * Note that _ref.Target is referenced only under the protection
         * of the lock. (Is this necessary?) 
         */ 
        internal void Cache(Object obj) {
            if (0 == Interlocked.Exchange(ref _locked, 1)) { 
                _ref.Target = obj;
                _locked = 0;
            }
        } 
    }
 
} 

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
//------------------------------------------------------------------------------ 
// 
//     Copyright (c) Microsoft Corporation.  All rights reserved.
// 
//----------------------------------------------------------------------------- 

// The Regex class represents a single compiled instance of a regular 
// expression. 

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;
    using System.Security.Policy; 
    using System.Security.Permissions;
    using System.Runtime.CompilerServices;
    using System.Collections.Generic;
    using System.Runtime.Versioning; 

    ///  
    ///     
    ///       Represents an immutable, compiled regular expression. Also
    ///       contains static methods that allow use of regular expressions without instantiating 
    ///       a Regex explicitly.
    ///    
    /// 
    [ Serializable() ] 
    public class Regex : ISerializable {
 
        // Fields used by precompiled regexes 
        protected internal string pattern;
        protected internal RegexRunnerFactory factory;       // if compiled, this is the RegexRunner subclass 
        protected internal RegexOptions roptions;            // the top-level options from the options string
        protected internal Hashtable caps;                   // if captures are sparse, this is the hashtable capnum->index
        protected internal Hashtable capnames;               // if named captures are used, this maps names->index
        protected internal String[]  capslist;               // if captures are sparse or named captures are used, this is the sorted list of names 
        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  bool refsInitialized = false;

        internal static LinkedList livecode = new LinkedList();// the cached of code and factories that are currently loaded
        internal static int cacheSize = 15; 

        internal const int MaxOptionShift = 10; 
 
        protected Regex() {
        } 

        /*
         * Compiles and returns a Regex object corresponding to the given pattern
         */ 
        /// 
        ///     
        ///       Creates and compiles a regular expression object for the specified regular 
        ///       expression.
        ///     
        /// 
        public Regex(String pattern) : this(pattern, RegexOptions.None, false) {
        }
 
        /*
         * Returns a Regex object corresponding to the given pattern, compiled with 
         * the specified options. 
         */
        ///  
        ///    
        ///       Creates and compiles a regular expression object for the
        ///       specified regular expression
        ///       with options that modify the pattern. 
        ///    
        ///  
        public Regex(String pattern, RegexOptions options) : this(pattern, options, false){ 
        }
 
        private Regex(String pattern, RegexOptions options, bool useCache) {
            RegexTree tree;
            CachedCodeEntry cached = null;
            string cultureKey = null; 

            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 |
                             RegexOptions.CultureInvariant 
#if DBG 
                           | RegexOptions.Debug
#endif 
                                               )) != 0)
                throw new ArgumentOutOfRangeException("options");

            // Try to look up this regex in the cache.  We do this regardless of whether useCache is true since there's 
            // really no reason not to.
            if ((options & RegexOptions.CultureInvariant) != 0) 
                cultureKey = CultureInfo.InvariantCulture.ThreeLetterWindowsLanguageName; 
            else
                cultureKey = CultureInfo.CurrentCulture.ThreeLetterWindowsLanguageName; 

            String key = ((int) options).ToString(NumberFormatInfo.InvariantInfo) + ":" + cultureKey + ":" + pattern;
            cached = LookupCachedAndUpdate(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;
                if (useCache) 
                    cached = 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; 
            }
 
            // if the compile option is set, then compile the code if it's not already
            if (UseOptionC() && factory == null) {
                factory = Compile(code, roptions);
 
                if (useCache && cached != null)
                    cached.AddCompiled(factory); 
                code = null; 
            }
        } 

        /*
         *  ISerializable constructor
         */ 
        protected Regex(SerializationInfo info, StreamingContext context) : this(info.GetString("pattern"), (RegexOptions) info.GetInt32("options")) {
        } 
 
        /*
         *  ISerializable method 
         */
        /// 
        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.
        */ 
        [
            HostProtection(MayLeakOnAbort=true), 
            MethodImplAttribute(MethodImplOptions.NoInlining) 
        ]
        internal RegexRunnerFactory Compile(RegexCode code, RegexOptions roptions) { 
            return RegexCompiler.Compile(code, roptions);
        }

        /* 
         * Escape metacharacters within the string
         */ 
        ///  
        ///    
        ///       Escapes 
        ///          a minimal set of metacharacters (\, *, +, ?, |, {, [, (, ), ^, $, ., #, and
        ///          whitespace) by replacing them with their \ codes. This converts a string so that
        ///          it can be used as a constant within a regular expression safely. (Note that the
        ///          reason # and whitespace must be escaped is so the string can be used safely 
        ///          within an expression parsed with x mode. If future Regex features add
        ///          additional metacharacters, developers should depend on Escape to escape those 
        ///          characters as well.) 
        ///       
        ///     
        public static String Escape(String str) {
            if (str==null)
                throw new ArgumentNullException("str");
 
            return RegexParser.Escape(str);
        } 
 
        /*
         * Unescape character codes within the string 
         */
        /// 
        ///    
        ///       Unescapes any escaped characters in the input string. 
        ///    
        ///  
        public static String Unescape(String str) { 
            if (str==null)
                throw new ArgumentNullException("str"); 

            return RegexParser.Unescape(str);
        }
 
        public static int CacheSize {
            get { 
                return cacheSize; 
            }
            set { 
                if (value < 0)
                    throw new ArgumentOutOfRangeException("value");

                cacheSize = value; 
                if (livecode.Count > cacheSize) {
                    lock (livecode) { 
                        while (livecode.Count > cacheSize) 
                            livecode.RemoveLast();
                    } 
                }
            }
        }
 
        /// 
        ///     
        ///       Returns the options passed into the constructor 
        ///    
        ///  
        public RegexOptions Options {
            get { return roptions;}
        }
 
        /*
         * True if the regex is leftward 
         */ 
        /// 
        ///     
        ///       Indicates whether the regular expression matches from right to
        ///       left.
        ///    
        ///  
        public bool RightToLeft {
            get { 
                return UseOptionR(); 
            }
        } 

        /// 
        ///    
        ///       Returns the regular expression pattern passed into the constructor 
        ///    
        ///  
        public override string ToString() { 
            return pattern;
        } 

        /*
         * Returns an array of the group names that are used to capture groups
         * in the regular expression. Only needed if the regex is not known until 
         * runtime, and one wants to extract captured groups. (Probably unusual,
         * but supplied for completeness.) 
         */ 
        /// 
        ///    Returns 
        ///       the GroupNameCollection for the regular expression. This collection contains the
        ///       set of strings used to name capturing groups in the expression.
        ///    
        public String[] GetGroupNames() { 
            String[] result;
 
            if (capslist == null) { 
                int max = capsize;
                result = new String[max]; 

                for (int i = 0; i < max; i++) {
                    result[i] = Convert.ToString(i, CultureInfo.InvariantCulture);
                } 
            }
            else { 
                result = new String[capslist.Length]; 

                System.Array.Copy(capslist, 0, result, 0, capslist.Length); 
            }

            return result;
        } 

        /* 
         * Returns an array of the group numbers that are used to capture groups 
         * in the regular expression. Only needed if the regex is not known until
         * runtime, and one wants to extract captured groups. (Probably unusual, 
         * but supplied for completeness.)
         */
        /// 
        ///    returns 
        ///       the integer group number corresponding to a group name.
        ///     
        public int[] GetGroupNumbers() { 
            int[] result;
 
            if (caps == null) {
                int max = capsize;
                result = new int[max];
 
                for (int i = 0; i < max; i++) {
                    result[i] = i; 
                } 
            }
            else { 
                result = new int[caps.Count];

                IDictionaryEnumerator de = caps.GetEnumerator();
                while (de.MoveNext()) { 
                    result[(int)de.Value] = (int)de.Key;
                } 
            } 

            return result; 
        }

        /*
         * Given a group number, maps it to a group name. Note that nubmered 
         * groups automatically get a group name that is the decimal string
         * equivalent of its number. 
         * 
         * Returns null if the number is not a recognized group number.
         */ 
        /// 
        ///    
        ///       Retrieves a group name that corresponds to a group number.
        ///     
        /// 
        public String GroupNameFromNumber(int i) { 
            if (capslist == null) { 
                if (i >= 0 && i < capsize)
                    return i.ToString(CultureInfo.InvariantCulture); 

                return String.Empty;
            }
            else { 
                if (caps != null) {
                    Object obj = caps[i]; 
                    if (obj == null) 
                        return String.Empty;
 
                    i = (int)obj;
                }

                if (i >= 0 && i < capslist.Length) 
                    return capslist[i];
 
                return String.Empty; 
            }
        } 

        /*
         * Given a group name, maps it to a group number. Note that nubmered
         * groups automatically get a group name that is the decimal string 
         * equivalent of its number.
         * 
         * Returns -1 if the name is not a recognized group name. 
         */
        ///  
        ///    
        ///       Returns a group number that corresponds to a group name.
        ///    
        ///  
        public int GroupNumberFromName(String name) {
            int result = -1; 
 
            if (name == null)
                throw new ArgumentNullException("name"); 

            // look up name if we have a hashtable of names
            if (capnames != null) {
                Object ret = capnames[name]; 

                if (ret == null) 
                    return -1; 

                return(int)ret; 
            }

            // convert to an int if it looks like a number
            result = 0; 
            for (int i = 0; i < name.Length; i++) {
                char ch = name[i]; 
 
                if (ch > '9' || ch < '0')
                    return -1; 

                result *= 10;
                result += (ch - '0');
            } 

            // return int if it's in range 
            if (result >= 0 && result < capsize) 
                return result;
 
            return -1;
        }

        /* 
         * Static version of simple IsMatch call
         */ 
        ///     
        ///       
        ///          Searches the input 
        ///             string for one or more occurrences of the text supplied in the pattern
        ///             parameter.
        ///       
        ///     
        public static bool IsMatch(String input, String pattern) {
            return new Regex(pattern, RegexOptions.None, true).IsMatch(input); 
        } 

        /* 
         * Static version of simple IsMatch call
         */
        /// 
        ///     
        ///       Searches the input string for one or more occurrences of the text
        ///          supplied in the pattern parameter with matching options supplied in the options 
        ///          parameter. 
        ///       
        ///     
        public static bool IsMatch(String input, String pattern, RegexOptions options) {
            return new Regex(pattern, options, true).IsMatch(input);
        }
 
        /*
         * Returns true if the regex finds a match within the specified string 
         */ 
        /// 
        ///     
        ///       Searches the input string for one or
        ///          more matches using the previous pattern, options, and starting
        ///          position.
        ///        
        ///    
        public bool IsMatch(String input) { 
            if (input == null) 
                throw new ArgumentNullException("input");
 
            return(null == Run(true, -1, input, 0, input.Length, UseOptionR() ? input.Length : 0));
        }

        /* 
         * Returns true if the regex finds a match after the specified position
         * (proceeding leftward if the regex is leftward and rightward otherwise) 
         */ 
        /// 
        ///     
        ///       Searches the input
        ///          string for one or more matches using the previous pattern and options, with
        ///          a new starting position.
        ///     
        /// 
        public bool IsMatch(String input, int startat) { 
            if (input == null) 
                throw new ArgumentNullException("input");
 
            return(null == Run(true, -1, input, 0, input.Length, startat));
        }

        /* 
         * Static version of simple Match call
         */ 
        ///     
        ///       
        ///          Searches the input string for one or more occurrences of the text 
        ///             supplied in the pattern parameter.
        ///       
        ///    
        public static Match Match(String input, String pattern) { 
            return new Regex(pattern, RegexOptions.None, true).Match(input);
        } 
 
        /*
         * Static version of simple Match call 
         */
        /// 
        ///    
        ///       Searches the input string for one or more occurrences of the text 
        ///          supplied in the pattern parameter. Matching is modified with an option
        ///          string. 
        ///        
        ///    
        public static Match Match(String input, String pattern, RegexOptions options) { 
            return new Regex(pattern, options, true).Match(input);
        }

        /* 
         * Finds the first match for the regular expression starting at the beginning
         * of the string (or at the end of the string if the regex is leftward) 
         */ 
        /// 
        ///     
        ///       Matches a regular expression with a string and returns
        ///       the precise result as a RegexMatch object.
        ///    
        ///  
        public Match Match(String input) {
            if (input == null) 
                throw new ArgumentNullException("input"); 

            return Run(false, -1, input, 0, input.Length, UseOptionR() ? input.Length : 0); 
        }

        /*
         * Finds the first match, starting at the specified position 
         */
        ///  
        ///    Matches a regular expression with a string and returns 
        ///    the precise result as a RegexMatch object.
        ///  
        public Match Match(String input, int startat) {
            if (input == null)
                throw new ArgumentNullException("input");
 
            return Run(false, -1, input, 0, input.Length, startat);
        } 
 
        /*
         * Finds the first match, restricting the search to the specified interval of 
         * the char array.
         */
        /// 
        ///     
        ///       Matches a
        ///       regular expression with a string and returns the precise result as a 
        ///       RegexMatch object. 
        ///    
        ///  
        public Match Match(String input, int beginning, int length) {
            if (input == null)
                throw new ArgumentNullException("input");
 
            return Run(false, -1, input, beginning, length, UseOptionR() ? beginning + length : beginning);
        } 
 
        /*
         * Static version of simple Matches call 
         */
        ///    
        ///       
        ///          Returns all the successful matches as if Match were 
        ///          called iteratively numerous times.
        ///        
        ///     
        public static MatchCollection Matches(String input, String pattern) {
            return new Regex(pattern, RegexOptions.None, true).Matches(input); 
        }

        /*
         * Static version of simple Matches call 
         */
        ///  
        ///     
        ///       Returns all the successful matches as if Match were called iteratively
        ///       numerous times. 
        ///    
        /// 
        public static MatchCollection Matches(String input, String pattern, RegexOptions options) {
            return new Regex(pattern, options, true).Matches(input); 
        }
 
        /* 
         * Finds the first match for the regular expression starting at the beginning
         * of the string Enumerator(or at the end of the string if the regex is leftward) 
         */
        /// 
        ///    
        ///       Returns 
        ///       all the successful matches as if Match was called iteratively numerous
        ///       times. 
        ///     
        /// 
        public MatchCollection Matches(String input) { 
            if (input == null)
                throw new ArgumentNullException("input");

            return new MatchCollection(this, input, 0, input.Length, UseOptionR() ? input.Length : 0); 
        }
 
        /* 
         * Finds the first match, starting at the specified position
         */ 
        /// 
        ///    
        ///       Returns
        ///       all the successful matches as if Match was called iteratively numerous 
        ///       times.
        ///     
        ///  
        public MatchCollection Matches(String input, int startat) {
            if (input == null) 
                throw new ArgumentNullException("input");

            return new MatchCollection(this, input, 0, input.Length, startat);
        } 

        /* 
         * Static version of simple Replace call 
         */
        ///  
        ///    
        ///       Replaces
        ///          all occurrences of the pattern with the  pattern, starting at
        ///          the first character in the input string. 
        ///       
        ///     
        public static String Replace(String input, String pattern, String replacement) { 
            return new Regex(pattern, RegexOptions.None, true).Replace(input, replacement);
        } 

        /*
         * Static version of simple Replace call
         */ 
        /// 
        ///     
        ///       Replaces all occurrences of 
        ///          the with the 
        ///          pattern, starting at the first character in the input string. 
        ///       
        ///    
        public static String Replace(String input, String pattern, String replacement, RegexOptions options) {
            return new Regex(pattern, options, true).Replace(input, replacement); 
        }
 
        /* 
         * Does the replacement
         */ 
        /// 
        ///    
        ///       Replaces all occurrences of
        ///          the  with the  pattern, starting at the 
        ///          first character in the input string, using the previous patten.
        ///        
        ///     
        public String Replace(String input, String replacement) {
            if (input == null) 
                throw new ArgumentNullException("input");

            return Replace(input, replacement, -1, UseOptionR() ? input.Length : 0);
        } 

        /* 
         * Does the replacement 
         */
        ///  
        ///    
        ///    Replaces all occurrences of the (previously defined) with the
        ///     pattern, starting at the first character in the input string.
        ///  
        /// 
        public String Replace(String input, String replacement, int count) { 
            if (input == null) 
                throw new ArgumentNullException("input");
 
            return Replace(input, replacement, count, UseOptionR() ? input.Length : 0);
        }

        /* 
         * Does the replacement
         */ 
        ///  
        ///    
        ///    Replaces all occurrences of the with the recent 
        ///     pattern, starting at the character position
        ///    
        /// 
        ///  
        public String Replace(String input, String replacement, int count, int startat) {
            RegexReplacement repl; 
 
            if (input == null)
                throw new ArgumentNullException("input"); 
            if (replacement == null)
                throw new ArgumentNullException("replacement");

            // a little code to grab a cached parsed replacement object 
            repl = (RegexReplacement)replref.Get();
 
            if (repl == null || !repl.Pattern.Equals(replacement)) { 
                repl = RegexParser.ParseReplacement(replacement, caps, capsize, capnames, this.roptions);
                replref.Cache(repl); 
            }

            return repl.Replace(this, input, count, startat);
        } 

        /* 
         * Static version of simple Replace call 
         */
        ///  
        ///    
        ///    Replaces all occurrences of the with the
        ///     pattern
        ///     
        /// 
        ///  
        public static String Replace(String input, String pattern, MatchEvaluator evaluator) { 
            return new Regex(pattern, RegexOptions.None, true).Replace(input, evaluator);
        } 

        /*
         * Static version of simple Replace call
         */ 
        /// 
        ///     
        ///    Replaces all occurrences of the with the recent 
        ///     pattern, starting at the first character
        ///  
        /// 
        public static String Replace(String input, String pattern, MatchEvaluator evaluator, RegexOptions options) {
            return new Regex(pattern, options, true).Replace(input, evaluator);
        } 

        /* 
         * Does the replacement 
         */
        ///  
        ///    
        ///    Replaces all occurrences of the with the recent
        ///     pattern, starting at the first character
        ///    position 
        /// 
        ///  
        public String Replace(String input, MatchEvaluator evaluator) { 
            if (input==null)
                throw new ArgumentNullException("input"); 

            return Replace(input, evaluator, -1, UseOptionR() ? input.Length : 0);
        }
 
        /*
         * Does the replacement 
         */ 
        /// 
        ///     
        ///    Replaces all occurrences of the with the recent
        ///     pattern, starting at the first character
        ///    position
        ///  
        /// 
        public String Replace(String input, MatchEvaluator evaluator, int count) { 
            if (input==null) 
                throw new ArgumentNullException("input");
 
            return Replace(input, evaluator, count, UseOptionR() ? input.Length : 0);
        }

        /* 
         * Does the replacement
         */ 
        ///  
        ///    
        ///    Replaces all occurrences of the (previouly defined) with 
        ///       the recent  pattern, starting at the character
        ///    position
        /// 
        ///  
        public String Replace(String input, MatchEvaluator evaluator, int count, int startat) {
            if (input==null) 
                throw new ArgumentNullException("input"); 

            return RegexReplacement.Replace(evaluator, this, input, count, startat); 
        }

        /*
         * Static version of simple Split call 
         */
        ///     
        ///        
        ///          Splits the string at the position defined
        ///          by . 
        ///       
        ///    
        public static String[] Split(String input, String pattern) {
            return new Regex(pattern, RegexOptions.None, true).Split(input); 
        }
 
        /* 
         * Static version of simple Split call
         */ 
        /// 
        ///    
        ///       Splits the string at the position defined by .
        ///     
        /// 
        public static String[] Split(String input, String pattern, RegexOptions options) { 
            return new Regex(pattern, options, true).Split(input); 
        }
 
        /*
         * Does a split
         */
        ///  
        ///    
        ///       Splits the string at the position defined by 
        ///       a previous  
        ///       .
        ///     
        /// 
        public String[] Split(String input) {
            if (input==null)
                throw new ArgumentNullException("input"); 

            return Split(input, 0, UseOptionR() ? input.Length : 0); 
        } 

        /* 
         * Does a split
         */
        /// 
        ///     
        ///       Splits the string at the position defined by a previous
        ///     . 
        ///     
        /// 
        public String[] Split(String input, int count) { 
            if (input==null)
                throw new ArgumentNullException("input");

            return RegexReplacement.Split(this, input, count, UseOptionR() ? input.Length : 0); 
        }
 
        /* 
         * Does a split
         */ 
        /// 
        ///    
        ///       Splits the string at the position defined by a previous
        ///     . 
        ///    
        ///  
        public String[] Split(String input, int count, int startat) { 
            if (input==null)
                throw new ArgumentNullException("input"); 

            return RegexReplacement.Split(this, input, count, startat);
        }
 
        /// 
        ///  
        [HostProtection(MayLeakOnAbort=true)] 
        [ResourceExposure(ResourceScope.Machine)] // The AssemblyName is interesting.
        [ResourceConsumption(ResourceScope.Machine)] 
        public static void CompileToAssembly(RegexCompilationInfo[] regexinfos, AssemblyName assemblyname) {

            CompileToAssemblyInternal(regexinfos, assemblyname, null, null, Assembly.GetCallingAssembly().Evidence);
        } 

        ///  
        ///  
        [HostProtection(MayLeakOnAbort=true)]
        [ResourceExposure(ResourceScope.Machine)] // The AssemblyName is interesting. 
        [ResourceConsumption(ResourceScope.Machine)]
        public static void CompileToAssembly(RegexCompilationInfo[] regexinfos, AssemblyName assemblyname, CustomAttributeBuilder[] attributes) {
            CompileToAssemblyInternal(regexinfos, assemblyname, attributes, null, Assembly.GetCallingAssembly().Evidence);
        } 

        [HostProtection(MayLeakOnAbort=true)] 
        [ResourceExposure(ResourceScope.Machine)] 
        [ResourceConsumption(ResourceScope.Machine)]
        public static void CompileToAssembly(RegexCompilationInfo[] regexinfos, AssemblyName assemblyname, CustomAttributeBuilder[] attributes, String resourceFile) { 
            CompileToAssemblyInternal(regexinfos, assemblyname, attributes, resourceFile, Assembly.GetCallingAssembly().Evidence);
        }

        [ResourceExposure(ResourceScope.Machine)]  // AssemblyName & resourceFile 
        [ResourceConsumption(ResourceScope.Machine)]
        private static void CompileToAssemblyInternal (RegexCompilationInfo[] regexinfos, AssemblyName assemblyname, CustomAttributeBuilder[] attributes, String resourceFile, Evidence evidence) { 
            if (assemblyname == null) 
                throw new ArgumentNullException("assemblyname");
 
            if (regexinfos == null)
                throw new ArgumentNullException("regexinfos");

            RegexCompiler.CompileToAssembly(regexinfos, assemblyname, attributes, resourceFile, evidence); 
        }
 
        ///  
        /// 
        protected void InitializeReferences() { 
            if (refsInitialized)
                throw new NotSupportedException(SR.GetString(SR.OnlyAllowedOnce));

            refsInitialized = true; 
            runnerref  = new ExclusiveReference();
            replref    = new SharedReference(); 
        } 

        /* 
         * Internal worker called by all the public APIs
         */
        internal Match Run(bool quick, int prevlen, String input, int beginning, int length, int startat) {
            Match match; 
            RegexRunner runner = null;
 
            if (startat < 0 || startat > input.Length) 
                throw new ArgumentOutOfRangeException("start", SR.GetString(SR.BeginIndexNotNegative));
 
            if (length < 0 || length > input.Length)
                throw new ArgumentOutOfRangeException("length", SR.GetString(SR.LengthNotNegative));

            // There may be a cached runner; grab ownership of it if we can. 

            runner = (RegexRunner)runnerref.Get(); 
 
            // Create a RegexRunner instance if we need to
 
            if (runner == null) {
                // Use the compiled RegexRunner factory if the code was compiled to MSIL

                if (factory != null) 
                    runner = factory.CreateInstance();
                else 
                    runner = new RegexInterpreter(code, UseOptionInvariant() ? CultureInfo.InvariantCulture : CultureInfo.CurrentCulture); 
            }
 
            // Do the scan starting at the requested position

            match = runner.Scan(this, input, beginning, beginning + length, startat, prevlen, quick);
 
            // Release or fill the cache slot
 
            runnerref.Release(runner); 

#if DBG 
            if (Debug && match != null)
                match.Dump();
#endif
            return match; 
        }
 
        /* 
         * Find code cache based on options+pattern
         */ 
        private static CachedCodeEntry LookupCachedAndUpdate(String key) {
            lock (livecode) {
                for (LinkedListNode current = livecode.First; current != null; current = current.Next) {
                    if (current.Value._key == key) { 
                        // If we find an entry in the cache, move it to the head at the same time.
                        livecode.Remove(current); 
                        livecode.AddFirst(current); 
                        return current.Value;
                    } 
                }
            }

            return null; 
        }
 
        /* 
         * Add current code to the cache
         */ 
        private CachedCodeEntry CacheCode(String key) {
            CachedCodeEntry newcached = null;

            lock (livecode) { 
                // first look for it in the cache and move it to the head
                for (LinkedListNode current = livecode.First; current != null; current = current.Next) { 
                    if (current.Value._key == key) { 
                        livecode.Remove(current);
                        livecode.AddFirst(current); 
                        return current.Value;
                    }
                }
 
                // it wasn't in the cache, so we'll add a new one.  Shortcut out for the case where cacheSize is zero.
                if (cacheSize != 0) { 
                    newcached = new CachedCodeEntry(key, capnames, capslist, code, caps, capsize, runnerref, replref); 
                    livecode.AddFirst(newcached);
                    if (livecode.Count > cacheSize) 
                        livecode.RemoveLast();
                }
            }
 
            return newcached;
        } 
 
        /*
         * True if the O option was set 
         */
        /// 
        /// 
        ///  
        protected bool UseOptionC() {
            return(roptions & RegexOptions.Compiled) != 0; 
        } 

        /* 
         * True if the L option was set
         */
        /// 
        ///  
        /// 
        protected bool UseOptionR() { 
            return(roptions & RegexOptions.RightToLeft) != 0; 
        }
 
        internal bool UseOptionInvariant() {
            return(roptions & RegexOptions.CultureInvariant) != 0;
        }
 

#if DBG 
        /* 
         * True if the regex has debugging enabled
         */ 
        /// 
        /// 
        /// 
        internal bool Debug { 
            get {
                return(roptions & RegexOptions.Debug) != 0; 
            } 
        }
 
#endif
    }

 
    /*
     * Callback class 
     */ 
    /// 
    ///  
    [ Serializable() ]
    public delegate String MatchEvaluator(Match match);

 
    /*
     * Used to cache byte codes or compiled factories 
     */ 
    internal sealed class CachedCodeEntry {
        internal string _key; 
        internal RegexCode _code;
        internal Hashtable _caps;
        internal Hashtable _capnames;
        internal String[]  _capslist; 
        internal int       _capsize;
        internal RegexRunnerFactory _factory; 
        internal ExclusiveReference _runnerref; 
        internal SharedReference _replref;
 
        internal CachedCodeEntry(string key, Hashtable capnames, String[] capslist, RegexCode code, Hashtable caps, int capsize, ExclusiveReference runner, SharedReference repl) {

            _key        = key;
            _capnames   = capnames; 
            _capslist   = capslist;
 
            _code       = code; 
            _caps       = caps;
            _capsize    = capsize; 

            _runnerref     = runner;
            _replref       = repl;
        } 

        internal void AddCompiled(RegexRunnerFactory factory) { 
            _factory = factory; 
            _code = null;
        } 
    }

    /*
     * Used to cache one exclusive runner reference 
     */
    internal sealed class ExclusiveReference { 
        RegexRunner _ref; 
        Object _obj;
        int _locked; 

        /*
         * Return an object and grab an exclusive lock.
         * 
         * If the exclusive lock can't be obtained, null is returned;
         * if the object can't be returned, the lock is released. 
         * 
         */
        internal Object Get() { 
            // try to obtain the lock

            if (0 == Interlocked.Exchange(ref _locked, 1)) {
                // grab reference 

 
                Object obj = _ref; 

                // release the lock and return null if no reference 

                if (obj == null) {
                    _locked = 0;
                    return null; 
                }
 
                // remember the reference and keep the lock 

                _obj = obj; 
                return obj;
            }

            return null; 
        }
 
        /* 
         * Release an object back to the cache
         * 
         * If the object is the one that's under lock, the lock
         * is released.
         *
         * If there is no cached object, then the lock is obtained 
         * and the object is placed in the cache.
         * 
         */ 
        internal void Release(Object obj) {
            if (obj == null) 
                throw new ArgumentNullException("obj");

            // if this reference owns the lock, release it
 
            if (_obj == obj) {
                _obj = null; 
                _locked = 0; 
                return;
            } 

            // if no reference owns the lock, try to cache this reference

            if (_obj == null) { 
                // try to obtain the lock
 
                if (0 == Interlocked.Exchange(ref _locked, 1)) { 
                    // if there's really no reference, cache this reference
 
                    if (_ref == null)
                        _ref = (RegexRunner) obj;

                    // release the lock 

                    _locked = 0; 
                    return; 
                }
            } 
        }
    }

    /* 
     * Used to cache a weak reference in a threadsafe way
     */ 
    internal sealed class SharedReference { 
        WeakReference _ref = new WeakReference(null);
        int _locked; 

        /*
         * Return an object from a weakref, protected by a lock.
         * 
         * If the exclusive lock can't be obtained, null is returned;
         * 
         * Note that _ref.Target is referenced only under the protection 
         * of the lock. (Is this necessary?)
         */ 
        internal  Object Get() {
            if (0 == Interlocked.Exchange(ref _locked, 1)) {
                Object obj = _ref.Target;
                _locked = 0; 
                return obj;
            } 
 
            return null;
        } 

        /*
         * Suggest an object into a weakref, protected by a lock.
         * 
         * Note that _ref.Target is referenced only under the protection
         * of the lock. (Is this necessary?) 
         */ 
        internal void Cache(Object obj) {
            if (0 == Interlocked.Exchange(ref _locked, 1)) { 
                _ref.Target = obj;
                _locked = 0;
            }
        } 
    }
 
} 

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
                        

Link Menu

Network programming in C#, Network Programming in VB.NET, Network Programming in .NET
This book is available now!
Buy at Amazon US or
Buy at Amazon UK