Code:
/ Dotnetfx_Win7_3.5.1 / Dotnetfx_Win7_3.5.1 / 3.5.1 / DEVDIV / depot / DevDiv / releases / whidbey / NetFXspW7 / ndp / fx / src / Regex / System / Text / RegularExpressions / RegexMatch.cs / 1 / RegexMatch.cs
//------------------------------------------------------------------------------ //// Copyright (c) Microsoft Corporation. All rights reserved. // //----------------------------------------------------------------------------- // Match is the result class for a regex search. // It returns the location, length, and substring for // the entire match as well as every captured group. // Match is also used during the search to keep track of each capture for each group. This is // done using the "_matches" array. _matches[x] represents an array of the captures for group x. // This array consists of start and length pairs, and may have empty entries at the end. _matchcount[x] // stores how many captures a group has. Note that _matchcount[x]*2 is the length of all the valid // values in _matches. _matchcount[x]*2-2 is the Start of the last capture, and _matchcount[x]*2-1 is the // Length of the last capture // // For example, if group 2 has one capture starting at position 4 with length 6, // _matchcount[2] == 1 // _matches[2][0] == 4 // _matches[2][1] == 6 // // Values in the _matches array can also be negative. This happens when using the balanced match // construct, "(?...)". When the "end" group matches, a capture is added for both the "start" // and "end" groups. The capture added for "start" receives the negative values, and these values point to // the next capture to be balanced. They do NOT point to the capture that "end" just balanced out. The negative // values are indices into the _matches array transformed by the formula -3-x. This formula also untransforms. // namespace System.Text.RegularExpressions { using System.Collections; using System.Diagnostics; using System.Security.Permissions; using System.Globalization; /// /// [ Serializable() ] public class Match : Group { internal static Match _empty = new Match(null, 1, String.Empty, 0, 0, 0); internal GroupCollection _groupcoll; // input to the match internal Regex _regex; internal int _textbeg; internal int _textpos; internal int _textend; internal int _textstart; // output from the match internal int[][] _matches; internal int[] _matchcount; internal bool _balancing; // whether we've done any balancing with this match. If we // have done balancing, we'll need to do extra work in Tidy(). ////// Represents /// the results from a single regular expression match. /// ////// public static Match Empty { get { return _empty; } } /* * Nonpublic constructor */ internal Match(Regex regex, int capcount, String text, int begpos, int len, int startpos) : base(text, new int[2], 0) { _regex = regex; _matchcount = new int[capcount]; _matches = new int[capcount][]; _matches[0] = _caps; _textbeg = begpos; _textend = begpos + len; _textstart = startpos; _balancing = false; // No need for an exception here. This is only called internally, so we'll use an Assert instead System.Diagnostics.Debug.Assert(!(_textbeg < 0 || _textstart < _textbeg || _textend < _textstart || _text.Length < _textend), "The parameters are out of range."); } /* * Nonpublic set-text method */ internal virtual void Reset(Regex regex, String text, int textbeg, int textend, int textstart) { _regex = regex; _text = text; _textbeg = textbeg; _textend = textend; _textstart = textstart; for (int i = 0; i < _matchcount.Length; i++) { _matchcount[i] = 0; } _balancing = false; } ////// Returns an empty Match object. /// ////// public virtual GroupCollection Groups { get { if (_groupcoll == null) _groupcoll = new GroupCollection(this, null); return _groupcoll; } } /* * Returns the next match */ ///[To be supplied.] ////// public Match NextMatch() { if (_regex == null) return this; return _regex.Run(false, _length, _text, _textbeg, _textend - _textbeg, _textpos); } /* * Return the result string (using the replacement pattern) */ ///Returns a new Match with the results for the next match, starting /// at the position at which the last match ended (at the character beyond the last /// matched character). ////// public virtual String Result(String replacement) { RegexReplacement repl; if (replacement == null) throw new ArgumentNullException("replacement"); if (_regex == null) throw new NotSupportedException(SR.GetString(SR.NoResultOnFailed)); repl = (RegexReplacement)_regex.replref.Get(); if (repl == null || !repl.Pattern.Equals(replacement)) { repl = RegexParser.ParseReplacement(replacement, _regex.caps, _regex.capsize, _regex.capnames, _regex.roptions); _regex.replref.Cache(repl); } return repl.Replacement(this); } /* * Used by the replacement code */ internal virtual String GroupToStringImpl(int groupnum) { int c = _matchcount[groupnum]; if (c == 0) return String.Empty; int [] matches = _matches[groupnum]; return _text.Substring(matches[(c - 1) * 2], matches[(c * 2) - 1]); } /* * Used by the replacement code */ internal String LastGroupToStringImpl() { return GroupToStringImpl(_matchcount.Length - 1); } /* * Convert to a thread-safe object by precomputing cache contents */ ////// Returns the expansion of the passed replacement pattern. For /// example, if the replacement pattern is ?$1$2?, Result returns the concatenation /// of Group(1).ToString() and Group(2).ToString(). /// ////// [HostProtection(Synchronization=true)] static public Match Synchronized(Match inner) { if (inner == null) throw new ArgumentNullException("inner"); int numgroups = inner._matchcount.Length; // Populate all groups by looking at each one for (int i = 0; i < numgroups; i++) { Group group = inner.Groups[i]; // Depends on the fact that Group.Synchronized just // operates on and returns the same instance System.Text.RegularExpressions.Group.Synchronized(group); } return inner; } /* * Nonpublic builder: add a capture to the group specified by "cap" */ internal virtual void AddMatch(int cap, int start, int len) { int capcount; if (_matches[cap] == null) _matches[cap] = new int[2]; capcount = _matchcount[cap]; if (capcount * 2 + 2 > _matches[cap].Length) { int[] oldmatches = _matches[cap]; int[] newmatches = new int[capcount * 8]; for (int j = 0; j < capcount * 2; j++) newmatches[j] = oldmatches[j]; _matches[cap] = newmatches; } _matches[cap][capcount * 2] = start; _matches[cap][capcount * 2 + 1] = len; _matchcount[cap] = capcount + 1; } /* * Nonpublic builder: Add a capture to balance the specified group. This is used by the balanced match construct. (?/// Returns a Match instance equivalent to the one supplied that is safe to share /// between multiple threads. /// ///...) If there were no such thing as backtracking, this would be as simple as calling RemoveMatch(cap). However, since we have backtracking, we need to keep track of everything. */ internal virtual void BalanceMatch(int cap) { int capcount; int target; _balancing = true; // we'll look at the last capture first capcount = _matchcount[cap]; target = capcount * 2 - 2; // first see if it is negative, and therefore is a reference to the next available // capture group for balancing. If it is, we'll reset target to point to that capture. if (_matches[cap][target] < 0) target = -3 - _matches[cap][target]; // move back to the previous capture target -= 2; // if the previous capture is a reference, just copy that reference to the end. Otherwise, point to it. if (target >= 0 && _matches[cap][target] < 0) AddMatch(cap, _matches[cap][target], _matches[cap][target+1]); else AddMatch(cap, -3 - target, -4 - target /* == -3 - (target + 1) */ ); } /* * Nonpublic builder: removes a group match by capnum */ internal virtual void RemoveMatch(int cap) { _matchcount[cap]--; } /* * Nonpublic: tells if a group was matched by capnum */ internal virtual bool IsMatched(int cap) { return cap < _matchcount.Length && _matchcount[cap] > 0 && _matches[cap][_matchcount[cap] * 2 - 1] != (-3 + 1); } /* * Nonpublic: returns the index of the last specified matched group by capnum */ internal virtual int MatchIndex(int cap) { int i = _matches[cap][_matchcount[cap] * 2 - 2]; if (i >= 0) return i; return _matches[cap][-3 - i]; } /* * Nonpublic: returns the length of the last specified matched group by capnum */ internal virtual int MatchLength(int cap) { int i = _matches[cap][_matchcount[cap] * 2 - 1]; if (i >= 0) return i; return _matches[cap][-3 - i]; } /* * Nonpublic: tidy the match so that it can be used as an immutable result */ internal virtual void Tidy(int textpos) { int[] interval; interval = _matches[0]; _index = interval[0]; _length = interval[1]; _textpos = textpos; _capcount = _matchcount[0]; if (_balancing) { // The idea here is that we want to compact all of our unbalanced captures. To do that we // use j basically as a count of how many unbalanced captures we have at any given time // (really j is an index, but j/2 is the count). First we skip past all of the real captures // until we find a balance captures. Then we check each subsequent entry. If it's a balance // capture (it's negative), we decrement j. If it's a real capture, we increment j and copy // it down to the last free position. for (int cap = 0; cap < _matchcount.Length; cap++) { int limit; int[] matcharray; limit = _matchcount[cap] * 2; matcharray = _matches[cap]; int i = 0; int j; for (i = 0; i < limit; i++) { if (matcharray[i] < 0) break; } for (j = i; i < limit; i++) { if (matcharray[i] < 0) { // skip negative values j--; } else { // but if we find something positive (an actual capture), copy it back to the last // unbalanced position. if (i != j) matcharray[j] = matcharray[i]; j++; } } _matchcount[cap] = j / 2; } _balancing = false; } } #if DBG /// /// /// public bool Debug { get { if (_regex == null) return false; return _regex.Debug; } } ////// /// internal virtual void Dump() { int i,j; for (i = 0; i < _matchcount.Length; i++) { System.Diagnostics.Debug.WriteLine("Capnum " + i.ToString(CultureInfo.InvariantCulture) + ":"); for (j = 0; j < _matchcount[i]; j++) { String text = ""; if (_matches[i][j * 2] >= 0) text = _text.Substring(_matches[i][j * 2], _matches[i][j * 2 + 1]); System.Diagnostics.Debug.WriteLine(" (" + _matches[i][j * 2].ToString(CultureInfo.InvariantCulture) + "," + _matches[i][j * 2 + 1].ToString(CultureInfo.InvariantCulture) + ") " + text); } } } #endif } /* * MatchSparse is for handling the case where slots are * sparsely arranged (e.g., if somebody says use slot 100000) */ internal class MatchSparse : Match { // the lookup hashtable new internal Hashtable _caps; /* * Nonpublic constructor */ internal MatchSparse(Regex regex, Hashtable caps, int capcount, String text, int begpos, int len, int startpos) : base(regex, capcount, text, begpos, len, startpos) { _caps = caps; } public override GroupCollection Groups { get { if (_groupcoll == null) _groupcoll = new GroupCollection(this, _caps); return _groupcoll; } } #if DBG internal override void Dump() { if (_caps != null) { IEnumerator e = _caps.Keys.GetEnumerator(); while (e.MoveNext()) { System.Diagnostics.Debug.WriteLine("Slot " + e.Current.ToString() + " -> " + _caps[e.Current].ToString()); } } base.Dump(); } #endif } } // File provided for Reference Use Only by Microsoft Corporation (c) 2007. //------------------------------------------------------------------------------ //// Copyright (c) Microsoft Corporation. All rights reserved. // //----------------------------------------------------------------------------- // Match is the result class for a regex search. // It returns the location, length, and substring for // the entire match as well as every captured group. // Match is also used during the search to keep track of each capture for each group. This is // done using the "_matches" array. _matches[x] represents an array of the captures for group x. // This array consists of start and length pairs, and may have empty entries at the end. _matchcount[x] // stores how many captures a group has. Note that _matchcount[x]*2 is the length of all the valid // values in _matches. _matchcount[x]*2-2 is the Start of the last capture, and _matchcount[x]*2-1 is the // Length of the last capture // // For example, if group 2 has one capture starting at position 4 with length 6, // _matchcount[2] == 1 // _matches[2][0] == 4 // _matches[2][1] == 6 // // Values in the _matches array can also be negative. This happens when using the balanced match // construct, "(?...)". When the "end" group matches, a capture is added for both the "start" // and "end" groups. The capture added for "start" receives the negative values, and these values point to // the next capture to be balanced. They do NOT point to the capture that "end" just balanced out. The negative // values are indices into the _matches array transformed by the formula -3-x. This formula also untransforms. // namespace System.Text.RegularExpressions { using System.Collections; using System.Diagnostics; using System.Security.Permissions; using System.Globalization; /// /// [ Serializable() ] public class Match : Group { internal static Match _empty = new Match(null, 1, String.Empty, 0, 0, 0); internal GroupCollection _groupcoll; // input to the match internal Regex _regex; internal int _textbeg; internal int _textpos; internal int _textend; internal int _textstart; // output from the match internal int[][] _matches; internal int[] _matchcount; internal bool _balancing; // whether we've done any balancing with this match. If we // have done balancing, we'll need to do extra work in Tidy(). ////// Represents /// the results from a single regular expression match. /// ////// public static Match Empty { get { return _empty; } } /* * Nonpublic constructor */ internal Match(Regex regex, int capcount, String text, int begpos, int len, int startpos) : base(text, new int[2], 0) { _regex = regex; _matchcount = new int[capcount]; _matches = new int[capcount][]; _matches[0] = _caps; _textbeg = begpos; _textend = begpos + len; _textstart = startpos; _balancing = false; // No need for an exception here. This is only called internally, so we'll use an Assert instead System.Diagnostics.Debug.Assert(!(_textbeg < 0 || _textstart < _textbeg || _textend < _textstart || _text.Length < _textend), "The parameters are out of range."); } /* * Nonpublic set-text method */ internal virtual void Reset(Regex regex, String text, int textbeg, int textend, int textstart) { _regex = regex; _text = text; _textbeg = textbeg; _textend = textend; _textstart = textstart; for (int i = 0; i < _matchcount.Length; i++) { _matchcount[i] = 0; } _balancing = false; } ////// Returns an empty Match object. /// ////// public virtual GroupCollection Groups { get { if (_groupcoll == null) _groupcoll = new GroupCollection(this, null); return _groupcoll; } } /* * Returns the next match */ ///[To be supplied.] ////// public Match NextMatch() { if (_regex == null) return this; return _regex.Run(false, _length, _text, _textbeg, _textend - _textbeg, _textpos); } /* * Return the result string (using the replacement pattern) */ ///Returns a new Match with the results for the next match, starting /// at the position at which the last match ended (at the character beyond the last /// matched character). ////// public virtual String Result(String replacement) { RegexReplacement repl; if (replacement == null) throw new ArgumentNullException("replacement"); if (_regex == null) throw new NotSupportedException(SR.GetString(SR.NoResultOnFailed)); repl = (RegexReplacement)_regex.replref.Get(); if (repl == null || !repl.Pattern.Equals(replacement)) { repl = RegexParser.ParseReplacement(replacement, _regex.caps, _regex.capsize, _regex.capnames, _regex.roptions); _regex.replref.Cache(repl); } return repl.Replacement(this); } /* * Used by the replacement code */ internal virtual String GroupToStringImpl(int groupnum) { int c = _matchcount[groupnum]; if (c == 0) return String.Empty; int [] matches = _matches[groupnum]; return _text.Substring(matches[(c - 1) * 2], matches[(c * 2) - 1]); } /* * Used by the replacement code */ internal String LastGroupToStringImpl() { return GroupToStringImpl(_matchcount.Length - 1); } /* * Convert to a thread-safe object by precomputing cache contents */ ////// Returns the expansion of the passed replacement pattern. For /// example, if the replacement pattern is ?$1$2?, Result returns the concatenation /// of Group(1).ToString() and Group(2).ToString(). /// ////// [HostProtection(Synchronization=true)] static public Match Synchronized(Match inner) { if (inner == null) throw new ArgumentNullException("inner"); int numgroups = inner._matchcount.Length; // Populate all groups by looking at each one for (int i = 0; i < numgroups; i++) { Group group = inner.Groups[i]; // Depends on the fact that Group.Synchronized just // operates on and returns the same instance System.Text.RegularExpressions.Group.Synchronized(group); } return inner; } /* * Nonpublic builder: add a capture to the group specified by "cap" */ internal virtual void AddMatch(int cap, int start, int len) { int capcount; if (_matches[cap] == null) _matches[cap] = new int[2]; capcount = _matchcount[cap]; if (capcount * 2 + 2 > _matches[cap].Length) { int[] oldmatches = _matches[cap]; int[] newmatches = new int[capcount * 8]; for (int j = 0; j < capcount * 2; j++) newmatches[j] = oldmatches[j]; _matches[cap] = newmatches; } _matches[cap][capcount * 2] = start; _matches[cap][capcount * 2 + 1] = len; _matchcount[cap] = capcount + 1; } /* * Nonpublic builder: Add a capture to balance the specified group. This is used by the balanced match construct. (?/// Returns a Match instance equivalent to the one supplied that is safe to share /// between multiple threads. /// ///...) If there were no such thing as backtracking, this would be as simple as calling RemoveMatch(cap). However, since we have backtracking, we need to keep track of everything. */ internal virtual void BalanceMatch(int cap) { int capcount; int target; _balancing = true; // we'll look at the last capture first capcount = _matchcount[cap]; target = capcount * 2 - 2; // first see if it is negative, and therefore is a reference to the next available // capture group for balancing. If it is, we'll reset target to point to that capture. if (_matches[cap][target] < 0) target = -3 - _matches[cap][target]; // move back to the previous capture target -= 2; // if the previous capture is a reference, just copy that reference to the end. Otherwise, point to it. if (target >= 0 && _matches[cap][target] < 0) AddMatch(cap, _matches[cap][target], _matches[cap][target+1]); else AddMatch(cap, -3 - target, -4 - target /* == -3 - (target + 1) */ ); } /* * Nonpublic builder: removes a group match by capnum */ internal virtual void RemoveMatch(int cap) { _matchcount[cap]--; } /* * Nonpublic: tells if a group was matched by capnum */ internal virtual bool IsMatched(int cap) { return cap < _matchcount.Length && _matchcount[cap] > 0 && _matches[cap][_matchcount[cap] * 2 - 1] != (-3 + 1); } /* * Nonpublic: returns the index of the last specified matched group by capnum */ internal virtual int MatchIndex(int cap) { int i = _matches[cap][_matchcount[cap] * 2 - 2]; if (i >= 0) return i; return _matches[cap][-3 - i]; } /* * Nonpublic: returns the length of the last specified matched group by capnum */ internal virtual int MatchLength(int cap) { int i = _matches[cap][_matchcount[cap] * 2 - 1]; if (i >= 0) return i; return _matches[cap][-3 - i]; } /* * Nonpublic: tidy the match so that it can be used as an immutable result */ internal virtual void Tidy(int textpos) { int[] interval; interval = _matches[0]; _index = interval[0]; _length = interval[1]; _textpos = textpos; _capcount = _matchcount[0]; if (_balancing) { // The idea here is that we want to compact all of our unbalanced captures. To do that we // use j basically as a count of how many unbalanced captures we have at any given time // (really j is an index, but j/2 is the count). First we skip past all of the real captures // until we find a balance captures. Then we check each subsequent entry. If it's a balance // capture (it's negative), we decrement j. If it's a real capture, we increment j and copy // it down to the last free position. for (int cap = 0; cap < _matchcount.Length; cap++) { int limit; int[] matcharray; limit = _matchcount[cap] * 2; matcharray = _matches[cap]; int i = 0; int j; for (i = 0; i < limit; i++) { if (matcharray[i] < 0) break; } for (j = i; i < limit; i++) { if (matcharray[i] < 0) { // skip negative values j--; } else { // but if we find something positive (an actual capture), copy it back to the last // unbalanced position. if (i != j) matcharray[j] = matcharray[i]; j++; } } _matchcount[cap] = j / 2; } _balancing = false; } } #if DBG /// /// /// public bool Debug { get { if (_regex == null) return false; return _regex.Debug; } } ////// /// internal virtual void Dump() { int i,j; for (i = 0; i < _matchcount.Length; i++) { System.Diagnostics.Debug.WriteLine("Capnum " + i.ToString(CultureInfo.InvariantCulture) + ":"); for (j = 0; j < _matchcount[i]; j++) { String text = ""; if (_matches[i][j * 2] >= 0) text = _text.Substring(_matches[i][j * 2], _matches[i][j * 2 + 1]); System.Diagnostics.Debug.WriteLine(" (" + _matches[i][j * 2].ToString(CultureInfo.InvariantCulture) + "," + _matches[i][j * 2 + 1].ToString(CultureInfo.InvariantCulture) + ") " + text); } } } #endif } /* * MatchSparse is for handling the case where slots are * sparsely arranged (e.g., if somebody says use slot 100000) */ internal class MatchSparse : Match { // the lookup hashtable new internal Hashtable _caps; /* * Nonpublic constructor */ internal MatchSparse(Regex regex, Hashtable caps, int capcount, String text, int begpos, int len, int startpos) : base(regex, capcount, text, begpos, len, startpos) { _caps = caps; } public override GroupCollection Groups { get { if (_groupcoll == null) _groupcoll = new GroupCollection(this, _caps); return _groupcoll; } } #if DBG internal override void Dump() { if (_caps != null) { IEnumerator e = _caps.Keys.GetEnumerator(); while (e.MoveNext()) { System.Diagnostics.Debug.WriteLine("Slot " + e.Current.ToString() + " -> " + _caps[e.Current].ToString()); } } base.Dump(); } #endif } } // File provided for Reference Use Only by Microsoft Corporation (c) 2007.
Link Menu
This book is available now!
Buy at Amazon US or
Buy at Amazon UK
- RayMeshGeometry3DHitTestResult.cs
- MetaDataInfo.cs
- RegisteredExpandoAttribute.cs
- Rotation3DKeyFrameCollection.cs
- PriorityRange.cs
- _NestedMultipleAsyncResult.cs
- RenderTargetBitmap.cs
- CleanUpVirtualizedItemEventArgs.cs
- Missing.cs
- SystemMulticastIPAddressInformation.cs
- RawTextInputReport.cs
- StateManagedCollection.cs
- DataBinder.cs
- XmlBindingWorker.cs
- ArcSegment.cs
- AxisAngleRotation3D.cs
- Propagator.JoinPropagator.cs
- XmlSerializerNamespaces.cs
- XmlParserContext.cs
- WinFormsSpinner.cs
- KeyGestureValueSerializer.cs
- GlobalEventManager.cs
- WebPartConnectionsConfigureVerb.cs
- FontFamilyValueSerializer.cs
- Html32TextWriter.cs
- SpotLight.cs
- Int32EqualityComparer.cs
- Reference.cs
- TypeUsageBuilder.cs
- Crc32.cs
- XamlPathDataSerializer.cs
- PanelStyle.cs
- WorkflowFileItem.cs
- WebPartDisplayModeCollection.cs
- ExpressionDumper.cs
- ConfigurationSchemaErrors.cs
- SystemDropShadowChrome.cs
- XPathArrayIterator.cs
- TextElementCollectionHelper.cs
- ColumnMapTranslator.cs
- Pkcs7Recipient.cs
- IdentityManager.cs
- XPathScanner.cs
- ModuleElement.cs
- VolatileEnlistmentMultiplexing.cs
- Assembly.cs
- QueryInterceptorAttribute.cs
- TableLayoutPanel.cs
- BasicAsyncResult.cs
- XsdBuilder.cs
- TraceSection.cs
- CommonObjectSecurity.cs
- XmlTextReaderImplHelpers.cs
- RSAPKCS1SignatureFormatter.cs
- path.cs
- ObjectTag.cs
- FlowLayoutPanel.cs
- WSSecurityOneDotZeroSendSecurityHeader.cs
- ResourcePart.cs
- EntityDataSourceWrapper.cs
- CompositeCollection.cs
- AuthenticationModulesSection.cs
- TextEffectResolver.cs
- MouseGestureValueSerializer.cs
- SecurityToken.cs
- HierarchicalDataBoundControlAdapter.cs
- MessageQueueException.cs
- FixedMaxHeap.cs
- AnnotationHighlightLayer.cs
- RegexStringValidatorAttribute.cs
- Command.cs
- ADMembershipProvider.cs
- LayoutEditorPart.cs
- CreateParams.cs
- AppDomainFactory.cs
- ColorConvertedBitmapExtension.cs
- CancelRequestedRecord.cs
- Util.cs
- ArrayTypeMismatchException.cs
- ResXBuildProvider.cs
- QuadraticBezierSegment.cs
- BindingCollection.cs
- BindingExpressionUncommonField.cs
- MethodAccessException.cs
- DashStyle.cs
- StyleHelper.cs
- WebBrowserNavigatedEventHandler.cs
- InputProcessorProfilesLoader.cs
- XmlnsCache.cs
- Oid.cs
- QilReference.cs
- LayoutManager.cs
- SymmetricKey.cs
- EncodingDataItem.cs
- FormatterConverter.cs
- OrderedDictionaryStateHelper.cs
- _FtpControlStream.cs
- IERequestCache.cs
- PrintPageEvent.cs
- TemplatedMailWebEventProvider.cs