суббота, 22 декабря 2012 г.

Кодирование строк Unicode в Python


Экранированные значения байтов в шестнадцатеричном виде:

\xNN

например:
\xc4
\x84

Экранированные значения символов Unicode из четырех шестнадцатеричных цифр
( 2- байтовые 16 - битные)  коды символов:

\uNNNN

например:
\u00C4

Экранированные значения символов Unicode из восьми шестнадцатеричных цифр
( 4- байтовые 32 - битные)  коды символов:

\UNNNNNNNN

например:
\U000000E8

 Шестнадцатеричное представление ASCII - кодов символов:

O - 4F
R - 52
A - 41
C - 43
L - 4C
E - 45


>>> s = '\x4f\x52\x41\x43\x4c\x45'
>>> s
'ORACLE'
>>>

Символы UNICODE  2-х  байтовые (16- битные):

O - 004F
R - 0052
A - 0041
C - 0043
L - 004C
E - 0045

>>> s = '\u004f\u0052\u0041\u0043\u004c\u0045'
>>> s
'ORACLE'
>>>

Символы UNICODE  4-x  байтовые (32 - битные):

 >>> s = '\U0000004f\U00000052\U00000041\U00000043\U0000004c\U00000045'
>>> s
'ORACLE'
>>>


Кодирование - процесс преобразования строки символов в последовательность простых байтов в соответствии с желаемой кодировкой.

Декодирование - процесс преобразования последовательности байтов в строку символов в соответствии с желаемой кодировкой.


Пример кодирования:

Преобразуем объект типа str (последовательность символов unicode) в объект типа bytes (последовательность байтов, т.е. коротких целых чисел)

>>> s = 'Java'
>>> s.encode()
b'Java'
>>>

Фактически объекты типа bytes, возвращаемые данной операцией кодирования строки символов, в действительности являются последовательностью коротких целых чисел, которые просто выводятся как символы ASCII, когда это возможно.

Так как мы не указали желаемой кодировки, то наши символы были преобразованы в последовательность простых байтов в соответствии с кодировкой по умолчанию:

>>> import sys
>>> sys.platform
'win32'
>>>
>>> sys.getdefaultencoding()
'utf-8'
>>>

А вообще функцию str.encode() следует вызывать явно указывая кодировку:

s.encode('utf-8')


Пример декодирования:

Существует и обратная функция, которая преобразует последовательность простых байтов в строку и на основе объекта типа bytes создает объект типа str.

>>> b = b'Java'
>>> b.decode()
'Java'
>>>

Тут также, если кодировка не указана, то используется по умолчанию.


Существуют еще две функции кодирования и декодирования:

Кодирование:
Функция    bytes(s, encoding)

Декодирование:
Функция    str(b, encoding)

в этих функциях параметр encoding является обязательным.

Первая функция вообще выдаст ошибку, если не указать параметр encoding:

>>> s = 'Java'

>>> bytes(s)
Traceback (most recent call last):
  File "", line 1, in
    bytes(s)
TypeError: string argument without an encoding
>>>


А вторая сработает, но вернет вместо объекта str  строковую форму объекта bytes (это не то, что требуется):

>>> b = b'Java'
>>> str(b)
"b'Java'"
>>>

Используйте эти две функции всегда с параметром encoding:

>>> s = 'Java'
>>> bytes(s, encoding='ascii')
b'Java'
>>>


>>> b = b'Java'
>>> str(b, encoding='ascii')
'Java'
>>>


Еще примеры:

>>> s = 'ORACLE'
>>> s.encode('ascii')
b'ORACLE'
>>>

>>> s.encode('latin-1')
b'ORACLE'
>>>

>>> s.encode('utf-8')
b'ORACLE'
>>>

Объекты типа bytes, в действительности являются последовательностью коротких целых чисел, которые выводятся как символы  ASCII, когда это возможно:

>>> s = 'ORACLE'
>>> s.encode('latin-1')[0]
79
>>>

>>> list(s.encode('latin-1'))
[79, 82, 65, 67, 76, 69]
>>>


Рассмотрим еще несколько примеров:

Кодировка по умолчанию у нас utf-8

Рассмотрим строковый символ 'O'

Его ASCII представление : '\x4f'
Его unicode представление : '\u004f'   или  '\U0000004f'

Данный символ в кодировке по умолчанию (utf-8) будет иметь код в виде байта с целочисленным значением:

>>> ord('O')
79
>>> ord('\x4f')
79
>>> ord('\u004f')
79
>>> ord('\U0000004f')
79
>>>

Как видим, неважно в каком представлении мы передали строковый символ функции ord().
Его код в кодировке utf-8 имеет одно значение.

При декодировании данного байта кода, используя кодировку по умолчанию (utf-8) мы получим представление символа которому соответствует этот код:

>>> chr(79)
'O'
>>>


Еще примеры:

Возьмем любой символ ASCII

>>> s = 'G'
>>>

Его байтовое представление находим так:

>>> s = 'G'

>>> ord(s)
71

>>> hex(71)
'0x47'
>>>

Значит его можно представить:

>>> s = '\x47'
>>> s
'G'
>>> s = '\u0047'
>>> s
'G'
>>> s = '\U00000047'
>>> s
'G'
>>>
>>> s.encode('utf-8')
b'G'
>>>
>>> b = b'G'
>>>
>>> list(b)
[71]
>>>
>>> b.decode('utf-8')
'G'
>>>


Возьмем не ASCII символ:

