Java,Regex,嵌套可选组

时间:2015-03-31 03:29:09

标签: java regex

我试图用Java捕获嵌套的可选组,但它没有用完。

我尝试捕获关键字后跟一个间隔,其中关键字现在是任何东西,间隔只是两个日期。间隔可以是可选的,并且两个日期也可以是可选的。所以,以下是有效的匹配。

  • 字[01/01/1900,]
  • 字[,01/01/2000]
  • 字[01/01/1900,01/01/2000]

我想捕获关键字和两个日期,即使它们为空。

这是我提出的Java MWE。

public class Parser {
    public static void main(String[] args) {
        Parser parser = new Parser();
        String s = "word [01/01/1900, 01/01/2000]";
        parser.parse(s);
    }

    public void parse(String s) {
        String date = "\\d{2}/\\d{2}/\\d{4}";
        String interval = "\\[("+date+")?, ("+date+")?\\]";
        String keyword = "(.+)( "+interval+")?";
        Pattern p = Pattern.compile(keyword);
        Matcher m = p.matcher(s);
        if (m.matches()) {
            for (int i = 0; i <= m.groupCount(); ++i) {
                System.out.println(i + ": " + m.group(i));
            }
        }
    }
}

这是输出

0: word [01/01/1900, 01/01/2000]
1: word [01/01/1900, 01/01/2000]
2: null
3: null
4: null

如果间隔不是可选的,那么它可以正常工作。

String keyword = "(.+)( "+interval+")";

0: word [01/01/1900, 01/01/2000]
1: word
2:  [01/01/1900, 01/01/2000]
3: 01/01/1900
4: 01/01/2000

如果interval是不匹配的组(但仍然是可选的),那么它就不起作用。

String keyword = "(.+)(?: "+interval+")?";

0: word [01/01/1900, 01/01/2000]
1: word [01/01/1900, 01/01/2000]
2: null
3: null

我需要做什么才能找回这两个日期?谢谢。


编辑:第2部分。

假设现在我注意匹配重复的关键字。即正则表达式,keyword(, keyword)*。我尝试了这个,但只捕获了第一个和最后一个实例。

为简单起见,假设我想将以下a, b, c, d与正则表达式([a-z])(?:, ([a-z]))*匹配

但是,我只能找回第一组和最后一组。

0: a, b, c, d
1: a
2: d

为什么会这样?

刚刚发现无法做到这一点。 Capture group multiple times

1 个答案:

答案 0 :(得分:0)

keyword的第一部分从(.+)更改为(.+?)

如果没有?,则(.+)贪心量词。这意味着它将尝试尽可能多地匹配。我不知道正则表达式引擎是如何工作的所有机制,但我相信在你的情况下,它所做的是将一些计数器N设置为源中剩余的字符数。如果它可以消耗那么多的字符并使整个正则表达式匹配,它就会。否则,它会尝试N-1N-2等,直到整个正则表达式匹配为止。在尝试这个时,我也认为它从左到右;也就是说,因为(.+)是最左边的&#34;部分&#34;对于模式(对于&#34; part&#34;的某些定义),它在尝试对右边的部分进行任何循环之前在该部分上循环。因此,使(.+)贪婪比使模式的任何其他部分贪婪更重要; <{1}}优先。

在你的情况下,由于(.+)后跟一个可选部分,正则表达式匹配器首先尝试字符串的整个剩余部分 - 并且它成功,因为字符串的其余部分是空的,是可选子字符串的精确匹配。这也应该解释为什么如果您的子字符串不可选,它不起作用 - 空子字符串不再匹配。

添加(.+)使其成为&#34;不情愿的&#34; (或&#34;吝啬&#34;)量词,其工作方向相反。首先看看它是否可以匹配0个字符,然后是1,2,......,而不是从N开始向下。因此,当它达到5,匹配?时,它会发现字符串的其余部分与您的可选部分匹配,它会完成并提供您期望的结果。