Regex соответствует только запятым не в круглых скобках?

У меня есть строка, которая выглядит примерно так:

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

Я хотел бы создать регулярное выражение, соответствующее запятым, но только запятые, которые не находятся внутри круглых скобок (в приведенном выше примере, все запятые, за исключением двух после 23 и 45). Как это сделать (регулярные выражения Java, если это имеет значение)?

Ответ 1

Предполагая, что не могут быть вложенные parens (в противном случае вы не можете использовать Java Regex для этой задачи, потому что не поддерживается рекурсивное сопоставление):

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

Это регулярное выражение использует отрицательное утверждение lookback, чтобы следующая следующая скобка (если она есть) не была закрывающей скобкой. Только тогда запятая разрешается сопоставлять.

Ответ 2

Павел, воскресив этот вопрос, потому что у него было простое решение, о котором не упоминалось. (Нашел свой вопрос, проведя некоторое исследование для заданий по поиску регулярных выражений.)

Также существующее решение проверяет, что за запятой не следует скобка, но это не гарантирует, что она встроена в круглые скобки.

Регулярное выражение очень просто:

\(.*?\)|(,)

Левая часть чередования соответствует полному набору круглых скобок. Мы проигнорируем эти матчи. Правая сторона сопоставляет и фиксирует запятые для группы 1, и мы знаем, что они являются правыми запятыми, потому что они не соответствовали выражению слева.

В этой демо вы можете увидеть, как группа 1 захватывает в нижней правой панели.

Вы сказали, что хотите совместить запятые, но вы можете использовать одну и ту же общую идею для разделения или замены.

Чтобы соответствовать запятым, вам нужно проверить группу 1. Эта полная программа - единственная цель в жизни - это сделать именно это.

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

Вот живая демонстрация

Чтобы использовать тот же метод для разделения или замены, см. примеры кода в статье в ссылке.

Ссылка

Ответ 3

Я не понимаю эту одержимость регулярными выражениями, учитывая, что они не подходят для большинства задач, для которых они используются.

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

(Конечно, это предполагает, что всегда есть только одна открывающая скобка и одна соответствующая закрывающая скобка, которая появляется после нее.)