【问题标题】:Java, Regex, Nested optional groupsJava、Regex、嵌套可选组
【发布时间】:2015-06-04 06:56:19
【问题描述】:

我正在尝试在 Java 中捕获嵌套的可选组,但没有成功。

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

  • 字 [01/01/1900, ]​​i>
  • 字 [, 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

如果间隔是一个不匹配的组(但仍然是可选的),那么它不起作用。

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

【问题讨论】:

    标签: java regex


    【解决方案1】:

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

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

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

    添加? 使其成为“不情愿”(或“吝啬”)量词,其作用方向相反。它首先查看是否可以匹配 0 个字符,然后是 1、2、...,而不是从 N 开始并向下。因此,当它达到 5 时,匹配 "word ",并且它发现字符串的其余部分与您的可选部分匹配,它完成并给出您期望的结果。

    【讨论】:

    • 您好,感谢您快速详细的解释!它现在正在工作。但是,我还有 1 个问题要问,我已将其作为问题的编辑提出。我以前没有问过这个问题,因为我认为它与上一个问题相似。你知道为什么吗?
    • 因为正则表达式并非旨在解决世界上的所有问题。实际上,我想不出为什么该语言不能有一个“多组”可以为重复捕获组保留并返回多个匹配项的技术原因。我猜对这种功能的需求并不大。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-12-08
    • 2013-03-06
    • 2019-04-04
    • 2014-07-07
    • 1970-01-01
    相关资源
    最近更新 更多