Хотел Python для создания файла UTF-8, получил ANSI. Зачем? - PullRequest
3 голосов
/ 09 ноября 2011

У меня есть следующая функция:

def storeTaggedCorpus(corpus, filename):
    corpusFile = codecs.open(filename, mode = 'w', encoding = 'utf-8')
    for token in corpus:
        tagged_token = '/'.join(str for str in token)
        tagged_token = tagged_token.decode('ISO-8859-1')
        tagged_token = tagged_token.encode('utf-8')
        corpusFile.write(tagged_token)
        corpusFile.write(u"\n")
    corpusFile.close()

И когда я ее выполняю, у меня появляется следующая ошибка:

(...) in storeTaggedCorpus
    corpusFile.write(tagged_token)
  File "c:\Python26\lib\codecs.py", line 691, in write
    return self.writer.write(data)
  File "c:\Python26\lib\codecs.py", line 351, in write
    data, consumed = self.encode(object, self.errors)
UnicodeDecodeError: 'ascii' codec can't decode byte 0xc3 in position 0: ordinal not in range(128)

Итак, я пошел отлаживать ее и обнаружилчто созданный файл был закодирован как ANSI, а не как UTF-8, как объявлено в corpusFile = codecs.open(filename, mode = 'w', encoding = 'utf-8').Если удалить corpusFile.write(tagged_token), эта функция (очевидно) будет работать, и файл будет закодирован как ANSI.Если вместо этого я удаляю tagged_token = tagged_token.encode('utf-8'), он также будет работать, НО , полученный файл будет иметь кодировку "ANSI as UTF-8" (???) и символы латинского алфавита будут искажены.Поскольку я анализирую текст pt-br, это недопустимо.

Я считаю, что все будет работать нормально, если corpusFile будет открыт как UTF-8, но я не могу заставить его работать.Я искал в Интернете, но все, что я нашел в Python / Unicode, касалось чего-то еще ... s Так почему этот файл всегда заканчивается в ANSI?Я использую Python 2.6 в Windows 7 x64, и эти кодировки файлов были получены из Notepad ++.

Редактировать - О параметре corpus

Я не знаю кодировку corpus строкаОн был сгенерирован методом PlaintextCorpusReader.tag(), из NLTK .Исходный файл корпуса был закодирован в UTF-8, в соответствии с Notepad ++.tagged_token.decode('ISO-8859-1') это просто предположение.Я попытался декодировать его как cp1252 и получил те же искаженные символы из ISO-8859-1.

Ответы [ 3 ]

3 голосов
/ 09 ноября 2011

Когда вы открываете файл с помощью codec.open('w', encoding='utf8'), нет смысла записывать байтовые массивы (str объекты) в файл.Вместо этого напишите unicode объекты, например:

corpusFile = codecs.open(filename, mode = 'w', encoding = 'utf-8')
# ...
tagged_token = '\xdcml\xe4ut'
tagged_token = tagged_token.decode('ISO-8859-1')
corpusFile.write(tagged_token)
corpusFile.write(u'\n')

Это будет писать зависимые от платформы символы конца строки.

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

corpusFile = open(filename, mode = 'wb')
# ...
tagged_token = '\xdcml\xe4ut'
tagged_token = tagged_token.decode('ISO-8859-1')
corpusFile.write(tagged_token.encode('utf-8'))
corpusFile.write('\n')

Это будет писать независимые от платформы EOL.Если вы хотите зависящий от платформы EOL , выведите os.sep вместо '\n'.

Обратите внимание, что кодировка в Notepad ++ вводит в заблуждение : ANSI as UTF-8 - это что вы хотите.

1 голос
/ 09 ноября 2011

Попробуйте написать файл с подписью UTF-8 (он же BOM):

def storeTaggedCorpus(corpus, filename):
    corpusFile = codecs.open(filename, mode = 'w', encoding = 'utf-8-sig')
    for token in corpus:
        tagged_token = '/'.join(str for str in token)
        # print(type(tagged_token)); break
        # tagged_token = tagged_token.decode('cp1252')
        corpusFile.write(tagged_token)
        corpusFile.write(u"\n")
    corpusFile.close()

Обратите внимание, что это будет работать правильно только в том случае, если tagged_token является строкой Unicode.Чтобы проверить это, раскомментируйте первый комментарий в вышеприведенном коде - он должен напечатать <type 'unicode'>.

Если tagged_token не является строкой в ​​кодировке Unicode, вам необходимо сначала декодировать его, используя вторую строку с комментариями.(Примечание: я предположил кодировку "cp1252", но если вы уверены, что это "iso-8859-1", то, конечно, вам нужно будет изменить его.)

0 голосов
/ 09 ноября 2011

Если вы видите «искаженные» символы из файла, вам нужно убедиться, что все, что вы используете для просмотра файла, понимает, что файл имеет кодировку UTF-8.

Файлы, созданные этим кодом:

import codecs
for enc in "utf-8 utf-8-sig".split():
    with codecs.open(enc + ".txt", mode = 'w', encoding = enc) as corpusFile:
        tagged_token = '\xdcml\xe4ut'
        tagged_token = tagged_token.decode('cp1252') # not 'ISO-8859-1'
        corpusFile.write(tagged_token) # write unicode objects
        corpusFile.write(u'\n')

обозначены так:

Блокнот ++ (версия 5.7 (UNICODE)): UTF-8 без спецификации, UTF-8
Firefox (7.0.1): Western (ISO-8859-1), Unicode (UTF-8)
Блокнот (Windows 7): UTF-8, UTF-8

Размещение спецификации в файле UTF-8, хотя в Unix-системах она устарела, дает вам гораздо больше шансов в Windows, что другое программное обеспечение сможет распознавать ваш файл в кодировке UTF-8.

...