代码之家  ›  专栏  ›  技术社区  ›  Arthur

此regex捕获错误的组数

  •  2
  • Arthur  · 技术社区  · 14 年前

    我必须解析一个字符串并捕获一些值:

    freq=每周;wkst=mo;by day=2tu,2we

    我要捕获两个组:

    grp 1: 2, 2
    grp 2: TU, WE
    

    数字代表间隔。图,我们代表工作日。我两个都需要。

    我使用的代码是:

    private final static java.util.regex.Pattern regBYDAY = java.util.regex.Pattern.compile(".*;BYDAY=(?:([+-]?[0-9]*)([A-Z]{2}),?)*.*");
    
    String rrule = "FREQ=WEEKLY;WKST=MO;BYDAY=2TU,2WE";
    java.util.regex.Matcher result = regBYDAY.matcher(rrule);
    if (result.matches())
    {
        int grpCount = result.groupCount();
        for (int i = 1; i < grpCount; i++)
        {
            String g = result.group(i);
            ...
        }
    }
    

    grpccount==2-为什么?如果我正确地读取Java文档(那一点点),我应该得到5?0=整个表达式,1,2,3,4=我捕获了2,2,tu和we。

    result.group(1)=“2”;

    我是一个程序员很少的Java程序员,所以我在正则表达式Workbench中测试了正则表达式,这是一个测试正则表达式的很好的C语言程序。在那里,我的瑞格鞋很好用。

    https://code.msdn.microsoft.com/RegexWorkbench

    RegExWB:

    .*;BYDAY=(?:([+-]?[0-9]*)([A-Z]{2}),?)*.*
    
    Matching:
    FREQ=WEEKLY;WKST=MO;BYDAY=22TU,-2WE,+223FR
      1 => 22
      1 => -2
      1 => +223
      2 => TU
      2 => WE
      2 => FR
    
    3 回复  |  直到 7 年前
        1
  •  1
  •   Diego Torres Milano    14 年前

    您还可以使用这种方法来提高可读性,并在一定程度上独立于使用更常见的regexp子集的实现。

    final Pattern re1 = Pattern.compile(".*;BYDAY=(.*)");
    final Pattern re2 = Pattern.compile("(?:([+-]?[0-9]*)([A-Z]{2}),?)");
    
    final Matcher matcher1 = re1.matcher(rrule);
    if ( matcher1.matches() ) {
        final String group1 = matcher1.group(1);
        Matcher matcher2 = re2.matcher(group1);
        while(matcher2.find()) {
            System.out.println("group: " + matcher2.group(1) + " " +
                        matcher2.group(2));
        }
    }
    
        2
  •  1
  •   Alan Moore Chris Ballance    14 年前

    您的ReGEX在Java中与在C语言中一样,只是在Java中只能访问每个组的最终捕获。实际上,.NET是我所知道的两种让您检索中间捕获的regex风格之一(另一种是perl 6)。

    这可能是在Java中实现您想要的最简单的方法:

    String s= "FREQ=WEEKLY;WKST=MO;BYDAY=22TU,-2WE,+223FR";
    Pattern p = Pattern.compile("(?:;BYDAY=|,)([+-]?[0-9]+)([A-Z]{2})");
    Matcher m = p.matcher(s);
    while (m.find())
    {
      System.out.printf("Interval: %5s, Day of Week: %s%n",
                        m.group(1), m.group(2));
    }
    

    以下是等效的C代码,以防您感兴趣:

    string s = "FREQ=WEEKLY;WKST=MO;BYDAY=22TU,-2WE,+223FR";
    Regex r = new Regex(@"(?:;BYDAY=|,)([+-]?[0-9]+)([A-Z]{2})");
    foreach (Match m in r.Matches(s))
    {
      Console.WriteLine("Interval: {0,5}, Day of Week: {1}",
                        m.Groups[1], m.Groups[2]);
    }
    
        3
  •  0
  •   Bart Kiers    14 年前

    我有点生疏,但我建议“注意事项”。首先,regexp有多种方言。关于这一点,有一本很棒的O'Reilly书,但是您的C实用程序可能会应用稍微不同的规则。

    作为一个例子,我使用了类似的(但不同的 tool )并且发现它确实分析了不同的东西…

    首先,它拒绝了你的regexp(可能是一个拼写错误?)开头的“*”没有意义,除非你在它前面加上一个点(.)。这样地:

    .*;BYDAY=(?:([+-]?[0-9]*)([A-Z]{2}),?)*.*
    

    现在它被接受了,但是它只“匹配”了2/WE部分,并且“跳过”了2/TU对。

    (我建议您阅读关于贪婪和非贪婪匹配的文章,以便更好地理解这一点。

    因此,我将您的模式更新如下:

    .*;BYDAY=(?:([+-]?[0-9]*)([A-Z]{2}),?),(?:([+-]?[0-9]*)([A-Z]{2}),?)*.*
    

    现在它工作了,正确地捕获了2,tu,2和我们。

    也许这有帮助?