Espressione regolare con numero variabile di gruppi?

È ansible creare un’espressione regolare con un numero variabile di gruppi?

Dopo aver eseguito questo ad esempio …

Pattern p = Pattern.compile("ab([cd])*ef"); Matcher m = p.matcher("abcddcef"); m.matches(); 

… Mi piacerebbe avere qualcosa di simile

  • m.group(1) = "c"
  • m.group(2) = "d"
  • m.group(3) = "d"
  • m.group(4) = "c" .

(Sfondo: sto analizzando alcune righe di dati, e uno dei “campi” si sta ripetendo. Vorrei evitare un matcher.find loop per questi campi.)


Come sottolineato da @Tim Pietzcker nei commenti, perl6 e .NET hanno questa caratteristica.

Secondo la documentazione , le espressioni regolari di Java non possono farlo:

L’input acquisito associato a un gruppo è sempre la sottosequenza con cui il gruppo è stato associato più di recente . Se un gruppo viene valutato una seconda volta a causa della quantificazione, il valore precedentemente acquisito, se presente, verrà mantenuto se la seconda valutazione fallisce. Adattare la stringa “aba” rispetto all’espressione (a (b)?) +, Ad esempio, lascia il gruppo due impostato su “b”. Tutti gli input catturati vengono scartati all’inizio di ogni incontro.

(enfasi aggiunta)

 Pattern p = Pattern.compile("ab(?:(c)|(d))*ef"); Matcher m = p.matcher("abcdef"); m.matches(); 

dovrebbe fare quello che vuoi

MODIFICARE:

@ Aioobe, ho capito ora. Vuoi essere in grado di fare qualcosa come la grammatica

 A ::==    Foo ::== "foo" Baz ::== "baz" Bars ::==   | ε Bar ::== "A" | "B" 

e tira fuori tutte le partite individuali di Bar .

No, non c’è modo di farlo usando java.util.regex . Puoi recurse e utilizzare una regex sulla corrispondenza di Bars o utilizzare un parser generator come ANTLR e colbind un effetto collaterale a Bar .

Puoi usare split per ottenere i campi necessari in un array e scorrere attraverso quello.

http://download.oracle.com/javase/1,5.0/docs/api/java/lang/String.html#split(java.lang.String )

Non ho usato regex java, ma per molte lingue la risposta è: No.

Cattura di gruppi sembrano essere creati quando la regex viene analizzata e riempita quando corrisponde alla stringa. L’espressione (a)|(b)(c) ha tre gruppi di cattura, solo se uno o due di essi possono essere riempiti. (a)* ha un solo gruppo, il parser lascia l’ultima partita nel gruppo dopo averlo trovato.

Penserei che il backtracking inibisca questo comportamento e dica l’effetto di /([\S\s])/ nel suo stato cumulativo di raggruppamento su qualcosa come la Bibbia. Anche se può essere fatto, l’output è inconoscibile poiché i gruppi perderanno il significato posizionale. È meglio fare una regex distinta su un tipo simile in senso globale e farla depositare in un array.

Ho appena avuto il problema molto simile, e sono riuscito a fare “numero variabile di gruppi” ma una combinazione di un ciclo while e il reset del matcher.

  int i=0; String m1=null, m2=null; while(matcher.find(i) && (m1=matcher.group(1))!=null && (m2=matcher.group(2))!=null) { // do work on two found groups i=matcher.end(); } 

Ma questo è per il mio problema (con due ripetizioni

  Pattern pattern = Pattern.compile("(?<=^ab[cd]{0,100})[cd](?=[cd]{0,100}ef$)"); Matcher matcher = pattern.matcher("abcddcef") int i=0; String res=null; while(matcher.find(i) && (res=matcher.group())!=null) { System.out.println(res); i=matcher.end(); } 

Si perde la possibilità di specificare la lunghezza arbitraria della ripetizione con * o + perché look-ahead e look-behind devono essere della lunghezza prevedibile.