2013-07-31 20 views
103

Sto cercando di capire questo blocco di codice. Nel primo, che cosa stiamo cercando nell'espressione?Gruppi di acquisizione di Java Regex

La mia comprensione è che si tratta di qualsiasi carattere (0 o più volte *) seguito da qualsiasi numero compreso tra 0 e 9 (una o più volte +) seguito da qualsiasi carattere (0 o più volte *).

Quando questo viene eseguito il risultato è:

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

Qualcuno potrebbe passare attraverso questo con me?

Qual è il vantaggio dell'utilizzo di Catturare gruppi?

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"); 
     } 
    } 

} 
+0

Per inserire una nuova riga, posizionare 2 spazi alla fine della riga. Ulteriori informazioni sulla sintassi markdown: http://en.wikipedia.org/wiki/Markdown - Vedi anche: http: //stackoverflow.com/editing-help – assylias

risposta

158

Il problema riscontrato è con il tipo di quantificatore. Stai usando un avido quantificatore nel primo gruppo (indice - indice 0 rappresenta l'intero Pattern), il che significa che sarà corrisponde tanto quanto può (e dal momento che è qualsiasi carattere, sarà corrisponde a come molti caratteri come ci sono per soddisfare la condizione per i gruppi successivi).

In breve, il tuo gruppo 1 .* corrisponde a qualsiasi cosa purché il gruppo successivo \\d+ possa corrispondere a qualcosa (in questo caso, l'ultima cifra).

Come per il terzo gruppo, corrisponderà a qualsiasi cosa dopo l'ultima cifra.

Se si modifica a un riluttante quantificatore nel 1 ° gruppo, si otterrà il risultato suppongo ci si aspetta, cioè la parte .

Annotare il punto interrogativo nel 1o gruppo.

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)); 
} 

uscita:

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

Maggiori informazioni su Java Patternhere.

Infine, i gruppi di cattura sono delimitati da parentesi tonde e forniscono un modo molto utile per utilizzare i riferimenti a ritroso (tra le altre cose), una volta che lo Pattern corrisponde all'ingresso.

Nei gruppi Java 6 è possibile fare riferimento solo al loro ordine (attenzione ai gruppi nidificati e alla sottigliezza dell'ordine).

In Java 7 è molto più semplice, in quanto è possibile utilizzare i gruppi denominati.

+0

Grazie! È il motivo per cui il gruppo 2 ha memorizzato 0 perché l'intera riga è stata consumata dal quantificatore goloso che è poi retrocesso fino a quando non è entrato in contatto con uno o più numeri. 0 soddisfatto questo quindi l'espressione è riuscita. Trovo che il terzo gruppo confonda, che quel quantificatore avido consuma anche l'intera linea, ma arretra finché non trova uno o più numeri (\\ d +) che dovrebbe precederlo? – Xivilai

+0

@Xivilai fammi sintonizzare la mia spiegazione nella mia risposta, solo un secondo. – Mena

+0

Questa è una buona spiegazione. Quindi il riluttante parte da sinistra e prende il minimo mentre con l'avido, prenderà il più possibile (partendo da destra), fermandosi prima dell'ultima cifra per soddisfare quella condizione. Il terzo gruppo prende il resto. – Xivilai

3

La tua comprensione è corretta. Tuttavia, se attraversiamo:

  • (.*) inghiottirà l'intera stringa;
  • sarà necessario restituire i caratteri in modo che (\\d+) sia saturato (motivo per cui 0 viene catturato e non 3000);
  • l'ultimo (.*) quindi catturerà il resto.

Non sono sicuro di quale fosse l'intento originale dell'autore.

1

Dal doc:

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(). 

Quindi catturare gruppo 0 inviare tutta la linea.

11

Questo è assolutamente OK.

  1. Il primo gruppo (m.group(0)) cattura sempre tutta l'area che è coperto dalla vostra espressione regolare. In questo caso, è l'intera stringa.
  2. Le espressioni regolari sono avide per impostazione predefinita, ovvero il primo gruppo acquisisce il più possibile senza violare la regex. Il (.*)(\\d+) (la prima parte della tua regex) copre il ...QT300 int il primo gruppo e il 0 nel secondo.
  3. È possibile risolvere rapidamente questo problema rendendo il primo gruppo non-goloso: modificare (.*) in (.*?).

Per maggiori informazioni su avido vs pigro, controllare this site.

Problemi correlati