gruppi Java Matcher: Comprendere la differenza tra “(X | Y?)” e “(:? X) | (:? Y)”

StackOverflow https://stackoverflow.com/questions/2977195

  •  24-10-2019
  •  | 
  •  

Domanda

Qualcuno può spiegare:

  1. Perché i due modelli utilizzati qui di seguito danno risultati diversi? (Risposta di seguito)
  2. Perché il 2 ° esempio dà un conteggio gruppo di 1, ma dice che l'inizio e alla fine del gruppo 1 è -1?
 public void testGroups() throws Exception
 {
  String TEST_STRING = "After Yes is group 1 End";
  {
   Pattern p;
   Matcher m;
   String pattern="(?:Yes|No)(.*)End";
   p=Pattern.compile(pattern);
   m=p.matcher(TEST_STRING);
   boolean f=m.find();
   int count=m.groupCount();
   int start=m.start(1);
   int end=m.end(1);

   System.out.println("Pattern=" + pattern + "\t Found=" + f + " Group count=" + count + 
     " Start of group 1=" + start + " End of group 1=" + end );
  }

  {
   Pattern p;
   Matcher m;

   String pattern="(?:Yes)|(?:No)(.*)End";
   p=Pattern.compile(pattern);
   m=p.matcher(TEST_STRING);
   boolean f=m.find();
   int count=m.groupCount();
   int start=m.start(1);
   int end=m.end(1);

   System.out.println("Pattern=" + pattern + "\t Found=" + f + " Group count=" + count + 
     " Start of group 1=" + start + " End of group 1=" + end );
  }

 }

che fornisce il seguente output:

Pattern=(?:Yes|No)(.*)End  Found=true Group count=1 Start of group 1=9 End of group 1=21
Pattern=(?:Yes)|(?:No)(.*)End  Found=true Group count=1 Start of group 1=-1 End of group 1=-1
È stato utile?

Soluzione

In sintesi,

1) I due modelli danno risultati diversi a causa delle regole di precedenza degli operatori.

  • partite (?:Yes|No)(.*)End (Si o No), seguita da. * Fine
  • partite (?:Yes)|(?:No)(.*)End (Si) oppure (No seguito da. * Fine)

2) Il secondo modello fornisce il conteggio di gruppo 1, ma un inizio e la fine di -1 a causa della (non necessariamente intuitivo) significati dei risultati restituiti dalle chiamate al metodo Matcher.

  • Matcher.find() restituisce true se è stata trovata una corrispondenza. Nel tuo caso la partita è stata da parte (?:Yes) del modello.
  • Matcher.groupCount() restituisce il numero di gruppi di cattura nel modello indipendentemente dal fatto che i gruppi di cattura in realtà hanno partecipato alla partita . Nel tuo caso solo la parte non cattura (?:Yes) del modello ha partecipato alla partita, ma il gruppo di cattura (.*) era ancora una parte del modello in modo che il numero di gruppo è 1.
  • Matcher.start(n) e Matcher.end(n) restituiscono l'indice di inizio e la fine della sottosequenza di pari passo con il n th gruppo di cattura. Nel tuo caso, anche se è stata trovata una corrispondenza nel complesso, il gruppo (.*) cattura non ha partecipato alla partita e quindi non catturare una sottosequenza, quindi i risultati -1.

3) (Domanda posta in commento.) Al fine di determinare quanti gruppi di cattura in realtà catturato una sottosequenza, Matcher.start(n) iterare da 0 a Matcher.groupCount() contando il numero dei non -1 risultati. (Si noti che Matcher.start(0) è il gruppo di cattura che rappresenta l'intero modello, che si consiglia di escludere per i vostri scopi.)

Altri suggerimenti

  1. La differenza è che nel secondo "(?:Yes)|(?:No)(.*)End" modello, la concatenazione ( "X seguita da Y" in "XY") ha una maggiore precedenza rispetto alla scelta (" o X o Y" in "X | Y"), come moltiplicazione ha precedenza maggiore Inoltre, in modo che il modello è equivalente a

    "(?:Yes)|(?:(?:No)(.*)End)"
    

    Cosa si voleva ottenere è il seguente schema:

    "(?:(?:Yes)|(?:No))(.*)End"
    

    Questo produce lo stesso output come primo modello.

    Nel test, il secondo modello ha il gruppo 1 al (vuoto) gamma [-1, -1[ perché questo gruppo non corrisponde (la partenza è incluso -1, -1 alla fine è esclusa, rendendo il semiaperto intervallo vuoto)

  2. A gruppo di cattura è un gruppo che possono di cattura di ingresso. Se si cattura, si dice anche che incontri alcuni sottostringa dell'ingresso. Se l'espressione regolare contiene scelte, quindi non ogni gruppo di cattura può effettivamente ingresso di cattura, per cui ci possono essere i gruppi che non corrispondono, anche se le partite regex.

  3. Il conte di gruppo, come restituito da Matcher.groupCount() , viene acquisita puramente contando le staffe di raggruppamento di gruppi di cattura , indipendentemente dal fatto che uno di loro potrebbe corrispondere in un dato ingresso. Il tuo modello ha esattamente un gruppo di acquisizione: (.*). Questo è il gruppo 1. Le documentazione afferma :

    (?:X)    X, as a non-capturing group
    

    spiega :

    Gruppi che iniziano con (? sono o puri, non cattura i gruppi che non lo fanno testo cattura e non contano ai fini del totale di gruppo, o di nome-gruppo di cattura.

    Se qualsiasi gruppo specifico partite su un dato input, è irrilevante per tale definizione. Ad esempio, nel modello (Yes)|(No), ci sono due gruppi ((Yes) è gruppo 1, è (No) gruppo 2), ma solo uno di essi può corrispondere a qualsiasi ingresso.

  4. La chiamata a Matcher.find() restituisce true se l'espressione regolare è stato abbinato su alcuni sottostringa. È possibile determinare quali gruppi abbinati, cercando in loro inizio: Se è -1, allora il gruppo non ha prodotto risultati. In tal caso, l'estremità è a -1, anche. Non v'è alcun built-in metodo che indica il numero di gruppi di cattura in realtà abbinato dopo una chiamata al find() o match(). Dovreste contare questi da soli, cercando in partenza di ogni gruppo.

  5. Quando si tratta di backreference, nota anche ciò che l'espressione regolare esercitazione ha da dire:

    C'è una differenza tra un backreference a un gruppo di cattura che nulla ha trovato, e uno per un gruppo di cattura che non ha partecipato alla partita a tutti.

A causa della precedenza del "|" operatore nel modello, il secondo modello è equivalente a:

(?:Yes)|((?:No)(.*)End)

Quello che vuoi è

(?:(?:Yes)|(?:No))(.*)End

Quando si utilizza l'espressione regolare è importante ricordare non v'è un operatore AND implicita sul lavoro. Questo può essere visto dal JavaDoc per java.util.regex.Pattern coprire gli operatori logici:

Gli operatori logici
XY X seguito da Y
X | Y X o Y
(X) X, come un gruppo di cattura

Questo AND ha la precedenza sul OR nel secondo pattern. Il secondo modello è equivalente a
(?:Yes)|(?:(?:No)(.*)End).
In modo che esso sia equivalente al primo modello di essere modificata per
(?:(?:Yes)|(?:No))(.*)End

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top