Java Regex Group без захвата дает "нулевые" перехваты - PullRequest
0 голосов
/ 02 июня 2018

У меня есть Java-регулярное выражение с отформатированными (? :) группами без захвата, и я не могу понять, почему оно дает "нулевые" совпадения для групп без захвата.

Если я сокращаюприведенное ниже регулярное выражение "@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

Результат "@te (st) (?: aa)?"с тем же кодом:

Full match: @test
Group 1: st

Что это за первый регулярное выражение, которое соответствует группам без захвата как нулевым?

1 Ответ

0 голосов
/ 02 июня 2018

Ответ

Это шаблон регулярного выражения в вопросе:

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

Этот шаблон регулярного выражения имеет три группы захвата:

  1. ([:.\\w\\\\x7f-\\xff]+)
  2. (\\S*)
  3. (\\S*)

Итак, ваш первый пример не соответствует группам без захвата как 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
...