Бърза приказка за 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ще ви помогне - те премахват форматирането или скритите символи от текста в допълнение към копирането и поставянето му.