如何使用正则表达式替换命名组

4

我需要使用RegEx.Replace来替换输入字符串中特定的命名组。

因此,我可能会有这样一个模式:

"^(?<NoReplace>.+)(?<FirstPeriod>(\d{2})|CM|RM|PM|CN|RN){1}(?<LastPeriod>(\d{2})|CM|RM|PM|CN|RN){1}((#(?<NumberFormat>[#,\.\+\-%0]+))*)$"

令牌(例如CM,RM)正在使用Regex.Replace和MatchEvaluator进行替换。 但是,这应该仅替换FirstPeriod和LastPeriod组中的字符。
例如输入: "FIELDCNS 01CM"
期望输出: "FIELDCNS 0104"
不正确的输出: "FIELD **04** S 0104"
这是否可能?还是我最好先提取要替换的部分,然后重新组装?
5个回答

5

我不太确定我是否理解你的问题,但如果你想仅替换与正则表达式匹配的部分之间的某些字符串,则诀窍是捕获您不想替换的所有位。例如,要将所有"blah"替换为"XXXXX",但仅在"foo"和"bar"之间的部分中进行,则可以执行以下操作:

Dim regex As Regex = new Regex("(foo.*)blah(.*bar)")
Console.WriteLine(regex.Replace( _
    "blah foo bar baz blah baz bar blah blah foo blah", "$1XXXXX$2"))
Console.ReadLine()

blah foo bar baz XXXXX baz bar blah blah foo blah


1
我也遇到了这个问题,我通过在Match对象上创建一些扩展方法来解决它,以替换较大匹配值中命名组匹配值的值。在这个例子中,我想替换"id"组的值,而不必担心周围的垃圾代码:
Dim contents = Regex.Replace(contents, "\|(?'id'\d+)\r\n", 
                      Function(m As Match)
                         Return m.ReplaceGroupValue("id", "[REPLACEMENT VALUE]")
                      End Function)

使用以下内容:

<Extension()> _
Function ReplaceGroupValue(ByVal m As Match, ByVal sGroupName$, ByVal sNewValue$) As String
    'get the value of the specified group
    Dim value = m.Groups(sGroupName).Value

    Return m.Value.Replace(value, sNewValue)
End Function

如果替换值实际上是要被替换的值的更复杂函数,那么使用这种形式会更方便:
Dim contents = Regex.Replace(contents, "\|(?'id'\d+)\r\n", 
                      Function(m As Match)
                         Return m.ReplaceGroupValue("id", Function(id) [do something with the id])
                      End Function)

<Extension()> _
Function ReplaceGroupValue(ByVal m As Match, ByVal sGroupName$, ByVal callback As Func(Of String, String)) As String
    'get the value of the specified group
    Dim value = m.Groups(sGroupName).Value

    Return m.Value.Replace(value, callback(value))
End Function

ReplaceGroupValue函数替换较大匹配表达式中的组值,因此您可以专注于要处理的命名组。

1
你可以有类似这样的代码:
Dim evaluator as MatchEvaluator = AddressOf PeriodReplace
Regex.Replace("FIELDCNS 01CM", pattern, evaluator)

Public Function PeriodReplace(match As Match) As String
    Dim replaceTokens As New Regex("(CM|RM)")
    Dim replaceText As String = "04"
    Return match.Groups("NoReplace").Value & _
        replaceTokens.Replace(match.Groups("FirstPeriod").Value, replaceText) & _
        replaceTokens.Replace(match.Groups("LastPeriod").Value, replaceText) & _
        match.Groups("NumberFormat").Value
End Function

我的MatchEvaluator函数已经足够复杂了,我认为这会让事情变得更加困难! - Richard B

1
如果您想替换多个内容,则必须获取多个匹配项。 这意味着您的匹配字符串只能匹配要替换的表达式的部分,但您试图同时匹配它们两个。 我认为这里缺失的部分是正先行断言和正后行断言。
(?<=.)(\d{2})(?=(\d{2}|CM|RM|PM|CN|RN)|(((#(?<NumberFormat>[#,\.\+\-%0]+))*)$))

这意味着“任何后跟两个数字,后跟(两个数字或CM或RM ...)或(一个数字和输入的结尾)”都会被替换。前瞻(?=)和后顾(?<=)组不计入匹配的一部分,因此它们不会被替换。
这意味着对于像这样的字符串:
"FIELDCNS 01CM02CN"

你将会收到两个对你的MatchEvaluator的调用,可能会得到:

"FIELDCNS XXCMYYCN"

如果你只想将输入中所有的 "01" 匹配替换为 "04",那么你根本不需要一个 MatchEvaluator

不幸的是,我认为那样做行不通,因为我实际上需要在应用程序的其他地方使用<NoReplace>组,所以它必须是匹配的一部分。 - Richard B

1

我使用String.Remove而不是Replace来删除组字符串并插入替换字符串,如果要替换多个组,请小心。

Public Function ReplaceGroup(ByVal regexp As Text.RegularExpressions.Regex, ByVal input As String, ByVal group As String, ByVal replacement As String) As String
    Dim match As Text.RegularExpressions.Match = regexp.Match(input)
    If Not match.Success Then Return input
    Dim group As Text.RegularExpressions.Group = match.Groups(group)
    If Not group.Success Then Return input
    Return input.Remove(group.Index, group.Length).Insert(group.Index, replacement)
End Function

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