Regex para hacer coincidir solo las comas que no están entre paréntesis?

Tengo una cadena que se parece a lo siguiente:

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

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

Asumiendo que no puede haber parens nesteds (de lo contrario, no puede usar una Regex Java para esta tarea porque no se admite la coincidencia recursiva):

 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 usa una aserción de búsqueda anticipada negativa para garantizar que el próximo paréntesis siguiente (si lo hay) no es un paréntesis de cierre. Solo entonces la coma puede coincidir.

Paul, resucitando esta pregunta porque tenía una solución simple que no se mencionaba. (Encontró su pregunta mientras hacía una investigación para una búsqueda de recompensa de expresiones regulares ).

Además, 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 el conjunto 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 esta demostración , puede ver las capturas del Grupo 1 en el panel inferior derecho.

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

Para hacer coincidir las comas, debe inspeccionar el Grupo 1. La única meta de este progtwig 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 group1Caps = new ArrayList(); // 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í hay una demostración en vivo

Para usar la misma técnica para dividir o reemplazar, vea las muestras de código en el artículo en la referencia.

Referencia

  1. Cómo hacer coincidir el patrón, excepto en las situaciones s1, s2, s3
  2. Cómo hacer coincidir un patrón a menos que …

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 siempre hay exactamente un paréntesis de apertura y un paréntesis de cierre coincidente que viene algunos después).