Кавычки и переносы строк в CSV: как проверить повреждённое поле

Практический разбор удвоенных кавычек и многострочной ячейки с проверенными JSON-результатами и точными отказами парсера.

Складка бумаги внутри рамки как образ кавычек и переносов строк в CSV

Если одна CSV-запись занимает несколько строк текста, файл не обязательно повреждён. Перенос может находиться внутри поля в кавычках. Чтобы найти ошибку, нужно считать логические записи после CSV-разбора, а не физические строки файла. Простое разделение текста по запятым или переводам строк такой файл разбирает неверно.

Neraviko поддерживает многострочные поля и удвоенные внутренние кавычки. Парсер при этом строгий: после закрывающей кавычки допускается разделитель либо окончание записи. Лишний текст он не исправляет догадкой.

Два уровня экранирования

В CSV поле с запятой, кавычкой или переносом заключают в двойные кавычки. Буквальная двойная кавычка внутри такого поля записывается двумя кавычками подряд. RFC 4180, раздел 2, октябрь 2005; проверено 05.10.2026.

В JSON внутреннюю кавычку показывают как \", а перевод строки — как \n. Это другая система записи. При преобразовании CSV в JSON программа сначала получает содержимое ячейки, затем создаёт JSON-строку. Поэтому CSV-кавычки "" превращаются в JSON escape \", а не остаются двумя буквальными кавычками.

Обратная косая черта не является общим CSV-escape. Не заменяйте все "" на \" в исходном файле: это может нарушить CSV-синтаксис. Если исходник действительно использует нестандартный диалект с backslash-escape, нужен его поддерживаемый экспорт или другой parser; опции смены quote/escape в Neraviko версии 1 нет.

Проверенный многострочный пример

Все значения синтетические. В поле note ниже находится настоящий перевод строки:

id,note
A01,"сказал ""да""
новая строка"

В CSV → JSON выберите delimiter=comma, header=true, pretty=false, trailing_newline=false. Результат:

[{"id":"A01","note":"сказал \"да\"\nновая строка"}]

Пример проверен прямым локальным вызовом csv.to_json версии 1. В результате одна запись и две колонки. Видимый \n в JSON обозначает перевод строки внутри значения; он не начинает новую запись массива.

Проверка также выполнена для исходного переноса CRLF внутри поля. Текущая реализация нормализует CRLF и CR в LF. Значение остаётся многострочным, но исходные байты окончания строки не сохраняются. Если нужна байтовая копия исходника, храните оригинал отдельно: преобразование формата для такой задачи не подходит.

Найдите точный тип повреждения

У незакрытого поля, например A01,"unfinished, будет UNCLOSED_CSV_QUOTE. Проверьте исходную запись полностью: закрывающая кавычка может находиться дальше на следующей физической строке. Не добавляйте кавычку в конец каждой строки автоматически, иначе разделите одно поле на несколько записей.

Фрагмент A01,"done" x возвращает INVALID_CSV: после закрывающей кавычки появился пробел и буква, а не разделитель или окончание записи. Этот отказ проверен локально. Если пробел входит в значение, он должен находиться внутри кавычек. Если это артефакт выгрузки, исправляйте экспортёр или конкретную известную запись.

У корректно закрытых полей может оставаться другая ошибка: число ячеек не совпадает с заголовком. В таком случае приходит INCONSISTENT_CSV_COLUMNS. Нужно сверить ожидаемые границы колонок; правильные кавычки не создают отсутствующую ячейку.

Подготовьте контрольный набор

Используйте пять искусственных значений: обычный текст, текст с запятой, кавычку, настоящий перенос и пустую ячейку. Проверьте их содержимое после преобразования, а затем после импорта в целевую систему. Количество физических строк здесь не является метрикой количества данных.

Не удаляйте все кавычки ради «очистки». После этого запятая внутри текста может стать разделителем, а перенос — окончанием записи. Аналогично нельзя свести все пробельные символы к одному пробелу, если многострочность является частью данных.

Для обратного экспорта JSON → CSV передавайте исходные значения обычными JSON-строками. CSV-writer самостоятельно расставляет нужные кавычки; предварительное ручное экранирование даст лишние символы в значении.

Парсер ограничен 5 000 логическими записями, включая заголовок, 256 колонками и 65 536 байтами на поле. Многострочное поле не занимает несколько записей лимита. Лимит запроса — 262 144 байта. Операция выполняется на сервере; сырые входы и выходы по контракту не сохраняются и не логируются по умолчанию. Для диагностики достаточно синтетического фрагмента с тем же синтаксисом.