Написание текста Unicode в текстовый файл?
Я вытаскиваю данные из документа Google, обрабатываю их и записываю в файл (который в итоге вставлю на страницу Wordpress).
У него есть не-ASCII символы. Как я могу безопасно преобразовать их в символы, которые можно использовать в исходном коде HTML?
В настоящее время я конвертирую все в Unicode по пути, объединяю все это в строку Python, затем делаю:
import codecs
f = codecs.open('out.txt', mode="w", encoding="iso-8859-1")
f.write(all_html.encode("iso-8859-1", "replace"))
В последней строке есть ошибка кодирования:
UnicodeDecodeError: кодек "ascii" не может декодировать байт 0xa0 в позиции 12286: порядковый номер не в диапазоне (128)
Частичное решение:
Этот Python работает без ошибок:
row = [unicode(x.strip()) if x is not None else u'' for x in row]
all_html = row[0] + "<br/>" + row[1]
f = open('out.txt', 'w')
f.write(all_html.encode("utf-8"))
Но затем, если я открою текстовый файл, я вижу много символов, таких как:
Qur’an
Может быть, мне нужно написать что-то, кроме текстового файла?
Ответы
Ответ 1
Сделки исключительно с объектами unicode как можно больше, расшифровывая объекты для юникодов, когда вы их сначала получаете и кодируете по мере необходимости на выходе.
Если ваша строка на самом деле является объектом unicode, вам нужно будет преобразовать ее в строковый объект, закодированный в Юникоде, прежде чем записывать его в файл:
foo = u'Δ, Й, ק, م, ๗, あ, 叶, 葉, and 말.'
f = open('test', 'w')
f.write(foo.encode('utf8'))
f.close()
Когда вы снова прочтете этот файл, вы получите строку в кодировке unicode, которую вы можете декодировать для объекта unicode:
f = file('test', 'r')
print f.read().decode('utf8')
Ответ 2
В Python 2.6+ вы можете использовать io.open()
по умолчанию (builtin open()
) на Python 3:
import io
with io.open(filename, 'w', encoding=character_encoding) as file:
file.write(unicode_text)
Это может быть более удобно, если вам нужно постепенно писать текст (вам не нужно вызывать unicode_text.encode(character_encoding)
несколько раз). В отличие от модуля codecs
, модуль io
имеет правильную универсальную поддержку новых строк.
Ответ 3
Обработка строк в Юникоде уже стандартизирована в Python 3.
- char уже хранятся в Unicode (32-бит) в памяти
-
Вам нужно только открыть файл в UTF-8
(32-битное преобразование Unicode в utf-8 автоматически выполняется из памяти в файл.)
out1 = "(嘉南大圳 ㄐㄧㄚ ㄋㄢˊ ㄉㄚˋ ㄗㄨㄣˋ )"
fobj = open("t1.txt", "w", encoding="utf-8")
fobj.write(out1)
fobj.close()
Ответ 4
Файл, открытый с помощью codecs.open
, представляет собой файл, который принимает данные unicode
, кодирует его в iso-8859-1
и записывает в файл. Однако вы пытаетесь написать не unicode
; вы берете unicode
и кодируете его в iso-8859-1
самостоятельно. Это то, что делает метод unicode.encode
, а результат кодирования строки в Юникоде - это bytestring (a str
type.)
Вы должны либо использовать обычный open()
, либо самостоятельно кодировать юникод, либо (обычно лучше) использовать codecs.open()
, а не сами кодировать данные.
Ответ 5
Предисловие: будет ли ваш зритель работать?
Убедитесь, что ваш просмотрщик/редактор/терминал (однако вы взаимодействуете с вашим кодированным файлом utf-8) можете прочитать файл. Это часто бывает проблемой Windows, например, "Блокнот".
Написание текста Unicode в текстовый файл?
В Python 2 используйте open
из модуля io
(это то же самое, что встроенный open
в Python 3):
import io
Лучшая практика, в общем, использует UTF-8
для записи в файлы (нам даже не нужно беспокоиться о байтовом порядке с utf-8).
encoding = 'utf-8'
utf-8 - это самая современная и универсально используемая кодировка - она работает во всех веб-браузерах, большинстве текстовых редакторов (см. ваши настройки, если есть проблемы) и большинство терминалов/оболочек.
В Windows вы можете попробовать utf-16le
, если вы ограничены просмотром вывода в Notepad (или другом ограниченном просмотре).
encoding = 'utf-16le' # sorry, Windows users... :(
И просто откройте его с помощью диспетчера контекстов и напишите символы юникода:
with io.open(filename, 'w', encoding=encoding) as f:
f.write(unicode_object)
Пример использования многих символов Unicode
Вот пример, который пытается сопоставить все возможные символы шириной до трех бит (4 - это максимальная, но это будет немного далеко) от цифрового представления (в целых числах) до кодированного вывода для печати, а также его имя, если возможно (поместите это в файл с именем uni.py
):
from __future__ import print_function
import io
from unicodedata import name, category
from curses.ascii import controlnames
from collections import Counter
try: # use these if Python 2
unicode_chr, range = unichr, xrange
except NameError: # Python 3
unicode_chr = chr
exclude_categories = set(('Co', 'Cn'))
counts = Counter()
control_names = dict(enumerate(controlnames))
with io.open('unidata', 'w', encoding='utf-8') as f:
for x in range((2**8)**3):
try:
char = unicode_chr(x)
except ValueError:
continue # can't map to unicode, try next x
cat = category(char)
counts.update((cat,))
if cat in exclude_categories:
continue # get rid of noise & greatly shorten result file
try:
uname = name(char)
except ValueError: # probably control character, don't use actual
uname = control_names.get(x, '')
f.write(u'{0:>6x} {1} {2}\n'.format(x, cat, uname))
else:
f.write(u'{0:>6x} {1} {2} {3}\n'.format(x, cat, char, uname))
# may as well describe the types we logged.
for cat, count in counts.items():
print('{0} chars of category, {1}'.format(count, cat))
Это должно выполняться примерно в минуту, и вы можете просмотреть файл данных, и если ваш просмотрщик файлов может отображать Unicode, вы увидите его. Информацию о категориях можно найти здесь. Основываясь на подсчетах, мы, вероятно, можем улучшить наши результаты, исключив категории Cn и Co, у которых нет связанных с ними символов.
$ python uni.py
Он отобразит шестнадцатеричное отображение, category, символ (если не может получить имя, возможно, контрольный символ) и имя символа. например.
Я рекомендую less
в Unix или Cygwin (не печатайте/не катадируйте весь файл на ваш вывод):
$ less unidata
например. будет отображаться аналогично следующим строкам, которые я выбрал из него, используя Python 2 (unicode 5.2):
0 Cc NUL
20 Zs SPACE
21 Po ! EXCLAMATION MARK
b6 So ¶ PILCROW SIGN
d0 Lu Ð LATIN CAPITAL LETTER ETH
e59 Nd ๙ THAI DIGIT NINE
2887 So ⢇ BRAILLE PATTERN DOTS-1238
bc13 Lo 밓 HANGUL SYLLABLE MIH
ffeb Sm → HALFWIDTH RIGHTWARDS ARROW
My Python 3.5 из Anaconda имеет unicode 8.0, я бы предположил, что большинство 3 будет.
Ответ 6
Как печатать символы Unicode в файл:
Сохраните это в файл: foo.py:
#!/usr/bin/python -tt
# -*- coding: utf-8 -*-
import codecs
import sys
UTF8Writer = codecs.getwriter('utf8')
sys.stdout = UTF8Writer(sys.stdout)
print(u'e with obfuscation: é')
Запустите его и выведите файл в файл:
python foo.py > tmp.txt
Откройте tmp.txt и загляните внутрь, вы увидите следующее:
[email protected]:~$ cat tmp.txt
e with obfuscation: é
Таким образом, вы сохранили unicode e с отметкой обфускации на нем в файл.
Ответ 7
Эта ошибка возникает, когда вы пытаетесь закодировать строку, отличную от юникода: она пытается ее декодировать, предполагая ее в простом ASCII. Возможны две возможности:
- Вы кодируете его в bytestring, но поскольку вы использовали codecs.open, метод write ожидает объект unicode. Поэтому вы кодируете его, и он пытается его снова декодировать. Попробуйте:
f.write(all_html)
вместо этого.
- all_html не является, по сути, объектом unicode. Когда вы выполняете
.encode(...)
, он сначала пытается его декодировать.
Ответ 8
В случае записи в python3
>>> a = u'bats\u00E0'
>>> print a
batsà
>>> f = open("/tmp/test", "w")
>>> f.write(a)
>>> f.close()
>>> data = open("/tmp/test").read()
>>> data
'batsà'
В случае записи на python2:
>>> a = u'bats\u00E0'
>>> f = open("/tmp/test", "w")
>>> f.write(a)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
UnicodeEncodeError: 'ascii' codec can't encode character u'\xe0' in position 4: ordinal not in range(128)
Чтобы избежать этой ошибки, вы должны закодировать ее в байты, используя кодеки "utf-8", например так:
>>> f.write(a.encode("utf-8"))
>>> f.close()
и декодировать данные при чтении с использованием кодеков "utf-8":
>>> data = open("/tmp/test").read()
>>> data.decode("utf-8")
u'bats\xe0'
А также, если вы попытаетесь выполнить печать для этой строки, она будет автоматически декодирована с использованием кодеков "utf-8", подобных этой
>>> print a
batsà