Regex.cs

None.gif // ------------------------------------------------------------------------------
None.gif
//  <copyright file="Regex.cs" company="Microsoft">
None.gif
//      
None.gif
//       Copyright (c) 2002 Microsoft Corporation.  All rights reserved.
None.gif
//      
None.gif
//       The use and distribution terms for this software are contained in the file
None.gif
//       named license.txt, which can be found in the root of this distribution.
None.gif
//       By using this software in any fashion, you are agreeing to be bound by the
None.gif
//       terms of this license.
None.gif
//      
None.gif
//       You must not remove this notice, or any other, from this software.
None.gif
//      
None.gif
//  </copyright>                                                                
None.gif
// ------------------------------------------------------------------------------
None.gif
None.gif
//  The Regex class represents a single compiled instance of a regular
None.gif
//  expression.
None.gif
//
None.gif
#define  ECMA
None.gif
ExpandedBlockStart.gifContractedBlock.gif
namespace  System.Text.RegularExpressions  dot.gif {
InBlock.gif
InBlock.gif    
using System;
InBlock.gif    
using System.Threading;
InBlock.gif    
using System.Collections;
InBlock.gif    
using System.Runtime.Serialization;
InBlock.gif    
using System.Reflection;
InBlock.gif    
using System.Reflection.Emit;
InBlock.gif    
using System.Globalization;
InBlock.gif
ExpandedSubBlockStart.gifContractedSubBlock.gif    
/**//// <include file='doc\Regex.uex' path='docs/doc[@for="Regex"]/*' />
InBlock.gif    
/// <devdoc>
InBlock.gif    
///    <para>
InBlock.gif    
///       Represents an immutable, compiled regular expression. Also
InBlock.gif    
///       contains static methods that allow use of regular expressions without instantiating
InBlock.gif    
///       a Regex explicitly.
InBlock.gif    
///    </para>
ExpandedSubBlockEnd.gif    
/// </devdoc>

InBlock.gif    [ Serializable() ] 
ExpandedSubBlockStart.gifContractedSubBlock.gif    
public class Regex : ISerializable dot.gif{
InBlock.gif
InBlock.gif        
// Fields used by precompiled regexes
ExpandedSubBlockStart.gifContractedSubBlock.gif
        /**//// <include file='doc\Regex.uex' path='docs/doc[@for="Regex.pattern"]/*' />
InBlock.gif        
/// <devdoc>
InBlock.gif        
///    <para>[To be supplied.]</para>
ExpandedSubBlockEnd.gif        
/// </devdoc>

InBlock.gif        protected internal string pattern;
ExpandedSubBlockStart.gifContractedSubBlock.gif        
/**//// <include file='doc\Regex.uex' path='docs/doc[@for="Regex.factory"]/*' />
InBlock.gif        
/// <devdoc>
InBlock.gif        
///    <para>[To be supplied.]</para>
ExpandedSubBlockEnd.gif        
/// </devdoc>

InBlock.gif        protected internal RegexRunnerFactory factory;       // if compiled, this is the RegexRunner subclass
ExpandedSubBlockStart.gifContractedSubBlock.gif
        /**//// <include file='doc\Regex.uex' path='docs/doc[@for="Regex.roptions"]/*' />
InBlock.gif        
/// <devdoc>
InBlock.gif        
///    <para>[To be supplied.]</para>
ExpandedSubBlockEnd.gif        
/// </devdoc>

InBlock.gif        protected internal RegexOptions roptions;            // the top-level options from the options string
ExpandedSubBlockStart.gifContractedSubBlock.gif
        /**//// <include file='doc\Regex.uex' path='docs/doc[@for="Regex.caps"]/*' />
InBlock.gif        
/// <devdoc>
InBlock.gif        
///    <para>[To be supplied.]</para>
ExpandedSubBlockEnd.gif        
/// </devdoc>

InBlock.gif        protected internal Hashtable caps;                   // if captures are sparse, this is the hashtable capnum->index
ExpandedSubBlockStart.gifContractedSubBlock.gif
        /**//// <include file='doc\Regex.uex' path='docs/doc[@for="Regex.capnames"]/*' />
InBlock.gif        
/// <devdoc>
InBlock.gif        
///    <para>[To be supplied.]</para>
ExpandedSubBlockEnd.gif        
/// </devdoc>

InBlock.gif        protected internal Hashtable capnames;               // if named captures are used, this maps names->index
ExpandedSubBlockStart.gifContractedSubBlock.gif
        /**//// <include file='doc\Regex.uex' path='docs/doc[@for="Regex.capslist"]/*' />
InBlock.gif        
/// <devdoc>
InBlock.gif        
///    <para>[To be supplied.]</para>
ExpandedSubBlockEnd.gif        
/// </devdoc>

InBlock.gif        protected internal String[]  capslist;               // if captures are sparse or named captures are used, this is the sorted list of names
ExpandedSubBlockStart.gifContractedSubBlock.gif
        /**//// <include file='doc\Regex.uex' path='docs/doc[@for="Regex.capsize"]/*' />
InBlock.gif        
/// <devdoc>
InBlock.gif        
///    <para>[To be supplied.]</para>
ExpandedSubBlockEnd.gif        
/// </devdoc>

InBlock.gif        protected internal int       capsize;                // the size of the capture array
InBlock.gif

InBlock.gif        
internal  ExclusiveReference runnerref;              // cached runner
InBlock.gif
        internal  SharedReference    replref;                // cached parsed replacement pattern
InBlock.gif
        internal  RegexCode          code;                   // if interpreted, this is the code for RegexIntepreter
InBlock.gif
        internal  CachedCodeEntry    cachedentry;
InBlock.gif        
internal  bool refsInitialized = false;
InBlock.gif
InBlock.gif        
internal static Hashtable livecode = new Hashtable();// the cached of code and factories that are currently loaded
InBlock.gif

InBlock.gif        
internal const int MaxOptionShift = 10;
InBlock.gif
ExpandedSubBlockStart.gifContractedSubBlock.gif        
/**//// <include file='doc\Regex.uex' path='docs/doc[@for="Regex.Regex2"]/*' />
ExpandedSubBlockStart.gifContractedSubBlock.gif        protected Regex() dot.gif{
ExpandedSubBlockEnd.gif        }

InBlock.gif
InBlock.gif        
// Compiles and returns a Regex object corresponding to the given pattern
ExpandedSubBlockStart.gifContractedSubBlock.gif
        /**//// <include file='doc\Regex.uex' path='docs/doc[@for="Regex.Regex"]/*' />
InBlock.gif        
/// <devdoc>
InBlock.gif        
///    <para>
InBlock.gif        
///       Creates and compiles a regular expression object for the specified regular
InBlock.gif        
///       expression.
InBlock.gif        
///    </para>
ExpandedSubBlockEnd.gif        
/// </devdoc>

ExpandedSubBlockStart.gifContractedSubBlock.gif        public Regex(String pattern) : this(pattern, RegexOptions.None) dot.gif{
ExpandedSubBlockEnd.gif        }

InBlock.gif
InBlock.gif        
// Returns a Regex object corresponding to the given pattern, compiled with
InBlock.gif        
// the specified options.
ExpandedSubBlockStart.gifContractedSubBlock.gif
        /**//// <include file='doc\Regex.uex' path='docs/doc[@for="Regex.Regex1"]/*' />
InBlock.gif        
/// <devdoc>
InBlock.gif        
///    <para>
InBlock.gif        
///       Creates and compiles a regular expression object for the
InBlock.gif        
///       specified regular expression
InBlock.gif        
///       with options that modify the pattern.
InBlock.gif        
///    </para>
ExpandedSubBlockEnd.gif        
/// </devdoc>

ExpandedSubBlockStart.gifContractedSubBlock.gif        public Regex(String pattern, RegexOptions options) dot.gif{
InBlock.gif            RegexTree tree;
InBlock.gif            CachedCodeEntry cached;
InBlock.gif
InBlock.gif            
if (pattern == null
InBlock.gif                
throw new ArgumentNullException("pattern");
InBlock.gif
InBlock.gif
InBlock.gif            
if (options < RegexOptions.None || ( ((int) options) >> MaxOptionShift) != 0)
InBlock.gif                
throw new ArgumentOutOfRangeException("options");
InBlock.gif            
if ((options &   RegexOptions.ECMAScript) != 0
InBlock.gif             
&& (options & ~(RegexOptions.ECMAScript | RegexOptions.IgnoreCase | RegexOptions.Multiline | RegexOptions.Compiled
InBlock.gif
#if DBG
InBlock.gif                           
| RegexOptions.Debug
InBlock.gif
#endif
InBlock.gif                                               )) 
!= 0)
InBlock.gif                
throw new ArgumentOutOfRangeException("options");
InBlock.gif
InBlock.gif            String key 
= ((int) options).ToString(NumberFormatInfo.InvariantInfo) + ":" + pattern;
InBlock.gif
InBlock.gif            cached 
= LookupCached(key);
InBlock.gif
InBlock.gif            
this.pattern = pattern;
InBlock.gif            
this.roptions = options;
InBlock.gif
ExpandedSubBlockStart.gifContractedSubBlock.gif            
if (cached == nulldot.gif{
InBlock.gif                
// Parse the input
InBlock.gif
                tree = RegexParser.Parse(pattern, roptions);
InBlock.gif
InBlock.gif                
// Extract the relevant information
InBlock.gif
                capnames   = tree._capnames;
InBlock.gif                capslist   
= tree._capslist;
InBlock.gif                code       
= RegexWriter.Write(tree);
InBlock.gif                caps       
= code._caps;
InBlock.gif                capsize    
= code._capsize;
InBlock.gif
InBlock.gif                InitializeReferences();
InBlock.gif
InBlock.gif                tree 
= null;
InBlock.gif                cachedentry
= CacheCode(key);
ExpandedSubBlockEnd.gif            }

ExpandedSubBlockStart.gifContractedSubBlock.gif            
else dot.gif{
InBlock.gif                caps       
= cached._caps;
InBlock.gif                capnames   
= cached._capnames;
InBlock.gif                capslist   
= cached._capslist;
InBlock.gif                capsize    
= cached._capsize;
InBlock.gif                code       
= cached._code;
InBlock.gif                factory    
= cached._factory;
InBlock.gif                runnerref  
= cached._runnerref;
InBlock.gif                replref    
= cached._replref;
InBlock.gif                refsInitialized 
= true;
InBlock.gif
InBlock.gif                cachedentry     
= cached;
ExpandedSubBlockEnd.gif            }

InBlock.gif
InBlock.gif            
// if the compile option is set, then compile the code if it's not already
ExpandedSubBlockStart.gifContractedSubBlock.gif
            if (UseOptionC() && factory == nulldot.gif{
InBlock.gif                factory 
= Compile(code, roptions);
InBlock.gif                cachedentry.AddCompiled(factory);
InBlock.gif                code 
= null;
ExpandedSubBlockEnd.gif            }

ExpandedSubBlockEnd.gif        }

InBlock.gif
InBlock.gif        
//  ISerializable constructor
ExpandedSubBlockStart.gifContractedSubBlock.gif
        private Regex(SerializationInfo info, StreamingContext context) : this(info.GetString("pattern"), (RegexOptions) info.GetInt32("options")) dot.gif{
ExpandedSubBlockEnd.gif        }

InBlock.gif
InBlock.gif        
//  ISerializable method
ExpandedSubBlockStart.gifContractedSubBlock.gif
        /**//// <include file='doc\Regex.uex' path='docs/doc[@for="Regex.ISerializable.GetObjectData"]/*' />
ExpandedSubBlockEnd.gif        
/// <internalonly/>

ExpandedSubBlockStart.gifContractedSubBlock.gif        void ISerializable.GetObjectData(SerializationInfo si, StreamingContext context) dot.gif{
InBlock.gif            si.AddValue(
"pattern"this.ToString());
InBlock.gif            si.AddValue(
"options"this.Options);
ExpandedSubBlockEnd.gif        }

InBlock.gif
InBlock.gif       
// This method is here for perf reasons: if the call to RegexCompiler is NOT in the 
InBlock.gif       
// Regex constructor, we don't load RegexCompiler and its reflection classes when
InBlock.gif       
// instantiating a non-compiled regex
InBlock.gif       
// This method is internal virtual so the jit does not inline it.
ExpandedSubBlockStart.gifContractedSubBlock.gif
        internal virtual RegexRunnerFactory Compile(RegexCode code, RegexOptions roptions) dot.gif{
InBlock.gif            
return RegexCompiler.Compile(code, roptions);
ExpandedSubBlockEnd.gif        }

InBlock.gif
InBlock.gif        
// No refs -> we can release our ref on the cached code
ExpandedSubBlockStart.gifContractedSubBlock.gif
        /**//// <include file='doc\Regex.uex' path='docs/doc[@for="Regex.Finalize"]/*' />
InBlock.gif        
/// <devdoc>
InBlock.gif        
///    <para>[To be supplied.]</para>
ExpandedSubBlockEnd.gif        
/// </devdoc>

ExpandedSubBlockStart.gifContractedSubBlock.gif        ~Regex() dot.gif{
InBlock.gif            UncacheCode();
ExpandedSubBlockEnd.gif        }

InBlock.gif
InBlock.gif        
// Escape metacharacters within the string
ExpandedSubBlockStart.gifContractedSubBlock.gif
        /**//// <include file='doc\Regex.uex' path='docs/doc[@for="Regex.Escape"]/*' />
InBlock.gif        
/// <devdoc>
InBlock.gif        
///    <para>
InBlock.gif        
///       Escapes 
InBlock.gif        
///          a minimal set of metacharacters (\, *, +, ?, |, {, [, (, ), ^, $, ., #, and
InBlock.gif        
///          whitespace) by replacing them with their \ codes. This converts a string so that
InBlock.gif        
///          it can be used as a constant within a regular expression safely. (Note that the
InBlock.gif        
///          reason # and whitespace must be escaped is so the string can be used safely
InBlock.gif        
///          within an expression parsed with x mode. If future Regex features add
InBlock.gif        
///          additional metacharacters, developers should depend on Escape to escape those
InBlock.gif        
///          characters as well.)
InBlock.gif        
///       </para>
ExpandedSubBlockEnd.gif        
///    </devdoc>

ExpandedSubBlockStart.gifContractedSubBlock.gif        public static String Escape(String str) dot.gif{
InBlock.gif            
if (str==null)
InBlock.gif                
throw new ArgumentNullException("str");
InBlock.gif            
InBlock.gif            
return RegexParser.Escape(str);
ExpandedSubBlockEnd.gif        }

InBlock.gif
InBlock.gif        
// Unescape character codes within the string
ExpandedSubBlockStart.gifContractedSubBlock.gif
        /**//// <include file='doc\Regex.uex' path='docs/doc[@for="Regex.Unescape"]/*' />
InBlock.gif        
/// <devdoc>
InBlock.gif        
///    <para>
InBlock.gif        
///       Unescapes any escaped characters in the input string.
InBlock.gif        
///    </para>
ExpandedSubBlockEnd.gif        
/// </devdoc>

ExpandedSubBlockStart.gifContractedSubBlock.gif        public static String Unescape(String str) dot.gif{
InBlock.gif            
if (str==null)
InBlock.gif                
throw new ArgumentNullException("str");
InBlock.gif            
InBlock.gif            
return RegexParser.Unescape(str);
ExpandedSubBlockEnd.gif        }

InBlock.gif
InBlock.gif        
// True if the regex is leftward
ExpandedSubBlockStart.gifContractedSubBlock.gif
        /**//// <include file='doc\Regex.uex' path='docs/doc[@for="Regex.RightToLeft"]/*' />
InBlock.gif        
/// <devdoc>
InBlock.gif        
///    <para>
InBlock.gif        
///       Indicates whether the regular expression matches from right to
InBlock.gif        
///       left.
InBlock.gif        
///    </para>
ExpandedSubBlockEnd.gif        
/// </devdoc>

ExpandedSubBlockStart.gifContractedSubBlock.gif        public bool RightToLeft dot.gif{
ExpandedSubBlockStart.gifContractedSubBlock.gif            
get dot.gif{
InBlock.gif                
return UseOptionR();
ExpandedSubBlockEnd.gif            }

ExpandedSubBlockEnd.gif        }

InBlock.gif
ExpandedSubBlockStart.gifContractedSubBlock.gif        
/**//// <include file='doc\Regex.uex' path='docs/doc[@for="Regex.ToString"]/*' />
InBlock.gif        
/// <devdoc>
InBlock.gif        
///    <para>
InBlock.gif        
///       Returns the regular expression pattern passed into the constructor
InBlock.gif        
///    </para>
ExpandedSubBlockEnd.gif        
/// </devdoc>

ExpandedSubBlockStart.gifContractedSubBlock.gif        public override string ToString() dot.gif{
InBlock.gif            
return pattern;
ExpandedSubBlockEnd.gif        }

InBlock.gif
ExpandedSubBlockStart.gifContractedSubBlock.gif        
/**//// <include file='doc\Regex.uex' path='docs/doc[@for="Regex.Options"]/*' />
InBlock.gif        
/// <devdoc>
InBlock.gif        
///    <para>
InBlock.gif        
///       Returns the options passed into the constructor
InBlock.gif        
///    </para>
ExpandedSubBlockEnd.gif        
/// </devdoc>

ExpandedSubBlockStart.gifContractedSubBlock.gif        public RegexOptions Options dot.gif{
ExpandedSubBlockStart.gifContractedSubBlock.gif            
get dot.gifreturn roptions;}
ExpandedSubBlockEnd.gif        }

InBlock.gif
InBlock.gif        
// Returns an array of the group names that are used to capture groups
InBlock.gif        
// in the regular expression. Only needed if the regex is not known until
InBlock.gif        
// runtime, and one wants to extract captured groups. (Probably unusual,
InBlock.gif        
// but supplied for completeness.)
ExpandedSubBlockStart.gifContractedSubBlock.gif
        /**//// <include file='doc\Regex.uex' path='docs/doc[@for="Regex.GetGroupNames"]/*' />
InBlock.gif        
/// <devdoc>
InBlock.gif        
///    Returns 
InBlock.gif        
///       the GroupNameCollection for the regular expression. This collection contains the
InBlock.gif        
///       set of strings used to name capturing groups in the expression. 
ExpandedSubBlockEnd.gif        
///    </devdoc>

ExpandedSubBlockStart.gifContractedSubBlock.gif        public String[] GetGroupNames() dot.gif{
InBlock.gif            String[] result;
InBlock.gif
ExpandedSubBlockStart.gifContractedSubBlock.gif            
if (capslist == nulldot.gif{
InBlock.gif                
int max = capsize;
InBlock.gif                result 
= new String[max];
InBlock.gif
ExpandedSubBlockStart.gifContractedSubBlock.gif                
for (int i = 0; i < max; i++dot.gif{
InBlock.gif                    result[i] 
= Convert.ToString(i);
ExpandedSubBlockEnd.gif                }

ExpandedSubBlockEnd.gif            }

ExpandedSubBlockStart.gifContractedSubBlock.gif            
else dot.gif{
InBlock.gif                result 
= new String[capslist.Length];
InBlock.gif
InBlock.gif                System.Array.Copy(capslist, 
0, result, 0, capslist.Length);
ExpandedSubBlockEnd.gif            }

InBlock.gif
InBlock.gif            
return result;
ExpandedSubBlockEnd.gif        }

InBlock.gif
InBlock.gif        
// Returns an array of the group numbers that are used to capture groups
InBlock.gif        
// in the regular expression. Only needed if the regex is not known until
InBlock.gif        
// runtime, and one wants to extract captured groups. (Probably unusual,
InBlock.gif        
// but supplied for completeness.)
ExpandedSubBlockStart.gifContractedSubBlock.gif
        /**//// <include file='doc\Regex.uex' path='docs/doc[@for="Regex.GetGroupNumbers"]/*' />
InBlock.gif        
/// <devdoc>
InBlock.gif        
///    returns 
InBlock.gif        
///       the integer group number corresponding to a group name. 
ExpandedSubBlockEnd.gif        
///    </devdoc>

ExpandedSubBlockStart.gifContractedSubBlock.gif        public int[] GetGroupNumbers() dot.gif{
InBlock.gif            
int[] result;
InBlock.gif
ExpandedSubBlockStart.gifContractedSubBlock.gif            
if (caps == nulldot.gif{
InBlock.gif                
int max = capsize;
InBlock.gif                result 
= new int[max];
InBlock.gif
ExpandedSubBlockStart.gifContractedSubBlock.gif                
for (int i = 0; i < max; i++dot.gif{
InBlock.gif                    result[i] 
= i;
ExpandedSubBlockEnd.gif                }

ExpandedSubBlockEnd.gif            }

ExpandedSubBlockStart.gifContractedSubBlock.gif            
else dot.gif{
InBlock.gif                result 
= new int[caps.Count];
InBlock.gif
InBlock.gif                IDictionaryEnumerator de 
= caps.GetEnumerator();
ExpandedSubBlockStart.gifContractedSubBlock.gif                
while (de.MoveNext()) dot.gif{
InBlock.gif                    result[(
int)de.Value] = (int)de.Key;
ExpandedSubBlockEnd.gif                }

ExpandedSubBlockEnd.gif            }

InBlock.gif
InBlock.gif            
return result;
ExpandedSubBlockEnd.gif        }

InBlock.gif
InBlock.gif        
// Given a group number, maps it to a group name. Note that nubmered
InBlock.gif        
// groups automatically get a group name that is the decimal string
InBlock.gif        
// equivalent of its number.
InBlock.gif        
//
InBlock.gif        
// Returns null if the number is not a recognized group number.
ExpandedSubBlockStart.gifContractedSubBlock.gif
        /**//// <include file='doc\Regex.uex' path='docs/doc[@for="Regex.GroupNameFromNumber"]/*' />
InBlock.gif        
/// <devdoc>
InBlock.gif        
///    <para>
InBlock.gif        
///       Retrieves a group name that corresponds to a group number.
InBlock.gif        
///    </para>
ExpandedSubBlockEnd.gif        
/// </devdoc>

ExpandedSubBlockStart.gifContractedSubBlock.gif        public String GroupNameFromNumber(int i) dot.gif{
ExpandedSubBlockStart.gifContractedSubBlock.gif            
if (capslist == nulldot.gif{
InBlock.gif                
if (i >= 0 && i < capsize)
InBlock.gif                    
return i.ToString();
InBlock.gif
InBlock.gif                
return String.Empty;
ExpandedSubBlockEnd.gif            }

ExpandedSubBlockStart.gifContractedSubBlock.gif            
else dot.gif{
ExpandedSubBlockStart.gifContractedSubBlock.gif                
if (caps != nulldot.gif{
InBlock.gif                    Object obj 
= caps[i];
InBlock.gif                    
if (obj == null)
InBlock.gif                        
return String.Empty;
InBlock.gif
InBlock.gif                    i 
= (int)obj;
ExpandedSubBlockEnd.gif                }

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

ExpandedSubBlockEnd.gif        }

InBlock.gif
InBlock.gif        
// Given a group name, maps it to a group number. Note that nubmered
InBlock.gif        
// groups automatically get a group name that is the decimal string
InBlock.gif        
// equivalent of its number.
InBlock.gif        
//
InBlock.gif        
// Returns -1 if the name is not a recognized group name.
ExpandedSubBlockStart.gifContractedSubBlock.gif
        /**//// <include file='doc\Regex.uex' path='docs/doc[@for="Regex.GroupNumberFromName"]/*' />
InBlock.gif        
/// <devdoc>
InBlock.gif        
///    <para>
InBlock.gif        
///       Returns a group number that corresponds to a group name.
InBlock.gif        
///    </para>
ExpandedSubBlockEnd.gif        
/// </devdoc>

ExpandedSubBlockStart.gifContractedSubBlock.gif        public int GroupNumberFromName(String name) dot.gif{
InBlock.gif            
int result = -1;
InBlock.gif
InBlock.gif            
if (name == null)
InBlock.gif                
throw new ArgumentNullException("name");
InBlock.gif
InBlock.gif            
// look up name if we have a hashtable of names
ExpandedSubBlockStart.gifContractedSubBlock.gif
            if (capnames != nulldot.gif{
InBlock.gif                Object ret 
= capnames[name];
InBlock.gif
InBlock.gif                
if (ret == null)
InBlock.gif                    
return -1;
InBlock.gif
InBlock.gif                
return(int)ret;
ExpandedSubBlockEnd.gif            }

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

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

InBlock.gif
InBlock.gif        
// Static version of simple IsMatch call
ExpandedSubBlockStart.gifContractedSubBlock.gif
        /**//// <include file='doc\Regex.uex' path='docs/doc[@for="Regex.IsMatch"]/*' />
InBlock.gif        
///    <devdoc>
InBlock.gif        
///       <para>
InBlock.gif        
///          Searches the input 
InBlock.gif        
///             string for one or more occurrences of the text supplied in the pattern
InBlock.gif        
///             parameter.
InBlock.gif        
///       </para>
ExpandedSubBlockEnd.gif        
///    </devdoc>

ExpandedSubBlockStart.gifContractedSubBlock.gif        public static bool IsMatch(String input, String pattern) dot.gif{
InBlock.gif            
return new Regex(pattern).IsMatch(input);
ExpandedSubBlockEnd.gif        }

InBlock.gif
InBlock.gif        
// Static version of simple IsMatch call
ExpandedSubBlockStart.gifContractedSubBlock.gif
        /**//// <include file='doc\Regex.uex' path='docs/doc[@for="Regex.IsMatch1"]/*' />
InBlock.gif        
/// <devdoc>
InBlock.gif        
///    <para>
InBlock.gif        
///       Searches the input string for one or more occurrences of the text 
InBlock.gif        
///          supplied in the pattern parameter with matching options supplied in the options
InBlock.gif        
///          parameter.
InBlock.gif        
///       </para>
ExpandedSubBlockEnd.gif        
///    </devdoc>

ExpandedSubBlockStart.gifContractedSubBlock.gif        public static bool IsMatch(String input, String pattern, RegexOptions options) dot.gif{
InBlock.gif            
return new Regex(pattern, options).IsMatch(input);
ExpandedSubBlockEnd.gif        }

InBlock.gif
InBlock.gif        
// Returns true if the regex finds a match within the specified string
ExpandedSubBlockStart.gifContractedSubBlock.gif
        /**//// <include file='doc\Regex.uex' path='docs/doc[@for="Regex.IsMatch2"]/*' />
InBlock.gif        
/// <devdoc>
InBlock.gif        
///    <para>
InBlock.gif        
///       Searches the input string for one or 
InBlock.gif        
///          more matches using the previous pattern, options, and starting
InBlock.gif        
///          position.
InBlock.gif        
///       </para>
ExpandedSubBlockEnd.gif        
///    </devdoc>

ExpandedSubBlockStart.gifContractedSubBlock.gif        public bool IsMatch(String input) dot.gif{
InBlock.gif            
if (input == null)
InBlock.gif                
throw new ArgumentNullException("input");
InBlock.gif
InBlock.gif            
return(null == Run(true-1, input, 0, input.Length, UseOptionR() ? input.Length : 0));
ExpandedSubBlockEnd.gif        }

InBlock.gif
InBlock.gif        
// Returns true if the regex finds a match after the specified position
InBlock.gif        
// (proceeding leftward if the regex is leftward and rightward otherwise)
ExpandedSubBlockStart.gifContractedSubBlock.gif
        /**//// <include file='doc\Regex.uex' path='docs/doc[@for="Regex.IsMatch3"]/*' />
InBlock.gif        
/// <devdoc>
InBlock.gif        
///    <para>
InBlock.gif        
///       Searches the input 
InBlock.gif        
///          string for one or more matches using the previous pattern and options, with
InBlock.gif        
///          a new starting position.
InBlock.gif        
///    </para>
ExpandedSubBlockEnd.gif        
/// </devdoc>

ExpandedSubBlockStart.gifContractedSubBlock.gif        public bool IsMatch(String input, int startat) dot.gif{
InBlock.gif            
if (input == null)
InBlock.gif                
throw new ArgumentNullException("input");
InBlock.gif
InBlock.gif            
return(null == Run(true-1, input, 0, input.Length, startat));
ExpandedSubBlockEnd.gif        }

InBlock.gif
InBlock.gif        
// Static version of simple Match call
ExpandedSubBlockStart.gifContractedSubBlock.gif
        /**//// <include file='doc\Regex.uex' path='docs/doc[@for="Regex.Match"]/*' />
InBlock.gif        
///    <devdoc>
InBlock.gif        
///       <para>
InBlock.gif        
///          Searches the input string for one or more occurrences of the text 
InBlock.gif        
///             supplied in the pattern parameter.
InBlock.gif        
///       </para>
ExpandedSubBlockEnd.gif        
///    </devdoc>

ExpandedSubBlockStart.gifContractedSubBlock.gif        public static Match Match(String input, String pattern) dot.gif{
InBlock.gif            
return new Regex(pattern).Match(input);
ExpandedSubBlockEnd.gif        }

InBlock.gif
InBlock.gif        
// Static version of simple Match call
ExpandedSubBlockStart.gifContractedSubBlock.gif
        /**//// <include file='doc\Regex.uex' path='docs/doc[@for="Regex.Match1"]/*' />
InBlock.gif        
/// <devdoc>
InBlock.gif        
///    <para>
InBlock.gif        
///       Searches the input string for one or more occurrences of the text 
InBlock.gif        
///          supplied in the pattern parameter. Matching is modified with an option
InBlock.gif        
///          string.
InBlock.gif        
///       </para>
ExpandedSubBlockEnd.gif        
///    </devdoc>

ExpandedSubBlockStart.gifContractedSubBlock.gif        public static Match Match(String input, String pattern, RegexOptions options) dot.gif{
InBlock.gif            
return new Regex(pattern, options).Match(input);
ExpandedSubBlockEnd.gif        }

InBlock.gif
InBlock.gif        
// Finds the first match for the regular expression starting at the beginning
InBlock.gif        
// of the string (or at the end of the string if the regex is leftward)
ExpandedSubBlockStart.gifContractedSubBlock.gif
        /**//// <include file='doc\Regex.uex' path='docs/doc[@for="Regex.Match2"]/*' />
InBlock.gif        
/// <devdoc>
InBlock.gif        
///    <para>
InBlock.gif        
///       Matches a regular expression with a string and returns
InBlock.gif        
///       the precise result as a RegexMatch object.
InBlock.gif        
///    </para>
ExpandedSubBlockEnd.gif        
/// </devdoc>

ExpandedSubBlockStart.gifContractedSubBlock.gif        public Match Match(String input) dot.gif{
InBlock.gif            
if (input == null)
InBlock.gif                
throw new ArgumentNullException("input");
InBlock.gif
InBlock.gif            
return Run(false-1, input, 0, input.Length, UseOptionR() ? input.Length : 0);
ExpandedSubBlockEnd.gif        }

InBlock.gif
InBlock.gif        
// Finds the first match, starting at the specified position
ExpandedSubBlockStart.gifContractedSubBlock.gif
        /**//// <include file='doc\Regex.uex' path='docs/doc[@for="Regex.Match3"]/*' />
InBlock.gif        
/// <devdoc>
InBlock.gif        
///    Matches a regular expression with a string and returns
InBlock.gif        
///    the precise result as a RegexMatch object.
ExpandedSubBlockEnd.gif        
/// </devdoc>

ExpandedSubBlockStart.gifContractedSubBlock.gif        public Match Match(String input, int startat) dot.gif{
InBlock.gif            
if (input == null)
InBlock.gif                
throw new ArgumentNullException("input");
InBlock.gif
InBlock.gif            
return Run(false-1, input, 0, input.Length, startat);
ExpandedSubBlockEnd.gif        }

InBlock.gif
InBlock.gif        
// Finds the first match, restricting the search to the specified interval of
InBlock.gif        
// the char array.
ExpandedSubBlockStart.gifContractedSubBlock.gif
        /**//// <include file='doc\Regex.uex' path='docs/doc[@for="Regex.Match4"]/*' />
InBlock.gif        
/// <devdoc>
InBlock.gif        
///    <para>
InBlock.gif        
///       Matches a
InBlock.gif        
///       regular expression with a string and returns the precise result as a
InBlock.gif        
///       RegexMatch object.
InBlock.gif        
///    </para>
ExpandedSubBlockEnd.gif        
/// </devdoc>

ExpandedSubBlockStart.gifContractedSubBlock.gif        public Match Match(String input, int beginning, int length) dot.gif{
InBlock.gif            
if (input == null)
InBlock.gif                
throw new ArgumentNullException("input");
InBlock.gif
InBlock.gif            
return Run(false-1, input, beginning, length, UseOptionR() ? beginning + length : beginning);
ExpandedSubBlockEnd.gif        }

InBlock.gif
InBlock.gif        
// Static version of simple Matches call
ExpandedSubBlockStart.gifContractedSubBlock.gif
        /**//// <include file='doc\Regex.uex' path='docs/doc[@for="Regex.Matches"]/*' />
InBlock.gif        
///    <devdoc>
InBlock.gif        
///       <para>
InBlock.gif        
///          Returns all the successful matches as if Match were
InBlock.gif        
///          called iteratively numerous times.
InBlock.gif        
///       </para>
ExpandedSubBlockEnd.gif        
///    </devdoc>

ExpandedSubBlockStart.gifContractedSubBlock.gif        public static MatchCollection Matches(String input, String pattern) dot.gif{
InBlock.gif            
return new Regex(pattern).Matches(input);
ExpandedSubBlockEnd.gif        }

InBlock.gif
InBlock.gif        
// Static version of simple Matches call
ExpandedSubBlockStart.gifContractedSubBlock.gif
        /**//// <include file='doc\Regex.uex' path='docs/doc[@for="Regex.Matches1"]/*' />
InBlock.gif        
/// <devdoc>
InBlock.gif        
///    <para>
InBlock.gif        
///       Returns all the successful matches as if Match were called iteratively
InBlock.gif        
///       numerous times.
InBlock.gif        
///    </para>
ExpandedSubBlockEnd.gif        
/// </devdoc>

ExpandedSubBlockStart.gifContractedSubBlock.gif        public static MatchCollection Matches(String input, String pattern, RegexOptions options) dot.gif{
InBlock.gif            
return new Regex(pattern, options).Matches(input);
ExpandedSubBlockEnd.gif        }

InBlock.gif
InBlock.gif        
// Finds the first match for the regular expression starting at the beginning
InBlock.gif        
// of the string Enumerator(or at the end of the string if the regex is leftward)
ExpandedSubBlockStart.gifContractedSubBlock.gif
        /**//// <include file='doc\Regex.uex' path='docs/doc[@for="Regex.Matches2"]/*' />
InBlock.gif        
/// <devdoc>
InBlock.gif        
///    <para>
InBlock.gif        
///       Returns
InBlock.gif        
///       all the successful matches as if Match was called iteratively numerous
InBlock.gif        
///       times.
InBlock.gif        
///    </para>
ExpandedSubBlockEnd.gif        
/// </devdoc>

ExpandedSubBlockStart.gifContractedSubBlock.gif        public MatchCollection Matches(String input) dot.gif{
InBlock.gif            
if (input == null)
InBlock.gif                
throw new ArgumentNullException("input");
InBlock.gif
InBlock.gif            
return new MatchCollection(this, input, 0, input.Length, UseOptionR() ? input.Length : 0);
ExpandedSubBlockEnd.gif        }

InBlock.gif
InBlock.gif        
// Finds the first match, starting at the specified position
ExpandedSubBlockStart.gifContractedSubBlock.gif
        /**//// <include file='doc\Regex.uex' path='docs/doc[@for="Regex.Matches3"]/*' />
InBlock.gif        
/// <devdoc>
InBlock.gif        
///    <para>
InBlock.gif        
///       Returns
InBlock.gif        
///       all the successful matches as if Match was called iteratively numerous
InBlock.gif        
///       times.
InBlock.gif        
///    </para>
ExpandedSubBlockEnd.gif        
/// </devdoc>

ExpandedSubBlockStart.gifContractedSubBlock.gif        public MatchCollection Matches(String input, int startat) dot.gif{
InBlock.gif            
if (input == null)
InBlock.gif                
throw new ArgumentNullException("input");
InBlock.gif
InBlock.gif            
return new MatchCollection(this, input, 0, input.Length, startat);
ExpandedSubBlockEnd.gif        }

InBlock.gif
InBlock.gif        
// Static version of simple Replace call
ExpandedSubBlockStart.gifContractedSubBlock.gif
        /**//// <include file='doc\Regex.uex' path='docs/doc[@for="Regex.Replace"]/*' />
InBlock.gif        
/// <devdoc>
InBlock.gif        
///    <para>
InBlock.gif        
///       Replaces 
InBlock.gif        
///          all occurrences of the pattern with the <paramref name="replacement"/> pattern, starting at
InBlock.gif        
///          the first character in the input string. 
InBlock.gif        
///       </para>
ExpandedSubBlockEnd.gif        
///    </devdoc>

ExpandedSubBlockStart.gifContractedSubBlock.gif        public static String Replace(String input, String pattern, String replacement) dot.gif{
InBlock.gif            
return new Regex(pattern).Replace(input, replacement);
ExpandedSubBlockEnd.gif        }

InBlock.gif
InBlock.gif        
// Static version of simple Replace call
ExpandedSubBlockStart.gifContractedSubBlock.gif
        /**//// <include file='doc\Regex.uex' path='docs/doc[@for="Regex.Replace1"]/*' />
InBlock.gif        
/// <devdoc>
InBlock.gif        
///    <para>
InBlock.gif        
///       Replaces all occurrences of 
InBlock.gif        
///          the <paramref name="pattern "/>with the <paramref name="replacement "/>
InBlock.gif        
///          pattern, starting at the first character in the input string. 
InBlock.gif        
///       </para>
ExpandedSubBlockEnd.gif        
///    </devdoc>

ExpandedSubBlockStart.gifContractedSubBlock.gif        public static String Replace(String input, String pattern, String replacement, RegexOptions options) dot.gif{
InBlock.gif            
return new Regex(pattern, options).Replace(input, replacement);
ExpandedSubBlockEnd.gif        }

InBlock.gif
InBlock.gif        
// Does the replacement
ExpandedSubBlockStart.gifContractedSubBlock.gif
        /**//// <include file='doc\Regex.uex' path='docs/doc[@for="Regex.Replace2"]/*' />
InBlock.gif        
/// <devdoc>
InBlock.gif        
///    <para>
InBlock.gif        
///       Replaces all occurrences of 
InBlock.gif        
///          the <paramref name="pattern "/> with the <paramref name="replacement"/> pattern, starting at the
InBlock.gif        
///          first character in the input string, using the previous patten. 
InBlock.gif        
///       </para>
ExpandedSubBlockEnd.gif        
///    </devdoc>

ExpandedSubBlockStart.gifContractedSubBlock.gif        public String Replace(String input, String replacement) dot.gif{
InBlock.gif            
if (input == null)
InBlock.gif                
throw new ArgumentNullException("input");
InBlock.gif
InBlock.gif            
return Replace(input, replacement, -1, UseOptionR() ? input.Length : 0);
ExpandedSubBlockEnd.gif        }

InBlock.gif
InBlock.gif        
// Does the replacement
ExpandedSubBlockStart.gifContractedSubBlock.gif
        /**//// <include file='doc\Regex.uex' path='docs/doc[@for="Regex.Replace3"]/*' />
InBlock.gif        
/// <devdoc>
InBlock.gif        
///    <para>
InBlock.gif        
///    Replaces all occurrences of the (previously defined) <paramref name="pattern "/>with the 
InBlock.gif        
///    <paramref name="replacement"/> pattern, starting at the first character in the input string. 
InBlock.gif        
/// </para>
ExpandedSubBlockEnd.gif        
/// </devdoc>

ExpandedSubBlockStart.gifContractedSubBlock.gif        public String Replace(String input, String replacement, int count) dot.gif{
InBlock.gif            
if (input == null)
InBlock.gif                
throw new ArgumentNullException("input");
InBlock.gif
InBlock.gif            
return Replace(input, replacement, count, UseOptionR() ? input.Length : 0);
ExpandedSubBlockEnd.gif        }

InBlock.gif
InBlock.gif        
// Does the replacement
ExpandedSubBlockStart.gifContractedSubBlock.gif
        /**//// <include file='doc\Regex.uex' path='docs/doc[@for="Regex.Replace4"]/*' />
InBlock.gif        
/// <devdoc>
InBlock.gif        
///    <para>
InBlock.gif        
///    Replaces all occurrences of the <paramref name="pattern "/>with the recent 
InBlock.gif        
///    <paramref name="replacement"/> pattern, starting at the character position 
InBlock.gif        
///    <paramref name="startat."/>
InBlock.gif        
/// </para>
ExpandedSubBlockEnd.gif        
/// </devdoc>

ExpandedSubBlockStart.gifContractedSubBlock.gif        public String Replace(String input, String replacement, int count, int startat) dot.gif{
InBlock.gif            RegexReplacement repl;
InBlock.gif
InBlock.gif            
if (input == null)
InBlock.gif                
throw new ArgumentNullException("input");
InBlock.gif            
if (replacement == null)
InBlock.gif                
throw new ArgumentNullException("replacement");
InBlock.gif
InBlock.gif            
// a little code to grab a cached parsed replacement object
InBlock.gif
            repl = (RegexReplacement)replref.Get();
InBlock.gif
ExpandedSubBlockStart.gifContractedSubBlock.gif            
if (repl == null || !repl.Pattern.Equals(replacement)) dot.gif{
InBlock.gif                repl 
= RegexParser.ParseReplacement(replacement, caps, capsize, capnames, this.roptions);
InBlock.gif                replref.Cache(repl);
ExpandedSubBlockEnd.gif            }

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

InBlock.gif
InBlock.gif        
// Static version of simple Replace call
ExpandedSubBlockStart.gifContractedSubBlock.gif
        /**//// <include file='doc\Regex.uex' path='docs/doc[@for="Regex.Replace5"]/*' />
InBlock.gif        
/// <devdoc>
InBlock.gif        
///    <para>
InBlock.gif        
///    Replaces all occurrences of the <paramref name="pattern "/>with the 
InBlock.gif        
///    <paramref name="replacement"/> pattern 
InBlock.gif        
///    <paramref name="."/>
InBlock.gif        
/// </para>
ExpandedSubBlockEnd.gif        
/// </devdoc>

ExpandedSubBlockStart.gifContractedSubBlock.gif        public static String Replace(String input, String pattern, MatchEvaluator evaluator) dot.gif{
InBlock.gif            
return new Regex(pattern).Replace(input, evaluator);
ExpandedSubBlockEnd.gif        }

InBlock.gif
InBlock.gif        
// Static version of simple Replace call
ExpandedSubBlockStart.gifContractedSubBlock.gif
        /**//// <include file='doc\Regex.uex' path='docs/doc[@for="Regex.Replace6"]/*' />
InBlock.gif        
/// <devdoc>
InBlock.gif        
///    <para>
InBlock.gif        
///    Replaces all occurrences of the <paramref name="pattern "/>with the recent 
InBlock.gif        
///    <paramref name="replacement"/> pattern, starting at the first character<paramref name="."/>
InBlock.gif        
/// </para>
ExpandedSubBlockEnd.gif        
/// </devdoc>

ExpandedSubBlockStart.gifContractedSubBlock.gif        public static String Replace(String input, String pattern, MatchEvaluator evaluator, RegexOptions options) dot.gif{
InBlock.gif            
return new Regex(pattern, options).Replace(input, evaluator);
ExpandedSubBlockEnd.gif        }

InBlock.gif
InBlock.gif        
// Does the replacement
ExpandedSubBlockStart.gifContractedSubBlock.gif
        /**//// <include file='doc\Regex.uex' path='docs/doc[@for="Regex.Replace7"]/*' />
InBlock.gif        
/// <devdoc>
InBlock.gif        
///    <para>
InBlock.gif        
///    Replaces all occurrences of the <paramref name="pattern "/>with the recent 
InBlock.gif        
///    <paramref name="replacement"/> pattern, starting at the first character 
InBlock.gif        
///    position<paramref name="."/>
InBlock.gif        
/// </para>
ExpandedSubBlockEnd.gif        
/// </devdoc>

ExpandedSubBlockStart.gifContractedSubBlock.gif        public String Replace(String input, MatchEvaluator evaluator) dot.gif{
InBlock.gif            
if (input==null)
InBlock.gif                
throw new ArgumentNullException("input");
InBlock.gif
InBlock.gif            
return Replace(input, evaluator, -1, UseOptionR() ? input.Length : 0);
ExpandedSubBlockEnd.gif        }

InBlock.gif
InBlock.gif        
// Does the replacement
ExpandedSubBlockStart.gifContractedSubBlock.gif
        /**//// <include file='doc\Regex.uex' path='docs/doc[@for="Regex.Replace8"]/*' />
InBlock.gif        
/// <devdoc>
InBlock.gif        
///    <para>
InBlock.gif        
///    Replaces all occurrences of the <paramref name="pattern "/>with the recent 
InBlock.gif        
///    <paramref name="replacement"/> pattern, starting at the first character 
InBlock.gif        
///    position<paramref name="."/>
InBlock.gif        
/// </para>
ExpandedSubBlockEnd.gif        
/// </devdoc>

ExpandedSubBlockStart.gifContractedSubBlock.gif        public String Replace(String input, MatchEvaluator evaluator, int count) dot.gif{
InBlock.gif            
if (input==null)
InBlock.gif                
throw new ArgumentNullException("input");
InBlock.gif
InBlock.gif            
return Replace(input, evaluator, count, UseOptionR() ? input.Length : 0);
ExpandedSubBlockEnd.gif        }

InBlock.gif
InBlock.gif        
// Does the replacement
ExpandedSubBlockStart.gifContractedSubBlock.gif
        /**//// <include file='doc\Regex.uex' path='docs/doc[@for="Regex.Replace9"]/*' />
InBlock.gif        
/// <devdoc>
InBlock.gif        
///    <para>
InBlock.gif        
///    Replaces all occurrences of the (previouly defined) <paramref name="pattern "/>with 
InBlock.gif        
///       the recent <paramref name="replacement"/> pattern, starting at the character
InBlock.gif        
///    position<paramref name=" startat."/> 
InBlock.gif        
/// </para>
ExpandedSubBlockEnd.gif        
/// </devdoc>

ExpandedSubBlockStart.gifContractedSubBlock.gif        public String Replace(String input, MatchEvaluator evaluator, int count, int startat) dot.gif{
InBlock.gif            
if (input==null)
InBlock.gif                
throw new ArgumentNullException("input");
InBlock.gif
InBlock.gif            
return RegexReplacement.Replace(evaluator, this, input, count, startat);
ExpandedSubBlockEnd.gif        }

InBlock.gif
InBlock.gif        
// Static version of simple Split call
ExpandedSubBlockStart.gifContractedSubBlock.gif
        /**//// <include file='doc\Regex.uex' path='docs/doc[@for="Regex.Split"]/*' />
InBlock.gif        
///    <devdoc>
InBlock.gif        
///       <para>
InBlock.gif        
///          Splits the <paramref name="input "/>string at the position defined
InBlock.gif        
///          by <paramref name="pattern"/>.
InBlock.gif        
///       </para>
ExpandedSubBlockEnd.gif        
///    </devdoc>

ExpandedSubBlockStart.gifContractedSubBlock.gif        public static String[] Split(String input, String pattern) dot.gif{
InBlock.gif            
return new Regex(pattern).Split(input);
ExpandedSubBlockEnd.gif        }

InBlock.gif
InBlock.gif        
// Static version of simple Split call
ExpandedSubBlockStart.gifContractedSubBlock.gif
        /**//// <include file='doc\Regex.uex' path='docs/doc[@for="Regex.Split1"]/*' />
InBlock.gif        
/// <devdoc>
InBlock.gif        
///    <para>
InBlock.gif        
///       Splits the <paramref name="input "/>string at the position defined by <paramref name="pattern"/>.
InBlock.gif        
///    </para>
ExpandedSubBlockEnd.gif        
/// </devdoc>

ExpandedSubBlockStart.gifContractedSubBlock.gif        public static String[] Split(String input, String pattern, RegexOptions options) dot.gif{
InBlock.gif            
return new Regex(pattern, options).Split(input);
ExpandedSubBlockEnd.gif        }

InBlock.gif
InBlock.gif        
// Does a split
ExpandedSubBlockStart.gifContractedSubBlock.gif
        /**//// <include file='doc\Regex.uex' path='docs/doc[@for="Regex.Split2"]/*' />
InBlock.gif        
/// <devdoc>
InBlock.gif        
///    <para>
InBlock.gif        
///       Splits the <paramref name="input "/>string at the position defined by
InBlock.gif        
///       a previous <paramref name="pattern"/>
InBlock.gif        
///       .
InBlock.gif        
///    </para>
ExpandedSubBlockEnd.gif        
/// </devdoc>

ExpandedSubBlockStart.gifContractedSubBlock.gif        public String[] Split(String input) dot.gif{
InBlock.gif            
if (input==null)
InBlock.gif                
throw new ArgumentNullException("input");
InBlock.gif
InBlock.gif            
return Split(input, 0, UseOptionR() ? input.Length : 0);
ExpandedSubBlockEnd.gif        }

InBlock.gif
InBlock.gif        
// Does a split
ExpandedSubBlockStart.gifContractedSubBlock.gif
        /**//// <include file='doc\Regex.uex' path='docs/doc[@for="Regex.Split3"]/*' />
InBlock.gif        
/// <devdoc>
InBlock.gif        
///    <para>
InBlock.gif        
///       Splits the <paramref name="input "/>string at the position defined by a previous
InBlock.gif        
///    <paramref name="pattern"/> . 
InBlock.gif        
///    </para>
ExpandedSubBlockEnd.gif        
/// </devdoc>

ExpandedSubBlockStart.gifContractedSubBlock.gif        public String[] Split(String input, int count) dot.gif{
InBlock.gif            
if (input==null)
InBlock.gif                
throw new ArgumentNullException("input");
InBlock.gif            
InBlock.gif            
return RegexReplacement.Split(this, input, count, UseOptionR() ? input.Length : 0);
ExpandedSubBlockEnd.gif        }

InBlock.gif
InBlock.gif        
// Does a split
ExpandedSubBlockStart.gifContractedSubBlock.gif
        /**//// <include file='doc\Regex.uex' path='docs/doc[@for="Regex.Split4"]/*' />
InBlock.gif        
/// <devdoc>
InBlock.gif        
///    <para>
InBlock.gif        
///       Splits the <paramref name="input "/>string at the position defined by a previous
InBlock.gif        
///    <paramref name="pattern"/> . 
InBlock.gif        
///    </para>
ExpandedSubBlockEnd.gif        
/// </devdoc>

ExpandedSubBlockStart.gifContractedSubBlock.gif        public String[] Split(String input, int count, int startat) dot.gif{
InBlock.gif            
if (input==null)
InBlock.gif                
throw new ArgumentNullException("input");
InBlock.gif
InBlock.gif            
return RegexReplacement.Split(this, input, count, startat);
ExpandedSubBlockEnd.gif        }

InBlock.gif        
ExpandedSubBlockStart.gifContractedSubBlock.gif        
/**//// <include file='doc\Regex.uex' path='docs/doc[@for="Regex.CompileToAssembly"]/*' />
InBlock.gif        
/// <devdoc>
ExpandedSubBlockEnd.gif        
/// </devdoc>

ExpandedSubBlockStart.gifContractedSubBlock.gif        public static void CompileToAssembly(RegexCompilationInfo[] regexinfos, AssemblyName assemblyname) dot.gif{
InBlock.gif            CompileToAssembly(regexinfos, assemblyname, 
nullnull);
ExpandedSubBlockEnd.gif        }

InBlock.gif
ExpandedSubBlockStart.gifContractedSubBlock.gif        
/**//// <include file='doc\Regex.uex' path='docs/doc[@for="Regex.CompileToAssembly1"]/*' />
InBlock.gif        
/// <devdoc>
ExpandedSubBlockEnd.gif        
/// </devdoc>

ExpandedSubBlockStart.gifContractedSubBlock.gif        public static void CompileToAssembly(RegexCompilationInfo[] regexinfos, AssemblyName assemblyname, CustomAttributeBuilder[] attributes) dot.gif{
InBlock.gif            CompileToAssembly(regexinfos, assemblyname, attributes, 
null);
ExpandedSubBlockEnd.gif        }

InBlock.gif
ExpandedSubBlockStart.gifContractedSubBlock.gif        
/**//// <include file='doc\Regex.uex' path='docs/doc[@for="Regex.CompileToAssembly2"]/*' />
ExpandedSubBlockStart.gifContractedSubBlock.gif        public static void CompileToAssembly(RegexCompilationInfo[] regexinfos, AssemblyName assemblyname, CustomAttributeBuilder[] attributes, String resourceFile) dot.gif{
InBlock.gif            
if (assemblyname == null)
InBlock.gif                
throw new ArgumentNullException("assemblyname");
InBlock.gif
InBlock.gif            
if (regexinfos == null)
InBlock.gif                
throw new ArgumentNullException("regexinfos");
InBlock.gif
InBlock.gif            RegexCompiler.CompileToAssembly(regexinfos, assemblyname, attributes, resourceFile);
ExpandedSubBlockEnd.gif        }

InBlock.gif
ExpandedSubBlockStart.gifContractedSubBlock.gif        
/**//// <include file='doc\Regex.uex' path='docs/doc[@for="Regex.InitializeReferences"]/*' />
InBlock.gif        
/// <devdoc>
ExpandedSubBlockEnd.gif        
/// </devdoc>

ExpandedSubBlockStart.gifContractedSubBlock.gif        protected void InitializeReferences() dot.gif{
InBlock.gif            
if (refsInitialized)
InBlock.gif                
throw new NotSupportedException(SR.GetString(SR.OnlyAllowedOnce));
InBlock.gif            
InBlock.gif            refsInitialized 
= true;
InBlock.gif            runnerref  
= new ExclusiveReference();
InBlock.gif            replref    
= new SharedReference();
ExpandedSubBlockEnd.gif        }

InBlock.gif
InBlock.gif        
// Internal worker called by all the public APIs
ExpandedSubBlockStart.gifContractedSubBlock.gif
        internal Match Run(bool quick, int prevlen, String input, int beginning, int length, int startat) dot.gif{
InBlock.gif            Match match;
InBlock.gif            RegexRunner runner 
= null;
InBlock.gif
InBlock.gif            
if (startat < 0 || startat > input.Length)
InBlock.gif                
throw new ArgumentOutOfRangeException("start", SR.GetString(SR.BeginIndexNotNegative));
InBlock.gif
InBlock.gif            
if (length < 0 || length > input.Length)
InBlock.gif                
throw new ArgumentOutOfRangeException("length", SR.GetString(SR.LengthNotNegative));
InBlock.gif
InBlock.gif            
// There may be a cached runner; grab ownership of it if we can.
InBlock.gif

InBlock.gif            runner 
= (RegexRunner)runnerref.Get();
InBlock.gif
InBlock.gif            
// Create a RegexRunner instance if we need to
InBlock.gif

ExpandedSubBlockStart.gifContractedSubBlock.gif            
if (runner == nulldot.gif{
InBlock.gif                
// Use the compiled RegexRunner factory if the code was compiled to MSIL
InBlock.gif

InBlock.gif                
if (factory != null)
InBlock.gif                    runner 
= factory.CreateInstance();
InBlock.gif                
else
InBlock.gif                    runner 
= new RegexInterpreter(code, UseOptionInvariant() ? CultureInfo.InvariantCulture : CultureInfo.CurrentCulture);
ExpandedSubBlockEnd.gif            }

InBlock.gif
InBlock.gif            
// Do the scan starting at the requested position
InBlock.gif

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

InBlock.gif            runnerref.Release(runner);
InBlock.gif
InBlock.gif
#if DBG
InBlock.gif            
if (UseOptionDebug())
InBlock.gif                match.Dump();
InBlock.gif
#endif
InBlock.gif            
return match;
ExpandedSubBlockEnd.gif        }

InBlock.gif
InBlock.gif        
// Find code cache based on options+pattern
ExpandedSubBlockStart.gifContractedSubBlock.gif
        private static CachedCodeEntry LookupCached(String key) dot.gif{
InBlock.gif            CachedCodeEntry cached;
InBlock.gif
ExpandedSubBlockStart.gifContractedSubBlock.gif            
lock (livecode) dot.gif{
InBlock.gif                cached 
= (CachedCodeEntry)livecode[key];
InBlock.gif                
if (cached != null)
InBlock.gif                    cached.AddRef();
ExpandedSubBlockEnd.gif            }

InBlock.gif
InBlock.gif            
return cached;
ExpandedSubBlockEnd.gif        }

InBlock.gif
InBlock.gif        
// Add current code to the cache
ExpandedSubBlockStart.gifContractedSubBlock.gif
        private CachedCodeEntry CacheCode(String key) dot.gif{
InBlock.gif            CachedCodeEntry newcached;
InBlock.gif
InBlock.gif            newcached 
= new CachedCodeEntry(roptions, capnames, capslist, code, caps, capsize, runnerref, replref);
InBlock.gif
ExpandedSubBlockStart.gifContractedSubBlock.gif            
lock (livecode) dot.gif{
InBlock.gif                livecode[key] 
= newcached;
ExpandedSubBlockEnd.gif            }

InBlock.gif
InBlock.gif            
return newcached;
ExpandedSubBlockEnd.gif        }

InBlock.gif
InBlock.gif        
// Release current code (and remove from cache if last ref)
ExpandedSubBlockStart.gifContractedSubBlock.gif
        private void UncacheCode() dot.gif{
InBlock.gif            
// Note that cachedentry can be null if the constructor never
InBlock.gif            
// completed because of an exception. The finalizer can
InBlock.gif            
// still be called.
InBlock.gif

InBlock.gif            
if (cachedentry == null)
InBlock.gif                
return;
InBlock.gif
InBlock.gif            cachedentry.Release();
InBlock.gif            String key 
= ((int) roptions).ToString(NumberFormatInfo.InvariantInfo) + ":" + pattern;
InBlock.gif
ExpandedSubBlockStart.gifContractedSubBlock.gif            
if (cachedentry.NoReferences()) dot.gif{
ExpandedSubBlockStart.gifContractedSubBlock.gif                
lock (livecode) dot.gif{
ExpandedSubBlockStart.gifContractedSubBlock.gif                    
if (cachedentry.NoReferences()) dot.gif{
InBlock.gif                        
if (livecode[key] == cachedentry)
InBlock.gif                            livecode.Remove(key);
ExpandedSubBlockEnd.gif                    }

ExpandedSubBlockEnd.gif                }

ExpandedSubBlockEnd.gif            }

ExpandedSubBlockEnd.gif        }

InBlock.gif
InBlock.gif        
// True if the O option was set
ExpandedSubBlockStart.gifContractedSubBlock.gif
        /**//// <include file='doc\Regex.uex' path='docs/doc[@for="Regex.UseOptionC"]/*' />
InBlock.gif        
/// <internalonly/>
InBlock.gif        
/// <devdoc>
ExpandedSubBlockEnd.gif        
/// </devdoc>

ExpandedSubBlockStart.gifContractedSubBlock.gif        protected bool UseOptionC() dot.gif{
InBlock.gif            
return(roptions & RegexOptions.Compiled) != 0;
ExpandedSubBlockEnd.gif        }

InBlock.gif
InBlock.gif        
// True if the L option was set
ExpandedSubBlockStart.gifContractedSubBlock.gif
        /**//// <include file='doc\Regex.uex' path='docs/doc[@for="Regex.UseOptionR"]/*' />
InBlock.gif        
/// <internalonly/>
InBlock.gif        
/// <devdoc>
ExpandedSubBlockEnd.gif        
/// </devdoc>

ExpandedSubBlockStart.gifContractedSubBlock.gif        protected bool UseOptionR() dot.gif{
InBlock.gif            
return(roptions & RegexOptions.RightToLeft) != 0;
ExpandedSubBlockEnd.gif        }

InBlock.gif
ExpandedSubBlockStart.gifContractedSubBlock.gif        
internal bool UseOptionInvariant() dot.gif{
InBlock.gif            
return(roptions & RegexOptions.CultureInvariant) != 0;
ExpandedSubBlockEnd.gif        }

InBlock.gif            
InBlock.gif
InBlock.gif
#if DBG
InBlock.gif        
// True if the regex has debugging enabled
ExpandedSubBlockStart.gifContractedSubBlock.gif
        /**//// <include file='doc\Regex.uex' path='docs/doc[@for="Regex.Debug"]/*' />
InBlock.gif        
/// <internalonly/>
InBlock.gif        
/// <devdoc>
ExpandedSubBlockEnd.gif        
/// </devdoc>

ExpandedSubBlockStart.gifContractedSubBlock.gif        public virtual bool Debug dot.gif{
ExpandedSubBlockStart.gifContractedSubBlock.gif            
get dot.gif{
InBlock.gif                
return UseOptionDebug();
ExpandedSubBlockEnd.gif            }

ExpandedSubBlockEnd.gif        }

InBlock.gif
InBlock.gif        
// True if the Debug option was set
ExpandedSubBlockStart.gifContractedSubBlock.gif
        /**//// <include file='doc\Regex.uex' path='docs/doc[@for="Regex.UseOptionDebug"]/*' />
InBlock.gif        
/// <internalonly/>
InBlock.gif        
/// <devdoc>
ExpandedSubBlockEnd.gif        
/// </devdoc>

ExpandedSubBlockStart.gifContractedSubBlock.gif        protected bool UseOptionDebug() dot.gif{
InBlock.gif            
return(roptions & RegexOptions.Debug) != 0;
ExpandedSubBlockEnd.gif        }

InBlock.gif
ExpandedSubBlockStart.gifContractedSubBlock.gif        
/**//// <include file='doc\Regex.uex' path='docs/doc[@for="Regex.Dump"]/*' />
InBlock.gif        
/// <internalonly/>
InBlock.gif        
/// <devdoc>
ExpandedSubBlockEnd.gif        
/// </devdoc>

ExpandedSubBlockStart.gifContractedSubBlock.gif        public virtual String Dump() dot.gif{
InBlock.gif            String key 
= roptions + ":" + pattern;
InBlock.gif            
if (key[0== ':')
InBlock.gif                
return key.Substring(1, key.Length - 1);
InBlock.gif
InBlock.gif            
return key;
ExpandedSubBlockEnd.gif        }

InBlock.gif
ExpandedSubBlockStart.gifContractedSubBlock.gif        
/**//// <include file='doc\Regex.uex' path='docs/doc[@for="Regex.Dump1"]/*' />
InBlock.gif        
/// <internalonly/>
InBlock.gif        
/// <devdoc>
ExpandedSubBlockEnd.gif        
/// </devdoc>

ExpandedSubBlockStart.gifContractedSubBlock.gif        public virtual String Dump(String indent) dot.gif{
InBlock.gif            
return indent + Dump() + "\n";
ExpandedSubBlockEnd.gif        }

InBlock.gif
#endif
ExpandedSubBlockEnd.gif    }

InBlock.gif
InBlock.gif
InBlock.gif    
// Callback class
ExpandedSubBlockStart.gifContractedSubBlock.gif
    /**//// <include file='doc\Regex.uex' path='docs/doc[@for="MatchEvaluator"]/*' />
InBlock.gif    
/// <devdoc>
ExpandedSubBlockEnd.gif    
/// </devdoc>

InBlock.gif    [ Serializable() ] 
InBlock.gif    
public delegate String MatchEvaluator(Match match);
InBlock.gif
InBlock.gif
InBlock.gif    
// Used to cache byte codes or compiled factories
ExpandedSubBlockStart.gifContractedSubBlock.gif
    internal sealed class CachedCodeEntry dot.gif{
InBlock.gif        
internal int _references;
InBlock.gif
InBlock.gif        
internal RegexCode _code;
InBlock.gif        
internal RegexOptions _options;
InBlock.gif        
internal Hashtable _caps;
InBlock.gif        
internal Hashtable _capnames;
InBlock.gif        
internal String[]  _capslist;
InBlock.gif        
internal int       _capsize;
InBlock.gif        
internal RegexRunnerFactory _factory;
InBlock.gif        
internal ExclusiveReference _runnerref;
InBlock.gif        
internal SharedReference _replref;
InBlock.gif
ExpandedSubBlockStart.gifContractedSubBlock.gif        
internal CachedCodeEntry(RegexOptions options, Hashtable capnames, String[] capslist, RegexCode code, Hashtable caps, int capsize, ExclusiveReference runner, SharedReference repl) dot.gif{
InBlock.gif
InBlock.gif            _options    
= options;
InBlock.gif            _capnames   
= capnames;
InBlock.gif            _capslist   
= capslist;
InBlock.gif
InBlock.gif            _code       
= code;
InBlock.gif            _caps       
= caps;
InBlock.gif            _capsize    
= capsize;
InBlock.gif
InBlock.gif            _runnerref     
= runner;
InBlock.gif            _replref       
= repl;
InBlock.gif
InBlock.gif            _references 
= 1;
ExpandedSubBlockEnd.gif        }

InBlock.gif
ExpandedSubBlockStart.gifContractedSubBlock.gif        
internal CachedCodeEntry AddRef() dot.gif{
ExpandedSubBlockStart.gifContractedSubBlock.gif            
lock(thisdot.gif{
InBlock.gif                _references 
+= 1;
InBlock.gif                
return this;
ExpandedSubBlockEnd.gif            }

ExpandedSubBlockEnd.gif        }

InBlock.gif
ExpandedSubBlockStart.gifContractedSubBlock.gif        
internal void Release() dot.gif{
ExpandedSubBlockStart.gifContractedSubBlock.gif            
lock(thisdot.gif{
InBlock.gif                _references 
-= 1;
ExpandedSubBlockEnd.gif            }

ExpandedSubBlockEnd.gif        }

InBlock.gif
ExpandedSubBlockStart.gifContractedSubBlock.gif        
internal bool NoReferences() dot.gif{
InBlock.gif            
return(_references == 0);
ExpandedSubBlockEnd.gif        }

InBlock.gif
ExpandedSubBlockStart.gifContractedSubBlock.gif        
internal void AddCompiled(RegexRunnerFactory factory) dot.gif{
ExpandedSubBlockStart.gifContractedSubBlock.gif            
lock(thisdot.gif{
InBlock.gif                _code 
= null;
InBlock.gif                _factory 
= factory;
InBlock.gif                _references 
+= 1;   // will never be balanced since we never unload the type
ExpandedSubBlockEnd.gif
            }

ExpandedSubBlockEnd.gif        }

ExpandedSubBlockEnd.gif    }

InBlock.gif
InBlock.gif    
// Used to cache one exclusive weak reference
ExpandedSubBlockStart.gifContractedSubBlock.gif
    internal sealed class ExclusiveReference dot.gif{
InBlock.gif        WeakReference _ref 
= new WeakReference(null);
InBlock.gif        Object _obj;
InBlock.gif        
int _locked;
InBlock.gif
InBlock.gif        
// Return an object and grab an exclusive lock.
InBlock.gif        
//
InBlock.gif        
// If the exclusive lock can't be obtained, null is returned;
InBlock.gif        
// if the object can't be returned, the lock is released.
InBlock.gif        
//
InBlock.gif        
// Note that _ref.Target is referenced only under the protection
InBlock.gif        
// of the lock. (Is this necessary?)
ExpandedSubBlockStart.gifContractedSubBlock.gif
        internal Object Get() dot.gif{
InBlock.gif            
// try to obtain the lock
InBlock.gif

ExpandedSubBlockStart.gifContractedSubBlock.gif            
if (0 == Interlocked.Exchange(ref _locked, 1)) dot.gif{
InBlock.gif                
// grab reference
InBlock.gif

InBlock.gif                Object obj 
= _ref.Target;
InBlock.gif
InBlock.gif                
// release the lock and return null if no reference
InBlock.gif

ExpandedSubBlockStart.gifContractedSubBlock.gif                
if (obj == nulldot.gif{
InBlock.gif                    _locked 
= 0;
InBlock.gif                    
return null;
ExpandedSubBlockEnd.gif                }

InBlock.gif
InBlock.gif                
// remember the reference and keep the lock
InBlock.gif

InBlock.gif                _obj 
= obj;
InBlock.gif                
return obj;
ExpandedSubBlockEnd.gif            }

InBlock.gif
InBlock.gif            
return null;
ExpandedSubBlockEnd.gif        }

InBlock.gif
InBlock.gif        
// Release an object back to the cache
InBlock.gif        
//
InBlock.gif        
// If the object is the one that's under lock, the lock
InBlock.gif        
// is released.
InBlock.gif        
//
InBlock.gif        
// If there is no cached object, then the lock is obtained
InBlock.gif        
// and the object is placed in the cache.
InBlock.gif        
//
InBlock.gif        
// Note that _ref.Target is referenced only under the protection
InBlock.gif        
// of the lock. (Is this necessary?)
ExpandedSubBlockStart.gifContractedSubBlock.gif
        internal void Release(Object obj) dot.gif{
InBlock.gif            
if (obj == null)
InBlock.gif                
throw new ArgumentNullException("obj");
InBlock.gif
InBlock.gif            
// if this reference owns the lock, release it
InBlock.gif

ExpandedSubBlockStart.gifContractedSubBlock.gif            
if (_obj == obj) dot.gif{
InBlock.gif                _obj 
= null;
InBlock.gif                _locked 
= 0;
InBlock.gif                
return;
ExpandedSubBlockEnd.gif            }

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

ExpandedSubBlockStart.gifContractedSubBlock.gif            
if (_obj == nulldot.gif{
InBlock.gif                
// try to obtain the lock
InBlock.gif

ExpandedSubBlockStart.gifContractedSubBlock.gif                
if (0 == Interlocked.Exchange(ref _locked, 1)) dot.gif{
InBlock.gif                    
// if there's really no reference, cache this reference
InBlock.gif

InBlock.gif                    
if (_ref.Target == null)
InBlock.gif                        _ref.Target 
= obj;
InBlock.gif
InBlock.gif                    
// release the lock
InBlock.gif

InBlock.gif                    _locked 
= 0;
InBlock.gif                    
return;
ExpandedSubBlockEnd.gif                }

ExpandedSubBlockEnd.gif            }

ExpandedSubBlockEnd.gif        }

ExpandedSubBlockEnd.gif    }

InBlock.gif
InBlock.gif    
// Used to cache a weak reference in a threadsafe way
ExpandedSubBlockStart.gifContractedSubBlock.gif
    internal sealed class SharedReference dot.gif{
InBlock.gif        WeakReference _ref 
= new WeakReference(null);
InBlock.gif        
int _locked;
InBlock.gif
InBlock.gif        
// Return an object from a weakref, protected by a lock.
InBlock.gif        
//
InBlock.gif        
// If the exclusive lock can't be obtained, null is returned;
InBlock.gif        
//
InBlock.gif        
// Note that _ref.Target is referenced only under the protection
InBlock.gif        
// of the lock. (Is this necessary?)
ExpandedSubBlockStart.gifContractedSubBlock.gif
        internal  Object Get() dot.gif{
ExpandedSubBlockStart.gifContractedSubBlock.gif            
if (0 == Interlocked.Exchange(ref _locked, 1)) dot.gif{
InBlock.gif                Object obj 
= _ref.Target;
InBlock.gif                _locked 
= 0;
InBlock.gif                
return obj;
ExpandedSubBlockEnd.gif            }

InBlock.gif
InBlock.gif            
return null;
ExpandedSubBlockEnd.gif        }

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

ExpandedSubBlockEnd.gif        }

ExpandedSubBlockEnd.gif    }

InBlock.gif
ExpandedBlockEnd.gif}

None.gif

转载于:https://www.cnblogs.com/wannaCNBLOGS/archive/2005/08/04/207085.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值