You've already forked linux-packaging-mono
Imported Upstream version 4.6.0.125
Former-commit-id: a2155e9bd80020e49e72e86c44da02a8ac0e57a4
This commit is contained in:
parent
a569aebcfd
commit
e79aa3c0ed
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,396 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// <copyright file="RegexBoyerMoore.cs" company="Microsoft">
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// </copyright>
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
// The RegexBoyerMoore object precomputes the Boyer-Moore
|
||||
// tables for fast string scanning. These tables allow
|
||||
// you to scan for the first occurance of a string within
|
||||
// a large body of text without examining every character.
|
||||
// The performance of the heuristic depends on the actual
|
||||
// string and the text being searched, but usually, the longer
|
||||
// the string that is being searched for, the fewer characters
|
||||
// need to be examined.
|
||||
|
||||
namespace System.Text.RegularExpressions
|
||||
{
|
||||
|
||||
using System.Collections;
|
||||
using System.Diagnostics;
|
||||
using System.Globalization;
|
||||
|
||||
internal sealed class RegexBoyerMoore {
|
||||
internal int[] _positive;
|
||||
internal int[] _negativeASCII;
|
||||
internal int[][] _negativeUnicode;
|
||||
internal String _pattern;
|
||||
internal int _lowASCII;
|
||||
internal int _highASCII;
|
||||
internal bool _rightToLeft;
|
||||
internal bool _caseInsensitive;
|
||||
internal CultureInfo _culture;
|
||||
|
||||
internal const int infinite = 0x7FFFFFFF;
|
||||
|
||||
/*
|
||||
* Constructs a Boyer-Moore state machine for searching for the string
|
||||
* pattern. The string must not be zero-length.
|
||||
*/
|
||||
internal RegexBoyerMoore(String pattern, bool caseInsensitive, bool rightToLeft, CultureInfo culture) {
|
||||
/*
|
||||
* Sorry, you just can't use Boyer-Moore to find an empty pattern.
|
||||
* We're doing this for your own protection. (Really, for speed.)
|
||||
*/
|
||||
Debug.Assert(pattern.Length != 0, "RegexBoyerMoore called with an empty string. This is bad for perf");
|
||||
|
||||
int beforefirst;
|
||||
int last;
|
||||
int bump;
|
||||
int examine;
|
||||
int scan;
|
||||
int match;
|
||||
char ch;
|
||||
|
||||
// We do the ToLower character by character for consistency. With surrogate chars, doing
|
||||
// a ToLower on the entire string could actually change the surrogate pair. This is more correct
|
||||
// linguistically, but since Regex doesn't support surrogates, it's more important to be
|
||||
// consistent.
|
||||
if (caseInsensitive) {
|
||||
StringBuilder sb = new StringBuilder(pattern.Length);
|
||||
for (int i=0; i<pattern.Length; i++)
|
||||
sb.Append(Char.ToLower(pattern[i], culture));
|
||||
pattern = sb.ToString();
|
||||
}
|
||||
|
||||
_pattern = pattern;
|
||||
_rightToLeft = rightToLeft;
|
||||
_caseInsensitive = caseInsensitive;
|
||||
_culture = culture;
|
||||
|
||||
if (!rightToLeft) {
|
||||
beforefirst = -1;
|
||||
last = pattern.Length - 1;
|
||||
bump = 1;
|
||||
}
|
||||
else {
|
||||
beforefirst = pattern.Length;
|
||||
last = 0;
|
||||
bump = -1;
|
||||
}
|
||||
|
||||
/*
|
||||
* PART I - the good-suffix shift table
|
||||
*
|
||||
* compute the positive requirement:
|
||||
* if char "i" is the first one from the right that doesn't match,
|
||||
* then we know the matcher can advance by _positive[i].
|
||||
*
|
||||
* <
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
*/
|
||||
_positive = new int[pattern.Length];
|
||||
|
||||
examine = last;
|
||||
ch = pattern[examine];
|
||||
_positive[examine] = bump;
|
||||
examine -= bump;
|
||||
|
||||
for (;;) {
|
||||
// find an internal char (examine) that matches the tail
|
||||
|
||||
for (;;) {
|
||||
if (examine == beforefirst)
|
||||
goto OuterloopBreak;
|
||||
if (pattern[examine] == ch)
|
||||
break;
|
||||
examine -= bump;
|
||||
}
|
||||
|
||||
match = last;
|
||||
scan = examine;
|
||||
|
||||
// find the length of the match
|
||||
|
||||
for (;;) {
|
||||
if (scan == beforefirst || pattern[match] != pattern[scan]) {
|
||||
// at the end of the match, note the difference in _positive
|
||||
// this is not the length of the match, but the distance from the internal match
|
||||
// to the tail suffix.
|
||||
if (_positive[match] == 0)
|
||||
_positive[match] = match - scan;
|
||||
|
||||
// System.Diagnostics.Debug.WriteLine("Set positive[" + match + "] to " + (match - scan));
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
scan -= bump;
|
||||
match -= bump;
|
||||
}
|
||||
|
||||
examine -= bump;
|
||||
}
|
||||
|
||||
OuterloopBreak:
|
||||
|
||||
match = last - bump;
|
||||
|
||||
// scan for the chars for which there are no shifts that yield a different candidate
|
||||
|
||||
/* <
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
*/
|
||||
while (match != beforefirst) {
|
||||
if (_positive[match] == 0)
|
||||
_positive[match] = bump;
|
||||
|
||||
match -= bump;
|
||||
}
|
||||
|
||||
//System.Diagnostics.Debug.WriteLine("good suffix shift table:");
|
||||
//for (int i=0; i<_positive.Length; i++)
|
||||
// System.Diagnostics.Debug.WriteLine("\t_positive[" + i + "] = " + _positive[i]);
|
||||
|
||||
|
||||
/*
|
||||
* PART II - the bad-character shift table
|
||||
*
|
||||
* compute the negative requirement:
|
||||
* if char "ch" is the reject character when testing position "i",
|
||||
* we can slide up by _negative[ch];
|
||||
* (_negative[ch] = str.Length - 1 - str.LastIndexOf(ch))
|
||||
*
|
||||
* the lookup table is divided into ASCII and Unicode portions;
|
||||
* only those parts of the Unicode 16-bit code set that actually
|
||||
* appear in the string are in the table. (Maximum size with
|
||||
* Unicode is 65K; ASCII only case is 512 bytes.)
|
||||
*/
|
||||
|
||||
_negativeASCII = new int[128];
|
||||
|
||||
for (int i = 0; i < 128; i++)
|
||||
_negativeASCII[i] = last - beforefirst;
|
||||
|
||||
_lowASCII = 127;
|
||||
_highASCII = 0;
|
||||
|
||||
for (examine = last; examine != beforefirst; examine -= bump) {
|
||||
ch = pattern[examine];
|
||||
|
||||
if (ch < 128) {
|
||||
if (_lowASCII > ch)
|
||||
_lowASCII = ch;
|
||||
|
||||
if (_highASCII < ch)
|
||||
_highASCII = ch;
|
||||
|
||||
if (_negativeASCII[ch] == last - beforefirst)
|
||||
_negativeASCII[ch] = last - examine;
|
||||
}
|
||||
else {
|
||||
int i = ch >> 8;
|
||||
int j = ch & 0xFF;
|
||||
|
||||
if (_negativeUnicode == null) {
|
||||
_negativeUnicode = new int[256][];
|
||||
}
|
||||
|
||||
if (_negativeUnicode[i] == null) {
|
||||
int[] newarray = new int[256];
|
||||
|
||||
for (int k = 0; k < 256; k++)
|
||||
newarray[k] = last - beforefirst;
|
||||
|
||||
if (i == 0) {
|
||||
System.Array.Copy(_negativeASCII, newarray, 128);
|
||||
_negativeASCII = newarray;
|
||||
}
|
||||
|
||||
_negativeUnicode[i] = newarray;
|
||||
}
|
||||
|
||||
if (_negativeUnicode[i][j] == last - beforefirst)
|
||||
_negativeUnicode[i][j] = last - examine;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private bool MatchPattern(string text, int index) {
|
||||
if (_caseInsensitive) {
|
||||
if( text.Length - index < _pattern.Length) {
|
||||
return false;
|
||||
}
|
||||
|
||||
TextInfo textinfo = _culture.TextInfo;
|
||||
for( int i = 0; i < _pattern.Length; i++) {
|
||||
Debug.Assert(textinfo.ToLower(_pattern[i]) == _pattern[i], "pattern should be converted to lower case in constructor!");
|
||||
if( textinfo.ToLower(text[index + i]) != _pattern[i]) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
return(0 == String.CompareOrdinal(_pattern, 0, text, index, _pattern.Length));
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* When a regex is anchored, we can do a quick IsMatch test instead of a Scan
|
||||
*/
|
||||
internal bool IsMatch(String text, int index, int beglimit, int endlimit) {
|
||||
|
||||
if (!_rightToLeft) {
|
||||
if (index < beglimit || endlimit - index < _pattern.Length)
|
||||
return false;
|
||||
|
||||
return MatchPattern(text, index);
|
||||
}
|
||||
else {
|
||||
if (index > endlimit || index - beglimit < _pattern.Length)
|
||||
return false;
|
||||
|
||||
return MatchPattern(text, index - _pattern.Length);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Scan uses the Boyer-Moore algorithm to find the first occurrance
|
||||
* of the specified string within text, beginning at index, and
|
||||
* constrained within beglimit and endlimit.
|
||||
*
|
||||
* The direction and case-sensitivity of the match is determined
|
||||
* by the arguments to the RegexBoyerMoore constructor.
|
||||
*/
|
||||
internal int Scan(String text, int index, int beglimit, int endlimit) {
|
||||
int test;
|
||||
int test2;
|
||||
int match;
|
||||
int startmatch;
|
||||
int endmatch;
|
||||
int advance;
|
||||
int defadv;
|
||||
int bump;
|
||||
char chMatch;
|
||||
char chTest;
|
||||
int[] unicodeLookup;
|
||||
|
||||
if (!_rightToLeft) {
|
||||
defadv = _pattern.Length;
|
||||
startmatch = _pattern.Length - 1;
|
||||
endmatch = 0;
|
||||
test = index + defadv - 1;
|
||||
bump = 1;
|
||||
}
|
||||
else {
|
||||
defadv = -_pattern.Length;
|
||||
startmatch = 0;
|
||||
endmatch = -defadv - 1;
|
||||
test = index + defadv;
|
||||
bump = -1;
|
||||
}
|
||||
|
||||
chMatch = _pattern[startmatch];
|
||||
|
||||
for (;;) {
|
||||
if (test >= endlimit || test < beglimit)
|
||||
return -1;
|
||||
|
||||
chTest = text[test];
|
||||
|
||||
if (_caseInsensitive)
|
||||
chTest = Char.ToLower(chTest, _culture);
|
||||
|
||||
if (chTest != chMatch) {
|
||||
if (chTest < 128)
|
||||
advance = _negativeASCII[chTest];
|
||||
else if (null != _negativeUnicode && (null != (unicodeLookup = _negativeUnicode[chTest >> 8])))
|
||||
advance = unicodeLookup[chTest & 0xFF];
|
||||
else
|
||||
advance = defadv;
|
||||
|
||||
test += advance;
|
||||
}
|
||||
else { // if (chTest == chMatch)
|
||||
test2 = test;
|
||||
match = startmatch;
|
||||
|
||||
for (;;) {
|
||||
if (match == endmatch)
|
||||
return(_rightToLeft ? test2 + 1 : test2);
|
||||
|
||||
match -= bump;
|
||||
test2 -= bump;
|
||||
|
||||
chTest = text[test2];
|
||||
|
||||
if (_caseInsensitive)
|
||||
chTest = Char.ToLower(chTest, _culture);
|
||||
|
||||
if (chTest != _pattern[match]) {
|
||||
advance = _positive[match];
|
||||
if ((chTest & 0xFF80) == 0)
|
||||
test2 = (match - startmatch) + _negativeASCII[chTest];
|
||||
else if (null != _negativeUnicode && (null != (unicodeLookup = _negativeUnicode[chTest >> 8])))
|
||||
test2 = (match - startmatch) + unicodeLookup[chTest & 0xFF];
|
||||
else {
|
||||
test += advance;
|
||||
break;
|
||||
}
|
||||
|
||||
if (_rightToLeft ? test2 < advance : test2 > advance)
|
||||
advance = test2;
|
||||
|
||||
test += advance;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Used when dumping for debugging.
|
||||
*/
|
||||
public override String ToString() {
|
||||
return _pattern;
|
||||
}
|
||||
|
||||
#if DBG
|
||||
public String Dump(String indent) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
||||
sb.Append(indent + "BM Pattern: " + _pattern + "\n");
|
||||
sb.Append(indent + "Positive: ");
|
||||
for (int i = 0; i < _positive.Length; i++) {
|
||||
sb.Append(_positive[i].ToString(CultureInfo.InvariantCulture) + " ");
|
||||
}
|
||||
sb.Append("\n");
|
||||
|
||||
if (_negativeASCII != null) {
|
||||
sb.Append(indent + "Negative table\n");
|
||||
for (int i = 0; i < _negativeASCII.Length; i++) {
|
||||
if (_negativeASCII[i] != _pattern.Length) {
|
||||
sb.Append(indent + " " + Regex.Escape(Convert.ToString((char)i, CultureInfo.InvariantCulture)) + " " + _negativeASCII[i].ToString(CultureInfo.InvariantCulture) + "\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return sb.ToString();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
@@ -0,0 +1,121 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// <copyright file="RegexCapture.cs" company="Microsoft">
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// </copyright>
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
// Capture is just a location/length pair that indicates the
|
||||
// location of a regular expression match. A single regexp
|
||||
// search may return multiple Capture within each capturing
|
||||
// RegexGroup.
|
||||
|
||||
namespace System.Text.RegularExpressions {
|
||||
|
||||
/// <devdoc>
|
||||
/// <para>
|
||||
/// Represents the results from a single subexpression capture. The object represents
|
||||
/// one substring for a single successful capture.</para>
|
||||
/// </devdoc>
|
||||
#if !SILVERLIGHT
|
||||
[ Serializable() ]
|
||||
#endif
|
||||
public class Capture {
|
||||
internal String _text;
|
||||
internal int _index;
|
||||
internal int _length;
|
||||
|
||||
internal Capture(String text, int i, int l) {
|
||||
_text = text;
|
||||
_index = i;
|
||||
_length = l;
|
||||
}
|
||||
|
||||
/*
|
||||
* The index of the beginning of the matched capture
|
||||
*/
|
||||
/// <devdoc>
|
||||
/// <para>Returns the position in the original string where the first character of
|
||||
/// captured substring was found.</para>
|
||||
/// </devdoc>
|
||||
public int Index {
|
||||
get {
|
||||
return _index;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* The length of the matched capture
|
||||
*/
|
||||
/// <devdoc>
|
||||
/// <para>
|
||||
/// Returns the length of the captured substring.
|
||||
/// </para>
|
||||
/// </devdoc>
|
||||
public int Length {
|
||||
get {
|
||||
return _length;
|
||||
}
|
||||
}
|
||||
|
||||
/// <devdoc>
|
||||
/// <para>[To be supplied.]</para>
|
||||
/// </devdoc>
|
||||
public string Value {
|
||||
get {
|
||||
return _text.Substring(_index, _length);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* The capture as a string
|
||||
*/
|
||||
/// <devdoc>
|
||||
/// <para>
|
||||
/// Returns
|
||||
/// the substring that was matched.
|
||||
/// </para>
|
||||
/// </devdoc>
|
||||
override public String ToString() {
|
||||
return Value;
|
||||
}
|
||||
|
||||
/*
|
||||
* The original string
|
||||
*/
|
||||
internal String GetOriginalString() {
|
||||
return _text;
|
||||
}
|
||||
|
||||
/*
|
||||
* The substring to the left of the capture
|
||||
*/
|
||||
internal String GetLeftSubstring() {
|
||||
return _text.Substring(0, _index);
|
||||
}
|
||||
|
||||
/*
|
||||
* The substring to the right of the capture
|
||||
*/
|
||||
internal String GetRightSubstring() {
|
||||
return _text.Substring(_index + _length, _text.Length - _index - _length);
|
||||
}
|
||||
|
||||
#if DBG
|
||||
internal virtual String Description() {
|
||||
StringBuilder Sb = new StringBuilder();
|
||||
|
||||
Sb.Append("(I = ");
|
||||
Sb.Append(_index);
|
||||
Sb.Append(", L = ");
|
||||
Sb.Append(_length);
|
||||
Sb.Append("): ");
|
||||
Sb.Append(_text, _index, _length);
|
||||
|
||||
return Sb.ToString();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
@@ -0,0 +1,219 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// <copyright file="RegexCaptureCollection.cs" company="Microsoft">
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// </copyright>
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
// The CaptureCollection lists the captured Capture numbers
|
||||
// contained in a compiled Regex.
|
||||
|
||||
namespace System.Text.RegularExpressions {
|
||||
|
||||
using System.Collections;
|
||||
|
||||
/*
|
||||
* This collection returns the Captures for a group
|
||||
* in the order in which they were matched (left to right
|
||||
* or right to left). It is created by Group.Captures
|
||||
*/
|
||||
/// <devdoc>
|
||||
/// <para>
|
||||
/// Represents a sequence of capture substrings. The object is used
|
||||
/// to return the set of captures done by a single capturing group.
|
||||
/// </para>
|
||||
/// </devdoc>
|
||||
#if !SILVERLIGHT
|
||||
[ Serializable() ]
|
||||
#endif
|
||||
public class CaptureCollection : ICollection {
|
||||
internal Group _group;
|
||||
internal int _capcount;
|
||||
internal Capture[] _captures;
|
||||
|
||||
/*
|
||||
* Nonpublic constructor
|
||||
*/
|
||||
internal CaptureCollection(Group group) {
|
||||
_group = group;
|
||||
_capcount = _group._capcount;
|
||||
}
|
||||
|
||||
/*
|
||||
* The object on which to synchronize
|
||||
*/
|
||||
/// <devdoc>
|
||||
/// <para>[To be supplied.]</para>
|
||||
/// </devdoc>
|
||||
public Object SyncRoot {
|
||||
get {
|
||||
return _group;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* ICollection
|
||||
*/
|
||||
/// <devdoc>
|
||||
/// <para>[To be supplied.]</para>
|
||||
/// </devdoc>
|
||||
public bool IsSynchronized {
|
||||
get {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* ICollection
|
||||
*/
|
||||
/// <devdoc>
|
||||
/// <para>[To be supplied.]</para>
|
||||
/// </devdoc>
|
||||
public bool IsReadOnly {
|
||||
get {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* The number of captures for the group
|
||||
*/
|
||||
/// <devdoc>
|
||||
/// <para>
|
||||
/// Returns the number of captures.
|
||||
/// </para>
|
||||
/// </devdoc>
|
||||
public int Count {
|
||||
get {
|
||||
return _capcount;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* The ith capture in the group
|
||||
*/
|
||||
/// <devdoc>
|
||||
/// <para>
|
||||
/// Provides a means of accessing a specific capture in the collection.
|
||||
/// </para>
|
||||
/// </devdoc>
|
||||
public Capture this[int i]
|
||||
{
|
||||
get {
|
||||
return GetCapture(i);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* As required by ICollection
|
||||
*/
|
||||
/// <devdoc>
|
||||
/// <para>
|
||||
/// Copies all the elements of the collection to the given array
|
||||
/// beginning at the given index.
|
||||
/// </para>
|
||||
/// </devdoc>
|
||||
public void CopyTo(Array array, int arrayIndex) {
|
||||
if (array == null)
|
||||
throw new ArgumentNullException("array");
|
||||
|
||||
for (int i = arrayIndex, j = 0; j < Count; i++, j++) {
|
||||
array.SetValue(this[j], i);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* As required by ICollection
|
||||
*/
|
||||
/// <devdoc>
|
||||
/// <para>
|
||||
/// Provides an enumerator in the same order as Item[].
|
||||
/// </para>
|
||||
/// </devdoc>
|
||||
public IEnumerator GetEnumerator() {
|
||||
return new CaptureEnumerator(this);
|
||||
}
|
||||
|
||||
/*
|
||||
* Nonpublic code to return set of captures for the group
|
||||
*/
|
||||
internal Capture GetCapture(int i) {
|
||||
if (i == _capcount - 1 && i >= 0)
|
||||
return _group;
|
||||
|
||||
if (i >= _capcount || i < 0)
|
||||
throw new ArgumentOutOfRangeException("i");
|
||||
|
||||
// first time a capture is accessed, compute them all
|
||||
if (_captures == null) {
|
||||
_captures = new Capture[_capcount];
|
||||
for (int j = 0; j < _capcount - 1; j++) {
|
||||
_captures[j] = new Capture(_group._text, _group._caps[j * 2], _group._caps[j * 2 + 1]);
|
||||
}
|
||||
}
|
||||
|
||||
return _captures[i];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* This non-public enumerator lists all the captures
|
||||
* Should it be public?
|
||||
*/
|
||||
#if !SILVERLIGHT
|
||||
[ Serializable() ]
|
||||
#endif
|
||||
internal class CaptureEnumerator : IEnumerator {
|
||||
internal CaptureCollection _rcc;
|
||||
internal int _curindex;
|
||||
|
||||
/*
|
||||
* Nonpublic constructor
|
||||
*/
|
||||
internal CaptureEnumerator(CaptureCollection rcc) {
|
||||
_curindex = -1;
|
||||
_rcc = rcc;
|
||||
}
|
||||
|
||||
/*
|
||||
* As required by IEnumerator
|
||||
*/
|
||||
public bool MoveNext() {
|
||||
int size = _rcc.Count;
|
||||
|
||||
if (_curindex >= size)
|
||||
return false;
|
||||
|
||||
_curindex++;
|
||||
|
||||
return(_curindex < size);
|
||||
}
|
||||
|
||||
/*
|
||||
* As required by IEnumerator
|
||||
*/
|
||||
public Object Current {
|
||||
get { return Capture;}
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns the current capture
|
||||
*/
|
||||
public Capture Capture {
|
||||
get {
|
||||
if (_curindex < 0 || _curindex >= _rcc.Count)
|
||||
throw new InvalidOperationException(SR.GetString(SR.EnumNotStarted));
|
||||
|
||||
return _rcc[_curindex];
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Reset to before the first item
|
||||
*/
|
||||
public void Reset() {
|
||||
_curindex = -1;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,393 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// <copyright file="RegexCode.cs" company="Microsoft">
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// </copyright>
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
// This RegexCode class is internal to the regular expression package.
|
||||
// It provides operator constants for use by the Builder and the Machine.
|
||||
|
||||
// Implementation notes:
|
||||
//
|
||||
// Regexps are built into RegexCodes, which contain an operation array,
|
||||
// a string table, and some constants.
|
||||
//
|
||||
// Each operation is one of the codes below, followed by the integer
|
||||
// operands specified for each op.
|
||||
//
|
||||
// Strings and sets are indices into a string table.
|
||||
|
||||
|
||||
namespace System.Text.RegularExpressions {
|
||||
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Globalization;
|
||||
|
||||
internal sealed class RegexCode {
|
||||
// the following primitive operations come directly from the parser
|
||||
|
||||
// lef/back operands description
|
||||
|
||||
internal const int Onerep = 0; // lef,back char,min,max a {n}
|
||||
internal const int Notonerep = 1; // lef,back char,min,max .{n}
|
||||
internal const int Setrep = 2; // lef,back set,min,max [\d]{n}
|
||||
|
||||
internal const int Oneloop = 3; // lef,back char,min,max a {,n}
|
||||
internal const int Notoneloop = 4; // lef,back char,min,max .{,n}
|
||||
internal const int Setloop = 5; // lef,back set,min,max [\d]{,n}
|
||||
|
||||
internal const int Onelazy = 6; // lef,back char,min,max a {,n}?
|
||||
internal const int Notonelazy = 7; // lef,back char,min,max .{,n}?
|
||||
internal const int Setlazy = 8; // lef,back set,min,max [\d]{,n}?
|
||||
|
||||
internal const int One = 9; // lef char a
|
||||
internal const int Notone = 10; // lef char [^a]
|
||||
internal const int Set = 11; // lef set [a-z\s] \w \s \d
|
||||
|
||||
internal const int Multi = 12; // lef string abcd
|
||||
internal const int Ref = 13; // lef group \#
|
||||
|
||||
internal const int Bol = 14; // ^
|
||||
internal const int Eol = 15; // $
|
||||
internal const int Boundary = 16; // \b
|
||||
internal const int Nonboundary = 17; // \B
|
||||
internal const int Beginning = 18; // \A
|
||||
internal const int Start = 19; // \G
|
||||
internal const int EndZ = 20; // \Z
|
||||
internal const int End = 21; // \Z
|
||||
|
||||
internal const int Nothing = 22; // Reject!
|
||||
|
||||
// primitive control structures
|
||||
|
||||
internal const int Lazybranch = 23; // back jump straight first
|
||||
internal const int Branchmark = 24; // back jump branch first for loop
|
||||
internal const int Lazybranchmark = 25; // back jump straight first for loop
|
||||
internal const int Nullcount = 26; // back val set counter, null mark
|
||||
internal const int Setcount = 27; // back val set counter, make mark
|
||||
internal const int Branchcount = 28; // back jump,limit branch++ if zero<=c<limit
|
||||
internal const int Lazybranchcount= 29; // back jump,limit same, but straight first
|
||||
internal const int Nullmark = 30; // back save position
|
||||
internal const int Setmark = 31; // back save position
|
||||
internal const int Capturemark = 32; // back group define group
|
||||
internal const int Getmark = 33; // back recall position
|
||||
internal const int Setjump = 34; // back save backtrack state
|
||||
internal const int Backjump = 35; // zap back to saved state
|
||||
internal const int Forejump = 36; // zap backtracking state
|
||||
internal const int Testref = 37; // backtrack if ref undefined
|
||||
internal const int Goto = 38; // jump just go
|
||||
|
||||
internal const int Prune = 39; // prune it baby
|
||||
internal const int Stop = 40; // done!
|
||||
|
||||
internal const int ECMABoundary = 41; // \b
|
||||
internal const int NonECMABoundary= 42; // \B
|
||||
|
||||
// modifiers for alternate modes
|
||||
|
||||
internal const int Mask = 63; // Mask to get unmodified ordinary operator
|
||||
internal const int Rtl = 64; // bit to indicate that we're reverse scanning.
|
||||
internal const int Back = 128; // bit to indicate that we're backtracking.
|
||||
internal const int Back2 = 256; // bit to indicate that we're backtracking on a second branch.
|
||||
internal const int Ci = 512; // bit to indicate that we're case-insensitive.
|
||||
|
||||
// the code
|
||||
|
||||
internal int[] _codes; // the code
|
||||
internal String[] _strings; // the string/set table
|
||||
// not used! internal int[] _sparseIndex; // a list of the groups that are used
|
||||
internal int _trackcount; // how many instructions use backtracking
|
||||
#if SILVERLIGHT
|
||||
internal Dictionary<Int32, Int32> _caps; // mapping of user group numbers -> impl group slots
|
||||
#else
|
||||
internal Hashtable _caps; // mapping of user group numbers -> impl group slots
|
||||
#endif
|
||||
internal int _capsize; // number of impl group slots
|
||||
internal RegexPrefix _fcPrefix; // the set of candidate first characters (may be null)
|
||||
internal RegexBoyerMoore _bmPrefix; // the fixed prefix string as a Boyer-Moore machine (may be null)
|
||||
internal int _anchors; // the set of zero-length start anchors (RegexFCD.Bol, etc)
|
||||
internal bool _rightToLeft; // true if right to left
|
||||
|
||||
// optimizations
|
||||
|
||||
// constructor
|
||||
|
||||
internal RegexCode(int [] codes, List<String> stringlist, int trackcount,
|
||||
#if SILVERLIGHT
|
||||
Dictionary<Int32, Int32> caps, int capsize,
|
||||
#else
|
||||
Hashtable caps, int capsize,
|
||||
#endif
|
||||
RegexBoyerMoore bmPrefix, RegexPrefix fcPrefix,
|
||||
int anchors, bool rightToLeft) {
|
||||
_codes = codes;
|
||||
_strings = new String[stringlist.Count];
|
||||
_trackcount = trackcount;
|
||||
_caps = caps;
|
||||
_capsize = capsize;
|
||||
_bmPrefix = bmPrefix;
|
||||
_fcPrefix = fcPrefix;
|
||||
_anchors = anchors;
|
||||
_rightToLeft = rightToLeft;
|
||||
stringlist.CopyTo(0, _strings, 0, stringlist.Count);
|
||||
}
|
||||
|
||||
internal static bool OpcodeBacktracks(int Op) {
|
||||
Op &= Mask;
|
||||
|
||||
switch (Op) {
|
||||
case Oneloop:
|
||||
case Notoneloop:
|
||||
case Setloop:
|
||||
case Onelazy:
|
||||
case Notonelazy:
|
||||
case Setlazy:
|
||||
case Lazybranch:
|
||||
case Branchmark:
|
||||
case Lazybranchmark:
|
||||
case Nullcount:
|
||||
case Setcount:
|
||||
case Branchcount:
|
||||
case Lazybranchcount:
|
||||
case Setmark:
|
||||
case Capturemark:
|
||||
case Getmark:
|
||||
case Setjump:
|
||||
case Backjump:
|
||||
case Forejump:
|
||||
case Goto:
|
||||
return true;
|
||||
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
internal static int OpcodeSize(int Opcode) {
|
||||
Opcode &= Mask;
|
||||
|
||||
switch (Opcode) {
|
||||
case Nothing:
|
||||
case Bol:
|
||||
case Eol:
|
||||
case Boundary:
|
||||
case Nonboundary:
|
||||
case ECMABoundary:
|
||||
case NonECMABoundary:
|
||||
case Beginning:
|
||||
case Start:
|
||||
case EndZ:
|
||||
case End:
|
||||
|
||||
case Nullmark:
|
||||
case Setmark:
|
||||
case Getmark:
|
||||
case Setjump:
|
||||
case Backjump:
|
||||
case Forejump:
|
||||
case Stop:
|
||||
|
||||
return 1;
|
||||
|
||||
case One:
|
||||
case Notone:
|
||||
case Multi:
|
||||
case Ref:
|
||||
case Testref:
|
||||
|
||||
|
||||
case Goto:
|
||||
case Nullcount:
|
||||
case Setcount:
|
||||
case Lazybranch:
|
||||
case Branchmark:
|
||||
case Lazybranchmark:
|
||||
case Prune:
|
||||
case Set:
|
||||
|
||||
return 2;
|
||||
|
||||
case Capturemark:
|
||||
case Branchcount:
|
||||
case Lazybranchcount:
|
||||
|
||||
case Onerep:
|
||||
case Notonerep:
|
||||
case Oneloop:
|
||||
case Notoneloop:
|
||||
case Onelazy:
|
||||
case Notonelazy:
|
||||
case Setlazy:
|
||||
case Setrep:
|
||||
case Setloop:
|
||||
|
||||
return 3;
|
||||
|
||||
default:
|
||||
|
||||
throw MakeException(SR.GetString(SR.UnexpectedOpcode, Opcode.ToString(CultureInfo.CurrentCulture)));
|
||||
}
|
||||
}
|
||||
|
||||
internal static ArgumentException MakeException(String message) {
|
||||
return new ArgumentException(message);
|
||||
}
|
||||
|
||||
// Debug only code below
|
||||
|
||||
#if DBG
|
||||
internal static String[] CodeStr = new String[]
|
||||
{
|
||||
"Onerep", "Notonerep", "Setrep",
|
||||
"Oneloop", "Notoneloop", "Setloop",
|
||||
"Onelazy", "Notonelazy", "Setlazy",
|
||||
"One", "Notone", "Set",
|
||||
"Multi", "Ref",
|
||||
"Bol", "Eol", "Boundary", "Nonboundary", "Beginning", "Start", "EndZ", "End",
|
||||
"Nothing",
|
||||
"Lazybranch", "Branchmark", "Lazybranchmark",
|
||||
"Nullcount", "Setcount", "Branchcount", "Lazybranchcount",
|
||||
"Nullmark", "Setmark", "Capturemark", "Getmark",
|
||||
"Setjump", "Backjump", "Forejump", "Testref", "Goto",
|
||||
"Prune", "Stop",
|
||||
#if ECMA
|
||||
"ECMABoundary", "NonECMABoundary",
|
||||
#endif
|
||||
};
|
||||
|
||||
internal static String OperatorDescription(int Opcode) {
|
||||
bool isCi = ((Opcode & Ci) != 0);
|
||||
bool isRtl = ((Opcode & Rtl) != 0);
|
||||
bool isBack = ((Opcode & Back) != 0);
|
||||
bool isBack2 = ((Opcode & Back2) != 0);
|
||||
|
||||
return CodeStr[Opcode & Mask] +
|
||||
(isCi ? "-Ci" : "") + (isRtl ? "-Rtl" : "") + (isBack ? "-Back" : "") + (isBack2 ? "-Back2" : "");
|
||||
}
|
||||
|
||||
internal String OpcodeDescription(int offset) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
int opcode = _codes[offset];
|
||||
|
||||
sb.AppendFormat("{0:D6} ", offset);
|
||||
sb.Append(OpcodeBacktracks(opcode & Mask) ? '*' : ' ');
|
||||
sb.Append(OperatorDescription(opcode));
|
||||
sb.Append('(');
|
||||
|
||||
opcode &= Mask;
|
||||
|
||||
switch (opcode) {
|
||||
case One:
|
||||
case Notone:
|
||||
case Onerep:
|
||||
case Notonerep:
|
||||
case Oneloop:
|
||||
case Notoneloop:
|
||||
case Onelazy:
|
||||
case Notonelazy:
|
||||
sb.Append("Ch = ");
|
||||
sb.Append(RegexCharClass.CharDescription((char)_codes[offset+1]));
|
||||
break;
|
||||
|
||||
case Set:
|
||||
case Setrep:
|
||||
case Setloop:
|
||||
case Setlazy:
|
||||
sb.Append("Set = ");
|
||||
sb.Append(RegexCharClass.SetDescription(_strings[_codes[offset+1]]));
|
||||
break;
|
||||
|
||||
case Multi:
|
||||
sb.Append("String = ");
|
||||
sb.Append(_strings[_codes[offset+1]]);
|
||||
break;
|
||||
|
||||
case Ref:
|
||||
case Testref:
|
||||
sb.Append("Index = ");
|
||||
sb.Append(_codes[offset+1]);
|
||||
break;
|
||||
|
||||
case Capturemark:
|
||||
sb.Append("Index = ");
|
||||
sb.Append(_codes[offset+1]);
|
||||
if (_codes[offset+2] != -1) {
|
||||
sb.Append(", Unindex = ");
|
||||
sb.Append(_codes[offset+2]);
|
||||
}
|
||||
break;
|
||||
|
||||
case Nullcount:
|
||||
case Setcount:
|
||||
sb.Append("Value = ");
|
||||
sb.Append(_codes[offset+1]);
|
||||
break;
|
||||
|
||||
case Goto:
|
||||
case Lazybranch:
|
||||
case Branchmark:
|
||||
case Lazybranchmark:
|
||||
case Branchcount:
|
||||
case Lazybranchcount:
|
||||
sb.Append("Addr = ");
|
||||
sb.Append(_codes[offset+1]);
|
||||
break;
|
||||
}
|
||||
|
||||
switch (opcode) {
|
||||
case Onerep:
|
||||
case Notonerep:
|
||||
case Oneloop:
|
||||
case Notoneloop:
|
||||
case Onelazy:
|
||||
case Notonelazy:
|
||||
case Setrep:
|
||||
case Setloop:
|
||||
case Setlazy:
|
||||
sb.Append(", Rep = ");
|
||||
if (_codes[offset + 2] == Int32.MaxValue)
|
||||
sb.Append("inf");
|
||||
else
|
||||
sb.Append(_codes[offset + 2]);
|
||||
break;
|
||||
|
||||
case Branchcount:
|
||||
case Lazybranchcount:
|
||||
sb.Append(", Limit = ");
|
||||
if (_codes[offset + 2] == Int32.MaxValue)
|
||||
sb.Append("inf");
|
||||
else
|
||||
sb.Append(_codes[offset + 2]);
|
||||
break;
|
||||
}
|
||||
|
||||
sb.Append(")");
|
||||
|
||||
return sb.ToString();
|
||||
}
|
||||
|
||||
internal void Dump() {
|
||||
int i;
|
||||
|
||||
Debug.WriteLine("Direction: " + (_rightToLeft ? "right-to-left" : "left-to-right"));
|
||||
Debug.WriteLine("Firstchars: " + (_fcPrefix == null ? "n/a" : RegexCharClass.SetDescription(_fcPrefix.Prefix)));
|
||||
Debug.WriteLine("Prefix: " + (_bmPrefix == null ? "n/a" : Regex.Escape(_bmPrefix.ToString())));
|
||||
Debug.WriteLine("Anchors: " + RegexFCD.AnchorDescription(_anchors));
|
||||
Debug.WriteLine("");
|
||||
if (_bmPrefix != null) {
|
||||
Debug.WriteLine("BoyerMoore:");
|
||||
Debug.WriteLine(_bmPrefix.Dump(" "));
|
||||
}
|
||||
for (i = 0; i < _codes.Length;) {
|
||||
Debug.WriteLine(OpcodeDescription(i));
|
||||
i += OpcodeSize(_codes[i]);
|
||||
}
|
||||
|
||||
Debug.WriteLine("");
|
||||
}
|
||||
#endif
|
||||
|
||||
}
|
||||
}
|
@@ -0,0 +1,131 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// <copyright file="RegexCompilationInfo.cs" company="Microsoft">
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// </copyright>
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
#if !SILVERLIGHT
|
||||
|
||||
using System;
|
||||
using System.Runtime.Serialization;
|
||||
using System.Runtime.Versioning;
|
||||
|
||||
namespace System.Text.RegularExpressions {
|
||||
|
||||
/// <devdoc>
|
||||
/// <para>
|
||||
/// [To be supplied]
|
||||
/// </para>
|
||||
/// </devdoc>
|
||||
[ Serializable() ]
|
||||
public class RegexCompilationInfo {
|
||||
private String pattern;
|
||||
private RegexOptions options;
|
||||
private String name;
|
||||
private String nspace;
|
||||
private bool isPublic;
|
||||
|
||||
[OptionalField(VersionAdded = 2)]
|
||||
private TimeSpan matchTimeout;
|
||||
|
||||
[OnDeserializing]
|
||||
private void InitMatchTimeoutDefaultForOldVersionDeserialization(StreamingContext unusedContext) {
|
||||
matchTimeout = Regex.DefaultMatchTimeout;
|
||||
}
|
||||
|
||||
/// <devdoc>
|
||||
/// <para>
|
||||
/// [To be supplied]
|
||||
/// </para>
|
||||
/// </devdoc>
|
||||
public RegexCompilationInfo(String pattern, RegexOptions options, String name, String fullnamespace, bool ispublic)
|
||||
: this(pattern, options, name, fullnamespace, ispublic, Regex.DefaultMatchTimeout) {
|
||||
}
|
||||
|
||||
public RegexCompilationInfo(String pattern, RegexOptions options, String name, String fullnamespace, bool ispublic, TimeSpan matchTimeout) {
|
||||
Pattern = pattern;
|
||||
Name = name;
|
||||
Namespace = fullnamespace;
|
||||
this.options = options;
|
||||
isPublic = ispublic;
|
||||
MatchTimeout = matchTimeout;
|
||||
}
|
||||
|
||||
/// <devdoc>
|
||||
/// <para>
|
||||
/// [To be supplied]
|
||||
/// </para>
|
||||
/// </devdoc>
|
||||
public String Pattern {
|
||||
get { return pattern; }
|
||||
set {
|
||||
if (value == null)
|
||||
throw new ArgumentNullException("value");
|
||||
pattern = value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <devdoc>
|
||||
/// <para>
|
||||
/// [To be supplied]
|
||||
/// </para>
|
||||
/// </devdoc>
|
||||
public RegexOptions Options {
|
||||
get { return options; }
|
||||
set { options = value;}
|
||||
}
|
||||
|
||||
/// <devdoc>
|
||||
/// <para>
|
||||
/// [To be supplied]
|
||||
/// </para>
|
||||
/// </devdoc>
|
||||
public String Name {
|
||||
get { return name; }
|
||||
set {
|
||||
if (value == null) {
|
||||
throw new ArgumentNullException("value");
|
||||
}
|
||||
|
||||
if (value.Length == 0) {
|
||||
throw new ArgumentException(SR.GetString(SR.InvalidNullEmptyArgument, "value"), "value");
|
||||
}
|
||||
|
||||
name = value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <devdoc>
|
||||
/// <para>
|
||||
/// [To be supplied]
|
||||
/// </para>
|
||||
/// </devdoc>
|
||||
public String Namespace {
|
||||
get { return nspace; }
|
||||
set {
|
||||
if (value == null)
|
||||
throw new ArgumentNullException("value");
|
||||
nspace = value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <devdoc>
|
||||
/// <para>
|
||||
/// [To be supplied]
|
||||
/// </para>
|
||||
/// </devdoc>
|
||||
public bool IsPublic {
|
||||
get { return isPublic; }
|
||||
set { isPublic = value;}
|
||||
}
|
||||
|
||||
public TimeSpan MatchTimeout {
|
||||
get { return matchTimeout; }
|
||||
set { Regex.ValidateMatchTimeout(value); matchTimeout = value; }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
|
@@ -0,0 +1 @@
|
||||
6f191129671672f5a0d3c58901385525b798814c
|
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,105 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// <copyright file="RegexGroup.cs" company="Microsoft">
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// </copyright>
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
// Group represents the substring or substrings that
|
||||
// are captured by a single capturing group after one
|
||||
// regular expression match.
|
||||
|
||||
namespace System.Text.RegularExpressions {
|
||||
using System.Security.Permissions;
|
||||
|
||||
/// <devdoc>
|
||||
/// Group
|
||||
/// represents the results from a single capturing group. A capturing group can
|
||||
/// capture zero, one, or more strings in a single match because of quantifiers, so
|
||||
/// Group supplies a collection of Capture objects.
|
||||
/// </devdoc>
|
||||
#if !SILVERLIGHT
|
||||
[ Serializable() ]
|
||||
#endif
|
||||
public class Group : Capture {
|
||||
// the empty group object
|
||||
internal static Group _emptygroup = new Group(String.Empty, new int[0], 0);
|
||||
|
||||
internal int[] _caps;
|
||||
internal int _capcount;
|
||||
internal CaptureCollection _capcoll;
|
||||
|
||||
internal Group(String text, int[] caps, int capcount)
|
||||
|
||||
: base(text, capcount == 0 ? 0 : caps[(capcount - 1) * 2],
|
||||
capcount == 0 ? 0 : caps[(capcount * 2) - 1]) {
|
||||
|
||||
_caps = caps;
|
||||
_capcount = capcount;
|
||||
}
|
||||
|
||||
/*
|
||||
* True if the match was successful
|
||||
*/
|
||||
/// <devdoc>
|
||||
/// <para>Indicates whether the match is successful.</para>
|
||||
/// </devdoc>
|
||||
public bool Success {
|
||||
get {
|
||||
return _capcount != 0;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* The collection of all captures for this group
|
||||
*/
|
||||
/// <devdoc>
|
||||
/// <para>
|
||||
/// Returns a collection of all the captures matched by the capturing
|
||||
/// group, in innermost-leftmost-first order (or innermost-rightmost-first order if
|
||||
/// compiled with the "r" option). The collection may have zero or more items.
|
||||
/// </para>
|
||||
/// </devdoc>
|
||||
public CaptureCollection Captures {
|
||||
get {
|
||||
if (_capcoll == null)
|
||||
_capcoll = new CaptureCollection(this);
|
||||
|
||||
return _capcoll;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Convert to a thread-safe object by precomputing cache contents
|
||||
*/
|
||||
/// <devdoc>
|
||||
/// <para>Returns
|
||||
/// a Group object equivalent to the one supplied that is safe to share between
|
||||
/// multiple threads.</para>
|
||||
/// </devdoc>
|
||||
#if !SILVERLIGHT
|
||||
#if FEATURE_MONO_CAS
|
||||
[HostProtection(Synchronization=true)]
|
||||
#endif
|
||||
static public Group Synchronized(Group inner) {
|
||||
#else
|
||||
static internal Group Synchronized(Group inner) {
|
||||
#endif
|
||||
if (inner == null)
|
||||
throw new ArgumentNullException("inner");
|
||||
|
||||
// force Captures to be computed.
|
||||
|
||||
CaptureCollection capcoll;
|
||||
Capture dummy;
|
||||
|
||||
capcoll = inner.Captures;
|
||||
|
||||
if (inner._capcount > 0)
|
||||
dummy = capcoll[0];
|
||||
|
||||
return inner;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
@@ -0,0 +1,246 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// <copyright file="RegexGroupCollection.cs" company="Microsoft">
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// </copyright>
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
// The GroupCollection lists the captured Capture numbers
|
||||
// contained in a compiled Regex.
|
||||
|
||||
namespace System.Text.RegularExpressions {
|
||||
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
|
||||
/// <devdoc>
|
||||
/// <para>
|
||||
/// Represents a sequence of capture substrings. The object is used
|
||||
/// to return the set of captures done by a single capturing group.
|
||||
/// </para>
|
||||
/// </devdoc>
|
||||
#if !SILVERLIGHT
|
||||
[ Serializable() ]
|
||||
#endif
|
||||
public class GroupCollection : ICollection {
|
||||
internal Match _match;
|
||||
#if SILVERLIGHT
|
||||
internal Dictionary<Int32, Int32> _captureMap;
|
||||
#else
|
||||
internal Hashtable _captureMap;
|
||||
#endif
|
||||
|
||||
// cache of Group objects fed to the user
|
||||
internal Group[] _groups;
|
||||
|
||||
/*
|
||||
* Nonpublic constructor
|
||||
*/
|
||||
#if SILVERLIGHT
|
||||
internal GroupCollection(Match match, Dictionary<Int32, Int32> caps) {
|
||||
#else
|
||||
internal GroupCollection(Match match, Hashtable caps) {
|
||||
#endif
|
||||
_match = match;
|
||||
_captureMap = caps;
|
||||
}
|
||||
|
||||
/*
|
||||
* The object on which to synchronize
|
||||
*/
|
||||
/// <devdoc>
|
||||
/// <para>[To be supplied.]</para>
|
||||
/// </devdoc>
|
||||
public Object SyncRoot {
|
||||
get {
|
||||
return _match;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* ICollection
|
||||
*/
|
||||
/// <devdoc>
|
||||
/// <para>[To be supplied.]</para>
|
||||
/// </devdoc>
|
||||
public bool IsSynchronized {
|
||||
get {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* ICollection
|
||||
*/
|
||||
/// <devdoc>
|
||||
/// <para>[To be supplied.]</para>
|
||||
/// </devdoc>
|
||||
public bool IsReadOnly {
|
||||
get {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/// <devdoc>
|
||||
/// <para>
|
||||
/// Returns the number of groups.
|
||||
/// </para>
|
||||
/// </devdoc>
|
||||
public int Count {
|
||||
get {
|
||||
return _match._matchcount.Length;
|
||||
}
|
||||
}
|
||||
|
||||
/// <devdoc>
|
||||
/// <para>[To be supplied.]</para>
|
||||
/// </devdoc>
|
||||
public Group this[int groupnum]
|
||||
{
|
||||
get {
|
||||
return GetGroup(groupnum);
|
||||
}
|
||||
}
|
||||
|
||||
/// <devdoc>
|
||||
/// <para>[To be supplied.]</para>
|
||||
/// </devdoc>
|
||||
public Group this[String groupname] {
|
||||
get {
|
||||
if (_match._regex == null)
|
||||
return Group._emptygroup;
|
||||
|
||||
return GetGroup(_match._regex.GroupNumberFromName(groupname));
|
||||
}
|
||||
}
|
||||
|
||||
internal Group GetGroup(int groupnum) {
|
||||
if (_captureMap != null) {
|
||||
Object o;
|
||||
|
||||
o = _captureMap[groupnum];
|
||||
if (o == null)
|
||||
return Group._emptygroup;
|
||||
//throw new ArgumentOutOfRangeException("groupnum");
|
||||
|
||||
return GetGroupImpl((int)o);
|
||||
}
|
||||
else {
|
||||
//if (groupnum >= _match._regex.CapSize || groupnum < 0)
|
||||
// throw new ArgumentOutOfRangeException("groupnum");
|
||||
if (groupnum >= _match._matchcount.Length || groupnum < 0)
|
||||
return Group._emptygroup;
|
||||
|
||||
return GetGroupImpl(groupnum);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Caches the group objects
|
||||
*/
|
||||
internal Group GetGroupImpl(int groupnum) {
|
||||
if (groupnum == 0)
|
||||
return _match;
|
||||
|
||||
// Construct all the Group objects the first time GetGroup is called
|
||||
|
||||
if (_groups == null) {
|
||||
_groups = new Group[_match._matchcount.Length - 1];
|
||||
for (int i = 0; i < _groups.Length; i++) {
|
||||
_groups[i] = new Group(_match._text, _match._matches[i + 1], _match._matchcount[i + 1]);
|
||||
}
|
||||
}
|
||||
|
||||
return _groups[groupnum - 1];
|
||||
}
|
||||
|
||||
/*
|
||||
* As required by ICollection
|
||||
*/
|
||||
/// <devdoc>
|
||||
/// <para>
|
||||
/// Copies all the elements of the collection to the given array
|
||||
/// beginning at the given index.
|
||||
/// </para>
|
||||
/// </devdoc>
|
||||
public void CopyTo(Array array, int arrayIndex) {
|
||||
if (array == null)
|
||||
throw new ArgumentNullException("array");
|
||||
|
||||
for (int i = arrayIndex, j = 0; j < Count; i++, j++) {
|
||||
array.SetValue(this[j], i);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* As required by ICollection
|
||||
*/
|
||||
/// <devdoc>
|
||||
/// <para>
|
||||
/// Provides an enumerator in the same order as Item[].
|
||||
/// </para>
|
||||
/// </devdoc>
|
||||
public IEnumerator GetEnumerator() {
|
||||
return new GroupEnumerator(this);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* This non-public enumerator lists all the captures
|
||||
* Should it be public?
|
||||
*/
|
||||
internal class GroupEnumerator : IEnumerator {
|
||||
internal GroupCollection _rgc;
|
||||
internal int _curindex;
|
||||
|
||||
/*
|
||||
* Nonpublic constructor
|
||||
*/
|
||||
internal GroupEnumerator(GroupCollection rgc) {
|
||||
_curindex = -1;
|
||||
_rgc = rgc;
|
||||
}
|
||||
|
||||
/*
|
||||
* As required by IEnumerator
|
||||
*/
|
||||
public bool MoveNext() {
|
||||
int size = _rgc.Count;
|
||||
|
||||
if (_curindex >= size)
|
||||
return false;
|
||||
|
||||
_curindex++;
|
||||
|
||||
return(_curindex < size);
|
||||
}
|
||||
|
||||
/*
|
||||
* As required by IEnumerator
|
||||
*/
|
||||
public Object Current {
|
||||
get { return Capture;}
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns the current capture
|
||||
*/
|
||||
public Capture Capture {
|
||||
get {
|
||||
if (_curindex < 0 || _curindex >= _rgc.Count)
|
||||
throw new InvalidOperationException(SR.GetString(SR.EnumNotStarted));
|
||||
|
||||
return _rgc[_curindex];
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Reset to before the first item
|
||||
*/
|
||||
public void Reset() {
|
||||
_curindex = -1;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,468 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// <copyright file="RegexMatch.cs" company="Microsoft">
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// </copyright>
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
// 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, "(?<start-end>...)". 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.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Security.Permissions;
|
||||
using System.Globalization;
|
||||
|
||||
/// <devdoc>
|
||||
/// <para>
|
||||
/// Represents
|
||||
/// the results from a single regular expression match.
|
||||
/// </para>
|
||||
/// </devdoc>
|
||||
#if !SILVERLIGHT
|
||||
[ Serializable() ]
|
||||
#endif
|
||||
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().
|
||||
|
||||
/// <devdoc>
|
||||
/// <para>
|
||||
/// Returns an empty Match object.
|
||||
/// </para>
|
||||
/// </devdoc>
|
||||
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;
|
||||
}
|
||||
|
||||
/// <devdoc>
|
||||
/// <para>[To be supplied.]</para>
|
||||
/// </devdoc>
|
||||
public virtual GroupCollection Groups {
|
||||
get {
|
||||
if (_groupcoll == null)
|
||||
_groupcoll = new GroupCollection(this, null);
|
||||
|
||||
return _groupcoll;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns the next match
|
||||
*/
|
||||
/// <devdoc>
|
||||
/// <para>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).</para>
|
||||
/// </devdoc>
|
||||
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)
|
||||
*/
|
||||
/// <devdoc>
|
||||
/// <para>
|
||||
/// 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().
|
||||
/// </para>
|
||||
/// </devdoc>
|
||||
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
|
||||
*/
|
||||
/// <devdoc>
|
||||
/// <para>
|
||||
/// Returns a Match instance equivalent to the one supplied that is safe to share
|
||||
/// between multiple threads.
|
||||
/// </para>
|
||||
/// </devdoc>
|
||||
|
||||
#if !SILVERLIGHT
|
||||
#if FEATURE_MONO_CAS
|
||||
[HostProtection(Synchronization=true)]
|
||||
#endif
|
||||
static public Match Synchronized(Match inner) {
|
||||
#else
|
||||
static internal Match Synchronized(Match inner) {
|
||||
#endif
|
||||
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. (?<foo-foo2>...)
|
||||
|
||||
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
|
||||
/// <internalonly/>
|
||||
/// <devdoc>
|
||||
/// </devdoc>
|
||||
public bool Debug {
|
||||
get {
|
||||
if (_regex == null)
|
||||
return false;
|
||||
|
||||
return _regex.Debug;
|
||||
}
|
||||
}
|
||||
|
||||
/// <internalonly/>
|
||||
/// <devdoc>
|
||||
/// </devdoc>
|
||||
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
|
||||
#if SILVERLIGHT
|
||||
new internal Dictionary<Int32, Int32> _caps;
|
||||
#else
|
||||
new internal Hashtable _caps;
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Nonpublic constructor
|
||||
*/
|
||||
#if SILVERLIGHT
|
||||
internal MatchSparse(Regex regex, Dictionary<Int32, Int32> caps, int capcount,
|
||||
#else
|
||||
internal MatchSparse(Regex regex, Hashtable caps, int capcount,
|
||||
#endif
|
||||
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) {
|
||||
#if SILVERLIGHT
|
||||
IEnumerator<Int32> e = _caps.Keys.GetEnumerator();
|
||||
#else
|
||||
IEnumerator e = _caps.Keys.GetEnumerator();
|
||||
#endif
|
||||
while (e.MoveNext()) {
|
||||
System.Diagnostics.Debug.WriteLine("Slot " + e.Current.ToString() + " -> " + _caps[e.Current].ToString());
|
||||
}
|
||||
}
|
||||
|
||||
base.Dump();
|
||||
}
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
@@ -0,0 +1,265 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// <copyright file="RegexMatchCollection.cs" company="Microsoft">
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// </copyright>
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
// The MatchCollection lists the successful matches that
|
||||
// result when searching a string for a regular expression.
|
||||
|
||||
namespace System.Text.RegularExpressions {
|
||||
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
|
||||
|
||||
/*
|
||||
* This collection returns a sequence of successful match results, either
|
||||
* from GetMatchCollection() or GetExecuteCollection(). It stops when the
|
||||
* first failure is encountered (it does not return the failed match).
|
||||
*/
|
||||
/// <devdoc>
|
||||
/// <para>
|
||||
/// Represents the set of names appearing as capturing group
|
||||
/// names in a regular expression.
|
||||
/// </para>
|
||||
/// </devdoc>
|
||||
#if !SILVERLIGHT
|
||||
[ Serializable() ]
|
||||
#endif
|
||||
public class MatchCollection : ICollection {
|
||||
internal Regex _regex;
|
||||
#if SILVERLIGHT
|
||||
internal List<Match> _matches;
|
||||
#else
|
||||
internal ArrayList _matches;
|
||||
#endif
|
||||
internal bool _done;
|
||||
internal String _input;
|
||||
internal int _beginning;
|
||||
internal int _length;
|
||||
internal int _startat;
|
||||
internal int _prevlen;
|
||||
|
||||
private static int infinite = 0x7FFFFFFF;
|
||||
|
||||
/*
|
||||
* Nonpublic constructor
|
||||
*/
|
||||
internal MatchCollection(Regex regex, String input, int beginning, int length, int startat) {
|
||||
if (startat < 0 || startat > input.Length)
|
||||
throw new ArgumentOutOfRangeException("startat", SR.GetString(SR.BeginIndexNotNegative));
|
||||
|
||||
_regex = regex;
|
||||
_input = input;
|
||||
_beginning = beginning;
|
||||
_length = length;
|
||||
_startat = startat;
|
||||
_prevlen = -1;
|
||||
#if SILVERLIGHT
|
||||
_matches = new List<Match>();
|
||||
#else
|
||||
_matches = new ArrayList();
|
||||
#endif
|
||||
_done = false;
|
||||
}
|
||||
|
||||
internal Match GetMatch(int i) {
|
||||
if (i < 0)
|
||||
return null;
|
||||
|
||||
if (_matches.Count > i)
|
||||
return (Match)_matches[i];
|
||||
|
||||
if (_done)
|
||||
return null;
|
||||
|
||||
Match match;
|
||||
|
||||
do {
|
||||
match = _regex.Run(false, _prevlen, _input, _beginning, _length, _startat);
|
||||
|
||||
if (!match.Success) {
|
||||
_done = true;
|
||||
return null;
|
||||
}
|
||||
|
||||
_matches.Add(match);
|
||||
|
||||
_prevlen = match._length;
|
||||
_startat = match._textpos;
|
||||
|
||||
} while (_matches.Count <= i);
|
||||
|
||||
return match;
|
||||
}
|
||||
|
||||
/// <devdoc>
|
||||
/// <para>
|
||||
/// Returns the number of captures.
|
||||
/// </para>
|
||||
/// </devdoc>
|
||||
public int Count {
|
||||
get {
|
||||
if (_done)
|
||||
return _matches.Count;
|
||||
|
||||
GetMatch(infinite);
|
||||
|
||||
return _matches.Count;
|
||||
}
|
||||
}
|
||||
|
||||
/// <devdoc>
|
||||
/// <para>[To be supplied.]</para>
|
||||
/// </devdoc>
|
||||
public Object SyncRoot {
|
||||
get {
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
/// <devdoc>
|
||||
/// <para>[To be supplied.]</para>
|
||||
/// </devdoc>
|
||||
public bool IsSynchronized {
|
||||
get {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/// <devdoc>
|
||||
/// <para>[To be supplied.]</para>
|
||||
/// </devdoc>
|
||||
public bool IsReadOnly {
|
||||
get {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <devdoc>
|
||||
/// <para>
|
||||
/// Returns the ith Match in the collection.
|
||||
/// </para>
|
||||
/// </devdoc>
|
||||
public virtual Match this[int i]
|
||||
{
|
||||
get {
|
||||
Match match;
|
||||
|
||||
match = GetMatch(i);
|
||||
|
||||
if (match == null)
|
||||
throw new ArgumentOutOfRangeException("i");
|
||||
|
||||
return match;
|
||||
}
|
||||
}
|
||||
|
||||
/// <devdoc>
|
||||
/// <para>
|
||||
/// Copies all the elements of the collection to the given array
|
||||
/// starting at the given index.
|
||||
/// </para>
|
||||
/// </devdoc>
|
||||
public void CopyTo(Array array, int arrayIndex) {
|
||||
if ((array != null) && (array.Rank != 1))
|
||||
{
|
||||
throw new ArgumentException(SR.GetString(SR.Arg_RankMultiDimNotSupported));
|
||||
}
|
||||
|
||||
// property access to force computation of whole array
|
||||
int count = Count;
|
||||
try
|
||||
{
|
||||
#if SILVERLIGHT
|
||||
// Array.Copy will check for null.
|
||||
Array.Copy(_matches.ToArray(), 0, array, arrayIndex, count);
|
||||
#else
|
||||
_matches.CopyTo(array, arrayIndex);
|
||||
#endif
|
||||
}
|
||||
catch (ArrayTypeMismatchException ex)
|
||||
{
|
||||
#if FEATURE_LEGACYNETCF
|
||||
if (CompatibilitySwitches.IsAppEarlierThanWindowsPhone8)
|
||||
throw;
|
||||
#endif
|
||||
throw new ArgumentException(SR.GetString(SR.Arg_InvalidArrayType), ex);
|
||||
}
|
||||
}
|
||||
|
||||
/// <devdoc>
|
||||
/// <para>
|
||||
/// Provides an enumerator in the same order as Item[i].
|
||||
/// </para>
|
||||
/// </devdoc>
|
||||
public IEnumerator GetEnumerator() {
|
||||
return new MatchEnumerator(this);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* This non-public enumerator lists all the group matches.
|
||||
* Should it be public?
|
||||
*/
|
||||
#if !SILVERLIGHT
|
||||
[ Serializable() ]
|
||||
#endif
|
||||
internal class MatchEnumerator : IEnumerator {
|
||||
internal MatchCollection _matchcoll;
|
||||
internal Match _match = null;
|
||||
internal int _curindex;
|
||||
internal bool _done;
|
||||
|
||||
/*
|
||||
* Nonpublic constructor
|
||||
*/
|
||||
internal MatchEnumerator(MatchCollection matchcoll) {
|
||||
_matchcoll = matchcoll;
|
||||
}
|
||||
|
||||
/*
|
||||
* Advance to the next match
|
||||
*/
|
||||
public bool MoveNext() {
|
||||
if (_done)
|
||||
return false;
|
||||
|
||||
_match = _matchcoll.GetMatch(_curindex);
|
||||
_curindex++;
|
||||
|
||||
if (_match == null) {
|
||||
_done = true;
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* The current match
|
||||
*/
|
||||
public Object Current {
|
||||
get {
|
||||
if (_match == null)
|
||||
throw new InvalidOperationException(SR.GetString(SR.EnumNotStarted));
|
||||
return _match;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Position before the first item
|
||||
*/
|
||||
public void Reset() {
|
||||
_curindex = 0;
|
||||
_done = false;
|
||||
_match = null;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
@@ -0,0 +1,168 @@
|
||||
///------------------------------------------------------------------------------
|
||||
/// <copyright file="RegexMatchTimeoutException.cs" company="Microsoft">
|
||||
/// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
/// </copyright>
|
||||
///
|
||||
/// <owner>gpaperin</owner>
|
||||
///------------------------------------------------------------------------------
|
||||
|
||||
using System;
|
||||
using System.Runtime.Serialization;
|
||||
using System.Security;
|
||||
using System.Security.Permissions;
|
||||
|
||||
|
||||
namespace System.Text.RegularExpressions {
|
||||
|
||||
/// <summary>
|
||||
/// This is the exception that is thrown when a RegEx matching timeout occurs.
|
||||
/// </summary>
|
||||
|
||||
#if SILVERLIGHT
|
||||
#if FEATURE_NETCORE
|
||||
public
|
||||
#else
|
||||
internal
|
||||
#endif
|
||||
class RegexMatchTimeoutException : TimeoutException {
|
||||
#else
|
||||
[Serializable]
|
||||
public class RegexMatchTimeoutException : TimeoutException, ISerializable {
|
||||
#endif
|
||||
|
||||
|
||||
private string regexInput = null;
|
||||
|
||||
private string regexPattern = null;
|
||||
|
||||
private TimeSpan matchTimeout = TimeSpan.FromTicks(-1);
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// This is the preferred constructor to use.
|
||||
/// The other constructors are provided for compliance to Fx design guidelines.
|
||||
/// </summary>
|
||||
/// <param name="regexInput">Matching timeout occured during mathing within the specified input.</param>
|
||||
/// <param name="regexPattern">Matching timeout occured during mathing to the specified pattern.</param>
|
||||
/// <param name="matchTimeout">Matching timeout occured becasue matching took longer than the specified timeout.</param>
|
||||
public RegexMatchTimeoutException(string regexInput, string regexPattern, TimeSpan matchTimeout) :
|
||||
base(SR.GetString(SR.RegexMatchTimeoutException_Occurred)) {
|
||||
Init(regexInput, regexPattern, matchTimeout);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// This constructor is provided in compliance with common NetFx design patterns;
|
||||
/// developers should prefer using the constructor
|
||||
/// <code>public RegexMatchTimeoutException(string input, string pattern, TimeSpan matchTimeout)</code>.
|
||||
/// </summary>
|
||||
public RegexMatchTimeoutException()
|
||||
: base() {
|
||||
Init();
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// This constructor is provided in compliance with common NetFx design patterns;
|
||||
/// developers should prefer using the constructor
|
||||
/// <code>public RegexMatchTimeoutException(string input, string pattern, TimeSpan matchTimeout)</code>.
|
||||
/// </summary>
|
||||
/// <param name="message">The error message that explains the reason for the exception.</param>
|
||||
public RegexMatchTimeoutException(string message)
|
||||
: base(message) {
|
||||
Init();
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// This constructor is provided in compliance with common NetFx design patterns;
|
||||
/// developers should prefer using the constructor
|
||||
/// <code>public RegexMatchTimeoutException(string input, string pattern, TimeSpan matchTimeout)</code>.
|
||||
/// </summary>
|
||||
/// <param name="message">The error message that explains the reason for the exception.</param>
|
||||
/// <param name="inner">The exception that is the cause of the current exception, or a <code>null</code>.</param>
|
||||
public RegexMatchTimeoutException(string message, Exception inner)
|
||||
: base(message, inner) {
|
||||
Init();
|
||||
}
|
||||
|
||||
|
||||
#if !SILVERLIGHT
|
||||
/// <summary>
|
||||
/// Initializes a new RegexMatchTimeoutException with serialized data.
|
||||
/// </summary>
|
||||
/// <param name="info">The SerializationInfo that holds the serialized object data about the exception being thrown.</param>
|
||||
/// <param name="context">The StreamingContext that contains contextual information about the source or destination.</param>
|
||||
[SecurityPermission(SecurityAction.LinkDemand, SerializationFormatter=true)]
|
||||
protected RegexMatchTimeoutException(SerializationInfo info, StreamingContext context) :
|
||||
base(info, context) {
|
||||
|
||||
string input = info.GetString("regexInput");
|
||||
string pattern = info.GetString("regexPattern");
|
||||
TimeSpan timeout = TimeSpan.FromTicks(info.GetInt64("timeoutTicks"));
|
||||
Init(input, pattern, timeout);
|
||||
}
|
||||
|
||||
[SecurityPermission(SecurityAction.LinkDemand, SerializationFormatter=true)]
|
||||
void ISerializable.GetObjectData(SerializationInfo si, StreamingContext context) {
|
||||
base.GetObjectData(si, context);
|
||||
si.AddValue("regexInput", this.regexInput);
|
||||
si.AddValue("regexPattern", this.regexPattern);
|
||||
si.AddValue("timeoutTicks", this.matchTimeout.Ticks);
|
||||
}
|
||||
#endif // !SILVERLIGHT
|
||||
|
||||
private void Init() {
|
||||
Init("", "", TimeSpan.FromTicks(-1));
|
||||
}
|
||||
|
||||
private void Init(string input, string pattern, TimeSpan timeout) {
|
||||
this.regexInput = input;
|
||||
this.regexPattern = pattern;
|
||||
this.matchTimeout = timeout;
|
||||
}
|
||||
|
||||
#if SILVERLIGHT && !FEATURE_NETCORE
|
||||
internal string Pattern {
|
||||
#else
|
||||
public string Pattern {
|
||||
#endif
|
||||
#if SILVERLIGHT
|
||||
[SecurityCritical]
|
||||
#else // SILVERLIGHT
|
||||
[PermissionSet(SecurityAction.LinkDemand, Unrestricted=true)]
|
||||
#endif // SILVERLIGHT
|
||||
get { return regexPattern; }
|
||||
}
|
||||
|
||||
#if SILVERLIGHT && !FEATURE_NETCORE
|
||||
internal string Input {
|
||||
#else
|
||||
public string Input {
|
||||
#endif
|
||||
#if SILVERLIGHT
|
||||
[SecurityCritical]
|
||||
#else // SILVERLIGHT
|
||||
[PermissionSet(SecurityAction.LinkDemand, Unrestricted=true)]
|
||||
#endif // SILVERLIGHT
|
||||
get { return regexInput; }
|
||||
}
|
||||
|
||||
#if SILVERLIGHT && !FEATURE_NETCORE
|
||||
internal TimeSpan MatchTimeout {
|
||||
#else
|
||||
public TimeSpan MatchTimeout {
|
||||
#endif
|
||||
#if SILVERLIGHT
|
||||
[SecurityCritical]
|
||||
#else // SILVERLIGHT
|
||||
[PermissionSet(SecurityAction.LinkDemand, Unrestricted=true)]
|
||||
#endif // SILVERLIGHT
|
||||
get { return matchTimeout; }
|
||||
}
|
||||
} // public class RegexMatchTimeoutException
|
||||
|
||||
|
||||
} // namespace System.Text.RegularExpressions
|
||||
|
||||
// file RegexMatchTimeoutException.cs
|
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,78 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// <copyright file="RegexOptions.cs" company="Microsoft">
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// </copyright>
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
|
||||
namespace System.Text.RegularExpressions {
|
||||
|
||||
using System;
|
||||
|
||||
/// <devdoc>
|
||||
/// <para>[To be supplied.]</para>
|
||||
/// </devdoc>
|
||||
[Flags]
|
||||
public enum RegexOptions {
|
||||
/// <devdoc>
|
||||
/// <para>[To be supplied.]</para>
|
||||
/// </devdoc>
|
||||
None = 0x0000,
|
||||
|
||||
/// <devdoc>
|
||||
/// <para>[To be supplied.]</para>
|
||||
/// </devdoc>
|
||||
IgnoreCase = 0x0001, // "i"
|
||||
|
||||
/// <devdoc>
|
||||
/// <para>[To be supplied.]</para>
|
||||
/// </devdoc>
|
||||
Multiline = 0x0002, // "m"
|
||||
|
||||
/// <devdoc>
|
||||
/// <para>[To be supplied.]</para>
|
||||
/// </devdoc>
|
||||
ExplicitCapture = 0x0004, // "n"
|
||||
#if !SILVERLIGHT || FEATURE_LEGACYNETCF || MOBILE
|
||||
/// <devdoc>
|
||||
/// <para>[To be supplied.]</para>
|
||||
/// </devdoc>
|
||||
Compiled = 0x0008, // "c"
|
||||
#endif
|
||||
/// <devdoc>
|
||||
/// <para>[To be supplied.]</para>
|
||||
/// </devdoc>
|
||||
Singleline = 0x0010, // "s"
|
||||
|
||||
/// <devdoc>
|
||||
/// <para>[To be supplied.]</para>
|
||||
/// </devdoc>
|
||||
IgnorePatternWhitespace = 0x0020, // "x"
|
||||
|
||||
/// <devdoc>
|
||||
/// <para>[To be supplied.]</para>
|
||||
/// </devdoc>
|
||||
RightToLeft = 0x0040, // "r"
|
||||
|
||||
#if DBG
|
||||
/// <internalonly/>
|
||||
/// <devdoc>
|
||||
/// <para>[To be supplied.]</para>
|
||||
/// </devdoc>
|
||||
Debug= 0x0080, // "d"
|
||||
#endif
|
||||
|
||||
/// <devdoc>
|
||||
/// <para>[To be supplied.]</para>
|
||||
/// </devdoc>
|
||||
ECMAScript = 0x0100, // "e"
|
||||
|
||||
/// <devdoc>
|
||||
/// <para>[To be supplied.]</para>
|
||||
/// </devdoc>
|
||||
CultureInvariant = 0x0200,
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,426 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// <copyright file="RegexReplacement.cs" company="Microsoft">
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// </copyright>
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
// The RegexReplacement class represents a substitution string for
|
||||
// use when using regexs to search/replace, etc. It's logically
|
||||
// a sequence intermixed (1) constant strings and (2) group numbers.
|
||||
|
||||
namespace System.Text.RegularExpressions {
|
||||
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
|
||||
internal sealed class RegexReplacement {
|
||||
/*
|
||||
* Since RegexReplacement shares the same parser as Regex,
|
||||
* the constructor takes a RegexNode which is a concatenation
|
||||
* of constant strings and backreferences.
|
||||
*/
|
||||
#if SILVERLIGHT
|
||||
internal RegexReplacement(String rep, RegexNode concat, Dictionary<Int32, Int32> _caps) {
|
||||
#else
|
||||
internal RegexReplacement(String rep, RegexNode concat, Hashtable _caps) {
|
||||
#endif
|
||||
StringBuilder sb;
|
||||
List<String> strings;
|
||||
List<Int32> rules;
|
||||
int slot;
|
||||
|
||||
_rep = rep;
|
||||
|
||||
if (concat.Type() != RegexNode.Concatenate)
|
||||
throw new ArgumentException(SR.GetString(SR.ReplacementError));
|
||||
|
||||
sb = new StringBuilder();
|
||||
strings = new List<String>();
|
||||
rules = new List<Int32>();
|
||||
|
||||
for (int i = 0; i < concat.ChildCount(); i++) {
|
||||
RegexNode child = concat.Child(i);
|
||||
|
||||
switch (child.Type()) {
|
||||
case RegexNode.Multi:
|
||||
sb.Append(child._str);
|
||||
break;
|
||||
case RegexNode.One:
|
||||
sb.Append(child._ch);
|
||||
break;
|
||||
case RegexNode.Ref:
|
||||
if (sb.Length > 0) {
|
||||
rules.Add(strings.Count);
|
||||
strings.Add(sb.ToString());
|
||||
sb.Length = 0;
|
||||
}
|
||||
slot = child._m;
|
||||
|
||||
if (_caps != null && slot >= 0)
|
||||
slot = (int)_caps[slot];
|
||||
|
||||
rules.Add(-Specials - 1 - slot);
|
||||
break;
|
||||
default:
|
||||
throw new ArgumentException(SR.GetString(SR.ReplacementError));
|
||||
}
|
||||
}
|
||||
|
||||
if (sb.Length > 0) {
|
||||
rules.Add(strings.Count);
|
||||
strings.Add(sb.ToString());
|
||||
}
|
||||
|
||||
_strings = strings;
|
||||
_rules = rules;
|
||||
}
|
||||
|
||||
internal String _rep;
|
||||
internal List<String> _strings; // table of string constants
|
||||
internal List<Int32> _rules; // negative -> group #, positive -> string #
|
||||
|
||||
// constants for special insertion patterns
|
||||
|
||||
internal const int Specials = 4;
|
||||
internal const int LeftPortion = -1;
|
||||
internal const int RightPortion = -2;
|
||||
internal const int LastGroup = -3;
|
||||
internal const int WholeString = -4;
|
||||
|
||||
/*
|
||||
* Given a Match, emits into the StringBuilder the evaluated
|
||||
* substitution pattern.
|
||||
*/
|
||||
private void ReplacementImpl(StringBuilder sb, Match match) {
|
||||
for (int i = 0; i < _rules.Count; i++) {
|
||||
int r = _rules[i];
|
||||
if (r >= 0) // string lookup
|
||||
sb.Append(_strings[r]);
|
||||
else if (r < -Specials) // group lookup
|
||||
sb.Append(match.GroupToStringImpl(-Specials - 1 - r));
|
||||
else {
|
||||
switch (-Specials - 1 - r) { // special insertion patterns
|
||||
case LeftPortion:
|
||||
sb.Append(match.GetLeftSubstring());
|
||||
break;
|
||||
case RightPortion:
|
||||
sb.Append(match.GetRightSubstring());
|
||||
break;
|
||||
case LastGroup:
|
||||
sb.Append(match.LastGroupToStringImpl());
|
||||
break;
|
||||
case WholeString:
|
||||
sb.Append(match.GetOriginalString());
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Given a Match, emits into the List<String> the evaluated
|
||||
* Right-to-Left substitution pattern.
|
||||
*/
|
||||
private void ReplacementImplRTL(List<String> al, Match match) {
|
||||
for (int i = _rules.Count - 1; i >= 0; i--) {
|
||||
int r = _rules[i];
|
||||
if (r >= 0) // string lookup
|
||||
al.Add(_strings[r]);
|
||||
else if (r < -Specials) // group lookup
|
||||
al.Add(match.GroupToStringImpl(-Specials - 1 - r));
|
||||
else {
|
||||
switch (-Specials - 1 - r) { // special insertion patterns
|
||||
case LeftPortion:
|
||||
al.Add(match.GetLeftSubstring());
|
||||
break;
|
||||
case RightPortion:
|
||||
al.Add(match.GetRightSubstring());
|
||||
break;
|
||||
case LastGroup:
|
||||
al.Add(match.LastGroupToStringImpl());
|
||||
break;
|
||||
case WholeString:
|
||||
al.Add(match.GetOriginalString());
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* The original pattern string
|
||||
*/
|
||||
internal String Pattern {
|
||||
get {
|
||||
return _rep;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns the replacement result for a single match
|
||||
*/
|
||||
internal String Replacement(Match match) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
||||
ReplacementImpl(sb, match);
|
||||
|
||||
return sb.ToString();
|
||||
}
|
||||
|
||||
/*
|
||||
* Three very similar algorithms appear below: replace (pattern),
|
||||
* replace (evaluator), and split.
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
* Replaces all ocurrances of the regex in the string with the
|
||||
* replacement pattern.
|
||||
*
|
||||
* Note that the special case of no matches is handled on its own:
|
||||
* with no matches, the input string is returned unchanged.
|
||||
* The right-to-left case is split out because StringBuilder
|
||||
* doesn't handle right-to-left string building directly very well.
|
||||
*/
|
||||
internal String Replace(Regex regex, String input, int count, int startat) {
|
||||
Match match;
|
||||
|
||||
if (count < -1)
|
||||
throw new ArgumentOutOfRangeException("count", SR.GetString(SR.CountTooSmall));
|
||||
if (startat < 0 || startat > input.Length)
|
||||
throw new ArgumentOutOfRangeException("startat", SR.GetString(SR.BeginIndexNotNegative));
|
||||
|
||||
if (count == 0)
|
||||
return input;
|
||||
|
||||
match = regex.Match(input, startat);
|
||||
if (!match.Success) {
|
||||
return input;
|
||||
}
|
||||
else {
|
||||
StringBuilder sb;
|
||||
|
||||
if (!regex.RightToLeft) {
|
||||
sb = new StringBuilder();
|
||||
int prevat = 0;
|
||||
|
||||
do {
|
||||
if (match.Index != prevat)
|
||||
sb.Append(input, prevat, match.Index - prevat);
|
||||
|
||||
prevat = match.Index + match.Length;
|
||||
ReplacementImpl(sb, match);
|
||||
if (--count == 0)
|
||||
break;
|
||||
|
||||
match = match.NextMatch();
|
||||
} while (match.Success);
|
||||
|
||||
if (prevat < input.Length)
|
||||
sb.Append(input, prevat, input.Length - prevat);
|
||||
}
|
||||
else {
|
||||
List<String> al = new List<String>();
|
||||
int prevat = input.Length;
|
||||
|
||||
do {
|
||||
if (match.Index + match.Length != prevat)
|
||||
al.Add(input.Substring(match.Index + match.Length, prevat - match.Index - match.Length));
|
||||
|
||||
prevat = match.Index;
|
||||
ReplacementImplRTL(al, match);
|
||||
if (--count == 0)
|
||||
break;
|
||||
|
||||
match = match.NextMatch();
|
||||
} while (match.Success);
|
||||
|
||||
sb = new StringBuilder();
|
||||
|
||||
if (prevat > 0)
|
||||
sb.Append(input, 0, prevat);
|
||||
|
||||
for (int i = al.Count - 1; i >= 0; i--) {
|
||||
sb.Append(al[i]);
|
||||
}
|
||||
}
|
||||
|
||||
return sb.ToString();
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Replaces all ocurrances of the regex in the string with the
|
||||
* replacement evaluator.
|
||||
*
|
||||
* Note that the special case of no matches is handled on its own:
|
||||
* with no matches, the input string is returned unchanged.
|
||||
* The right-to-left case is split out because StringBuilder
|
||||
* doesn't handle right-to-left string building directly very well.
|
||||
*/
|
||||
internal static String Replace(MatchEvaluator evaluator, Regex regex,
|
||||
String input, int count, int startat) {
|
||||
Match match;
|
||||
|
||||
if (evaluator == null)
|
||||
throw new ArgumentNullException("evaluator");
|
||||
if (count < -1)
|
||||
throw new ArgumentOutOfRangeException("count", SR.GetString(SR.CountTooSmall));
|
||||
if (startat < 0 || startat > input.Length)
|
||||
throw new ArgumentOutOfRangeException("startat", SR.GetString(SR.BeginIndexNotNegative));
|
||||
|
||||
if (count == 0)
|
||||
return input;
|
||||
|
||||
match = regex.Match(input, startat);
|
||||
|
||||
if (!match.Success) {
|
||||
return input;
|
||||
}
|
||||
else {
|
||||
StringBuilder sb;
|
||||
|
||||
if (!regex.RightToLeft) {
|
||||
sb = new StringBuilder();
|
||||
int prevat = 0;
|
||||
|
||||
do {
|
||||
if (match.Index != prevat)
|
||||
sb.Append(input, prevat, match.Index - prevat);
|
||||
|
||||
prevat = match.Index + match.Length;
|
||||
|
||||
sb.Append(evaluator(match));
|
||||
|
||||
if (--count == 0)
|
||||
break;
|
||||
|
||||
match = match.NextMatch();
|
||||
} while (match.Success);
|
||||
|
||||
if (prevat < input.Length)
|
||||
sb.Append(input, prevat, input.Length - prevat);
|
||||
}
|
||||
else {
|
||||
List<String> al = new List<String>();
|
||||
int prevat = input.Length;
|
||||
|
||||
do {
|
||||
if (match.Index + match.Length != prevat)
|
||||
al.Add(input.Substring(match.Index + match.Length, prevat - match.Index - match.Length));
|
||||
|
||||
prevat = match.Index;
|
||||
|
||||
al.Add(evaluator(match));
|
||||
|
||||
if (--count == 0)
|
||||
break;
|
||||
|
||||
match = match.NextMatch();
|
||||
} while (match.Success);
|
||||
|
||||
sb = new StringBuilder();
|
||||
|
||||
if (prevat > 0)
|
||||
sb.Append(input, 0, prevat);
|
||||
|
||||
for (int i = al.Count - 1; i >= 0; i--) {
|
||||
sb.Append(al[i]);
|
||||
}
|
||||
}
|
||||
|
||||
return sb.ToString();
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Does a split. In the right-to-left case we reorder the
|
||||
* array to be forwards.
|
||||
*/
|
||||
internal static String[] Split(Regex regex, String input, int count, int startat) {
|
||||
Match match;
|
||||
String[] result;
|
||||
|
||||
if (count < 0)
|
||||
throw new ArgumentOutOfRangeException("count", SR.GetString(SR.CountTooSmall));
|
||||
|
||||
if (startat < 0 || startat > input.Length)
|
||||
throw new ArgumentOutOfRangeException("startat", SR.GetString(SR.BeginIndexNotNegative));
|
||||
|
||||
if (count == 1) {
|
||||
result = new String[1];
|
||||
result[0] = input;
|
||||
return result;
|
||||
}
|
||||
|
||||
count -= 1;
|
||||
|
||||
match = regex.Match(input, startat);
|
||||
|
||||
if (!match.Success) {
|
||||
result = new String[1];
|
||||
result[0] = input;
|
||||
return result;
|
||||
}
|
||||
else {
|
||||
List<String> al = new List<String>();
|
||||
|
||||
if (!regex.RightToLeft) {
|
||||
int prevat = 0;
|
||||
|
||||
for (;;) {
|
||||
al.Add(input.Substring(prevat, match.Index - prevat));
|
||||
|
||||
prevat = match.Index + match.Length;
|
||||
|
||||
// add all matched capture groups to the list.
|
||||
for (int i=1; i<match.Groups.Count; i++) {
|
||||
if (match.IsMatched(i))
|
||||
al.Add(match.Groups[i].ToString());
|
||||
}
|
||||
|
||||
if (--count == 0)
|
||||
break;
|
||||
|
||||
match = match.NextMatch();
|
||||
|
||||
if (!match.Success)
|
||||
break;
|
||||
}
|
||||
|
||||
al.Add(input.Substring(prevat, input.Length - prevat));
|
||||
}
|
||||
else {
|
||||
int prevat = input.Length;
|
||||
|
||||
for (;;) {
|
||||
al.Add(input.Substring(match.Index + match.Length, prevat - match.Index - match.Length));
|
||||
|
||||
prevat = match.Index;
|
||||
|
||||
// add all matched capture groups to the list.
|
||||
for (int i=1; i<match.Groups.Count; i++) {
|
||||
if (match.IsMatched(i))
|
||||
al.Add(match.Groups[i].ToString());
|
||||
}
|
||||
|
||||
if (--count == 0)
|
||||
break;
|
||||
|
||||
match = match.NextMatch();
|
||||
|
||||
if (!match.Success)
|
||||
break;
|
||||
}
|
||||
|
||||
al.Add(input.Substring(0, prevat));
|
||||
|
||||
al.Reverse(0, al.Count);
|
||||
}
|
||||
|
||||
return al.ToArray();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
File diff suppressed because it is too large
Load Diff
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user