Заметки о данных и инженерии

Аналитика, инфраструктура и всё, что между ними

Выгрузка в двух кодировках сразу

·

Каждый раз, когда кажется, что тема кодировок закрыта, приходит выгрузка, где половина колонок в UTF-8, а половина в CP1251. В одном файле. Так бывает, когда его собирали конкатенацией из двух источников.

Сначала посмотреть, потом читать

Главная ошибка — сразу пытаться прочитать файл в надежде угадать кодировку. Быстрее посмотреть на байты:

file -i data.csv
head -c 2000 data.csv | hexdump -C | head -20

Если в начале ef bb bf — это BOM, файл почти наверняка UTF-8, и его сделал Excel. Если вместо русских букв идут одиночные байты в диапазоне c0ff — это CP1251. Пары вида d0 xx — уже UTF-8.

Когда кодировки смешаны

Тут не помогает ни один флаг чтения. Что сработало — читать построчно в байтах и решать по каждой строке:

def decode_line(raw: bytes) -> str:
    try:
        return raw.decode('utf-8')
    except UnicodeDecodeError:
        # не UTF-8 — значит однобайтовая; для наших данных это CP1251
        return raw.decode('cp1251', errors='replace')

with open('data.csv', 'rb') as f:
    rows = [decode_line(line) for line in f]

Важно именно так, а не наоборот: CP1251 декодирует почти любые байты без ошибки, поэтому если начать с неё, UTF-8 превратится в «Ð¿Ñ€Ð¸Ð²ÐµÑ‚» молча. UTF-8 же строгий и честно падает на чужих байтах — этим и пользуемся.

Что делать, чтобы не повторялось

Договориться с источником об UTF-8 без BOM — идеальный вариант, но он редко достижим, если выгрузку делает чужая система. Реалистичнее — проверка на входе пайплайна: считать долю строк, не декодируемых в UTF-8, и падать, если она выросла. Тихая порча данных хуже упавшего джоба.

И не открывать такие файлы в Excel «просто посмотреть». Он сохранит обратно в своей кодировке, и вы получите третий вариант.

данныеPython

← ко всем записям