如何RegEx替换命名组

时间:2009-07-27 22:27:38

标签: vb.net regex

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

所以我可能会有这样的模式:

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

使用带有MatchEvaluator的Regex.Replace替换CM,RM等标记。但是,这应该只替换FirstPeriod和LastPeriod组中的字符。

示例输入: "FIELDCNS 01CM"

期望的输出: "FIELDCNS 0104"

输出不正确: "FIELD**04**S 0104"

这是可能的还是我最好只是拔出我想要更换的部件并在之后重新组装?

5 个答案:

答案 0 :(得分: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 :(得分:1)

如果你想用多个东西替换,你必须得到多个匹配。这意味着您的匹配字符串只能匹配您要替换的表达式的部分,但您尝试同时匹配它们。我认为这里缺少的部分是后视和前瞻。

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

这意味着“任何后跟两位数后跟(两位数字或CM或RM ......)或(数字和输入结束)”的内容将被替换。前瞻(?=)和后瞻(?<=)组不算作比赛的一部分,因此不会被替换。

这意味着对于像:

这样的字符串
"FIELDCNS 01CM02CN"

您可以拨打MatchEvaluator两次电话,然后就可以获得:

"FIELDCNS XXCMYYCN"

如果您只想将输入中的所有“01”匹配替换为“04”,那么您根本不需要MatchEvaluator

答案 2 :(得分:1)

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

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

答案 3 :(得分:0)

你可以这样:

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

答案 4 :(得分:0)

我也有这个问题,我通过在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函数替换较大匹配表达式中的组值,因此您可以专注于要使用的命名组。