.. _unicode: 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 *byte*\ a 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 neka pretvaranja iz normalizacije u normalizaciju mogu biti ireverzibilna. Više na: - http://www.dabeaz.com/python3io/MasteringIO.pdf - http://en.wikipedia.org/wiki/UTF-8 - http://www.joelonsoftware.com/articles/Unicode.html - https://docs.python.org/3/howto/unicode.html - https://www.pythonsheets.com/notes/python-unicode.html Da bi se omogućio rad s UTF-8 u pythonu potrebno je: #. u editoru to odabrati kao opciju. #. u samim python 2 programima dodati liniju koja označava da je kodiranje koje se koristi UTF-8. u pythonu 3 UTF-8 je default pa to nije potrebno. U pythonu 3 nazivi varijabli mogu biti unicode znakovi, u pythonu 2 ne mogu. (Više na https://stackoverflow.com/a/46001544/2866169) Sadržaj varijabli može biti niz unicode znakova i u pythonu 2 i u pythonu 3, ali postoje razlike: .. tabularcolumns:: p{ 1.6514559983395598in } p{ 1.6514559983395598in } p{ 1.6514559983395598in } p{ 1.6514559983395598in } .. list-table:: :header-rows: 1 * - Sadržaj niza - Python 2 - Python 3 - Ispis * - Byteovi - Tip ``str``; unosi se pomoću "..."; dopušteno "č" - Tip ``bytes``; unosi se pomoću b"..." (potreban prefiks b); zabranjeno b"č" - Prilikom ispisa python 2 pretvara niz byteova u niz unicode znakova. Python 3 ne pretvara niz byteova u unicode znakove nego samo ispisuje byteove. * - Unicode znakovi - Tip ``unicode``; unosi se pomoću u"..." (potreban prefiks u); dopušteno u"č" - Tip ``str``; unosi se pomoću "..."; dopušteno "č" - U obje verzije pythona ispisuju se kao unicode znakovi U verziji 3 razlikuju se nizovi byteova od nizova unicode znakova. U pythonu 2 ta distinkcija nije bila toliko izražena jer se (kao što vidimo u tablici) prilikom ispisa byteovi pokušaju ispisati kao unicode znakovi. U pythonu 2 zbunjuje što je i u unicode stringove i u nizove byteova dopušteno upisati unicode znakove. **U pythonu 3 je situacija pojednostavljena: nizovi byteova su uvijek byteovi, stringovi su uvijek nizovi unicode znakova.** Da bi se izbjegle moguće zabune u pythonu 3 je zabranjeno u nizove byteova direktno upisivati unicode znakove ako ih se nije prethodno kodiralo pomoću :meth:`str.encode`. U pythonu 3 stringovi su nizovi unicode kodova. Za određeni string i kodnu stranicu, pomoću :meth:`str.encode` možemo dobiti niz byteova koji taj string predstavlja. Za određeni niz byteova i kodnu stranicu, pomoću :meth:`bytes.decode` možemo dobiti niz unicode znakova koji je predstavljen tim byteovima. .. literalinclude:: un01b.py :language: python .. literalinclude:: un01b.py.filtered :language: text Razna kodiranja istog unicode znaka daju različite nizove byteova: .. literalinclude:: un04.py :language: python .. literalinclude:: un04.py.filtered :language: text Umjesto ``'č'.encode('utf8')`` mogli smo koristiti ``bytes('č','utf8')`` ili samo ``'č'.encode()`` jer je ``'utf8'`` default za :meth:`str.encode` u pythonu 3. Popis kodiranja koje python podržava: https://docs.python.org/3/library/codecs.html#standard-encodings Ako radimo s tekstualnom datotekom a ona nije u UTF-8 kodiranju, u pravilu je potrebno otvoriti takvu datoteku navodeći argument ``encoding=...`` prilikom pozivanja funkcije :func:`open`. (Drugi način bi bio pročitati je kao binarnu a zatim koristiti :meth:`bytes.decode`.) Na nekim operativnim sustavima nazivi datoteka su nizovi byteova (linux), a na nekim su nizovi unicode znakova (Windows). U slučaju da je naziv datoteke niz byteova koji se ne može "ispravno" dekodirati u niz unicode znakova (jer je kodiran u drugoj kodnoj stranici, ili je to proizvoljni niz byteova koji ne predstavlja unicode znakove) unicode zapis se komplicira (vidi https://www.python.org/dev/peps/pep-0383). Tada postoji mogućnost otvaranja datoteke pomoću naziva predstavljenog nizom byteova ``open(b'naziv.dat',...)``. Za detalje pogledati: http://www.dabeaz.com/python3io/MasteringIO.pdf Modul :mod:`unicodedata` nam može dati podatke o pojedinom unicode znaku: .. literalinclude:: un02.py :language: python .. literalinclude:: un02.py.filtered :language: text Promjenom normalizacije možemo prebaciti prikaz npr. sa č na c + kvačica: .. literalinclude:: un05.py :language: python .. literalinclude:: un05.py.filtered :language: text Na sličan način možemo prebaciti npr. znak № u slova od kojih se on sastoji N i o: .. literalinclude:: un06.py :language: python .. literalinclude:: un06.py.filtered :language: text