>>> s = 'Ä'
>>>


Его байтовое представление находим так:

>>> ord(s)
196
>>> hex(196)
'0xc4'
>>>


Значит его можно представить:

>>> s = '\xc4'
>>> s
'Ä'
>>>
>>> s = '\u00c4'
>>> s
'Ä'
>>>
>>> s = '\U000000c4'
>>> s
'Ä'
>>>
>>> s.encode('utf-8')
b'\xc3\x84'
>>>
>>> b = b'\xc3\x84'
>>>
>>> list(b)
[195, 132]
>>>
>>> b.decode('utf-8')
'Ä'
>>>


Возьмем символ  '茶'  (этот символ в китае  означает слово чай)

>>> s = '茶'
>>>
>>> ord(s)
33590
>>> hex(33590)
'0x8336'
>>>

В однобайтовом виде его уже не представить

>>> s = '\u8336'
>>> s
'茶'
>>>
>>> s = '\U00008336'
>>> s
'茶'
>>>
>>> s.encode('utf-8')
b'\xe8\x8c\xb6'
>>>
>>> b = b'\xe8\x8c\xb6'
>>>
>>> list(b)
[232, 140, 182]
>>>
>>> b.decode('utf-8')
'茶'
>>>

Любая строка хранится в памяти компьютера в виде последовательности символов, однако эти символы могут представляться различными способами, в зависимости от того, какой набор символов используется.

Набор символов ASCII - это символы с кодами в диапазоне  от 0 до 127.
(Что позволяет сохранять каждый символ в одном 8-битовом байте, в котором фактически используется только 7 младших байтов)

Некоторые стандарты позволяют использовать все возможные значения 8-битных байтов от 0 до 255, чтобы обеспечить возможность представления специальных символов, отображая их в диапазоне значений от 128 до 255 (за пределами диапазона ASCII).

Один из таких стандартов, известный под названием Latin-1, широко  используется в западной европе.

В некоторых алфавитах так много символов, что нет никакой возможности представить каждый из них одним байтом.

Стандарт Unicode обеспечивает более гибкие возможности.
Каждый символ в строке Unicode может быть представлен несколькими байтами.

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

Для некоторых кодировок процесс преобразования тривиально прост:

в  кодировках ASCII и Latin-1, например, каждому символу соответствует единственный байт, поэтому фактически никакого преобразования не требуется.

Для других кодировок процедура отображения может оказаться намного сложнее и порождать по несколько байтов для каждого символа.

Кодировка UTF-8 позволяет представить широкий диапазон символов, используя схему с переменным числом байтов.

Символы с кодами в диапазоне от 128 до 2047  преобразуются в двухбайтовые последовательности, где каждый байт имеет значение от 128 до 255.

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

Строки с символами ASCII остаются компактными.
Набор ASCII является подмножеством обеих кодировок, Latin-1 и UTF-8.

Все текстовые файлы, состоящие из символов ASCII, будут считаться допустимыми текстовыми файлами с точки зрения кодировки UTF-8, потому что ASCII - это подмножество 7-битных символов в кодировке UTF-8.


С точки зрения программиста на языке Python, кодировки определяются как строки, содержащие названия кодировок.

Язык Python поддерживает примерно 100 различных кодировок.
Полный список можно посмотреть так:

>>> import encodings

>>> help(encodings)

...........................................
...........................................

PACKAGE CONTENTS
    aliases
    ascii
    base64_codec
    big5
    big5hkscs
    bz2_codec
    charmap
    cp037
    cp1006
    cp1026
    cp1140
    cp1250
    cp1251
    cp1252
    cp1253
    cp1254
    cp1255
    cp1256
    cp1257
    cp1258
    cp424
    cp437
    cp500
    cp720
    cp737
    cp775
    cp850
    cp852
    cp855
    cp856
    cp857
    cp858
    cp860
    cp861
    cp862
    cp863
    cp864
    cp865
    cp866
    cp869
    cp874
    cp875
    cp932
    cp949
    cp950
    euc_jis_2004
    euc_jisx0213
    euc_jp
    euc_kr
    gb18030
    gb2312
    gbk
    hex_codec
    hp_roman8
    hz
    idna
    iso2022_jp
    iso2022_jp_1
    iso2022_jp_2
    iso2022_jp_2004
    iso2022_jp_3
    iso2022_jp_ext
    iso2022_kr
    iso8859_1
    iso8859_10
    iso8859_11
    iso8859_13
    iso8859_14
    iso8859_15
    iso8859_16
    iso8859_2
    iso8859_3
    iso8859_4
    iso8859_5
    iso8859_6
    iso8859_7
    iso8859_8
    iso8859_9
    johab
    koi8_r
    koi8_u
    latin_1
    mac_arabic
    mac_centeuro
    mac_croatian
    mac_cyrillic
    mac_farsi
    mac_greek
    mac_iceland
    mac_latin2
    mac_roman
    mac_romanian
    mac_turkish
    mbcs
    palmos
    ptcp154
    punycode
    quopri_codec
    raw_unicode_escape
    rot_13
    shift_jis
    shift_jis_2004
    shift_jisx0213
    tis_620
    undefined
    unicode_escape
    unicode_internal
    utf_16
    utf_16_be
    utf_16_le
    utf_32
    utf_32_be
    utf_32_le
    utf_7
    utf_8
    utf_8_sig
    uu_codec
    zlib_codec


Комментариев нет:

Отправить комментарий