【问题标题】:Why does a flag in a capture group remove the group?为什么捕获组中的标志会删除该组?
【发布时间】:2019-01-27 04:33:35
【问题描述】:

在以下代码中,(?i:hot) 是一个捕获组。或者至少应该是......它匹配表达式并消耗字符。

但是,当我尝试获取组数时,它返回 0。

Pattern pattern = Pattern.compile("(?i:hot)");
Matcher matcher = pattern.matcher("hot diggity dog");
while (matcher.find()) {
    int groupCount = matcher.groupCount(); // returns 0
    for (int i = 0; i <= groupCount; i++) {
        System.out.printf("%d. %s%n", i, matcher.group(i));
    }
}

括号确实捕获。如您所见,如果我们这样做了

matcher.replaceAll("cold")

它会返回“cold diggity dog”

我希望 (?i:hot) 等价于 ((?i)hot),但事实并非如此。后一种情况是捕获组。

这不是 Java RegEx Matcher.groupCount returns 0 的副本,因为在那个问题中,确实没有捕获组,因此 groupCount 正确返回 0。但是在我的情况下,这确实应该被视为捕获组,因为它确实执行捕获!

【问题讨论】:

  • 我不认为这是一个捕获组 - 相反,我认为语法 (?i 意味着将内部部分解释为带有 @987654329 的 非捕获组 @ 旗帜。字符被消耗,但未被捕获,可能是regex101.com/r/1yCnzv/1
  • 它不是那个的副本。在这种情况下,没有指定捕获组,因此 groupCount 正确返回 0。在我的情况下,模式是从表达式中捕获字符。
  • 它不是捕获组。第一个评论者是正确的。参考the documentation
  • 这不是因为(?:blah) 是非捕获组的语法。 阅读文档

标签: java regex


【解决方案1】:

就在documentation

(?idmsux-idmsux:X)  X,作为一个非捕获组,具有给定标志 idmsux on - off

如果你想要一个捕获组,只需将它包装在另一组括号中:

((?i:hot))

【讨论】:

    【解决方案2】:

    您正在使用?i:。这不是忽略大小写的提示,而是非捕获组的语法。我发现的一个用例是在正则表达式的中间使用 (?i) 来忽略反向引用\1 的大小写匹配。下面是使用它的程序的修改版本

    Pattern pattern = Pattern.compile("\\b(\\w+)(\\W+(?i:\\1)\\b)+");
    Matcher matcher = pattern.matcher("Hello hello");
        while (matcher.find()) {
            int groupCount = matcher.groupCount(); // returns 0
            for (int i = 0; i <= groupCount; i++) {
                System.out.printf("%d. %s%n", i, matcher.group(i));
            }
        }
    

    【讨论】:

    • 这不是向前或向后。这是一个提示正则表达式处理器忽略此“捕获组”(或任何您想要调用的名称)中的大小写
    • 那为什么会忽略大小写呢? ?i 不编译(?i hot)。您必须将其括在括号中 ((?i)hot)。为什么?
    • 如果你删除关于前瞻的位,我会检查你
    • @VictorGrazi 检查Pattern.class 第2048 行和第2894 行的源代码。基于此,可以清楚地看出,如果模式以(? 开头并且没有以下字符为:=!&gt;&lt;$@,那么它会继续到default 部分并检查第二个连续字符必须是):,否则抛出错误。所以肖恩说的是对的(?...)是非捕获组的语法。
    • 很棒的用例和很棒的提示!谢谢
    【解决方案3】:

    TL;博士

    我希望(?i:hot) 等同于((?i)hot),但事实并非如此。后一种情况是捕获组。

    几乎所有正则表达式引擎都会在看到同一级别的右括号后立即关闭内联修饰符。所以除了捕获部分之外,以上两者都是等价的。

    第一个语法完全是另外一回事。

    模式修改跨度

    括号不应该表示捕获组或非捕获组,但它们可以将不同的功能带入可能捕获或不捕获的用法中。紧跟问号的所有左括号对于正则表达式引擎都有特殊含义:

    (?...)
    

    标志i 是一个修饰符。修饰符可以在正则表达式上下文之外启用,但一些正则表达式引擎支持 内联修饰符 的语法,这使您能够在正则表达式本身内启用它们。因此inline这个词:

    (?i)test(?-i)
     ^        ^
     E        D
    

    另一方面,还有另一种类似的语法,称为 mode-modified span(?modifiers:...),它类似于一个非捕获组 (?:...),它有一些修饰符在?: 之间,并将它们应用于包含的子表达式:

    (?i:test)
    

    话虽如此,(?i)test(?-i)(?i:test) 都是相等的。此功能应该启用/禁用修饰符。期间。

    我们不希望它提供更多功能。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2018-07-07
      • 2013-01-25
      • 2019-03-08
      • 1970-01-01
      • 1970-01-01
      • 2017-08-03
      • 2016-02-09
      • 1970-01-01
      相关资源
      最近更新 更多