/// <summary> /// Replaces all occurrences 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. /// </summary> private static string Replace(MatchEvaluator evaluator, Regex regex, string input, int count, int startat) { if (evaluator is null) { ThrowHelper.ThrowArgumentNullException(ExceptionArgument.evaluator); } if (count < -1) { ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.count, ExceptionResource.CountTooSmall); } if ((uint)startat > (uint)input.Length) { ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.startat, ExceptionResource.BeginIndexNotNegative); } if (count == 0) { return(input); } var state = (segments : SegmentStringBuilder.Create(), evaluator, prevat : 0, input, count); if (!regex.RightToLeft) { regex.Run(input, startat, ref state, static (ref (SegmentStringBuilder segments, MatchEvaluator evaluator, int prevat, string input, int count)state, Match match) => { state.segments.Add(state.input.AsMemory(state.prevat, match.Index - state.prevat)); state.prevat = match.Index + match.Length; state.segments.Add(state.evaluator(match).AsMemory()); return(--state.count != 0); }, reuseMatchObject: false);
/// <summary> /// Given a Match, emits into the builder the evaluated /// Right-to-Left substitution pattern. /// </summary> public void ReplacementImplRTL(ref SegmentStringBuilder segments, Match match) { for (int i = _rules.Length - 1; i >= 0; i--) { int rule = _rules[i]; ReadOnlyMemory <char> segment = rule >= 0 ? _strings[rule].AsMemory() : // string lookup rule < -Specials?match.GroupToStringImpl(-Specials - 1 - rule) : // group lookup (-Specials - 1 - rule) switch // special insertion patterns { LeftPortion => match.GetLeftSubstring(), RightPortion => match.GetRightSubstring(), LastGroup => match.LastGroupToStringImpl(), WholeString => match.Text.AsMemory(), _ => default }; // Add the segment to the list if it's not empty. A common case for it being // empty is if the developer is using Regex.Replace as a way to implement // Regex.Remove, where the replacement string is empty. if (segment.Length != 0) { segments.Add(segment); } } }
/// <summary> /// Replaces all occurrences 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. /// </summary> public string Replace(Regex regex, string input, int count, int startat) { if (count < -1) { ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.count, ExceptionResource.CountTooSmall); } if ((uint)startat > (uint)input.Length) { ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.startat, ExceptionResource.BeginIndexNotNegative); } if (count == 0) { return(input); } var state = (replacement : this, segments : SegmentStringBuilder.Create(), inputMemory : input.AsMemory(), prevat : 0, count); if (!regex.RightToLeft) { regex.Run(input, startat, ref state, (ref (RegexReplacement thisRef, SegmentStringBuilder segments, ReadOnlyMemory <char> inputMemory, int prevat, int count)state, Match match) => { state.segments.Add(state.inputMemory.Slice(state.prevat, match.Index - state.prevat)); state.prevat = match.Index + match.Length; state.thisRef.ReplacementImpl(ref state.segments, match); return(--state.count != 0); }, reuseMatchObject: true);
/// <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> /// Given a Match, emits into the builder the evaluated /// Right-to-Left substitution pattern. /// </summary> public void ReplacementImplRTL(ref SegmentStringBuilder segments, Match match) { for (int i = _rules.Length - 1; i >= 0; i--) { int r = _rules[i]; if (r >= 0) { // string lookup segments.Add(_strings[r].AsMemory()); } else if (r < -Specials) { // group lookup segments.Add(match.GroupToStringImpl(-Specials - 1 - r)); } else { // special insertion patterns switch (-Specials - 1 - r) { case LeftPortion: segments.Add(match.GetLeftSubstring()); break; case RightPortion: segments.Add(match.GetRightSubstring()); break; case LastGroup: segments.Add(match.LastGroupToStringImpl()); break; case WholeString: segments.Add(match.Text.AsMemory()); break; } } } }