private readonly List <int> _rules; // negative -> group #, positive -> string # /// <summary> /// Since RegexReplacement shares the same parser as Regex, /// the constructor takes a RegexNode which is a concatenation /// of constant strings and backreferences. /// </summary> public RegexReplacement(string rep, RegexNode concat, Dictionary <int, int> _caps) { if (concat.Type() != RegexNode.Concatenate) { throw new ArgumentException(SR.ReplacementError); } Span <char> buffer = stackalloc char[ReplaceBufferSize]; ValueStringBuilder vsb = new ValueStringBuilder(buffer); List <string> strings = new List <string>(); List <int> rules = new List <int>(); for (int i = 0; i < concat.ChildCount(); i++) { RegexNode child = concat.Child(i); switch (child.Type()) { case RegexNode.Multi: vsb.Append(child.Str); break; case RegexNode.One: vsb.Append(child.Ch); break; case RegexNode.Ref: if (vsb.Length > 0) { rules.Add(strings.Count); strings.Add(vsb.ToString()); vsb.Length = 0; } int slot = child.M; if (_caps != null && slot >= 0) { slot = (int)_caps[slot]; } rules.Add(-Specials - 1 - slot); break; default: throw new ArgumentException(SR.ReplacementError); } } if (vsb.Length > 0) { rules.Add(strings.Count); strings.Add(vsb.ToString()); } Pattern = rep; _strings = strings; _rules = rules; }
private readonly List <int> _rules; // negative -> group #, positive -> string # /// <summary> /// Since RegexReplacement shares the same parser as Regex, /// the constructor takes a RegexNode which is a concatenation /// of constant strings and backreferences. /// </summary> internal RegexReplacement(string rep, RegexNode concat, Dictionary <int, int> _caps) { if (concat.Type() != RegexNode.Concatenate) { throw new ArgumentException(SR.ReplacementError); } StringBuilder sb = new StringBuilder(); List <string> strings = new List <string>(); List <int> rules = new List <int>(); 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; } int slot = child._m; if (_caps != null && slot >= 0) { slot = (int)_caps[slot]; } rules.Add(-Specials - 1 - slot); break; default: throw new ArgumentException(SR.ReplacementError); } } if (sb.Length > 0) { rules.Add(strings.Count); strings.Add(sb.ToString()); } _rep = rep; _strings = strings; _rules = rules; }
/* * Yet another related computation: it takes a RegexTree and computes the * leading anchors that it encounters. */ internal static int Anchors(RegexTree tree) { RegexNode curNode; RegexNode concatNode = null; int nextChild = 0; int result = 0; curNode = tree._root; for (; ;) { switch (curNode._type) { case RegexNode.Concatenate: if (curNode.ChildCount() > 0) { concatNode = curNode; nextChild = 0; } break; case RegexNode.Greedy: case RegexNode.Capture: curNode = curNode.Child(0); concatNode = null; continue; case RegexNode.Bol: case RegexNode.Eol: case RegexNode.Boundary: case RegexNode.ECMABoundary: case RegexNode.Beginning: case RegexNode.Start: case RegexNode.EndZ: case RegexNode.End: return(result | AnchorFromType(curNode._type)); case RegexNode.Empty: case RegexNode.Require: case RegexNode.Prevent: break; default: return(result); } if (concatNode == null || nextChild >= concatNode.ChildCount()) { return(result); } curNode = concatNode.Child(nextChild++); } }
/* * This is a related computation: it takes a RegexTree and computes the * leading substring if it see one. It's quite trivial and gives up easily. */ internal static RegexPrefix Prefix(RegexTree tree) { RegexNode curNode; RegexNode concatNode = null; int nextChild = 0; curNode = tree._root; for (; ;) { switch (curNode._type) { case RegexNode.Concatenate: if (curNode.ChildCount() > 0) { concatNode = curNode; nextChild = 0; } break; case RegexNode.Greedy: case RegexNode.Capture: curNode = curNode.Child(0); concatNode = null; continue; case RegexNode.Oneloop: case RegexNode.Onelazy: if (curNode._m > 0) { string pref = string.Empty.PadRight(curNode._m, curNode._ch); return(new RegexPrefix(pref, 0 != (curNode._options & RegexOptions.IgnoreCase))); } else { return(RegexPrefix.Empty); } case RegexNode.One: return(new RegexPrefix(curNode._ch.ToString(), 0 != (curNode._options & RegexOptions.IgnoreCase))); case RegexNode.Multi: return(new RegexPrefix(curNode._str, 0 != (curNode._options & RegexOptions.IgnoreCase))); case RegexNode.Bol: case RegexNode.Eol: case RegexNode.Boundary: case RegexNode.ECMABoundary: case RegexNode.Beginning: case RegexNode.Start: case RegexNode.EndZ: case RegexNode.End: case RegexNode.Empty: case RegexNode.Require: case RegexNode.Prevent: break; default: return(RegexPrefix.Empty); } if (concatNode == null || nextChild >= concatNode.ChildCount()) { return(RegexPrefix.Empty); } curNode = concatNode.Child(nextChild++); } }