Разделить строку на запятые, не содержащиеся в двойных кавычках с завихрением
Я задал этот вопрос раньше, и он был закрыт, потому что это был дубликат, который я принимаю и фактически нашел ответ в вопросе Java: разделение строки, разделенной запятыми, но игнорирование запятых в кавычках, поэтому благодаря тому, кто опубликовал его.
Но с тех пор я столкнулся с другой проблемой. По-видимому, мне нужно использовать "," как мой разделитель, когда есть нуль или четное число двойных кавычек, но также игнорировать любые ",", содержащиеся в скобках.
Итак, следующее:
"Thanks,", "in advance,", "for("the", "help")"
Будет означать как:
- Спасибо,
- заранее,
- для ( "the", "help" )
Я не уверен, если так или иначе, чтобы изменить текущее регулярное выражение, которое я использую для этого, но любое руководство будет оценено.
line.split(",(?=([^\"]*\"[^\"]*\")*[^\"]*$)");
Ответы
Ответ 1
Иногда вам легче сопоставить то, что вы хотите, а не то, что вам не нужно:
String s = "\"Thanks,\", \"in advance,\", \"for(\"the\", \"help\")\"";
String regex = "\"(\\([^)]*\\)|[^\"])*\"";
Pattern p = Pattern.compile(regex);
Matcher m = p.matcher(s);
while(m.find()) {
System.out.println(s.substring(m.start(),m.end()));
}
Вывод:
"Thanks,"
"in advance,"
"for("the", "help")"
Если вам также необходимо игнорировать закрывающие скобки внутри разделов кавычек, находящихся внутри скобок, вам нужно это:
String regex = "\"(\\((\"[^\"]*\"|[^)])*\\)|[^\"])*\"";
Пример строки, которая нуждается в этой второй, более сложной версии:
"foo","bar","baz(":-)",":-o")"
Вывод:
"foo"
"bar"
"baz(":-)",":-o")"
Однако я бы посоветовал вам изменить формат данных, если это вообще возможно. Это было бы намного проще, если бы вы использовали стандартный формат, например XML, для хранения ваших токенов.
Ответ 2
Доморощенный парсер легко пишется.
Например, эта грамматика ANTLR позаботится о вашем примере ввода без особых проблем:
parse
: line*
;
line
: Quoted ( ',' Quoted )* ( '\r'? '\n' | EOF )
;
Quoted
: '"' ( Atom )* '"'
;
fragment
Atom
: Parentheses
| ~( '"' | '\r' | '\n' | '(' | ')' )
;
fragment
Parentheses
: '(' ~( '(' | ')' | '\r' | '\n' )* ')'
;
Space
: ( ' ' | '\t' ) {skip();}
;
и было бы легко расширить это, чтобы принять во внимание экранированные кавычки или круглые скобки.
При подаче парсера, сгенерированного этой грамматикой, на следующие две строки ввода:
"Thanks,", "in advance,", "for("the", "help")"
"and(,some,more)","data , here"
это разбирается так:
![alt text]()
Если вы решите использовать ANTLR для этого, я могу опубликовать небольшую инструкцию, чтобы получить парсер из той грамматики, которую я разместил, если хотите.