如何仅对一个命名捕获组执行正则表达式替换?
Posted
技术标签:
【中文标题】如何仅对一个命名捕获组执行正则表达式替换?【英文标题】:How to perform a Regex replacement on one named capture group only? 【发布时间】:2015-02-03 00:19:14 【问题描述】:如果我有一个不同的正则表达式,它可能看起来像以下任何一种模式:
(.2)(?<somedigit>\d+)(.5)
(?<somedigit>\d+)(.7)
(.1)(?<somedigit>\d+)
我想用任何数字替换 somedigit 捕获组,而其他所有内容都保持不变,我该怎么做(比如在 C# 或 Java 中)?
例如,假设我有这个文本:
QB2-G456
我使用这个正则表达式:
(.2)(?<somedigit>\d+)(.5)
匹配它,并说我想用 35 替换 somedigit,以获得最终结果:
QB35-G456
我知道我可以使用这个替换文本:
$135$2
但我的问题的根源是我不知道我的正则表达式的格式。所以我不能硬编码我不想更改的文本的捕获组引用,因为可能会有不同的变化。
由于可能存在多个数字,我不能只替换 \d+,因为我不知道数字是在开头还是结尾或中间,以及文本中是否还有其他数字。
理想情况下,我希望得到类似的东西:
new Regex("(.2)(?<somedigit>\d+)(.5)").ReplaceCaptureGroup("QB2-G456", "somedigit", "35")
除了被替换的 somedigit 捕获组之外,所有内容都未经修改地通过。
我搜索了类似的问题,但只找到了正则表达式已修复和已知的解决方案,如上所述。
【问题讨论】:
为什么不将其他组转换为非捕获组((?:xxxx)
而不是(xxxx)
)?那你反正只有一件事要换?
当然可以,但是我将如何编写该代码?我需要包含其余文本以确定要替换的捕获组的位置,但是如果这样做,肯定会替换整个匹配项吗?也许是两个班轮的例子?
你应该用你正在使用的语言来标记它。
我希望能找到一个应用广泛的解决方案,可能是Java/C#/Perl/等等。
如果我对@JohnBustos 的理解正确,一般来说:echo QB2-G456 | perl -ne 's/(.2)\d+(.5)/$135$2/g; print'
使用非捕获组产生QB35-G456
我会这样做:echo QB2-G456 | perl -ne 's/(?:.2)\d+(?:.5)/35/g; print'
产生35
但正如您所见只打印替换的文本,而不是其他文本。
【参考方案1】:
以下是您可以在 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
【讨论】:
以上是关于如何仅对一个命名捕获组执行正则表达式替换?的主要内容,如果未能解决你的问题,请参考以下文章