Expresión regular con número variable de grupos?

¿Es posible crear una expresión regular con un número variable de grupos?

Después de ejecutar esto, por ejemplo …

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

… Me gustaría tener algo así como

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

(Fondo: estoy analizando algunas líneas de datos, y uno de los “campos” se repite. Me gustaría evitar un bucle matcher.find para estos campos).


Como señala @Tim Pietzcker en los comentarios, perl6 y .NET tienen esta característica.

De acuerdo con la documentación , las expresiones regulares de Java no pueden hacer esto:

La entrada capturada asociada con un grupo es siempre la subsecuencia con la que el grupo coincidió más recientemente . Si un grupo se evalúa por segunda vez debido a la cuantificación, su valor capturado previamente, si lo hubiera, se conservará si falla la segunda evaluación. Coincidiendo con la cadena “aba” contra la expresión (a (b)?) +, Por ejemplo, deja el grupo dos establecido en “b”. Toda la entrada capturada se descarta al comienzo de cada partida.

(énfasis añadido)

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

debería hacer lo que quieras

EDITAR:

@aioobe, lo entiendo ahora. Quieres ser capaz de hacer algo como la gramática

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

y saca todas las coincidencias individuales de Bar .

No, no hay forma de hacerlo usando java.util.regex . Puede volver a recurrir y usar una expresión regular en la coincidencia de Bars o usar un generador de analizador como ANTLR y adjuntar un efecto secundario a Bar .

Puede usar división para obtener los campos que necesita en una matriz y recorrerlos.

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

No he usado java regex, pero para muchos idiomas la respuesta es: No.

Parece que se crean grupos de captura cuando se analiza la expresión regular y se llena cuando coincide con la cadena. La expresión (a)|(b)(c) tiene tres grupos de captura, solo si se puede llenar uno o dos de ellos. (a)* tiene solo un grupo, el analizador sale del último partido del grupo después de la coincidencia.

Creo que retroceder inhibe este comportamiento y decir el efecto de /([\S\s])/ en su estado acumulativo de agrupación en algo parecido a la Biblia. Incluso si se puede hacer, la salida es incognoscible ya que los grupos perderán el significado posicional. Es mejor hacer una expresión regular por separado en el mismo tipo en un sentido global y hacer que se deposite en una matriz.

Acabo de tener el problema muy similar y logré hacer un “número variable de grupos”, pero una combinación de un ciclo while y restablecer el 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(); } 

Pero esto es por mi problema (con dos repeticiones

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

Se pierde la capacidad de especificar una duración de repetición arbitraria con * o + porque look-ahead y look-behind deben ser de la longitud predecible.