Чтение символов из файла в Python

102

В текстовом файле есть строка «Мне это не нравится».

Однако, когда я считываю это в строке, это становится «Я не \ xe2 \ x80 \ x98t как это». Я понимаю, что \ u2018 является представлением "'" в Юникоде. я использую

f1 = open (file1, "r")
text = f1.read()

команда для чтения.

Теперь, возможно ли прочитать строку таким образом, чтобы, когда она считывалась в строке, это было «Мне это не нравится» вместо «Мне это не нравится \ xe2 \ x80 \ x98t вот так»?

Второе редактирование: я видел, как некоторые люди использовали сопоставление для решения этой проблемы, но на самом деле нет встроенного преобразования, которое выполняет такое преобразование ANSI в unicode (и наоборот)?

Гравитон
источник
Некоторые комментарии: Я видел, как некоторые люди используют сопоставление для решения этой проблемы, но на самом деле нет встроенного преобразования, которое выполняет преобразование такого типа из ANSI в Unicode (и наоборот)? Спасибо!
Graviton
Нет, потому что существуют сотни тысяч кодовых точек Unicode. Как бы вы решили, какие символы ASCII должны быть сопоставлены?
Джон Милликин,
2
кстати, ваш текстовый файл сломан! U + 2018 - это «ЛЕВЫЙ ОДИНОЧНЫЙ ЗНАК», а не апостроф (чаще всего U + 0027).
Джон, ваш комментарий неверен, по крайней мере, в общем смысле. iconv lib может использоваться для транслитерации символов Юникода в ascii (даже в зависимости от локали. $ python -c 'print u "\ u2018" .encode ("utf-8")' | iconv -t 'ascii // translit' | xxd 0000000: 270a
дело в том, что вам нужно преобразовать UNICODE в ASCII (а не наоборот).
hasen

Ответы:

158

Ссылка: http://docs.python.org/howto/unicode

Поэтому читать Unicode из файла очень просто:

import codecs
with codecs.open('unicode.rst', encoding='utf-8') as f:
    for line in f:
        print repr(line)

Также можно открывать файлы в режиме обновления, что позволяет читать и писать:

with codecs.open('test', encoding='utf-8', mode='w+') as f:
    f.write(u'\u4500 blah blah blah\n')
    f.seek(0)
    print repr(f.readline()[:1])

РЕДАКТИРОВАТЬ : Я предполагаю, что ваша предполагаемая цель - просто правильно прочитать файл в строке в Python. Если вы пытаетесь преобразовать в строку ASCII из Unicode, тогда на самом деле нет прямого способа сделать это, поскольку символы Unicode не обязательно будут существовать в ASCII.

Если вы пытаетесь преобразовать в строку ASCII, попробуйте одно из следующих действий:

  1. Замените определенные символы Unicode эквивалентами ASCII, если вы хотите обрабатывать только несколько особых случаев, таких как этот конкретный пример

  2. Используйте unicodedataмодуль normalize()и string.encode()метод для преобразования, насколько это возможно, в следующий ближайший эквивалент ASCII (Ссылка https://web.archive.org/web/20090228203858/http://techxplorer.com/2006/07/18/converting- unicode-to-ascii-using-python ):

    >>> teststr
    u'I don\xe2\x80\x98t like this'
    >>> unicodedata.normalize('NFKD', teststr).encode('ascii', 'ignore')
    'I donat like this'
Джей
источник
3
codecsмодуль не обрабатывает универсальный режим новой строки должным образом. Используйте io.open()вместо этого на Python 2.7+ (он построен open()на Python 3).
jfs
15

Следует учесть несколько моментов.

Символ \ u2018 может появляться только как фрагмент представления строки Unicode в Python, например, если вы напишете:

>>> text = u'‘'
>>> print repr(text)
u'\u2018'

Теперь, если вы просто хотите красиво распечатать строку Unicode, просто используйте encodeметод unicode :

>>> text = u'I don\u2018t like this'
>>> print text.encode('utf-8')
I dont like this

Чтобы гарантировать, что каждая строка из любого файла будет читаться как unicode, вам лучше использовать codecs.openфункцию вместо просто open, которая позволяет вам указать кодировку файла:

>>> import codecs
>>> f1 = codecs.open(file1, "r", "utf-8")
>>> text = f1.read()
>>> print type(text)
<type 'unicode'>
>>> print text.encode('utf-8')
I dont like this
DzinX
источник
7

Также можно прочитать закодированный текстовый файл с помощью метода чтения python 3:

f = open (file.txt, 'r', encoding='utf-8')
text = f.read()
f.close()

В этом варианте нет необходимости импортировать дополнительные библиотеки.

Stein
источник
6

Но на самом деле это «мне это не нравится», а не «мне это не нравится». Символ u '\ u2018' - это совершенно другой символ, чем "'" (и визуально должен больше соответствовать' '').

Если вы пытаетесь преобразовать закодированный Unicode в простой ASCII, возможно, вы могли бы сохранить отображение знаков препинания Unicode, которое вы хотели бы перевести в ASCII.

punctuation = {
  u'\u2018': "'",
  u'\u2019': "'",
}
for src, dest in punctuation.iteritems():
  text = text.replace(src, dest)

Однако в юникоде очень много знаков пунктуации , но я полагаю, вы можете рассчитывать на то, что лишь некоторые из них действительно будут использоваться любым приложением, создающим документы, которые вы читаете.

Логан
источник
1
на самом деле, если вы сделаете dict сопоставление порядковых номеров Unicode с порядковыми номерами Unicode ({0x2018: 0x27, 0x2019: 0x27}), вы можете просто передать весь dict в text.translate (), чтобы выполнить всю замену за один раз.
Томас Воутерс,
3

Не говоря уже о том, что ваш текстовый файл поврежден (U + 2018 - это левая кавычка, а не апостроф): iconv можно использовать для транслитерации символов Юникода в ascii.

Вам придется поискать "iconvcodec" в Google, поскольку модуль, похоже, больше не поддерживается, и я не могу найти для него каноническую домашнюю страницу.

>>> import iconvcodec
>>> from locale import setlocale, LC_ALL
>>> setlocale(LC_ALL, '')
>>> u'\u2018'.encode('ascii//translit')
"'"

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

$ xxd foo
0000000: e280 980a                                ....
$ iconv -t 'ascii//translit' foo | xxd
0000000: 270a                                     '.

источник
2

Существует вероятность того, что у вас есть строка, отличная от Unicode, с escape-символами Unicode, например:

>>> print repr(text)
'I don\\u2018t like this'

На самом деле это однажды случилось со мной. Вы можете использовать unicode_escapeкодек для декодирования строки в Unicode, а затем закодировать ее в любой желаемый формат:

>>> uni = text.decode('unicode_escape')
>>> print type(uni)
<type 'unicode'>
>>> print uni.encode('utf-8')
I dont like this
DzinX
источник
1

Это способ Pythons показать вам строки в кодировке Unicode. Но я думаю, вы сможете без проблем распечатать строку на экране или записать ее в новый файл.

>>> test = u"I don\u2018t like this"
>>> test
u'I don\u2018t like this'
>>> print test
I dont like this
ксардии
источник
1

Фактически, U + 2018 - это Unicode-представление специального символа '. Если хотите, вы можете преобразовать экземпляры этого символа в U + 0027 с помощью этого кода:

text = text.replace (u"\u2018", "'")

Кроме того, что вы используете для записи файла? f1.read()должен вернуть строку, которая выглядит так:

'I don\xe2\x80\x98t like this'

Если он возвращает эту строку, файл записывается неправильно:

'I don\u2018t like this'
Джон Милликин
источник
Сожалею! Как вы сказали, он возвращает «Мне не \ xe2 \ x80 \ x98t нравится это»
Graviton
То, что вы видите, «Мне это не нравится \ xe2 \ x80 \ x98t» - это то, что Python назвал бы str. Похоже, это кодировка utf-8 для u'I don't \ u2018t like this ', которая является экземпляром Unicode в Python. Попробуйте вызвать .decode ('utf-8') для первого или .encode ('utf-8') для второго.
Логан,
@hop: упс, забыл ord () возвращает десятичное вместо шестнадцатеричного. Спасибо за улов.
Джон Милликин,