正则表达式用通配符替换多个组

Regex replace multiple groups with wildcards

当我们不使用通配符时,我找到了答案。所以问题是 - 如何通过正则表达式执行多个替换。这段代码显示了我想要做什么

internal class Program
{
    private static void Main(string[] args)
    {
        var rules = new Dictionary<string, string>
                    {
                        {@"F\S+", "Replace 1"},
                        {@"\S+z", "Replace 2"},
                    };

        string s = "Foo bar baz";
        string result = ProcessText(s, rules);
        Console.WriteLine(result);
    }

    private static string ProcessText(string input, Dictionary<string, string> rules)
    {
        string[] patterns = rules.Keys.ToArray();
        string pattern = string.Join("|", patterns);
        return Regex.Replace(input, pattern, match =>
                                             {
                                                 int index = GetMatchIndex(match);
                                                 return rules[patterns[index]];
                                             });
    }

    private static int GetMatchIndex(Match match)
    {
        int i = 0;
        foreach (Match g in match.Groups)
        {
            if (g.Success)
                return i;
            i++;
        }
        throw new Exception("Never throws");
    }
}

match.Groups.Count 始终为 1。

我正在寻找最快的替代方案。也许,它不应该使用正则表达式。

使其(可能方式)更快地提取

var keyArray = rules.Keys.ToArray()

在您使用它之前:

return Regex.Replace(input, pattern, match =>
{
    int index = GetMatchIndex(match);
    return rules[keyArray[index]];
});

我不明白你为什么要连接模式然后在一个数组中执行这么多搜索。

你不能像这样单独应用每个模式吗?

var rules = new Dictionary<string, string>
                {
                    {@"F\S+", "Replace 1"},
                    {@"\S+z", "Replace 2"},
                };

string s = "Foo bar baz";
var result = rules.Aggregate(s, (seed, rule) => Regex.Replace(seed, rule.Key, m => rule.Value));

编辑

您的 match.Groups.Count 始终是一个,因为您的匹配中没有定义任何组,并且值是 MSDN 中描述的整个匹配字符串。换句话说,您的 GetMatchIndex 方法什么都不做。

您可以尝试将您的模式转换为这样的命名组:

var patterns = rules.Select((kvp, index) => new 
{
    Key = String.Format("(?<{0}>{1})", index, kvp.Key),
    Value = kvp.Value
};

有了这个数组,在 GetMatchIndex 方法中,您只需将组名解析为匹配模式的索引:

private static int GetMatchIndex(Regex regex, Match match)
{
    foreach(var name in regex.GetGroupNames())
    {
        var group = match.Groups[name];
        if(group.Success)
            return int.Parse(name); //group name is a number
    }
    return -1;
}

现在,您可以像这样使用它:

var pattern = String.Join("|", patterns.Select(x => x.Key));
var regex = new Regex(pattern);
return regex.Replace(input, pattern, m => 
{
    var index = GetMatchIndex(regex, m);
    return patterns[index].Value;
});