CSVParser.javajava.io.Reader и токенизирует CSV-данные посимвольно, поддерживая поля в кавычках, встроенные символы новой строки внутри ячеек в кавычках, экранированные двойные кавычки (соглашение ""), настраиваемые разделители полей, сопоставление имён столбцов заголовка и обнаружение UTF-8 BOM. Написан Каем Райнхардом и Х. Шпивоком (2005), этот код предшествует внешним библиотекам CSV и избегает их использования.java.io.IOException / java.io.Reader — Ввод символьного потокаjava.util.ArrayList, HashMap, List, Map — Хранение результатов и индексация столбцов заголовкаorg.apache.commons.lang3.StringUtils — Проверка строк на пустоту в сообщениях об ошибкахorg.slf4j.Logger — Логирование ошибокВместо использования регулярных выражений или генератора парсеров, CSVParser реализует посимвольный лексер с буфером возврата. Такая конструкция отдаёт приоритет контролю над обработкой ошибок и производительности для конкретного подмножества форматирования CSV, используемого в ProjectForge.
enum Type { EOF, EOL, CHAR }
Типы токенов: конец файла, конец строки или символьные данные. Это управляет конечным автоматом парсера.
int[] из 5 элементов (pushbackBuffer) с отслеживанием индекса — обеспечивает опережающий просмотр и возврат без поддержки Reader'ом методов mark()/reset()\ncval для символьных токенов. Обрабатывает \r\n (Windows CRLF) как один токен EOLskipBOM() вызывается во время конструирования для обнаружения и пропуска метки порядка байтов UTF-8 (\uFEFF) в начале файла. Если BOM отсутствует, первый символ помещается обратно (unread). Это обеспечивает корректный разбор CSV-файлов, экспортированных из Microsoft Excel, который добавляет BOM для файлов UTF-8.
Основная логика разбора CSV обрабатывает следующие случаи:
| Случай | Поведение |
|---|---|
| Ячейка без кавычек | Символы накапливаются до разделителя или конца строки |
Ячейка в кавычках ("...") | Символы внутри кавычек накапливаются; кавычки должны быть правильно закрыты |
Экранированная кавычка ("") | Две последовательные двойные кавычки внутри ячейки в кавычках представляют один литеральный символ кавычки |
| Встроенный символ новой строки | Символы новой строки внутри ячеек в кавычках сохраняются (многострочные значения ячеек) |
| Замыкающие пробелы | Пробелы после закрывающей кавычки пропускаются; ожидается разделитель или конец строки |
| Незакрытая кавычка | Выбрасывает RuntimeException с информативным сообщением об ошибке, включающим номер строки/столбца |
Читает ячейки до конца строки или конца файла, собирая их в List<String>. Возвращает null в конце файла (не пустой список — вызывающие могут отличить конец файла от пустых строк).
Для CSV-файлов со строкой заголовка parseHeadCols() читает первую строку и строит colMap: Map<String, Integer>, сопоставляя имена столбцов с их позиционными индексами. Последующие вызовы getCell(List<String>, colname) получают значения по имени столбца, а не по позиции. Это обеспечивает доступ к именованным столбцам, как в Excel.
Три различных константы ошибок обеспечивают конкретную диагностику:
ERROR_UNEXPECTED_QUOTATIONMARK = "Неожиданный символ кавычки \" (допускается только в ячейках в кавычках)." ERROR_QUOTATIONMARK_MISSED_AT_END_OF_CELL = "Пропущена кавычка \" в конце ячейки." ERROR_DELIMITER_OR_NEW_LINE_EXPECTED_AFTER_QUOTATION_MARK = "После кавычки ожидается разделитель или новая строка." ERROR_UNEXPECTED_CHARACTER_AFTER_QUOTATION_MARK = "Неожиданный символ после кавычки."
Каждое сообщение дополняется номером строки и столбца через createMessage().
CSVParser использует CSVWriter.DEFAULT_CSV_SEPARATOR_CHAR (';' — точка с запятой) в качестве разделителя по умолчанию. Это европейское соглашение для CSV (Microsoft Excel в немецкой локали использует CSV с разделителем-точкой с запятой). Разделитель можно настроить через setCsvSeparatorChar().
parseLine() читает одну строку и возвращает все ячейки — подходит для файлов умеренного размера, но не для очень больших (много гигабайт) CSV868d6abb7 2025 -> 2026 161d71602 WIP: CSVParser: символы BOM. dfb2378df WIP: CSVParser: многострочные поля и т.д. 63081666f Заголовки исходных файлов: 2024 -> 2025. a73905c14 Исправление опечаток в каталогах projectforge*/ Найдено с помощью codespell a72903e36 *.java, *.kt: StringBuffer -> StringBuilder. b6092df09 Авторские права 2023 -> 2024 ab45d51fa Авторские права 2001-2022 -> 2001-2023.