2011-08-27 15 views
11

Aquí es simple patrón: [key]: [value1] [value2] [value3] [valueN]Java 6 varias coincidencias de expresiones regulares de un grupo

quiero llegar:

  1. clave
  2. matriz de valores

Aquí es mi expresión regular: ^([^:]+):(:? ([^ ]+))++$

Aquí está mi texto: foo: a b c d

Matcher me da 2 grupos: foo (como clave) y d (como valores).

Si uso +? en lugar de ++ obtengo a, no d.

Entonces java me devuelve la primera (o última) ocurrencia del grupo.

No puedo usar find() aquí porque solo hay una coincidencia.

¿Qué puedo hacer excepto dividir expresiones regex en 2 partes y usar find para la matriz de valores? He trabajado con expresiones regulares en muchos otros entornos y casi todos ellos tienen la capacidad de buscar "primera aparición del grupo 1", "segunda aparición del grupo 1" y así sucesivamente.

¿Cómo puedo hacer con java.util.regex en JDK6?

Gracias.

+0

¿Puede por favor aclarar el punto sobre la existencia de "una única * * partido?" No hay forma de capturar una cantidad indeterminada de coincidencias como las que está pidiendo, por lo que se requiere alguna iteración aquí. – seh

+0

¡Ya es 2013 y aún no hay una solución decente para este problema! * facepalm * – altern

Respuesta

9

El número total de grupos de coincidencias no depende de la cadena de destino ("foo: a b c d", en su caso), sino del patrón. Su patrón siempre tendrá 3 grupos:

^([^:]+):(:? ([^ ]+))++$ 
^  ^^
|  | | 
1  2 3 

El grupo 1 st llevaremos a cabo su clave, y el 2 nd grupo, que coincide con el mismo en el grupo 3, pero luego incluye un espacio en blanco, será siempre mantenga solo 1 de sus valores. Estos son los primeros valores (en el caso de los +? no codificados) o el último valor (en el caso de concordancia ambiciosa).

Lo que podría hacer es sólo partido:

^([^:]+):\s*(.*)$ 

quedando con los siguientes partidos:

- group(1) = "foo" 
- group(2) = "a b c d" 

y luego se dividió el grupo 2 nd en él está espacios en blanco para obtener toda valores:

import java.util.Arrays; 
import java.util.regex.Matcher; 
import java.util.regex.Pattern; 

public class Main { 
    public static void main (String[] args) throws Exception { 
    Matcher m = Pattern.compile("^([^:]+):\\s*(.*)$").matcher("foo: a b c d"); 
    if(m.find()) { 
     String key = m.group(1); 
     String[] values = m.group(2).split("\\s+"); 
     System.out.printf("key=%s, values=%s", key, Arrays.toString(values)); 
    } 
    } 
} 

que imprimirá:

key=foo, values=[a, b, c, d] 
+0

Una, creo que ella quiso decir '(?:' not '(:?'. Pero más importante aún, esto se pregunta bastante. Creo que C# tiene una manera de hacer esto. Podría ser útil amplíe la API para que uno pueda recuperar una matriz de coincidencias para el grupo Nᵗʰ a través de 'group_array (N)' o algo así; necesitaría una nueva bandera de compilación de patrones para habilitar eso, ya que es demasiado costoso para uso general. podría usar arrays '@ 1' y' @ 2' en vez de escalares '$ 1' y' $ 2', e incluso definir '$ 1' para significar' $ 1 [$ # 1] 'etc. ¿Eso es útil, malvado o ambos? :) – tchrist

+0

@tchrist, sí, podría tener razón sobre el ':?' <-> '?:'. No estoy muy familiarizado con C#, y nunca escuché acerca de esta característica de agrupación N (¿tiene un vínculo al MSDN? ¿para mí?). ¡Y definitivamente sería tanto útil como travieso! :) –

+0

¿Qué me hace contaminarme? :) [Esto lo sugiere] (http://msdn.microsoft.com/en-us/library/30wbz966 (v = vs.71) .aspx # Y2320) en Capture Collection y en Capture. Tengo problemas para leer eso, sin embargo. :) – tchrist

2
Scanner s = new Scanner(input).useDelimiter(Pattern.compile(":?\\s+")); 
String key = s.next(); 
ArrayList values = new ArrayList(); 
while (s.hasNext()) { 
    values.add(s.next()); 
} 
System.out.printf("key=%s, values=%s", key, values); 

Imprime:

key=foo, values=[a, b, c, d] 
Cuestiones relacionadas