此RegEx捕获错误的组数

时间:2010-02-18 17:10:11

标签: java android regex

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

  

FREQ = WEEKLY; WKST = MO; BYDAY = 2TU,2WE

我想拍摄两组:

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

数字代表间隔。 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);
        ...
    }
}

grpCount == 2 - 为什么?如果我正确阅读了java文档(那一点点)我应该得到5? 0 =整个表达式,1,2,3,4 =我的捕获2,2,TU和WE。

result.group(1)==“2”;

我是一名几乎没有Java经验的C#程序员,因此我在“正则表达式工作台”中测试了RegEx,这是一个用于测试RegEx的优秀C#程序。我的RegEx工作正常。

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 个答案:

答案 0 :(得分:1)

您也可以使用这种方法来提高可读性,并使用更常见的正则表达式子集来实现某些点独立性

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));
    }
}

答案 1 :(得分:1)

你的正则表达式在Java中的工作方式与在C#中的工作方式相同;只是在Java中,您只能访问每个组的最终捕获。事实上,.NET是我所知道的仅有的两种正则表达式之一,它可以让您检索中间捕获(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]);
}

答案 2 :(得分:0)

我有点生疏,但我会建议“警告”。首先,regexp(s)有各种方言。有一本关于此的精彩O'Reilly书,但您的C#实用程序可能会应用略有不同的规则。

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

首先它拒绝了你的正则表达式(也许是一个错字?),初始的“*”没有意义,除非你在它前面放一个点(。)。像这样:

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

现在它已被接受,但它“仅匹配”2 / WE部分,并“跳过”2 / TU对。

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

因此,我按如下方式更新了您的模式:

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

现在它可以正常捕获2,TU,2和WE。

也许这有帮助?