Comments 53
Годная, полезная статья.
Я бы еще раскрыл тему как читать/писать юникодные файлы: codecs.open вместо file() и про PEP 0263.
по поводу файлов

#! /usr/bin/env python
# -*- coding: utf-8 -*-

операции с файлами становятся уникодными=)

ну еще со строками магия проходит вроде
регулярки работают
m=re.match('^(第)([0-9]+)(届|期)',s)

Как практика показывает, входные данные лучше отгонять в UTF-8
тогда проблемы вроде того что одни и теже данные python, c++ и так далее не сильно актуальные…
Отдельно надо выделить если происходят операции за Базой данных тут кодировки тоже важно…

З.Ы каждый программист должен начинать новый язык с UTF-8 / Unicode :) решать вопрос чтобы устойчивая программа была к любым символам
Не операции становятся уникодными, а исходный текст скрипта :).
Файлы [данных] все же придется читать и декодировать руками.

> входные данные лучше отгонять в UTF-8

Ни в коем случае! UTF-8 — это внешнее представление. Входные данные надо отгонять в юникод, со всеми строками работать только в юникоде, а сохранять снова в UTF-8. Кстати, в C++ c UTF-8 вообще можно повеситься (ну или забыть работу со строками).
Насчет входных файлов соглашусь…

У меня просто все данные в UTF-8, входные из файлов поэтому работает 2.6/2.7
Внешение представление в UTF-8 спасает…

UTF-8 для символов a-z 1byte если идет кирилица А_Я и так далее 2 byte.

С точки зрения C/C++ когда strlen(ansi) = 10 с точки зрения strlen(utf-8) 10 длина не понятна(может символы 1 +2 +2 +2 +1+1 ).

Если код не ориентирован на чёткий поиск, а склейка строк то strcpy/strcat можно пользовать…

з.ы. пора тему Unicode / UTF-8/ UTF-16 как курс или пособие, обобщение для разных языков…
Что полезного сделали вы для хабрсообщества, чтоб его критиковать?
Это вы зря. Мне недавно пришла идея автоматического пополнения словаря с использованием нейронной сети. Идея не нова, просто самообучался. Столкнулся с проблемой кодировки, перерыл полинтернета. Нашел ответы на вопросы, но все очень разрозненно, плюс умные люди помогли, теория все равно осталась мне не понятна. А это фактически единственная статья в рунете, которая все раскладывает по полочкам.
Не знаю, столкнулся с юникодом в джанге, нашел решение за 5 минут. А в статье дикая мешанина из того, что такое юникод и работа с кодировками отличными от ascii в питоне.
ru.wikipedia.org/wiki/%D0%AE%D0%BD%D0%B8%D0%BA%D0%BE%D0%B4

кстати, по работе с кодировками по ссылке есть все в одном месте (например в self.статье про ignore, replace всего одна строчка, а в доках масса примеров и даже BOM упомянут :)):
docs.python.org/howto/unicode.html
Непонятно, чем «символы» отличаются от байтов. В конечном счете они все равно хранятся как любая другая информация в памяти — как байты. Поясните разницу.
Символ — это, например, «CYRILLIC SMALL LETTER A», а байт — это нолики и еденицы, например '\xe0'. Для того, что б байт стал символом, необходима кодировка. И в зависимоти от кодировки, этот байт (или байты) может представлять разные символы.
Я и сказал «чем символы отличаются от байтов?» а не «чем символ отличается от байта?».
Я понимаю, что символ может быть больше байта, я не понимаю вот это «не обязательно».
То есть в юникоде разные символы имеют разный размер? Вообще что можно почитать по этому поводу. поменьше и попроще, чем стандарт?
В Unicode определяются code points. Но code point — это число + название, он не задаёт байты. Для того, чтобы преобразовать последовательность code points в байты, вам нужно выбрать некоторый Unicode Transfotmation Format (UTF) и закодировать в соответствии с его правилами.
Да, но число — разве оно и не есть эти самые байты? А названия — разве не однозначно соответствуют числам?
Нет, число — это просто целое число. Оно может быть закодировано в виде байт (причём правила различны в зависимости от UTF, и ещё и не всеми битами этих байтов).
Похоже что косяки машинного перевода немного накладывает отпечаток…
...«Хорошо, я понял чем есть строка.»…

А так по логике вещей показалось странным, что:
байты в Unicode — это кодирование
а Unicode в батый — это де-кодирование

интуитивно хочется наоборот… хотя смысл, понятен, и зависит от того что-во-что кодировать и следовательно де-кодировать
А мне именно такая логика кажется естественной.
У символа есть «код», мы получаем код из символа декодированием оного.
Нет, это просто стиль такой выбран. А вобще автор совсем не русско-говорящий :)

>> интуитивно хочется наоборот

дык на самом деле и есть наоборот — байты в Unicode — это декодирование.
"string".decode('ascii') # декодируем в  юникод
u"string".encode('ascii') # переводим юникод в кодировку ascii


Все как раз наоборот
>>
На данный момент в Юникод-стандарте есть немного более 100 тысяч символов, тогда как UTF-16 позволяет поддерживать более одного миллиона (UTF-8 — и того больше).


