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

时间:2015-01-14 12:43:26

标签: c# .net regex

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

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。

我正在寻找最快的选择。也许,它不应该使用正则表达式。

2 个答案:

答案 0 :(得分:1)

我不明白为什么你要连接模式然后在数组中进行如此多的搜索。

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

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;
});

答案 1 :(得分:0)

使它(可能是方式)更快提取

var keyArray = rules.Keys.ToArray()
在您使用它之前

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