Короткий розповідь про FEFF, невидимого персонажа UTF-8, який зламав наші файли CSV

Сьогодні ми зіткнулися з помилкою під час спроби створити насіння бази даних із CSV. Цей CSV спочатку був створений мною за допомогою скрипта Ruby, який передавав вихідні дані до файлу та зберігав як CSV.

CSV було зареєстровано в Git і використовувалось деякий час, поки нам не довелося оновлювати деякі його частини, додаючи новий стовпець і виправляючи деякі значення.

Хоча ми поки не знаємо точної причини, моя теорія полягає в тому, що як-небудь Excel для Mac (усі ми використовуємо Mac) додав до нього деякі додаткові метадані навіть після збереження файлу як CSV.

Це, в свою чергу, змусило кожного, хто використовує насіння, отримати таку помилку:

CSV::MalformedCSVError: Illegal quoting in line 1.

Я відкрив файл CSV і нічого не виглядало підозрілим. Моя перша думка була кілька вліво / вправо лапок були як - то підмішують в файл , а не тільки в «нормальних» подвійних лапках: ". Але при подальшому розслідуванні не було нічого незвичайного. Це змусило мене просто видалити весь файл і фактично ввести перший рядок ще раз.

Я знову зберег цей файл і запустив міграцію:

CSV::MalformedCSVError: Illegal quoting in line 1.

Що?!

Гаразд, це зводило мене з розуму. Я відкрив новий файл, знову набрав точний рядок і запустив міграцію. Це спрацювало. То що було в цьому файлі ?!

Тільки один спосіб дізнатися:

cat companies.csv | pbcopy | pbpaste > temp.csv rm companies.csv mv temp.csv companies.csv git diff

Отже, OSX має ці дві дуже корисні функції: pbcopyі pbpaste. В основному все, що pbcopyнадходить до трубопроводу, потрапляє у ваш буфер обміну і переносить pbpasteте, що у вас є в буфер обміну, на стандартний вихід (stdout). Але це видаляє всі форматування.

Дуже корисно, коли ви хочете просто скопіювати якийсь текст звідки-небудь, і ви хочете вставити його у редактор WYSIWYG без усього форматування. Наприклад, як, наприклад, при написанні електронного листа з Gmail.

Потім я вилучив оригінальний файл і зберіг новий «неформатований» файл з тим самим іменем, щоб я міг побачити різницю.

І нарешті ми побачили людину-невидимку:

Швидкий пошук у Google повідомив, що нашого друга U+FEFFпокликали ZERO WIDTH NO-BREAK SPACE. Крім того, швидка поїздка до Вікіпедії розповіла нам про фактичне використання U+FEFF, більш відоме як Byte order markабо BOM.

Наш друг має на FEFFувазі різні речі, але в основному це сигнал для програми про те, як читати текст. Це може бути UTF-8(частіше) UTF-16, або навіть UTF-32.

FEFFсам по собі UTF-16- в UTF-8ньому більш відомий як 0xEF,0xBB, or 0xBF.

У моєму розумінні, коли файл CSV був відкритий в Excel і збережений, Excel створив простір для нашого невидимого зайця, U+FEFF. І перед файлом для завантаження!

Excel зробив трохи магії, і його, ймовірно, було збережено UTF-16замість UTF-8. UTF-8не розуміє BOMі просто трактує це як несимвол, тому візуально файл був у порядку. Але CSVдумка Рубі про те, що щось не так, оскільки вона вважала, що файл, який вона читає, UTF-8і не могла ігнорувати пана U+FEFF.

Отже, отриманий урок: не відкривайте (і не зберігайте!) Файл CSV в Excel, якщо ви хочете подати його на CSVпарсер Ruby .

Якщо ви коли-небудь стикалися з такою помилкою, обов’язково шукайте приховані символи, не показані вашим редактором. Якщо ви все ще не можете його побачити і використовуєте OSX, тоді pbcopyі pbpasteдопоможуть вам - вони видаляють будь-яке форматування або приховані символи з тексту на додаток до копіювання та вставки.