Юникод (UTF-8) чтение и запись в файлы на Python
у меня есть некоторые мозговые сбои в понимании чтения и записи текста в файл (Python 2.4).
# The string, which has an a-acute in it.
ss = u'Capitxe1n'
ss8 = ss.encode('utf8')
repr(ss), repr(ss8)
("u'Capitxe1n'", "'Capitxc3xa1n'")
print ss, ss8
print >> open('f1','w'), ss8
>>> file('f1').read()
'Capitxc3xa1nn'
поэтому я набираю Capitxc3xa1n в мой любимый редактор, в файл f2.
затем:
>>> open('f1').read()
'Capitxc3xa1nn'
>>> open('f2').read()
'Capitxc3xa1nn'
>>> open('f1').read().decode('utf8')
u'Capitxe1nn'
>>> open('f2').read().decode('utf8')
u'Capitxc3xa1nn'
что я здесь не понимаю? Очевидно, что есть какая-то жизненно важная часть магии (или здравого смысла), которую мне не хватает. Что нужно ввести в текстовые файлы, чтобы получить правильный конверсии?
то, что я действительно не могу Грок здесь, это то, что точка представления UTF-8, Если вы не можете заставить Python распознать его, когда он приходит извне. Может быть, я должен просто JSON сбросить строку и использовать ее вместо этого, так как это имеет asciable представление! Более того, есть ли представление ASCII этого объекта Unicode, которое Python распознает и декодирует, когда входит из файла? Если да, то как мне его получить?
>>> print simplejson.dumps(ss)
'"Capitu00e1n"'
>>> print >> file('f3','w'), simplejson.dumps(ss)
>>> simplejson.load(open('f3'))
u'Capitxe1n'
13 ответов:
в формате
u'Capit\xe1n\n'"\xe1 " представляет только один байт. "\x " говорит вам, что "e1" находится в шестнадцатеричном формате. Когда вы пишете
Capit\xc3\xa1nв вашем файле у вас есть" \xc3 " в нем. Эти 4 байта и в вашем коде, вы прочитали их все. Вы можете увидеть это, когда вы показываете им:
>>> open('f2').read() 'Capit\xc3\xa1n\n'вы можете видеть, что обратная косая черта экранируется обратной косой чертой. Таким образом, у вас есть четыре байта в строке:"\", "x", "c" и "3".
Edit:
как другие указали в своих ответах, что вы должны просто ввести символы в редакторе, и ваш редактор должен затем обработать преобразование в UTF-8 и сохранить его.
если у вас действительно есть строки в этом формате вы можете использовать
string_escapeкодек для декодирования его в нормальную строку:In [15]: print 'Capit\xc3\xa1n\n'.decode('string_escape') Capitánрезультатом является строка, закодированная в UTF-8, где символ с ударением представлен двумя байтами, которые были записаны
\xc3\xa1в исходной строке. Если вы хотите иметь строка Юникода, которую вы должны декодировать снова с помощью UTF-8.для редактирования: у вас нет UTF-8 в вашем файле. Чтобы увидеть, как это будет выглядеть:
s = u'Capit\xe1n\n' sutf8 = s.encode('UTF-8') open('utf-8.out', 'w').write(sutf8)сравните содержимое файла
utf-8.outк содержимому файла, сохраненного с помощью редактора.
вместо того, чтобы возиться с методами кодирования и декодирования, мне проще указать кодировку при открытии файла. Элемент
ioмодуль (добавлено в Python 2.6) обеспечиваетio.openфункция, которая имеет параметр кодирования.используйте метод open из
ioмодуль.>>>import io >>>f = io.open("test", mode="r", encoding="utf-8")затем после вызова функции read() f возвращается закодированный объект Unicode.
>>>f.read() u'Capit\xe1l\n\n'обратите внимание, что в Python 3, то . Встроенная функция open поддерживает только аргумент кодирования в Python 3, а не Python 2.
Edit: ранее этот ответ рекомендовал кодеки модуль. Элемент модуль кодеков может вызвать проблемы при смешивании
read()иreadline(), так что этот ответ сейчас рекомендует io модуль.используйте метод open из кодеков модуль.
>>>import codecs >>>f = codecs.open("test", "r", "utf-8")затем после вызова функции read() f возвращается закодированный объект Unicode.
>>>f.read() u'Capit\xe1l\n\n'если вы знаете кодировку файла, использование пакета кодеков будет гораздо менее запутанным.
Теперь все, что вам нужно в Python3 это
open(Filename, 'r', encoding='utf-8')[редактирование на 2016-02-10 для запрашиваемого разъяснения]
Python3 добавил кодирование параметр к своей открытой функции. Здесь собрана следующая информация о функции open:https://docs.python.org/3/library/functions.html#open
open(file, mode='r', buffering=-1, encoding=None, errors=None, newline=None, closefd=True, opener=None)кодировка-это имя кодировки, используемой для декодирования или кодирования файл. Это должно быть используется только в текстовом режиме. Кодировку по умолчанию зависит от платформы (что угодно locale.getpreferredencoding () возвращает), но любой кодировка текста поддерживается Python может быть использован. Смотрите кодеки модуль для списка поддерживаемых кодировок.
добавить
encoding='utf-8'в качестве параметра для функции open чтение и запись файла выполняется как utf8 (который также является кодировкой по умолчанию для всего, что сделано в Питон.)
Итак, я нашел решение для того, что я ищу, а именно:
print open('f2').read().decode('string-escape').decode("utf-8")есть некоторые необычные кодеки, которые полезны здесь. Это конкретное чтение позволяет взять представления UTF-8 из Python, скопировать их в файл ASCII и прочитать их в Unicode. При декодировании "string-escape" косые черты не будут удвоены.
Это позволяет для рода туда и обратно, что я представлял.
на самом деле, это работает для меня для чтения файла с кодировкой UTF-8 в Python 3.2:
import codecs f = codecs.open('file_name.txt', 'r', 'UTF-8') for line in f: print(line)
# -*- encoding: utf-8 -*- # converting a unknown formatting file in utf-8 import codecs import commands file_location = "jumper.sub" file_encoding = commands.getoutput('file -b --mime-encoding %s' % file_location) file_stream = codecs.open(file_location, 'r', file_encoding) file_output = codecs.open(file_location+"b", 'w', 'utf-8') for l in file_stream: file_output.write(l) file_stream.close() file_output.close()
читать в строку, а затем отправить в HTML, я сделал это:
fileline.decode("utf-8").encode('ascii', 'xmlcharrefreplace')полезно для серверов HTTP с питанием от python.
за исключением
codecs.open()можно использоватьio.open()для работы с Python2 или Python3 для чтения / записи файла unicodeпример
import io text = u'á' encoding = 'utf8' with io.open('data.txt', 'w', encoding=encoding, newline='\n') as fout: fout.write(text) with io.open('data.txt', 'r', encoding=encoding, newline='\n') as fin: text2 = fin.read() assert text == text2
Ну, ваш любимый текстовый редактор не понимает, что
\xc3\xa1должны быть символьные литералы, но воспринимает их как текст. Вот почему вы получаете двойную обратную косую черту в последней строке - теперь это настоящая обратная косая черта +xc3и т. д. в вашем файле.Если вы хотите читать и писать зашифрованные файлы в Python, лучше использовать кодеки модуль.
вставка текста между терминалом и приложений, сложно, потому что вы не знаете, какая программа будет интерпретировать ваш текст, используя какую кодировку. Вы можете попробовать следующее:
>>> s = file("f1").read() >>> print unicode(s, "Latin-1") Capitánзатем вставьте эту строку в свой редактор и убедитесь, что он хранит ее с помощью Latin-1. В предположении, что буфер обмена не искажает строку, поездка туда и обратно должна работать.
вы наткнулись на общую проблему с кодировками: как я могу сказать, в какой кодировке находится файл?
ответ: Вы не можете если формат файла предусматривает это. XML, например, начинается с:
<?xml encoding="utf-8"?>этот заголовок был тщательно выбран, чтобы его можно было прочитать независимо от кодировки. В вашем случае такого намека нет, поэтому ни ваш редактор, ни Python не знают, что происходит. Поэтому вы должны использовать
codecsмодуль и использованиеcodecs.open(path,mode,encoding)который обеспечивает недостающий бит в Python.Что касается вашего редактора, вы должны проверить, предлагает ли он какой-либо способ установить кодировку файла.
смысл UTF-8 заключается в том, чтобы кодировать 21-битные символы (Unicode) как 8-битный поток данных (потому что это единственное, что могут обрабатывать все компьютеры в мире). Но поскольку большинство ОС предшествуют эпохе Unicode, у них нет подходящих инструментов для прикрепления информации о кодировке к файлам на жестком диске диск.
следующая проблема-это представление в Python. Это прекрасно объясняется в комментарий от heikogerlach. Вы должны понимать, что ваша консоль может отображать только ASCII. Чтобы отобразить Unicode или что-либо >= charcode 128, он должен использовать некоторые средства экранирования. В редакторе вы не должны вводить экранированную строку отображения, но то, что означает строка (в этом случае вы должны ввести umlaut и сохранить файл).
что сказал, Вы можете использовать функция Python eval () для преобразования экранированной строки в строку:
>>> x = eval("'Capit\xc3\xa1n\n'") >>> x 'Capit\xc3\xa1n\n' >>> x[5] '\xc3' >>> len(x[5]) 1как вы можете видеть, строка "\xc3 " была превращена в один символ. Теперь это 8-битная строка в кодировке UTF-8. Чтобы получить Юникод:
>>> x.decode('utf-8') u'Capit\xe1n\n'Грегг Линд спросил: я думаю, что здесь не хватает некоторых частей: файл f2 содержит: hex:
0000000: 4361 7069 745c 7863 335c 7861 316e Capit\xc3\xa1n
codecs.open('f2','rb', 'utf-8'), например, читает их все в отдельных символах (ожидается) есть ли способ написать в a файл в ASCII, который будет работать?ответ: зависит от того, что вы имеете в виду. ASCII не может представлять символы > 127. Поэтому вам нужно каким-то образом сказать: "следующие несколько символов означают что-то особенное", что и делает последовательность "\x". Он говорит: следующие два символа-это код одного символа. "\u " делает то же самое, используя четыре символа для кодирования Unicode до 0xFFFF (65535).
поэтому вы не можете напрямую писать Unicode в ASCII (потому что ASCII просто не содержит те же символы). Вы можете записать его как экранирование строки (как в f2); в этом случае файл может быть представлен как ASCII. Или вы можете написать его как UTF-8, и в этом случае вам нужен 8-битный безопасный поток.
ваше решение с помощью
decode('string-escape')работает, но вы должны знать, сколько памяти вы используете: в три раза больше, чем использованиеcodecs.open().помните, что файл-это просто последовательность байтов по 8 бит. Ни биты, ни байты не имеют значения. Это ты говоришь " 65 означает "А". Так как
\xc3\xa1должно стать "à", но компьютер не имеет средств, чтобы знать, вы должны сказать это, указав кодировку, которая была использована при записи файла.
\х.. последовательность-это то, что характерно для Python. Это не универсальная байтовая escape-последовательность.
Как вы на самом деле входите в UTF-8-encoded non-ASCII зависит от вашей ОС и/или вашего редактора. вот как вы это делаете в Windows. Для OS X ввести a С острым акцентом Вы можете просто ударить опции + E, потом A, и почти все текстовые редакторы в OS X поддерживают UTF-8.
вы также можете улучшить оригинал
open()функция для работы с файлами Unicode, заменив его на месте, используя
Я пытался разобрать iCal использование Python 2.7.9:
из календаря импорта icalendar
, но я получаю:
Traceback (most recent call last): File "ical.py", line 92, in parse print "{}".format(e[attr]) UnicodeEncodeError: 'ascii' codec can't encode character u'\xe1' in position 7: ordinal not in range(128)а всего:
print "{}".format(e[attr].encode("utf-8"))(теперь он может печатать как A böss.)
Comments