Уведомления

Группа в Telegram: @pythonsu

#1 Янв. 28, 2015 11:06:24

moskitos80
От: Luna
Зарегистрирован: 2015-01-28
Сообщения: 18
Репутация: +  0  -
Профиль  

Вывод юникода из файла

Здравствуйте Всем.

Помогите новичку разобраться (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)        # отобразить постранично содержимое
                                                    # файла, указанного в командной строке

То все ок. Может кто-нибудь объяснить почему так происходит?

Отредактировано moskitos80 (Янв. 28, 2015 11:17:15)

Офлайн

#2 Янв. 28, 2015 14:18:17

alex925
Зарегистрирован: 2015-01-08
Сообщения: 204
Репутация: +  14  -
Профиль   Отправить e-mail  

Вывод юникода из файла

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

В общем запомни на будущие, всегда явно указывай кодировку файла и тогда, твои скрипты будут кроссплатформенными и не будет ни каких неожиданностей.
open('file.txt', encoding='utf8')

Отредактировано alex925 (Янв. 28, 2015 14:23:01)

Офлайн

#3 Янв. 28, 2015 16:42:39

moskitos80
От: Luna
Зарегистрирован: 2015-01-28
Сообщения: 18
Репутация: +  0  -
Профиль  

Вывод юникода из файла

Спасибо alex925 по твоей наводке начал рыть в сторону системных кодировок и пр. в процессе наткнулся на интересный пост на хабре: Как я боролся с кодировками в консоли

Офлайн

#4 Янв. 29, 2015 03:01:33

py.user.next
От:
Зарегистрирован: 2010-04-29
Сообщения: 10015
Репутация: +  857  -
Профиль   Отправить e-mail  

Вывод юникода из файла

moskitos80
в процессе наткнулся на интересный пост на хабре
тот пост
Всё ниженаписанное применимо к Python 2.x ветке

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

В третьем питоне:
1) Файлы нужно открывать через with.
2) При открытии в текстовом режиме нужно всегда указывать кодировку. (Можно не указывать только тогда, когда файл в ascii.)



Офлайн

#5 Янв. 29, 2015 11:22:22

alex925
Зарегистрирован: 2015-01-08
Сообщения: 204
Репутация: +  14  -
Профиль   Отправить e-mail  

Вывод юникода из файла

py.user.next
Можно не указывать только тогда, когда файл в ascii.
Это только если работаешь в windows

Офлайн

#6 Янв. 29, 2015 11:23:00

alex925
Зарегистрирован: 2015-01-08
Сообщения: 204
Репутация: +  14  -
Профиль   Отправить e-mail  

Вывод юникода из файла

moskitos80
в процессе наткнулся на интересный пост на хабре: Как я боролся с кодировками в консоли
Это все не то и из другой степи.

Офлайн

#7 Янв. 29, 2015 14:11:46

py.user.next
От:
Зарегистрирован: 2010-04-29
Сообщения: 10015
Репутация: +  857  -
Профиль   Отправить e-mail  

Вывод юникода из файла

alex925
py.user.next
Можно не указывать только тогда, когда файл в ascii.
Это только если работаешь в windows
Если файл в ascii, можно нигде не указывать кодировку, потому что символы ascii отстаются неизменными во всех (на сегодняшний день) кодировках.



Отредактировано py.user.next (Янв. 29, 2015 14:12:12)

Офлайн

#8 Янв. 29, 2015 14:16:04

alex925
Зарегистрирован: 2015-01-08
Сообщения: 204
Репутация: +  14  -
Профиль   Отправить e-mail  

Вывод юникода из файла

py.user.next
А, ты об этом. Да, я прогнал маленько, о другом подумал.

Офлайн

Board footer

Модераторировать

Powered by DjangoBB

Lo-Fi Version