Kategorie szkoleń | Egzaminy | Kontakt
  • 1
  • 0
  • 128

Jaka jest różnica pomiędzy kwantyfikatorami zachłannymi, leniwymi i zaborczymi w wyrażeniach regularnych?

  • Zapytał
  • @ | 14.12.2015
  • TRENER MODERATOR ALTKOM AKADEMII

Odpowiedź (1)

  • 0

Spróbujmy wyjaśnić różnice na przykładzie...

Przyjmijmy, że łańcuchem wyjściowym (do którego będziemy dopasowywać wzorce) będzie słowo: rabarbar

Zadaniem wzorców będzie znalezienie ciągu znaków zakończonych sekwencją liter ar

 

Kwantyfikator zachłanny (greedy quantifier) o postaci (\w)*(ar)

Pierwsza część wyrażenia zawiera kwantyfikator zachłanny, który skonsumuje (dopasuje) na początku cały łańcuch. W tym momencie nie ma do czego dopasować drugiej części wyrażenia (nic nie pozostało). Z tego powodu sukcesywnie będzie zawężany (od końca) skonsumowany łańcuch do momentu, aż pozostanie ciąg znaków pasujący do drugiej części wyrażenia. W efekcie wyrażenie dopasuje się do maksymalnego ciągu znaków - w naszym przykładzie będzie to tekst: rabarbar

Kwantyfikator leniwy (reluctant quantifier) o postaci (\w)*?(ar)

Pierwsza część wyrażenia zawiera kwantyfikator leniwy, który nie skonsumuje na początku niczego (pusty łańcuch pasuje do tej części wyrażenia). Ponieważ kolejne znaki nie pasują do drugiej części wyrażenia, więc kwantyfikator leniwy będzie musiał konsumować kolejne znaki (od strony lewej w prawo), aż zostanie znaleziona sekwencja znaków pasująca do drugiej części wyrażenia. W efekcie dopasowana zostanie najmniejsza sekwencja znaków spełniająca kryteria zapisane w wyrażeniu regularnym - w naszym przykładzie te warunki spełniają teksty: rabar, a następnie bar

Kwantyfikator zaborczy (possessive quantifier) o postaci (\w)*+(ar)

Pierwsza część wyrażenia zawiera kwantyfikator zaborczy, który skonsumuje cały łańcuch. W tym momencie nie ma do czego dopasować drugiej części wyrażenia (nic nie pozostało). W odróżnieniu od kwantyfikatora zachłannego, ten nie "odda" znaków, które łapczywie skonsumował, aby dopasować drugą część wyrażenia - w efekcie w naszym przykładzie nie będzie żadnego dopasowania.

Aby przekonać się, czy tak jest faktycznie można uruchomić poniższy program:

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

public class Test {
  private static final String TEKST = "rabarbar";

  public static void main(String[] args) {
    dopasuj("ZACHŁANNY", "(\\w)*(ar)");
    dopasuj("LENIWY", "(\\w)*?(ar)");
    dopasuj("ZABORCZY", "(\\w)*+(ar)");
  }

  private static void dopasuj(String opis, String wzorzec) {
    System.out.printf("%nTEKST: %s, WZORZEC %s: %s%n", TEKST, opis, wzorzec);
    Pattern pattern = Pattern.compile(wzorzec);
    Matcher matcher = pattern.matcher(TEKST);

    int counter = 1;
    if (matcher.find()) {
      do {
        System.out.printf("dopasowanie #%d --> '%s' (start = %d, end = %d)%n", 
                          counter++, matcher.group(), matcher.start(), matcher.end());
      } while (matcher.find());
    } else {
      System.out.println("brak dopasowania");
    }
  }
}

Wynik działania programu jest następujący:

TEKST: rabarbar, WZORZEC ZACHŁANNY: (\w)*(ar)
dopasowanie #1 --> 'rabarbar' (start = 0, end = 8)

TEKST: rabarbar, WZORZEC LENIWY: (\w)*?(ar)
dopasowanie #1 --> 'rabar' (start = 0, end = 5)
dopasowanie #2 --> 'bar' (start = 5, end = 8)

TEKST: rabarbar, WZORZEC ZABORCZY: (\w)*+(ar)
brak dopasowania

 

 

 

 

  • Odpowiedział
  • @ | 15.12.2015
  • TRENER MODERATOR ALTKOM AKADEMII