Найти - Пользователи
Полная версия: Вывод юникода из файла
Начало » Python для новичков » Вывод юникода из файла
1
moskitos80
Здравствуйте Всем.

Помогите новичку разобраться (Python 3.4)
Есть такой файл в кодировке utf-8(без BOM) text-data.txt, содержит одну строку:

Привет Мир!

я пытаюсь читать его в текстовом режиме в консоли:
open(r'D:\python\text-data.txt').read()

Получаю: 'Привет РњРёСЂ!'

Если открываю тот же файл в двоичном режиме с последующей декодировкой:

open(r'D:\python\text-data.txt', 'rb').read().decode()

Получаю своё: 'Привет Мир!'

При этом, помнится, у М. Лутца (Изучаем Python 4 изд. стр. 1021 последний абзац) написано:

“Содержимое файлов, открытых в текстовом режиме, интерпретируется
как текст, состоящий из символов Юникода. При этом используется либо
кодировка по умолчанию в соответствии с настройками системы, либо
кодировка, которая была указана явно…”

Так вот я смотрю что системная кодировка у меня:

sys.getdefaultencoding() # utf-8

Вопрос почему при открытии файла в текстовом режиме и кодировке по умолчанию
utf-8 я получаю кракозябры? Оно что таки не работает в случае с файлами?

Просто в более сложном сценарии который имитирует утилиту “more” если попытаться этим сценарием прочитать самого себя:

>>>D:\python\programming1>more.py more.py

то русский текст (в комментах) так вообще вызывает ошибку:

def more(text, num_lines=15):
    lines = text.splitlines()                           # подобно split('\n') но без '' в конце
    while lines:
        chunk = lines[:num_lines]                       # от 0 до 15 линии
        lines = lines[num_lines:]                       # от 15 линии до конца
        for line in chunk:                              # печатаем линии от 0 до 15
            print(line)
        if lines and input('More?') not in ['y', 'Y']:  # Если еще остались линии на ззапрос 'More?'
            break                                       # ответили иначе чем 'y' или 'Y' то на выход
    
if __name__ == '__main__':
    import sys                                      # если запускается как сценарий
    more(open(sys.argv[1]).read(), 10)              # отобразить постранично содержимое
                                                    # файла, указанного в командной строке

- Этот сценарий вылетает с ошибкой:
UnicodeEncodeError: ‘charmap’ codec can't encode character ‘\u0455’ in position 61: character maps to <undefined>

Но вот если убрать комменты на русском, или если делать так:

def more(text, num_lines=15):
    lines = text.splitlines()                           # подобно split('\n') но без '' в конце
    while lines:
        chunk = lines[:num_lines]                       # от 0 до 15 линии
        lines = lines[num_lines:]                       # от 15 линии до конца
        for line in chunk:                              # печатаем линии от 0 до 15
            print(line.decode('utf-8'))
        if lines and input('More?') not in ['y', 'Y']:  # Если еще остались линии на ззапрос 'More?'
            break                                       # ответили иначе чем 'y' или 'Y' то на выход
    
if __name__ == '__main__':
    import sys                                      # если запускается как сценарий
    more(open(sys.argv[1], 'rb').read(), 10)        # отобразить постранично содержимое
                                                    # файла, указанного в командной строке

То все ок. Может кто-нибудь объяснить почему так происходит?
alex925
moskitos80
“Содержимое файлов, открытых в текстовом режиме, интерпретируетсякак текст, состоящий из символов Юникода
Python пытается открыть файл с системной кодировкой. В windows системной кодировкой является cp1251, по этому у тебя возникает ошибка.
Утверждение приведённое тобой выше верно для linux, там utf8 это системная кодировка и ошибки не будет.

В общем запомни на будущие, всегда явно указывай кодировку файла и тогда, твои скрипты будут кроссплатформенными и не будет ни каких неожиданностей.
open('file.txt', encoding='utf8')
moskitos80
Спасибо alex925 по твоей наводке начал рыть в сторону системных кодировок и пр. в процессе наткнулся на интересный пост на хабре: Как я боролся с кодировками в консоли
py.user.next
moskitos80
в процессе наткнулся на интересный пост на хабре
тот пост
Всё ниженаписанное применимо к Python 2.x ветке

moskitos80
начал рыть в сторону системных кодировок
Рыть не надо, это всё обходные варианты.

В третьем питоне:
1) Файлы нужно открывать через with.
2) При открытии в текстовом режиме нужно всегда указывать кодировку. (Можно не указывать только тогда, когда файл в ascii.)
alex925
py.user.next
Можно не указывать только тогда, когда файл в ascii.
Это только если работаешь в windows
alex925
moskitos80
в процессе наткнулся на интересный пост на хабре: Как я боролся с кодировками в консоли
Это все не то и из другой степи.
py.user.next
alex925
py.user.next
Можно не указывать только тогда, когда файл в ascii.
Это только если работаешь в windows
Если файл в ascii, можно нигде не указывать кодировку, потому что символы ascii отстаются неизменными во всех (на сегодняшний день) кодировках.
alex925
py.user.next
А, ты об этом. Да, я прогнал маленько, о другом подумал.
This is a "lo-fi" version of our main content. To view the full version with more information, formatting and images, please click here.
Powered by DjangoBB