0x85 Windows 1252 разрывает строку, если файл открыт в кодировке utf-8 - PullRequest
0 голосов
/ 06 ноября 2019

У меня есть файл со старым форматом из 70-х, используемый в Companies House (реестр компаний Великобритании).

Я унаследовал парсер, написанный 6 лет назад, который переходит строка за строкой и в соответствии с набором условий извлекает информацию из строки и вставляет ее в словарь.

Есть странный символ, ломающий линию.

Я скопировал эту строку в новый файл awk '{if(NR==33411) print $0}' PROD216_1950_ew_1.dat > broken и opend broken в vim.

Оказывается, что странный символ читается vim a <85>.

В результате все, что после MAYFIELD читается как новая строка.

Ниже рассматриваемой строки:

000376702103032986930001        1993010119941024        193709          0105<BARRY ALEXANDER<GROSVENOR<<<<MAYFIELD 3<41 PLANTATION ROAD<THE PEAK<<HONG KONG<BANK EXECUTIVE<BRITISH<<

в vim становится

000376702103032986930001        1993010119941024        193709          0105<BARRY ALEXANDER<GROSVENOR<<<<MAYFIELD <85>3<41 PLANTATION ROAD<THE PEAK<<HONG KONG<BANK EXECUTIVE<BRITISH<<

Я использую codecs для чтения этого файла с помощью диспетчера контекста, который яМысль была способ сделать это -

Есть ли что-то, что я пропускаю? Что это такое <85>?

with codecs.open(filepath, 'r', 'utf-8') as fh:
    for line in fh:
        linetype = determine_line_type(line)
        if linetype == 'header':
            continue
        elif linetype == 'company':
            do stuff...
        elif linetype == 'officer':
            do stuff...

Ответы [ 2 ]

1 голос
/ 07 ноября 2019

vim показывает <85> для обозначения шестнадцатеричного 85-байтового байта, который недопустим в текущей кодировке (т. Е. Кодировке, используемой для декодирования файла).

Я предполагаю, что кодировка файла Windows-1252 , в которой шестнадцатеричное 85 обозначает символ многоточия.

Таким образом, решение для вашего парсера может быть таким же простым, как изменение 'utf-8' на 'cp1252' в вызове codecs.open.

0 голосов
/ 11 ноября 2019

Пройдя некоторое время здесь и здесь Я пришел к этому решению, которое работает.

with open(path, encoding = 'cp1252') as fdata:
    for line in fdata:
        l = line.replace("Â…", "").encode("utf-8")  # "Â…" this how the hex 0x85 looks in cp1252 encoding.  
        line_decoded = l.decode("utf-8")
        # do stuff with line, like slice it!
        print(line_decoded)

Благодаря @Michael Dyck мы знаем, что кодировка файла cp1252, поэтому мы открываем файл с этой кодировкой. При чтении с этой кодировкой шестнадцатеричный код <85> фактически является символом .... Таким образом, мы удаляем это, затем перекодируем строку в utf-8 (превращает ее в ее байтовое представление) и затем, чтобы снова манипулировать ею, нам нужно снова преобразовать байты в строку с помощью str.decode.

В качестве альтернативы вы также можете просто удалить ошибки, вызванные другой кодировкой, с флагом ошибки.

with open(path, encoding = 'utf-8', errors="ignore") as fdata:
...