Парсер Java CSV с разделителем строк (многосимвольный) - PullRequest
11 голосов
/ 28 декабря 2011

Существует ли какая-либо библиотека Java с открытым исходным кодом, которая поддерживает многосимвольные (т.е. строки с длиной> 1) разделители (разделители) для CSV?

По определению, CSV = данные, разделенные запятыми, с одним символом (',') в качестве разделителя. Однако существует много других односимвольных альтернатив (например, табуляция), в результате чего CSV заменяет данные «Значения с разделением символов» (по существу, DSV: Данные с разделителями значений).

Основные библиотеки Java с открытым исходным кодом для CSV (например, OpenCSV ) поддерживают практически любой символ в качестве разделителя, но не строковые (многосимвольные) разделители. Таким образом, для данных, разделенных строками типа "|||" нет другого варианта, кроме предварительной обработки ввода для преобразования строки в разделитель из одного символа. С этого момента данные могут быть проанализированы как значения, разделенные одним символом.

Поэтому было бы неплохо, если бы существовала библиотека, которая изначально поддерживала разделители строк, чтобы не требовалась предварительная обработка. Это будет означать, что CSV теперь используется для данных "CharSequence-Separated Values". : -)

Ответы [ 3 ]

4 голосов
/ 31 декабря 2011

Это хороший вопрос.Проблема не была очевидна для меня, пока я не посмотрел на javadocs и не понял, что opencsv поддерживает только символ в качестве разделителя, а не строку ....

Вот пара предложенных работ-arounds (Примеры в Groovy можно преобразовать в java).

Игнорировать неявные промежуточные поля

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

    CSVParser csv = new CSVParser((char)'|')

    String[] result = csv.parseLine('J||Project report||"F, G, I"||1')

    assert result[0] == "J"
    assert result[2] == "Project report"
    assert result[4] == "F, G, I"
    assert result[6] == "1"

или

    CSVParser csv = new CSVParser((char)'|')

    String[] result = csv.parseLine('J|||Project report|||"F, G, I"|||1')

    assert result[0] == "J"
    assert result[3] == "Project report"
    assert result[6] == "F, G, I"
    assert result[9] == "1"

Сверните свой собственный

Используйте метод Java String tokenizer .

    def result = 'J|||Project report|||"F, G, I"|||1'.tokenize('|||')

    assert result[0] == "J"
    assert result[1] == "Project report"
    assert result[2] == "\"F, G, I\""
    assert result[3] == "1"

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

Обновление

Вместо предварительной обработки данных, изменениеэто содержание, почему бы не объединить оба вышеперечисленных подхода в двухэтапном процессе:

  1. Используйте «свернуть свой собственный», чтобы сначала проверить данные.Разбейте каждую строку и докажите, что она содержит требуемое количество полей.
  2. Используйте подход "игнорирование полей" для анализа проверенных данных и убедитесь, что указано правильное количество полей.

Не очень эффективно, но, возможно, проще, чем написание собственного синтаксического анализатора CSV: -)

0 голосов
/ 12 октября 2018

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

Я знаю, что это медленно, но я пошел с Scanner. Он обладает удивительным количеством функций и позволяет создавать собственный простой читатель CSV с любой строкой, которую вы хотите использовать в качестве разделителя записей. Он также позволяет вам анализировать очень большие файлы CSV (я уже делал 10 ГБ отдельных файлов), поскольку вы можете читать записи по одному за раз.

Scanner s = new Scanner(inputStream, "UTF-8").useDelimiter(">|\n");

Я бы предпочел более быстрое решение, но ни одна библиотека, которую я нашел, не поддерживает его. FasterXML имеет открытый билет для добавления этой функциональности с начала 2017 года: https://github.com/FasterXML/jackson-dataformats-text/issues/14

0 голосов
/ 28 декабря 2011

Попробуйте opencsv .

Он делает все, что вам нужно, включая (и особенно) обработку встроенных разделителей в указанных значениях (например, "a,b", "c" анализирует как ["a,b", "c"])

Я успешно его использовал и мне понравилось.

Отредактировано:

Поскольку opencsv обрабатывает только односимвольные разделители, вы можете обойти это следующим образом:

String input;
char someCharNotInInput = '|';
String delimiter = "abc"; // or whatever
input.replaceAll(delimiter, someCharNotInInput);
new CSVReader(input, someCharNotInInput); // etc
// Put it back into each value read
value.replaceAll(someCharNotInInput, delimiter); // in case it's inside delimiters
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...