正则表达式在文本文档的子部分中多次匹配捕获组

时间:2017-09-11 18:40:09

标签: c# regex

我正在传递XML文档,作为文本文档,虽然是正则表达式过程。

<YaddaYaddaPrecedingMarkup>includes (a) and (b) and (c) and (d) and ...

<MyElement>SECTIONBEGINS (a) Item A (b) Item B (c) Item C (d) Item D</MyElement>

<YaddaYaddaFollowingMarkup>includes (a) and (b) and (c) and (d) and ...

我希望我的正则表达式捕获子弹标签'(a)''(b)''(c)''(d)'。 (.. etc ...)出现在'MyElement'中,其文本以“SECTIONBEGINS”开头。

我需要这个正则表达式来忽略(a)......(b)......(c)出现在我的XML-as-text中的其他任何实例。

如果我使用:

(\([a-z]\))

我在整个文件中匹配(a),(b),(c)。那个表达太不受限制了。

如果我使用:

>SECTIONBEGINS(?:.*?)(\([a-z]\))(?:.*)<

我只在正确的部分内成功匹配,但我只匹配'(a)'(第一个匹配),而不匹配同一部分的(b),(c),(d)。

我已经尝试了很多其他的变体,其中一些会选择'(d)',但似乎没有任何变种可以捕获多个。

2 个答案:

答案 0 :(得分:2)

变式1:Lookbehind

(?<=SECTIONBEGINS[^>]*)\([a-z]\)

变式2:\ G anchor + capture group

(?:SECTIONBEGINS|\G)[^<(]*(\([a-z]\))

答案 1 :(得分:1)

您需要查看Match.Group.Captures

Regex.Match(xml, @">SECTIONBEGINS (?<items>\([a-z]\) .+?)+<")
    .Groups["items"].Captures.Cast<Capture>()
    .Select(x => x.Value)

或者,如果您想将它们分组为键/值对:

var match = Regex.Match(xml, @">SECTIONBEGINS( (\((?<index>[a-z])\) (?<item>.+?)))+<");
Enumerable.Zip(
    match.Groups["index"].Captures.Cast<Capture>(),
    match.Groups["item"].Captures.Cast<Capture>(),
    Tuple.Create)
    .ToDictionary(x => x.Item1.Value, x => x.Item2.Value)

编辑:如果您不关心子弹标签,可以通过以下方式提取项目:

Regex.Match(xml, @">SECTIONBEGINS( (\((?<index>[a-z])\) (?<item>.+?)))+<")
    .Groups["item"].Captures.Cast<Capture>()
    .Select(x => x.Value)

或者,如果您想要替换原有内容:

Regex.Replace(xml, @">SECTIONBEGINS( (\((?<index>[a-z])\) (?<item>.+?)))+<",
    m => string.Format(">SECTIONBEGINS {0}<", string.Join(" ", m.Groups["item"]
        .Captures.Cast<Capture>()
        .Select((x,i) => string.Format("({0}) {1}",
            (char)(((int)'a')+i),
            x.Value.ToUpper() // TODO: your replace logic here
    ))))
)