Unicode¶
Slova/znakovi su predstavljeni u memoriji pomoću brojeva. To pridruživanje se naziva kodiranje karaktera ili kodna stranica. Primjer je ASCII kôd koji definira kodove od 0-127 (npr. slovo ‘A’ ima kôd 65, slovo ‘B’ 66, itd.)
Slova s kvačicama nisu na tom popisu. Kroz povijest su se slovima s kvačicama dodjeljivali kodovi na više načina:
- umjesto nekih znakova ASCII kôda (0-127), npr.
ČĆĐŠŽ
umjesto^]\[@
, ačćđšž
umjesto~}|{\
. (postoje i druge nacionalne varijante http://en.wikipedia.org/wiki/ISO/IEC_646)- umjesto nekih znakova proširenog ASCII kôda (128-255). (vidi http://en.wikipedia.org/wiki/ISO/IEC_8859)
- unicode: kôd duljine 4 bytea pridružen svakom znaku/slovu iz bilo kojeg pisma (http://en.wikipedia.org/wiki/ISO_10646)
Mana ovog prvog pristupa je da se nije moglo u istom dokumentu imati istovremeno znakove kao \
, [
, {
i slova s kvačicama.
Situaciju donekle ispravlja drugi pristup u kojem također programi moraju znati koji skup kodova (kodna stranica) se koristi.
Treći način (unicode) omogućuje da se za sva pisma koristi ista kodna stranica. Međutim i tu postoji više varijanti zapisa. Razlikuju se po tome koliko se byteova koristi za zapis, kojim redoslijedom, itd., pa postoje tzv.: UCS-2, UCS-4, UTF-16, UTF-32, UTF-8, ...
Trenutno je najpopularniji način kodiranja UTF-8, koji koristi 1-6 byteova za kodiranje jednog znaka (broj byteova varira od znaka do znaka), a unazad je kompatibilan s ASCII standardom (to znači da je svaka ASCII tekst datoteka ujedno i UTF-8 datoteka). Također nikad ne koristi byte nula, tako da se neće nikad umjetno pojaviti null-terminator, pa će stoga funkcije iz C-a kao strcpy()
raditi ispravno. Također, vrijednosti kodova 0-127 se ne koriste za znakove koji zahtijevaju višebyteni zapis što znači da se npr. znak za novi red ne može slučajno pojaviti a to znači da editor koji ne zna da se radi o UTF-8 može točno odrediti koliko ima redaka teksta.
To su sve dobra svojstva u odnosu na ostale načine kodiranja, iako treba biti svjestan da prikaz znaka u UTF-8 (i u ostalim unicode kodiranjima) nije jednoznačan. Npr. slovo č posjeduje vlastiti kôd (NFC normalizacija), ali se č može prikazati kao kôd za c + kôd za kvačicu (NFD normalizacija). Više o normalizacijama na http://stackoverflow.com/a/7934397, http://www.unicode.org/reports/tr15. Dodatna komplikacija je da postoje i nizovi znakova koji kao niz imaju svoj kôd (npr. tri točke), pa neki načini normalizacije mogu biti ireverzibilni.
Više na:
Da bi se omogućio rad s UTF-8 u pythonu potrebno je:
- u editoru to odabrati kao opciju.
- u samim python programima dodati liniju koja označava da je kodiranje koje se koristi UTF-8
U nekim slučajevima je korisno da python interno vodi neki string kao unicode. To se može postići prefixom u
ispred navodnika.
# -*- coding: utf-8 -*-
a = "č"
print a
print repr(a)
a = u"č"
print a
print repr(a)
č
'\xc4\x8d'
č
u'\u010d'
Ako imamo string koji nije interno prikazan kao unicode možemo ga dekodirati iz njegovog kôda u unicode pomoću string.decode()
.
# -*- coding: utf-8 -*-
a = "č"
print repr(a.decode("utf8"))
u'\u010d'
Ako imamo string koji jest interno prikazan kao unicode, možemo ga kodirati u neki drugi kôd pomoću string.encode()
.
# -*- coding: utf-8 -*-
b = u"č"
print repr(b.encode('utf-8'))
print repr(b.encode('ISO-8859-2'))
print repr(b.encode('ISO-8859-16'))
print repr(b.encode('cp852'))
print repr(b.encode('cp1250'))
print repr(b.encode('UTF-32'))
print repr(b.encode('UTF-16'))
'\xc4\x8d'
'\xe8'
'\xb9'
'\x9f'
'\xe8'
'\xff\xfe\x00\x00\r\x01\x00\x00'
'\xff\xfe\r\x01'
Popis kodiranja koje python podržava: https://docs.python.org/2/library/codecs.html#standard-encodings
Na ovaj način, koristeći prvo decode, a zatim encode, možemo promijeniti kodiranje neke tekstualne datoteke. Za tu svrhu postoje i gotovi programi (npr. recode
) (http://stackoverflow.com/questions/64860/best-way-to-convert-text-files-between-character-sets).
Modul unicodedata
nam može dati podatke o pojedinom unicode znaku:
# -*- coding: utf-8 -*-
import unicodedata
a = u"čćžšđ"
for c in a:
print '%04x' % ord(c), "%10s" % repr(c), unicodedata.category(c), unicodedata.name(c)
010d u'\u010d' Ll LATIN SMALL LETTER C WITH CARON
0107 u'\u0107' Ll LATIN SMALL LETTER C WITH ACUTE
017e u'\u017e' Ll LATIN SMALL LETTER Z WITH CARON
0161 u'\u0161' Ll LATIN SMALL LETTER S WITH CARON
0111 u'\u0111' Ll LATIN SMALL LETTER D WITH STROKE
Promjenom normalizacije možemo prebaciti prikaz npr. sa č na c + kvačica:
# -*- coding: utf-8 -*-
import unicodedata
a = u"č"
b = unicodedata.normalize("NFD",a)
print repr(a)
for c in a:
print '%04x' % ord(c), "%10s" % repr(c), unicodedata.category(c), unicodedata.name(c)
print repr(b)
for c in b:
print '%04x' % ord(c), "%10s" % repr(c), unicodedata.category(c), unicodedata.name(c)
u'\u010d'
010d u'\u010d' Ll LATIN SMALL LETTER C WITH CARON
u'c\u030c'
0063 u'c' Ll LATIN SMALL LETTER C
030c u'\u030c' Mn COMBINING CARON
Na sličan način možemo prebaciti npr. znak № u slova od kojih se on sastoji N i o:
# -*- coding: utf-8 -*-
import unicodedata
a = u"№"
b = unicodedata.normalize("NFKC",a)
print repr(a)
for c in a:
print '%04x' % ord(c), "%10s" % repr(c), unicodedata.category(c), unicodedata.name(c)
print repr(b)
for c in b:
print '%04x' % ord(c), "%10s" % repr(c), unicodedata.category(c), unicodedata.name(c)
u'\u2116'
2116 u'\u2116' So NUMERO SIGN
u'No'
004e u'N' Lu LATIN CAPITAL LETTER N
006f u'o' Ll LATIN SMALL LETTER O