Java非捕获正则表达式组提供" null"捕获

时间:2018-06-02 03:43:36

标签: java regex regex-group

我有一个带有(?:)格式的非捕获组的java正则表达式,我无法理解为什么它会给出" null"匹配非捕获组。

如果我将下面的正则表达式缩短为" @te(st)(?:aa)?"使用相同的?:非捕获组,它给出我认为的预期行为,仅匹配1组和完全匹配。

请参阅下面的正则表达式:

package com.company;

import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class Main {

    public static void main(String[] args) {
        final String regex = "@test\\s+([:.\\w\\\\x7f-\\xff]+)(?:[\\t ]+(\\S*))?(?:[\\t ]+(\\S*))?\\s*$";
        final String string = "    /**\n     * @test     TestGroup\n     */\n";

        final Pattern pattern = Pattern.compile(regex, Pattern.MULTILINE);
        final Matcher matcher = pattern.matcher(string);

        while (matcher.find()) {
            System.out.println("Full match: " + matcher.group(0));
            for (int i = 1; i <= matcher.groupCount(); i++) {
                System.out.println("Group " + i + ": " + matcher.group(i));
            }
        }
    }
}

结果:

Full match: @test     TestGroup
Group 1: TestGroup
Group 2: null
Group 3: null

&#34; @te(st)(?:aa)的结果?&#34;使用相同的代码:

Full match: @test
Group 1: st

第一个将非捕获组匹配为null的正则表达式是什么?

1 个答案:

答案 0 :(得分:3)

答案

这是问题中的正则表达式模式:

"@test\\s+([:.\\w\\\\x7f-\\xff]+)(?:[\\t ]+(\\S*))?(?:[\\t ]+(\\S*))?\\s*$"

此正则表达式模式有三个捕获组:

  1. ([:.\\w\\\\x7f-\\xff]+)
  2. (\\S*)
  3. (\\S*)
  4. 因此,您的第一个示例未将非捕获组与null匹配。相反,正如预期的那样,它将最后两个捕获组匹配为null

    匹配所有捕获组的另一个示例

    如果我们将示例字符串更改为可匹配模式中所有三个捕获组的内容,我们将看到三个匹配项。例如:

    import java.util.regex.Matcher;
    import java.util.regex.Pattern;
    
    public class Main {
    
        public static void main(String[] args) {
            final String regex = "@test\\s+([:.\\w\\\\x7f-\\xff]+)(?:[\\t ]+(\\S*))?(?:[\\t ]+(\\S*))?\\s*$";
            final String string = "foo @test : bar baz\n";
            // final String string = "    /**\n     * @test     TestGroup\n     */\n";
    
            final Pattern pattern = Pattern.compile(regex, Pattern.MULTILINE);
            final Matcher matcher = pattern.matcher(string);
    
            while (matcher.find()) {
                System.out.println("Full match: " + matcher.group(0));
                for (int i = 1; i <= matcher.groupCount(); i++) {
                    System.out.println("Group " + i + ": " + matcher.group(i));
                }
            }
        }
    }
    

    上述代码的输出是:

    Full match: @test : bar baz
    
    Group 1: :
    Group 2: bar
    Group 3: baz
    

    其他语言中的更多示例如下所示,表明此行为在各种实现中大致相同。

    Python示例

    import re
    
    regex = re.compile('@test\\s+([:.\\w\\\\x7f-\\xff]+)(?:[\\t ]+(\\S*))?(?:[\\t ]+(\\S*))?\\s*$', re.MULTILINE)
    s1 = '    /**\n     * @test     TestGroup\n     */\n'
    s2 = 'foo @test : bar baz';
    
    match = re.search(regex, s1)
    for i in range(regex.groups + 1):
        print('Group {}: {}'.format(i, match.group(i)))
    print()
    
    match = re.search(regex, s2)
    for i in range(regex.groups + 1):
        print('Group {}: {}'.format(i, match.group(i)))
    

    输出结果为:

    Group 0: @test     TestGroup
    Group 1: TestGroup
    Group 2: None
    Group 3: None
    
    Group 0: @test : bar baz
    Group 1: :
    Group 2: bar
    Group 3: baz
    

    第二次匹配显示非捕获组内的捕获组确实匹配。唯一与Python没什么不同的是,不匹配的组不会出现在第一个示例的输出中。

    JavaScript示例

    var regex = new RegExp('@test\\s+([:.\\w\\\\x7f-\\xff]+)(?:[\\t ]+(\\S*))?(?:[\\t ]+(\\S*))?\\s*$', 'm')
    var s1 = '    /**\n     * @test     TestGroup\n     */\n'
    var s2 = 'foo @test : bar baz';
    var i
    
    var result = regex.exec(s1)
    for (i = 0; i < result.length; i++) {
        console.log('result[' + i + '] :', result[i])
    }
    console.log()
    
    var result = regex.exec(s2)
    for (i = 0; i < result.length; i++) {
        console.log('result[' + i + '] :', result[i])
    }
    

    输出结果为:

    result[0] : @test     TestGroup
    result[1] : TestGroup
    result[2] : undefined
    result[3] : undefined
    
    result[0] : @test : bar baz
    result[1] : :
    result[2] : bar
    result[3] : baz
    

    PHP示例

    <?php
    $regex = "/@test\\s+([:.\\w\\\\x7f-\\xff]+)(?:[\\t ]+(\\S*))?(?:[\\t ]+(\\S*))?\\s*$/m";
    $s1 = "    /**\n     * @test     TestGroup\n     */\n";
    $s2 = "foo @test : bar baz";
    
    preg_match($regex, $s1, $matches);
    for ($i = 0; $i < count($matches); $i++) {
        echo "Match $i: $matches[$i]\n";
    }
    echo "\n";
    
    preg_match($regex, $s2, $matches);
    for ($i = 0; $i < count($matches); $i++) {
        echo "Match $i: $matches[$i]\n";
    }
    ?>
    

    输出结果为:

    Match 0: @test     TestGroup
    Match 1: TestGroup
    
    Match 0: @test : bar baz
    Match 1: :
    Match 2: bar
    Match 3: baz