Esempio n. 1
0
        /// <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 == null)
            {
                throw new ArgumentNullException(nameof(evaluator));
            }
            if (count < -1)
            {
                throw new ArgumentOutOfRangeException(nameof(count), SR.CountTooSmall);
            }
            if (startat < 0 || startat > input.Length)
            {
                throw new ArgumentOutOfRangeException(nameof(startat), SR.BeginIndexNotNegative);
            }

            if (count == 0)
            {
                return(input);
            }

            Match match = regex.Match(input, startat);

            if (!match.Success)
            {
                return(input);
            }
            else
            {
                Span <char> charInitSpan = stackalloc char[ReplaceBufferSize];
                var         vsb          = new ValueStringBuilder(charInitSpan);

                if (!regex.RightToLeft)
                {
                    int prevat = 0;

                    do
                    {
                        if (match.Index != prevat)
                        {
                            vsb.Append(input.AsSpan(prevat, match.Index - prevat));
                        }

                        prevat = match.Index + match.Length;
                        string result = evaluator(match);
                        if (!string.IsNullOrEmpty(result))
                        {
                            vsb.Append(result);
                        }

                        if (--count == 0)
                        {
                            break;
                        }

                        match = match.NextMatch();
                    } while (match.Success);

                    if (prevat < input.Length)
                    {
                        vsb.Append(input.AsSpan(prevat, input.Length - prevat));
                    }
                }
                else
                {
                    // In right to left mode append all the inputs in reversed order to avoid an extra dynamic data structure
                    // and to be able to work with Spans. A final reverse of the transformed reversed input string generates
                    // the desired output. Similar to Tower of Hanoi.

                    int prevat = input.Length;

                    do
                    {
                        if (match.Index + match.Length != prevat)
                        {
                            vsb.AppendReversed(input.AsSpan(match.Index + match.Length, prevat - match.Index - match.Length));
                        }

                        prevat = match.Index;
                        vsb.AppendReversed(evaluator(match));

                        if (--count == 0)
                        {
                            break;
                        }

                        match = match.NextMatch();
                    } while (match.Success);

                    if (prevat > 0)
                    {
                        vsb.AppendReversed(input.AsSpan(0, prevat));
                    }

                    vsb.Reverse();
                }

                return(vsb.ToString());
            }
        }