На сколько я понимаю, UTF-16 может кодировать максимум 65 535 символов. Возможно, вы ошиблись?
Тогда UTF-8 кодирует 255 символов?

Нет. «16» в UTF-16 означает размер используемого слова: каждый code point в UTF-16 кодируется одним или более 16-битными словами.
Да, вы правы. Принцип работы UTF-16 аналогичен UTF-8 с разницей лишь в размере слова.

До этого момента я свято верил в то, что wchar_t в Windows — это UTF-16. Оказывается, это UCS-2 — строго 16-битная кодировка без возможности расширения до 32 бит.
16 в названии совсем не значит, что используются 16 бит\2 байта\65 535 доступных комбинаций. Деталей кодировки не знаю, число взял сами знаете откуда. Посмотреть детали думаю можно там же (пока не закрыли в знак протеста против SOPA:) )
Согласно Вики и в UTF-8 и в UTF-16 равное число возможных символов — 1,112,064
Совершенно верно. Но можно расширить по аналогии правила построения UTF-8 на более длинные последовательности и получить так называемые overlong sequences. Хотя в стандарте прямо написано, что они ошибочны, к сожалению некоторые «хакеры» считают, что они выше стандарта и говорят, что в UTF-8 больше кодов, чем написано в стандарте, да ещё и реализуют их поддержку в своих программах (например, в eglibc bugs.debian.org/cgi-bin/bugreport.cgi?bug=555922 ).

И да, не называйте юникодные code points символами. Не каждый code point можно нарисовать в виде символа и даже есть такие code points, которые называются noncharacters. См. также en.wikipedia.org/wiki/Mapping_of_Unicode_characters
ммм… Code point. Пасиб, проще с такой терминологией работать.
Какой-то русский аналог у этого названия есть?
прочитал ссылку на баг в eglibc. мдааа…
Ещё один кейс на проверку в программах (я тестировщик). Правда не очень понятно кого винить потом проблеме — своих разработчиков, или разработчиков билиотеки которую они использовали.
Особенно «порадовал» комментарий — «Nobody has ever shown any evidence why this is a bad idea.»
Стандарты видимо люди тоже просто так придумывали…
> в тоже время в кодировке ISO-8859-1 это греческая "ß".
В ISO-8859-1 нет греческих букв. Это немецкая Eszett. (на правах занудства)
Хорошая статья, советую еще раскрыть тему локалей, без этого материал неполный.

Жаль что не смотря на теорию проблема кодировок это сверхбольное место питона, которое каждый раз съедает у меня массу сил и времени. Заткнулся какой ни будь встроенный модуль для работы с gzip на русскоязычных именах файлах и рабочий день коту под хвост.

В python 3000 демонстрировать особо нечего, для самого питона проблема решена на корню как в java, все строки — юникод, на практике ад с портированием библиотек и, имхо, эта ветка сдохнет и на ее место доэволюционирует 2.x, х/з как при этом решится проблема со строками.
Помер как раз 2.х
3.3 выкатят к осени.
Трудности с портированием есть, но «адом» я их не назову.
Честно говоря, до этой статьи я понимал что такое кодировки и как с ними работать.
Очень тяжелая статья для новичков, которая лишь внесет кашу в головы.
Увидел сначала сколько букв — испугался.
Когда осилил, понял, что не так уж и много. Читается нормально.
Полезная статья!
Нужная статья, основная полезность направление decode / encode.
Некоторая мнемоника:
1. Для себя сделал ассоциации типа decode более тяжелое по звучанию соответственно создает тяжелый utf,
encode легкое создает легковесный байт.
2. Байты это непонятный код, который чтобы увидеть надо декодировать в символы (utf), а чтобы символы превратить в код (т.е. байты), их соответственно нужно закодировать (encode).
На виндах у петона вечные проблемы с юникодом, что у третьего, что у второго. На линуксе с этим проще.
Да и не только с юникодом.
Да, я по это причине все пытаюсь переползти на макось но пока не складывается.
не волнуйтесь, в линуксе тоже есть вечные проблемы с вводом/выводом изнутри библиотек.
например, stderr направленный в файл — работает, а на консоль — падает, а на appengine — генерит servererror.
Правильно ли я понимаю, что если везде и всюду в константах и на входе программы будет только юникод (вместо байтстрок) — это избавит от проблем вида «UnicodeDecodeError» в крайне неожиданных местах?
(например, от лютых кабздецов, когда appengine-приложение падает в «server error» из-за того, что логгер не может нарисовать лог.)
А в каком формате сам python внутри хранит строки в 2.х и 3.х?
Строки (str)? Естественно, байты char[]
Unicode — платформозависимо, обычно UCS-2(4)
Хотя что понимать под «хранит внутри» — я о памяти запущенной программы.
Меня спасает
# -*- coding: utf-8 -*-
from __future__ import unicode_literals


Таким образом весь текст становится unicode, если не укажете что он b'текст'
Only those users with full accounts are able to leave comments. Log in, please.