正则表达式:不是任意非捕获组

时间:2016-07-12 12:33:02

标签: .net regex

我正在尝试编写正则表达式以涵盖我的所有案例。 我必须解析Xml并捕获一些属性。 例如:

<item p2="2"/>
<item p1="1" p2="2"/>
<item p1="1" p2="2" p3="3"/>
<item p1="1" p2="2" p3="3" p4="4"/>
<item p1="1" p2="2" p3="3" p4="4" p5="5"/>

我必须捕捉&#34; p2&#34;的价值。财产,我知道&#34; p2&#34;将始终排在队中。 我也希望获得&#34; p4&#34;的价值。不会永远存在的财产。

首先,我试图满足前四个案例(例子中的前四行),我写了这样的正则表达式:

\<item.+?p2=\"(?<val1>\d+)".*?(?:p4=\"(?<val2>\d+)\")?\/\>

它工作正常。 &#34; VAL1&#34;组总是返回值。并且&#34; val2&#34;如果&#34; p4&#34;组返回值财产被提出。

但要涵盖我的最后一个案例:

<item p1="1" p2="2" p3="3" p4="4" p5="5"/>

我修改了我的正则表达式:

\<item.+?p2=\"(?<val1>\d+)".*?(?:p4=\"(?<val2>\d+)\")?.*?\/\>
______________________________________________________^^^

我发现&#34; val1&#34; group仍然返回值,但&#34; val2&#34; group不再返回所有情况的值。

你能告诉我我错过了什么,并帮助写出正则表达式以涵盖我的所有案件吗?

Example here in Regex tester

1 个答案:

答案 0 :(得分:0)

XML不是Regular language,因为使用正则表达式不是一种方法。您还需要parser

有很多方法可以做到这一点,但我个人会将XML文档加载到XmlDocument类中,并使用SelectNodes方法和XPath查询来查找项目列表。完成后,您可以在每个找到的XmlNode上使用foreach,并使用Attributes集合来获取所需的数据。

如果必须使用正则表达式执行此操作,则需要执行的操作是最后一个。?在非捕获组内。您所做的是授予正则表达式权限以省略p4补丁并匹配。?代替。通过。*?在集团内部,它消除了这种可能性。这可能很慢(甚至可能会受到catastrophic backtracking的影响)并且它无法处理XML的所有复杂性。这是一个演示程序:

using System;
using System.Text.RegularExpressions;

class Program
{
    static void Main()
    {
        var regex = new Regex(@"
        \<item                  # Capture <item
        .+?                     # Capture one or more characters as few times as possible 
        p2=                     # Capture p2=
        \""                     # Capture opening quote
        (?<val1>\d+)            # Capture one or more decimal digits and put them in val1
        ""                      # Capture closing quote
        .*?                     # Capture zero or more characters as few times as possible
        (?:                     # Begin a non capturing group
            p4=                 # Capture p4=
            \""                 # Capture opening quote
            (?<val2>\d+)        # Capture one or more decimal digits and put them in val2
            \""                 # Capture closing quote
            .*?                 # Capture zero or more characters as few times as possible
        )?                      # Capture 0 or 1 p4s        
        />                      # Capture \>
        ", RegexOptions.IgnorePatternWhitespace);

        Test(regex, @"<item p2=""2""/>", "2", string.Empty);
        Test(regex, @"<item p1=""1"" p2=""2""/>", "2", string.Empty);
        Test(regex, @"<item p1=""1"" p2=""2"" p3=""3""/>", "2", string.Empty);
        Test(regex, @"<item p1=""1"" p2=""2"" p3=""3"" p4=""4""/>", "2", "4");
        Test(regex, @"<item p1=""1"" p2=""2"" p3=""3"" p4=""4"" p5=""5""/>", "2", "4");
    }

    static void Test(Regex regex, string test, string p2, string p4)
    {
        Match m = regex.Match(test);

        string p2Group = m.Groups["val1"].Value;
        string p4Group = m.Groups["val2"].Value;

        Console.WriteLine("Test: '{0}'", test);
        Console.WriteLine("p2: '{0}' - {1}", p2Group, p2Group == p2 ? "Success" : "Fail");
        Console.WriteLine("p4: '{0}' - {1}", p4Group, p4Group == p4 ? "Success" : "Fail");
    }
}