用值替换正则表达式中的命名组

时间:2010-04-16 21:07:12

标签: c# regex

我想使用与string.Format相同的正则表达式。我会解释

我有:

string pattern = "^(?<PREFIX>abc_)(?<ID>[0-9])+(?<POSTFIX>_def)$";
string input = "abc_123_def";
Regex regex = new Regex(pattern, RegexOptions.IgnoreCase);
string replacement = "456";
Console.WriteLine(regex.Replace(input, string.Format("${{PREFIX}}{0}${{POSTFIX}}", replacement)));

这有效,但我必须为regex.Replace提供“输入”。我不要那个。我想使用模式进行匹配,但也使用与字符串格式相同的方式创建字符串,用值替换命名组“ID”。这可能吗?

我正在寻找类似的东西:

string pattern = "^(?<PREFIX>abc_)(?<ID>[0-9])+(?<POSTFIX>_def)$";
string result = ReplaceWithFormat(pattern, "ID", 999);

结果将包含“abc_999_def”。如何做到这一点?

8 个答案:

答案 0 :(得分:15)

是的,有可能:

public static class RegexExtensions
{
    public static string Replace(this string input, Regex regex, string groupName, string replacement)
    {
        return regex.Replace(input, m =>
        {
            return ReplaceNamedGroup(input, groupName, replacement, m);
        });
    }

    private static string ReplaceNamedGroup(string input, string groupName, string replacement, Match m)
    {
        string capture = m.Value;
        capture = capture.Remove(m.Groups[groupName].Index - m.Index, m.Groups[groupName].Length);
        capture = capture.Insert(m.Groups[groupName].Index - m.Index, replacement);
        return capture;
    }
}

用法:

Regex regex = new Regex("^(?<PREFIX>abc_)(?<ID>[0-9]+)(?<POSTFIX>_def)$");

string oldValue = "abc_123_def";
var result = oldValue.Replace(regex, "ID", "456");

结果是:abc_456_def

答案 1 :(得分:12)

不,如果不提供输入,则无法使用正则表达式。它必须有一些工作,模式不能向结果添加任何数据,一切都必须来自输入或替换。

使用String.Format的Intead,你可以使用后面的一个看,并指望前面指定“abc_”和“_def”之间的部分,并替换它:

string result = Regex.Replace(input, @"(?<=abc_)\d+(?=_def)", "999");

答案 2 :(得分:5)

user1817787回答出现问题,我必须对ReplaceNamedGroup函数进行如下修改。

private static string ReplaceNamedGroup(string input, string groupName, string replacement, Match m)
{
    string capture = m.Value;
    capture = capture.Remove(m.Groups[groupName].Index - m.Index, m.Groups[groupName].Length);
    capture = capture.Insert(m.Groups[groupName].Index - m.Index, replacement);
    return capture;
}

答案 3 :(得分:1)

@ user1817787的原始方法的另一个编辑版本,这个支持命名组的多个实例(还包括对@Justin发布的类似修复(使用{match.Index返回结果, match.Length}而不是{0,input.Length})):

public static string ReplaceNamedGroup(
    string input, string groupName, string replacement, Match match)
{
    var sb = new StringBuilder(input);
    var matchStart = match.Index;
    var matchLength = match.Length;

    var captures = match.Groups[groupName].Captures.OfType<Capture>()
        .OrderByDescending(c => c.Index);

    foreach (var capt in captures)
    {
        if (capt == null)
            continue;

        matchLength += replacement.Length - capt.Length;

        sb.Remove(capt.Index, capt.Length);
        sb.Insert(capt.Index, replacement);
    }

    var end = matchStart + matchLength;
    sb.Remove(end, sb.Length - end);
    sb.Remove(0, matchStart);

    return sb.ToString();
}

答案 4 :(得分:1)

我缩短了ReplaceNamedGroup,仍然支持多次捕获。

private static string ReplaceNamedGroup(string input, string groupName, string replacement, Match m)
{
  string result = m.Value;
  foreach (Capture cap in m.Groups[groupName]?.Captures)
  {
    result = result.Remove(cap.Index - m.Index, cap.Length);
    result = result.Insert(cap.Index - m.Index, replacement);
  }
return result;
}

答案 5 :(得分:0)

万一这对任何人都有帮助,我可以一次性替换多个命名的捕获组,从而增强了答案。

public static class RegexExtensions
    {
        public static string Replace(this string input, Regex regex, Dictionary<string, string> captureGroupReplacements)
        {
            string temp = input;

            foreach (var key in captureGroupReplacements.Keys)
            {
                temp = regex.Replace(temp, m =>
                {
                    return ReplaceNamedGroup(key, captureGroupReplacements[key], m);
                });
            }
            return temp;
        }

        private static string ReplaceNamedGroup(string groupName, string replacement, Match m)
        {
            string capture = m.Value;
            capture = capture.Remove(m.Groups[groupName].Index - m.Index, m.Groups[groupName].Length);
            capture = capture.Insert(m.Groups[groupName].Index - m.Index, replacement);
            return capture;
        }
    }

用法:

var regex = new Regex(@"C={BasePath:""(?<basePath>[^\""].*)"",ResultHeadersPath:""ResultHeaders"",CORS:(?<cors>true|false)");

content = content.Replace(regex, new Dictionary<string, string>
{
   { "basePath", "www.google.com" },
   { "cors", "false" }
};

为此,所有功劳应归功于user1817787。

答案 6 :(得分:0)

简单的解决方案是参考替换的匹配组。因此,前缀为$1,后缀为$3

我还没有测试过下面的代码,但应该与我最近写的regEx类似:

string pattern = "^(?<PREFIX>abc_)(?<ID>[0-9])+(?<POSTFIX>_def)$";
string input = "abc_123_def";
Regex regex = new Regex(pattern, RegexOptions.IgnoreCase);
string replacement = String.Format("$1{0}$3", "456");
Console.WriteLine(regex.Replace(input, string.Format("${{PREFIX}}{0}${{POSTFIX}}", replacement)));

答案 7 :(得分:-1)

您应该查看有关RegEx替换here

的文档

我创建了这个来替换一个命名组。我不能在所有组名称上使用循环解决方案,因为我的情况并非所有表达式都被分组。

    public static string ReplaceNamedGroup(this Regex regex, string input, string namedGroup, string value)
    {
        var replacement = Regex.Replace(regex.ToString(), 
            @"((?<GroupPrefix>\(\?)\<(?<GroupName>\w*)\>(?<Eval>.[^\)]+)(?<GroupPostfix>\)))", 
            @"${${GroupName}}").TrimStart('^').TrimEnd('$');
        replacement = replacement.Replace("${" + namedGroup + "}", value);
        return Regex.Replace(input, regex.ToString(), replacement);
    }