/// <summary> /// 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(). /// </summary> public virtual string Result(string replacement) { if (replacement is null) { ThrowHelper.ThrowArgumentNullException(ExceptionArgument.replacement); } Regex?regex = _regex; if (regex is null) { throw new NotSupportedException(SR.NoResultOnFailed); } // Gets the weakly cached replacement helper or creates one if there isn't one already. RegexReplacement repl = RegexReplacement.GetOrCreate(regex.RegexReplacementWeakReference, replacement, regex.caps !, regex.capsize, regex.capnames !, regex.roptions); SegmentStringBuilder segments = SegmentStringBuilder.Create(); repl.ReplacementImpl(ref segments, this); return(segments.ToString()); }
/// <summary> /// Does a split. In the right-to-left case we reorder the /// array to be forwards. /// </summary> private static string[] Split(Regex regex, string input, int count, int startat) { if (count < 0) { ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.count, ExceptionResource.CountTooSmall); } if ((uint)startat > (uint)input.Length) { ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.startat, ExceptionResource.BeginIndexNotNegative); } if (count == 1) { return(new[] { input }); } count--; var state = (results : new List <string>(), prevat : 0, input, count); if (!regex.RightToLeft) { regex.RunAllMatchesWithCallback(input, startat, ref state, static (ref (List <string> results, int prevat, string input, int count)state, Match match) => { state.results.Add(state.input.Substring(state.prevat, match.Index - state.prevat)); state.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)) { state.results.Add(match.Groups[i].Value); } } return(--state.count != 0); }, RegexRunnerMode.FullMatchRequired, reuseMatchObject: true);
private readonly 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, Hashtable _caps) { if (concat.Kind != RegexNodeKind.Concatenate) { throw ThrowHelper.CreateArgumentException(ExceptionResource.ReplacementError); } Span <char> vsbStack = stackalloc char[256]; var vsb = new ValueStringBuilder(vsbStack); FourStackStrings stackStrings = default; var strings = new ValueListBuilder <string>(MemoryMarshal.CreateSpan(ref stackStrings.Item1 !, 4)); var rules = new ValueListBuilder <int>(stackalloc int[64]); int childCount = concat.ChildCount(); for (int i = 0; i < childCount; i++) { RegexNode child = concat.Child(i); switch (child.Kind) { case RegexNodeKind.Multi: vsb.Append(child.Str !); break; case RegexNodeKind.One: vsb.Append(child.Ch); break; case RegexNodeKind.Backreference: if (vsb.Length > 0) { rules.Append(strings.Length); strings.Append(vsb.ToString()); vsb = new ValueStringBuilder(vsbStack); } int slot = child.M; if (_caps != null && slot >= 0) { slot = (int)_caps[slot] !; } rules.Append(-Specials - 1 - slot); break; default: throw ThrowHelper.CreateArgumentException(ExceptionResource.ReplacementError); } } if (vsb.Length > 0) { rules.Append(strings.Length); strings.Append(vsb.ToString()); } Pattern = rep; _strings = strings.AsSpan().ToArray(); _rules = rules.AsSpan().ToArray(); rules.Dispose(); }