如何仅对一个命名捕获组执行正则表达式替换?

4
如果我有一个变化的正则表达式,可能看起来像以下任何一种模式:
(.{2})(?<somedigit>\d+)(.{5})
(?<somedigit>\d+)(.{7})
(.{1})(?<somedigit>\d+)

如果我想用任意数字替换somedigit捕获组,并保留其他内容不变,我该如何做(比如在C#或Java中)?

例如,假设我有这个文本:

QB2-G456

我使用这个正则表达式:

(.{2})(?<somedigit>\d+)(.{5})

为了匹配它,假设我想用35替换somedigit,得到最终结果:

QB35-G456

我知道我可以使用这个替换文本:

${1}35${2}

但是我的问题在于,我事先不知道我的正则表达式的格式。因此,我不能硬编码不想更改的文本的捕获组引用,因为可能会有不同的变化。

由于可能存在多个数字,因此我不能仅替换\d+,因为我不知道数字是在开头、结尾还是中间,是否还有其他数字在文本中进一步出现。

理想情况下,我希望得到类似以下的内容:

new Regex("(.{2})(?<somedigit>\d+)(.{5})").ReplaceCaptureGroup("QB2-G456", "somedigit", "35")

除了需要替换的somedigit捕获组之外,我希望所有内容都不经修改地通过。

我搜索了类似的问题,只找到已知固定正则表达式的解决方案,如上面所述。


为什么不将其他组转换为非捕获组((?:xxxx)而不是(xxxx))呢?这样你只需要替换一件事情了吧? - John Bustos
当然,但我该如何编写那段代码呢?我需要包含其余文本以确定我想要替换的捕获组的位置,但如果这样做,整个匹配肯定会被替换吧?能否给出一个两行代码的例子? - pwnell
你应该标记你正在使用的编程语言。 - jpmc26
我希望能找到一种广泛适用的解决方案,比如Java/C#/Perl等。 - pwnell
1
如果我正确理解@JohnBustos的话,要通用地编写此代码:echo QB2-G456 | perl -ne 's/(.{2})\d+(.{5})/${1}35${2}/g; print' 可以生成 QB35-G456使用非捕获组,我会这样做:echo QB2-G456 | perl -ne 's/(?:.{2})\d+(?:.{5})/35/g; print' 可以生成 35但是,正如您所看到的,它只打印替换后的文本,而不是其他文本。 - pwnell
1个回答

2

以下是在C#中实现的方法:

 var str1 = "QB2-G456";
 var rx1 = new Regex(@"(.{2})(?<somedigit>\d+)(.{5})");
 var res = rx1.Replace(str1, m => m.Value.Replace(m.Groups["somedigit"].Value, "35"));
// Result: QB35-G35456

这将替换字符串中所有“somedigit”组的内容(即QB2-G2456将变成QB35-G35456)。要解决此问题,请使用Regex.Replace(input, regex, repl, numOfReplacements)或此方法:

public string ReplaceOnceAtIndex(string text, string search, string replace, int index)
{
    if (index < 0)
        return text;
    return text.Substring(0, index) + replace + text.Substring(index + search.Length);
}
// ... And thenin the caller ...
var res2 = rx1.Replace(str1, m => 
ReplaceOnceAtIndex(m.Value, m.Groups["somedigit"].Value, "35", m.Groups["somedigit"].Index));
// Result: QB35-G2456

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接