.NET Regex解析某些部分中重复值的标记,但不解析其他部分的重复值

时间:2011-08-28 03:05:55

标签: .net regex

我需要使用.NET正则表达式来删除标记文件的<value>标记之间的某些值(例如复制\粘贴摘录):

<Title>Section1</Title>

<attributeArray><name>Name1</name><value>Value1</value></attributeArray>

<attributeArray><name>Name2</name><value>Value2</value></attributeArray>

<attributeArray><name>Name3</name><value>Value3</value></attributeArray>

<attributeArray><name>Name4</name><value>Value4</value></attributeArray>

<Title>Section2</Title>

<attributeArray><name>Name1</name><value>Value1</value></attributeArray>

<attributeArray><name>Name2</name><value>Value2</value></attributeArray>

<attributeArray><name>Name3</name><value>Value3</value></attributeArray>

<attributeArray><name>Name4</name><value>Value4</value></attributeArray>

</node>

实际文本包括6个部分。我遇到的问题是每个部分的所有标签名称都是相同的,我只需要从第2节中提取值(所以不包括1,3,4,5,6)。

我已经挣扎了几天,并尝试了各种条件表达式,这对我来说是新的:

(?(<node>Section2)(.*?<value>(?<Value>.*?)<\/value>.*?))

如果是第2节,则解析值键,但它只提取第一个值 - 它不会遍历标记的每个<value>。标记通常有大约10个我需要提取的值(在上面的例子中缩写)。

这不是在代码中完成的,所以我没有使用XML解析器的自由。

我们将非常感谢任何建议 - 或者如果我能进一步澄清,请告诉我。

一个事后的想法 - 如果有一种方法可以在每个值匹配时包含标题的文本,那么我可以解析所有6个部分,但我可以稍后根据我之后的部分过滤结果也可以。

示例:

match1
group1 = Section2
group2 = Value1

match2
group1 = Section2
group2 = Value2

match3
group1 = Section2
group2 = Value3

match4
group1 = Section2
group2 = Value4

谢谢!

2 个答案:

答案 0 :(得分:2)

这是一个选项:

(?:
   <Title>Section2</Title>    # Match the header
   |                          # or
   \G(?!\A)                   # Match where the previous match ended
)\s*
<attributeArray>
    <name>(?<name>[^<]*)</name>
    <value>(?<value>[^<]*)</value>
</attributeArray>

第一场比赛包括标题,以下比赛必须从前一场比赛开始 工作示例:http://regexhero.net/tester/?id=321ce843-923d-4556-9b99-dbb72175929a


请注意,如果您在值或标题之间没有提及其他元素,则上述操作将失败。您可以使用可能效率较低的模式解决这个问题,使用事实.Net正则表达式可以具有可变长度的外观:

(?<=                          # lookbehind - check that before the current position
   <Title>Section2</Title>    #  we can see the wanted title,
   (?:(?!<Title>).)*          #  followed by no more title between it and here.
)
<attributeArray>
    <name>(?<name>[^<]*)</name>
    <value>(?<value>[^<]*)</value>
</attributeArray>

示例:http://regexhero.net/tester/?id=743c4de6-1b8a-48a4-a69b-63f3624de594

如果您愿意,可以将标题更改为<Title>(?<title>[^<]*)</Title>,捕获文件中的所有值,然后按所需标题进行过滤 - 它将添加到每个匹配项中。


最后,这里有一个类似的方法可以用于其他方面:它在标题Section3之前捕获键值/值对,假设它是有序的:

<attributeArray>
    <name>(?<name>[^<]*)</name>
    <value>(?<value>[^<]*)</value>
</attributeArray>
(?=
   (?:(?!<Title>).)*
   <Title>Section3</Title>
)

示例:http://regexhero.net/tester/?id=8d8ae0e8-5f10-439f-a5a5-50d0b4e73bd2

答案 1 :(得分:1)

我建议使用CaptureCollection:

string s = @"<Title>Section1</Title>
<attributeArray><name>Name1</name><value>Value1-1</value></attributeArray>
<attributeArray><name>Name2</name><value>Value1-2</value></attributeArray>
<attributeArray><name>Name3</name><value>Value1-3</value></attributeArray>
<attributeArray><name>Name4</name><value>Value1-4</value></attributeArray>

<Title>Section2</Title>
<attributeArray><name>Name1</name><value>Value2-1</value></attributeArray>
<attributeArray><name>Name2</name><value>Value2-2</value></attributeArray>
<attributeArray><name>Name3</name><value>Value2-3</value></attributeArray>
<attributeArray><name>Name4</name><value>Value2-4</value></attributeArray>

<Title>Section3</Title>
<attributeArray><name>Name1</name><value>Value3-1</value></attributeArray>
<attributeArray><name>Name2</name><value>Value3-2</value></attributeArray>
<attributeArray><name>Name3</name><value>Value3-3</value></attributeArray>
<attributeArray><name>Name4</name><value>Value3-4</value></attributeArray>";

Regex r = new Regex(
  @"<Title>(Section2)</Title>(?:\s*<attributeArray>.*?<value>(.*?)</value></attributeArray>)+");
Match m = r.Match(s);
if (m.Success)
{
  string section = m.Groups[1].Value;
  int i = 0;
  foreach (Capture c in m.Groups[2].Captures)
  {
    Console.WriteLine("match{0}\ngroup1 = {1}\ngroup2 = {2}\n",
                      ++i, section, c.Value);
  }
}

m.Groups[2].Value会返回Value2-4最后要在第2组中捕获。但是所有中间捕获都被保留,可以通过Captures property进行访问。