XFE Git
XFE Studio Git
Git 首页 全局搜索
XFE 主站 文档 NuGet

XFESystem

【Rust】XFE系统,基于Rust和汇编

公开
关注 0 Fork 0 Star 0
UTF-8
using System.Text;
using System.Text.RegularExpressions;

namespace XFESystem.Collections;

/// <summary>A bounded atom replacement fast path for the private Jint runtime.</summary>
public static class LiteralRegexReplacement
{
    public static string Replace(Regex regex, string input, string replacement, int count)
    {
        // Every other regex shape, option, replacement substitution and overload
        // retains the original engine and its timeout. No JS accessors or
        // callbacks are moved: Jint has already converted these exact arguments.
        if (count <= 0 || input.Length > 131_072 || replacement.Length > 4096 || replacement.Contains('$') ||
            (regex.Options & (RegexOptions.IgnoreCase | RegexOptions.IgnorePatternWhitespace | RegexOptions.RightToLeft)) != 0 ||
            !TryLiteral(regex.ToString(), out string literal) ||
            replacement.Length > literal.Length && input.Length + (long)(input.Length / literal.Length) * (replacement.Length - literal.Length) > 1_048_576)
            return RegexPauseRecovery.Replace(regex, input, replacement, count);
        int match = input.IndexOf(literal, StringComparison.Ordinal);
        if (match < 0) return input;
        var output = new StringBuilder(input.Length); int start = 0, replaced = 0;
        do
        {
            output.Append(input, start, match - start).Append(replacement);
            start = match + literal.Length;
            if (++replaced == count) break;
            match = input.IndexOf(literal, start, StringComparison.Ordinal);
        } while (match >= 0);
        return output.Append(input, start, input.Length - start).ToString();
    }

    private static bool TryLiteral(string pattern, out string literal)
    {
        literal = string.Empty;
        if (pattern.Length is < 1 or > 256) return false;
        Span<char> decoded = stackalloc char[256]; int count = 0;
        const string meta = @"\.^$|?*+()[]{}";
        for (int index = 0; index < pattern.Length; index++)
        {
            char value = pattern[index];
            if (value == '\\')
            {
                if (++index == pattern.Length || !meta.Contains(pattern[index])) return false;
                value = pattern[index];
            }
            else if (value is < ' ' or > '~' || meta.Contains(value)) return false;
            decoded[count++] = value;
        }
        literal = count == pattern.Length ? pattern : new string(decoded[..count]);
        return count > 0;
    }
}