Как сделать CSV файл совместимым с Excel

Для обмена данными многие приложения используют формат CSV. Этот формат стал своего рода стандартом и к нему выработаны требования. Перечень требований на английском (CSV well formedness): Требования к CSV В данной заметке я расскажу, как исправить нарушение требования к экранированию двойных кавычек, которое может повлечь лишние колонки при импорте данных в Excel. Будет использован небольшой скрипт на perl. Предусловием является то, что разделитель в CSV вы можете настроить в отличие от экранирования кавычек. Пусть это будет символ \x01, который обычно в текстовых файлах не встречается. Еще одно допущение: считается что кавычки не экранированы во всем документе. Корректно сгенерированная строка:
Jack;McGinnis;220 hobo Av.;Phila; PA;09119
Для наглядности символ \x01 (наш сконфигурированный разделитель) заменен на точку с запятой. Пример неправильной строки (вам понадобилось использовать запятую не как разделитель, а как символ в одном из полей с данными):
John "Da, Man" ;Repici;120 Jefferson St.;Riverside; NJ;08075
Для наглядности символ \x01 (наш сконфигурированный разделитель) заменен на точку с запятой. Эксель при импорте этого файла разделит первое поле по запятой и по сравнению с правильно сформированной строкой неожиданно появится дополнительная колонка. Вот во что должна превратиться строка в итоге:
"John ""Da, Man""",Repici,120 Jefferson St.,Riverside, NJ,08075
Такую строку Exсel поймет и не создаст лишнюю колонку. Выполняемая команда:
cat badly_formed.csv | perl -ne 'chomp; @a = split chr(1); print join( ",", map { s/"/""/g; qq["$_"] } @a), "\n"'
Что происходит при вызове этой длинной команды? Команда cat печатает ваш файл. Это заглушка, которая имитирует то самое приложение (выводящее в поток CSV), в котором вы настраиваете разделитель, но не можете настроить экранирование кавычек. Вторая команда в конвейере принимает строки по одной. chomp убирает '\n' - перевод строки Далее строка разбивается по нашему разделителю \x01 в массив (split). Теперь надо раскручивание стека начать из глубины 🙂 map() перебирает элементы массива/списка, заменяет в нем одинарные кавычки на двойные, и прячет весь элемент в двойные кавычки. join() объединяет их в строку, используя запятую как разделитель. В конце строки ставим символ \n. Вывод результата происходит в stdout. [sc:social_networks ]
You can leave a response, or trackback from your own site.

Leave a Reply