2012-01-27 24 views
21

tengo una cadena que se ve algo como lo siguiente:Regex para hacer coincidir solo las comas que no están entre paréntesis?

12,44,foo,bar,(23,45,200),6 

Me gustaría crear una expresión regular que coincide con las comas, pero sólo las comas que no están dentro de paréntesis (en el ejemplo anterior, todas de las comas, excepto para los dos después de 23 y 45). ¿Cómo podría hacer esto (expresiones regulares de Java, si eso hace la diferencia)?

+2

¿Puede haber paréntesis anidados? ¿Puede haber más de un par? – Nikodemus

+1

¿Puede la cadena tener paréntesis sin igual como '" 12,44,12) foo, barra, (23,45,200), 6 "'? – anubhava

Respuesta

44

el supuesto de que no puede haber parens anidados (de lo contrario, no se puede utilizar una expresión regular de Java para esta tarea porque coincidente recursiva no es compatible):

Pattern regex = Pattern.compile(
    ",   # Match a comma\n" + 
    "(?!  # only if it's not followed by...\n" + 
    " [^(]* # any number of characters except opening parens\n" + 
    " \\)  # followed by a closing parens\n" + 
    ")   # End of lookahead", 
    Pattern.COMMENTS); 

Esta expresión regular utiliza un negative lookahead assertion para asegurar que la el siguiente paréntesis siguiente (si lo hay) no es un paréntesis de cierre. Solo entonces la coma puede coincidir.

+3

buena explicación. Soy nuevo para reg. jst nw comenzó a entender con su respuesta. Gracias – praveenb

+4

Buena demostración del uso de 'Pattern.COMMENTS'. Esto es lo que deberían ser todas las respuestas de Regex en stackoverflow. – Wilt

+0

@Tim hay alguna expresión regular que pueda usar con esta cadena "12,44, foo, bar, (23,45,200 (10,11 (23))), 6". Por encima de la lógica falla con la cadena que mencioné. – fidato

-4

No entiendo esta obsesión con las expresiones regulares, dado que no son adecuadas para la mayoría de las tareas para las que se usan.

String beforeParen = longString.substring(longString.indexOf('(')) + longString.substring(longString.indexOf(')') + 1); 
int firstComma = beforeParen.indexOf(','); 
while (firstComma != -1) { 
    /* do something. */ 
    firstComma = beforeParen.indexOf(',', firstComma + 1); 
} 

(Por supuesto, esto supone que no siempre es exactamente un paréntesis de apertura y cierre de paréntesis de un juego que vienen en algún tiempo después de ella.)

+2

Y asume que no hay comas después del paréntesis. ¿Has probado esto? Incluso falla en la cadena de ejemplo que proporcionó Paul. Escribir un analizador correcto que tampoco se ahogue con una entrada mal formada probablemente sea tan difícil como escribir una expresión regular correcta (si no más). Preferiría * muchísimo * una expresión regular en este caso de uso, siempre que la entrada se ajuste a los criterios definidos. –

+0

Tiene razón, ignoré la parte después de la parálisis de cierre. Fijo. :) – Bombe

+1

¿Qué haces con entradas como '1,2, (3,4), 5,6, (7,8)'? –

5

Paul, resucitar a esta pregunta porque tenía una solución simple que no era mencionado. (Encontró su pregunta mientras investigaba un regex bounty quest.)

También la solución existente comprueba que la coma no vaya seguida por un paréntesis, pero eso no garantiza que esté incrustado entre paréntesis.

La expresión regular es muy simple:

\(.*?\)|(,) 

El lado izquierdo de la alternancia coincide con juego completo de paréntesis. Ignoraremos estos partidos. El lado derecho coincide y captura las comas en el Grupo 1, y sabemos que son las comas correctas porque no coinciden con la expresión de la izquierda.

En este demo, puede ver las capturas del Grupo 1 en el panel inferior derecho.

Dijiste que quieres hacer coincidir las comas, pero puedes usar la misma idea general para dividir o reemplazar.

Para hacer coincidir las comas, debe inspeccionar el Grupo 1. El único objetivo de este programa completo en la vida es hacer justamente eso.

import java.util.*; 
import java.io.*; 
import java.util.regex.*; 
import java.util.List; 

class Program { 
public static void main (String[] args) throws java.lang.Exception { 

String subject = "12,44,foo,bar,(23,45,200),6"; 
Pattern regex = Pattern.compile("\\(.*?\\)|(,)"); 
Matcher regexMatcher = regex.matcher(subject); 
List<String> group1Caps = new ArrayList<String>(); 

// put Group 1 captures in a list 
while (regexMatcher.find()) { 
if(regexMatcher.group(1) != null) { 
group1Caps.add(regexMatcher.group(1)); 
} 
} // end of building the list 

// What are all the matches? 
System.out.println("\n" + "*** Matches ***"); 
if(group1Caps.size()>0) { 
for (String match : group1Caps) System.out.println(match); 
} 
} // end main 
} // end Program 

Aquí es una live demo

Para utilizar la misma técnica para la división o sustitución, ver los ejemplos de código en el artículo en la referencia.

Referencia

  1. How to match pattern except in situations s1, s2, s3
  2. How to match a pattern unless...
Cuestiones relacionadas