Пытаться:
public class Main {
public static void main(String[] args) {
String line = "foo,bar,c;qual=\"baz,blurb\",d;junk=\"quux,syzygy\"";
String[] tokens = line.split(",(?=(?:[^\"]*\"[^\"]*\")*[^\"]*$)", -1);
for(String t : tokens) {
System.out.println("> "+t);
}
}
}
Вывод:
> foo
> bar
> c;qual="baz,blurb"
> d;junk="quux,syzygy"
Другими словами: разделять запятую, только если эта запятая имеет ноль или четное число кавычек перед ней .
Или немного дружелюбнее для глаз:
public class Main {
public static void main(String[] args) {
String line = "foo,bar,c;qual=\"baz,blurb\",d;junk=\"quux,syzygy\"";
String otherThanQuote = " [^\"] ";
String quotedString = String.format(" \" %s* \" ", otherThanQuote);
String regex = String.format("(?x) "+ // enable comments, ignore white spaces
", "+ // match a comma
"(?= "+ // start positive look ahead
" (?: "+ // start non-capturing group 1
" %s* "+ // match 'otherThanQuote' zero or more times
" %s "+ // match 'quotedString'
" )* "+ // end group 1 and repeat it zero or more times
" %s* "+ // match 'otherThanQuote'
" $ "+ // match the end of the string
") ", // stop positive look ahead
otherThanQuote, quotedString, otherThanQuote);
String[] tokens = line.split(regex, -1);
for(String t : tokens) {
System.out.println("> "+t);
}
}
}
который производит так же, как в первом примере.
РЕДАКТИРОВАТЬ
Как упомянуто @MikeFHay в комментариях:
Я предпочитаю использовать Splitter Guava , так как он имеет более разумные значения по умолчанию (см. Обсуждение выше об обрезании пустых совпадений String#split()
, поэтому я сделал:
Splitter.on(Pattern.compile(",(?=(?:[^\"]*\"[^\"]*\")*[^\"]*$)"))
String line = "equals: =,\"quote: \"\"\",\"comma: ,\""
все, что вам нужно, это удалить лишние двойные кавычки персонажи.-1
в методе раздельных пары:line.split(regex, -1)
. См .: docs.oracle.com/javase/6/docs/api/java/lang/…Splitter.on(Pattern.compile(",(?=([^\"]*\"[^\"]*\")*[^\"]*$)"))
.findAllIn("(?s)(?:\".*?\"|[^\",]*)*")
в сочетании с шагом постобработки для пропуска первого (всегда пустого) поля после каждого непустого поля.Хотя мне нравятся регулярные выражения в целом, для такого вида токенизации, зависящей от состояния, я считаю, что простой синтаксический анализатор (который в данном случае намного проще, чем это слово может сделать его звучащим), вероятно, является более чистым решением, особенно в том, что касается ремонтопригодности. Например:
Если вам не нужно сохранять запятые внутри кавычек, вы можете упростить этот подход (без обработки начального индекса, без особого случая последнего символа ), заменив запятые в кавычках чем-то другим, а затем разделив их запятыми:
источник
http://sourceforge.net/projects/javacsv/
https://github.com/pupi1985/JavaCSV-Reloaded (ветвь предыдущей библиотеки, которая позволит сгенерированному выводу иметь разделители строк Windows,
\r\n
когда Windows не работает)http://opencsv.sourceforge.net/
CSV API для Java
Можете ли вы порекомендовать библиотеку Java для чтения (и, возможно, записи) файлов CSV?
Java lib или приложение для преобразования CSV в XML-файл?
источник
Я бы не советовал ответить на регулярные выражения от Барта, я считаю, что в этом конкретном случае решение для разбора лучше (как предложил Фабиан). Я пробовал решение регулярных выражений и собственную реализацию синтаксического анализа, я обнаружил, что:
Мое решение и тест ниже.
Конечно, вы можете свободно переключаться на else-if в этом фрагменте, если чувствуете себя неловко из-за его уродства. Обратите внимание на отсутствие разрыва после переключения с разделителем. Вместо этого StringBuilder был выбран вместо StringBuffer для увеличения скорости, где безопасность потоков не имеет значения.
источник
-1
в метод split в ответе Барта, вы поймаете пустые строки (включая пустые строки после последней запятой):line.split(regex, -1)
Попробуйте выглядеть как
(?!\"),(?!\")
. Это должно соответствовать тому,,
что не окружено"
.источник
(?<!"),(?!")
, но это все равно не сработает. Учитывая строкуone,two,"three,four"
, она правильно соответствует запятой вone,two
, но она также совпадает с запятой в"three,four"
и не совпадает с одной вtwo,"three
.Вы находитесь в этой надоедливой граничной области, где регулярные выражения почти не подходят (как указывал Барт, выход из кавычек осложнил бы жизнь), и все же полноценный парсер кажется излишним.
Если вам, скорее всего, понадобится больше сложности в ближайшее время, я бы пошел искать библиотеку синтаксического анализатора. Например, этот
источник
Я был нетерпелив и решил не ждать ответов ... для справки не выглядит так сложно сделать что-то подобное (что работает для моего приложения, мне не нужно беспокоиться о экранированных кавычках, так как материал в кавычках) ограничено несколькими ограниченными формами):
(упражнение для читателя: перейдите к обработке экранированных кавычек, ища также обратную косую черту.)
источник
Простейший подход состоит не в том, чтобы сопоставлять разделители, то есть запятые, со сложной дополнительной логикой для сопоставления с тем, что на самом деле предназначено (данные, которые могут быть строками в кавычках), просто для исключения ложных разделителей, а скорее для сопоставления предполагаемых данных в первую очередь.
Шаблон состоит из двух альтернатив: строки в кавычках (
"[^"]*"
или".*?"
) или всего до следующей запятой ([^,]+
). Для поддержки пустых ячеек мы должны позволить пустому элементу без кавычек использовать следующую запятую, если она есть, и использовать\\G
привязку:Шаблон также содержит две группы захвата для получения: содержимое строки в кавычках или простое содержимое.
Затем, с Java 9, мы можем получить массив как
тогда как более старые версии Java нуждаются в цикле
Добавление элементов в
List
массив или массив остается акцизом для читателя.Для Java 8 вы можете использовать
results()
реализацию этого ответа , чтобы сделать это подобно решению Java 9.Для смешанного контента со встроенными строками, как в вопросе, вы можете просто использовать
Но затем строки хранятся в указанном виде.
источник
Вместо того, чтобы использовать lookahead и другие сумасшедшие регулярные выражения, сначала вытащите цитаты. То есть для каждой группировки цитат замените эту группировку
__IDENTIFIER_1
или каким-либо другим индикатором и сопоставьте эту группировку с картой строки, строки.После разделения на запятую замените все сопоставленные идентификаторы исходными строковыми значениями.
источник
как насчет однострочника с использованием String.split ()?
источник
Я бы сделал что-то вроде этого:
источник