Expressão regular com número variável de grupos?

É possível criar uma expressão regular com um número variável de grupos?

Depois de executar isso, por exemplo …

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

… eu gostaria de ter algo parecido

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

(Background: Estou analisando algumas linhas de dados e um dos “campos” está repetindo. Eu gostaria de evitar um loop matcher.find para esses campos.)


Como apontado por @Tim Pietzcker nos comentários, o perl6 e o .NET possuem esse recurso.

   

De acordo com a documentação , as expressões regulares do Java não podem fazer isso:

A input capturada associada a um grupo é sempre a subsequência que o grupo mais recentemente combinou. Se um grupo for avaliado uma segunda vez devido à quantificação, o valor anteriormente capturado, se houver, será retido se a segunda avaliação falhar. Combinando a string “aba” contra a expressão (a (b)?) +, Por exemplo, deixa o grupo dois definido como “b”. Toda input capturada é descartada no início de cada partida.

(enfase adicionada)

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

deve fazer o que quiser.

EDITAR:

@aioobe, eu entendo agora. Você quer ser capaz de fazer algo parecido com a gramática

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

e puxe todas as partidas individuais do Bar .

Não, não há como fazer isso usando java.util.regex . Você pode recorrer e usar um regex na correspondência de Bars ou usar um gerador de analisador como o ANTLR e append um efeito colateral ao Bar .

Você pode usar a divisão para obter os campos que você precisa em uma matriz e percorrê-lo.

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

Eu não usei java regex, mas para muitos idiomas a resposta é: Não.

Grupos de captura parecem ser criados quando o regex é analisado e preenchido quando corresponde à string. A expressão (a)|(b)(c) tem três grupos de captura, somente se um ou dois deles puderem ser preenchidos. (a)* tem apenas um grupo, o analisador deixa a última correspondência do grupo após a correspondência.

Eu pensaria que o retrocesso inibe esse comportamento e diz o efeito de /([\S\s])/ em seu estado acumulativo de agrupamento em algo como a Bíblia. Mesmo que isso possa ser feito, a saída é incognoscível, pois os grupos perderão o significado posicional. É melhor fazer um regex separado do tipo em um sentido global e tê-lo depositado em um array.

Acabei de ter o problema muito semelhante, e consegui fazer “número variável de grupos”, mas uma combinação de um loop while e redefinir o 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(); } 

Mas isso é para o meu problema (com dois repetindo

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

Você perde a capacidade de especificar o comprimento arbitrário de repetição com * ou + pois a antecipação e a aparência devem ser do tamanho previsível.