Групи захоплення Java Regex


170

Я намагаюся зрозуміти цей блок коду. У першому, що саме ми шукаємо у виразі?

Я розумію, що це будь-який символ (0 або більше разів *), за яким слід будь-яке число між 0 і 9 (один або більше разів +), а за ним будь-який символ (0 або більше разів *).

Коли це виконується, результат:

Found value: This order was placed for QT3000! OK?
Found value: This order was placed for QT300
Found value: 0

Може хтось, будь ласка, пережив це зі мною?

Яка перевага використання груп захоплення?

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

public class RegexTut3 {

    public static void main(String args[]) {
        String line = "This order was placed for QT3000! OK?"; 
        String pattern = "(.*)(\\d+)(.*)";

        // Create a Pattern object
        Pattern r = Pattern.compile(pattern);

        // Now create matcher object.
        Matcher m = r.matcher(line);

        if (m.find()) {
            System.out.println("Found value: " + m.group(0));
            System.out.println("Found value: " + m.group(1));
            System.out.println("Found value: " + m.group(2));
        } else {
            System.out.println("NO MATCH");
        }
    }

}

1
Щоб вставити новий рядок, розмістіть 2 пробіли в кінці рядка. Детальніше про уцінку синтаксису: en.wikipedia.org/wiki/Markdown - Дивіться також: stackoverflow.com/editing-help
assylias

Відповіді:


248

Проблема з типом кількісного показника. Ви використовуєте жадний кількісний показник у своїй першій групі (індекс 1 - індекс 0 являє собою ціле Pattern), а це означає, що він відповідатиме скільки завгодно (а оскільки це будь-який символ, він відповідатиме стільки символів, скільки є з метою виконання умови для наступних груп).

Коротше кажучи, ваша 1-я група .*відповідає будь-чому, поки наступна група \\d+може щось відповідати (у цьому випадку останньою цифрою).

Відповідно до третьої групи, вона відповідатиме будь-чому після останньої цифри.

Якщо ви зміните його на неохоче квантор у вашій 1-й групі, ви отримаєте результат, який, я думаю, ви очікуєте, тобто 3000 частину.

Зверніть увагу на знак питання в 1-й групі.

String line = "This order was placed for QT3000! OK?";
Pattern pattern = Pattern.compile("(.*?)(\\d+)(.*)");
Matcher matcher = pattern.matcher(line);
while (matcher.find()) {
    System.out.println("group 1: " + matcher.group(1));
    System.out.println("group 2: " + matcher.group(2));
    System.out.println("group 3: " + matcher.group(3));
}

Вихід:

group 1: This order was placed for QT
group 2: 3000
group 3: ! OK?

Більше інформації про Java Pattern тут .

Нарешті, групи захоплення розмежовані круглими дужками і забезпечують дуже корисний спосіб використання зворотних посилань (серед іншого), як тільки ваша Patternвідповідність вводиться.

На Java 6 групи можуть посилатися лише на їх порядок (остерігайтеся вкладених груп та тонкощів упорядкування).

У Java 7 це набагато простіше, оскільки ви можете використовувати названі групи.


Дякую! Чи зберігається причина 2 у групі 0, оскільки весь рядок був використаний жадібним квантором, який потім відступав, поки він не контактував з одним або кількома числами. 0 задовольнили це, тому вираз вдався. Я вважаю третю групу заплутаною, чи цей жадібний кількісний показник також споживає весь рядок, але відступає, поки не знайде одне чи більше чисел (\\ d +), які повинні йому передувати?
Xivilai

@Xivilai дозвольте мені тонко налагодити своє пояснення у своїй відповіді, лише на секунду.
Мена

Це гарне пояснення. Тож неохоче починається зліва і просто бере мінімум, тоді як з жадібним, це займе якомога більше (починаючи з правого), зупиняючись лише перед останньою цифрою, щоб задовольнити цю умову. Третя група бере решту.
Xivilai

@Xivilai більш-менш. Це завжди починається зліва, хоча в цьому випадку. Ось додаткова інформація про кількісні показники.
Мена

2
У Java 5/6 можна використовувати названі групи захоплення named-regexp.

16

Це абсолютно нормально.

  1. Перша група ( m.group(0)) завжди фіксує всю область, яку охоплює ваш регулярний вираз . У цьому випадку це вся струна.
  2. Регулярні вирази за замовчуванням жадібні, це означає, що перша група захоплює якомога більше, не порушуючи регулярного вираження. (.*)(\\d+)(Перша частина вашого регулярного виразу) охоплює ...QT300Int першу групу і 0в другому.
  3. Ви можете швидко виправити це, зробивши першу групу не жадібною: змінити (.*)на (.*?).

Для отримання додаткової інформації про жадібні проти ледачих, перегляньте цей сайт.


4

Від док.

Capturing groups</a> are indexed from left
 * to right, starting at one.  Group zero denotes the entire pattern, so
 * the expression m.group(0) is equivalent to m.group().

Тож група захоплення 0 надсилає весь рядок.


3

Ваше розуміння правильне. Однак, якщо ми проходимо через:

  • (.*) проковтне цілу струну;
  • йому потрібно буде повернути символи таким чином, щоб (\\d+)вони були насиченими (саме тому 0захоплюється, а не 3000);
  • останнє (.*)тоді захопить решту.

Я не впевнений, яким був початковий задум автора.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.